11# -*- coding: utf-8 -*-
22#
3- # Copyright (C) 2017, 2020, 2023-2024 Rocky Bernstein
3+ # Copyright (C) 2017, 2020, 2023-2024, 2026 Rocky Bernstein
44# This program is free software: you can redistribute it and/or modify
55# it under the terms of the GNU General Public License as published by
66# the Free Software Foundation, either version 3 of the License, or
@@ -98,7 +98,9 @@ def resolve_location(proc, location) -> Optional[Location]:
9898 # trepan-xpy() which has it's own type of compatible
9999 # Function, that would fail an `inspect.isfunction()`
100100 # test.
101- if hasattr (mod_or_func_or_code , "__code__" ) or hasattr (mod_or_func_or_code , "im_func" ):
101+ if hasattr (mod_or_func_or_code , "__code__" ) or hasattr (
102+ mod_or_func_or_code , "im_func"
103+ ):
102104 offset = - 1
103105 else :
104106 proc .errmsg (msg )
@@ -129,14 +131,18 @@ def resolve_location(proc, location) -> Optional[Location]:
129131 is_address = location .is_address
130132 if inspect .ismodule (mod_or_func_or_code ):
131133 if hasattr (mod_or_func_or_code , "__file__" ):
132- filename = pyficache .resolve_name_to_path (mod_or_func_or_code .__file__ )
134+ filename = pyficache .resolve_name_to_path (
135+ mod_or_func_or_code .__file__
136+ )
133137 filename = proc .core .canonic (filename )
134138 if not lineno :
135139 # use first line of module file
136140 lineno = 1
137141 offset = 0
138142 is_address = False
139- return Location (filename , lineno , is_address , mod_or_func_or_code , offset )
143+ return Location (
144+ filename , lineno , is_address , mod_or_func_or_code , offset
145+ )
140146 else :
141147 msg = f"module '{ location .path } ' doesn't have a file associated with it"
142148
@@ -159,7 +165,6 @@ def resolve_location(proc, location) -> Optional[Location]:
159165 else :
160166 return INVALID_LOCATION
161167
162-
163168 elif location .line_number :
164169 if curframe is None :
165170 proc .errmsg ("Current frame is not set" )
@@ -169,14 +174,37 @@ def resolve_location(proc, location) -> Optional[Location]:
169174 is_address = location .is_address
170175 mod_or_func_or_code = curframe .f_code
171176 if offset is None :
172- code_info , lineinfo = pyficache .code_line_info (filename , lineno , include_offsets = True )
177+ code_info , lineinfo = pyficache .code_line_info (
178+ filename , lineno , include_offsets = True
179+ )
173180 if lineinfo :
174- offset = lineinfo [0 ].offsets [0 ]
175- mod_or_func_or_code_name = lineinfo [0 ].name
176- if mod_or_func_or_code .co_name != mod_or_func_or_code_name :
177- # Breakpoint is in a nested function/method.
178- # Get new code object
179- mod_or_func_or_code = code_info .get (mod_or_func_or_code_name , mod_or_func_or_code )
181+ if location .offset is not None :
182+ # Find the more specific offset.
183+ desired_offset = location .offset
184+ for linegroup in lineinfo :
185+ offset = next (
186+ (
187+ try_offset
188+ for try_offset in linegroup .offsets
189+ if try_offset == desired_offset
190+ ),
191+ None
192+ )
193+ if offset is not None :
194+ break
195+ pass
196+ else :
197+ offset = lineinfo [0 ].offsets [0 ]
198+ proc .msg ("Offset %d not found for line %d; using offset %d instead." %
199+ (location .offset , location .line_number , offset ))
200+
201+ mod_or_func_or_code_name = lineinfo [0 ].name
202+ if mod_or_func_or_code .co_name != mod_or_func_or_code_name :
203+ # Breakpoint is in a nested function/method.
204+ # Get new code object
205+ mod_or_func_or_code = code_info .get (
206+ mod_or_func_or_code_name , mod_or_func_or_code
207+ )
180208 pass
181209 else :
182210 return INVALID_LOCATION
@@ -227,7 +255,9 @@ def resolve_address_location(proc, location) -> Optional[Location]:
227255
228256 try :
229257 # Check if the converted string is a function or instance method
230- if inspect .isfunction (mod_or_func_or_code ) or hasattr (mod_or_func_or_code , "im_func" ):
258+ if inspect .isfunction (mod_or_func_or_code ) or hasattr (
259+ mod_or_func_or_code , "im_func"
260+ ):
231261 pass
232262 else :
233263 proc .errmsg (msg )
@@ -257,13 +287,17 @@ def resolve_address_location(proc, location) -> Optional[Location]:
257287 is_address = location .is_address
258288 if inspect .ismodule (mod_or_func_or_code ):
259289 if hasattr (mod_or_func_or_code , "__file__" ):
260- filename = pyficache .resolve_name_to_path (mod_or_func_or_code .__file__ )
290+ filename = pyficache .resolve_name_to_path (
291+ mod_or_func_or_code .__file__
292+ )
261293 filename = proc .core .canonic (filename )
262294 if not offset :
263295 # use first offset of module file
264296 offset = 0
265297 is_address = True
266- return Location (filename , offset , is_address , mod_or_func_or_code , offset )
298+ return Location (
299+ filename , offset , is_address , mod_or_func_or_code , offset
300+ )
267301 else :
268302 msg = f"module '{ location .path } ' doesn't have a file associated with it"
269303
@@ -304,6 +338,9 @@ def resolve_address_location(proc, location) -> Optional[Location]:
304338 cmdproc = CommandProcessor (d .core )
305339 frame = cmdproc .frame = sys ._getframe ()
306340 cmdproc .setup ()
341+ location = Location (__file__ , 2 , False , None , None )
342+ assert resolve_location (cmdproc , location ) == INVALID_LOCATION
343+
307344 location = Location (__file__ , frame .f_lineno , False , None , frame .f_lasti )
308345 print (resolve_location (cmdproc , location ))
309346 location = Location (__file__ , None , False , "resolve_location" , frame .f_lasti )
0 commit comments