gdb.Frame.name() can return None when GDB cannot determine a frame's function name. and currently pass that value directly to Python's regular expression functions, causing a TypeError. Treat unnamed frames as non-matches. For None, keep walking older frames after encountering an unnamed frame. Add regression tests for both convenience functions. --- This is my first GDB contribution. I used ChatGPT to help investigate the issue and draft an initial version of the patch (it's fairly simple but still worth mentioning). I reviewed, simplified, and tested the final change myself. Tested with: make -C gdb check RUNTESTFLAGS='gdb.python/py-caller-is.exp' gdb/python/lib/gdb/function/caller_is.py | 6 ++++-- gdb/testsuite/gdb.python/py-caller-is.exp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py index bca09590811..a2a5798b914 100644 --- a/gdb/python/lib/gdb/function/caller_is.py +++ b/gdb/python/lib/gdb/function/caller_is.py @@ -80,7 +80,8 @@ class CallerMatches(gdb.Function): if frame is None: return False nframes = nframes - 1 - return re.match(name.string(), frame.name()) is not None + frame_name = frame.name() + return frame_name is not None and re.match(name.string(), frame_name) is not None class AnyCallerIs(gdb.Function): @@ -143,7 +144,8 @@ class AnyCallerMatches(gdb.Function): frame = gdb.selected_frame() name_re = re.compile(name.string()) while nframes >= 0: - if name_re.match(frame.name()) is not None: + frame_name = frame.name() + if frame_name is not None and name_re.match(frame_name) is not None: return True frame = frame.older() if frame is None: diff --git a/gdb/testsuite/gdb.python/py-caller-is.exp b/gdb/testsuite/gdb.python/py-caller-is.exp index d9b826cb6a2..74ee2ae645a 100644 --- a/gdb/testsuite/gdb.python/py-caller-is.exp +++ b/gdb/testsuite/gdb.python/py-caller-is.exp @@ -70,3 +70,23 @@ proc test_all_caller_is_fns { } { } test_all_caller_is_fns + +# Prepend an unnamed frame to the current stack without depending on +# missing symbols in the host's runtime libraries. +gdb_test_multiline "define unnamed frame helper" \ + "python" "" \ + "from unittest.mock import Mock, patch" "" \ + "def check_unnamed_frame(expr):" "" \ + " frame = Mock()" "" \ + " frame.name.return_value = None" "" \ + " frame.older.return_value = gdb.selected_frame()" "" \ + " with patch.object(gdb, 'selected_frame', return_value=frame):" "" \ + " print(int(gdb.parse_and_eval(expr)))" "" \ + "end" "" + +gdb_test {python check_unnamed_frame('$_caller_matches(".*", 0)')} \ + "0" "caller_matches with unnamed frame" +gdb_test {python check_unnamed_frame('$_any_caller_matches(".*", 0)')} \ + "0" "any_caller_matches with unnamed frame" +gdb_test {python check_unnamed_frame('$_any_caller_matches("^bottom_func$", 1)')} \ + "1" "any_caller_matches skips unnamed frame" -- 2.34.1