I wrote a minimal unwinder for libjit. You can see it here: http://lists.gnu.org/archive/html/libjit/2018-01/msg00013.html With an unmodified gdb, this unwinder causes a crash when it asks for the register "rip" in the pending frame. See the (partial) stack trace below. Reverting this patch: commit 33cc7d368f420326606695daafd6292e2779c6af Author: Kevin Buettner <kevinb@redhat.com> Date: Tue Sep 27 22:45:19 2016 -0700 ... fixes the problem for me. That is, no more crash, and my unwinder works. The assert in question is this one: gdb_assert (frame_id_p (get_frame_id (next_frame))); in value_of_register_lazy. (top-gdb) bt #0 0x00000000005e0d00 in internal_error(char const*, int, char const*, ...) (file=0xd76098 "../../binutils-gdb/gdb/frame.c", line=534, fmt=0xca2d0f "%s: Assertion `%s' failed.") at ../../binutils-gdb/gdb/common/errors.c:51 #1 0x00000000006b5477 in get_frame_id(frame_info*) (fi=0x2acd4a0) at ../../binutils-gdb/gdb/frame.c:534 #2 0x00000000006b34c6 in value_of_register_lazy(frame_info*, int) (frame=0x2acd560, regnum=16) at ../../binutils-gdb/gdb/findvar.c:298 #3 0x00000000006b360f in value_of_register(int, frame_info*) (regnum=16, frame=0x2acd560) at ../../binutils-gdb/gdb/findvar.c:274 #4 0x0000000000593ff4 in pending_framepy_read_register(PyObject*, PyObject*) (self=0x7ffff7f5e290, args=<optimized out>) at ../../binutils-gdb/gdb/python/py-unwind.c:402 #5 0x00007ffff668979e in PyEval_EvalFrameEx () at /lib64/libpython2.7.so.1.0 #6 0x00007ffff668a3f8 in PyEval_EvalCodeEx () at /lib64/libpython2.7.so.1.0 #7 0x00007ffff65d97ee in function_call.lto_priv () at /lib64/libpython2.7.so.1.0 #8 0x00007ffff65a2a53 in PyObject_Call () at /lib64/libpython2.7.so.1.0 #9 0x00007ffff65ce88e in instancemethod_call.lto_priv () at /lib64/libpython2.7.so.1.0 #10 0x00007ffff65a2a53 in PyObject_Call () at /lib64/libpython2.7.so.1.0 #11 0x00007ffff665ca2b in slot_tp_call () at /lib64/libpython2.7.so.1.0 #12 0x00007ffff65a2a53 in PyObject_Call () at /lib64/libpython2.7.so.1.0 #13 0x00007ffff6685454 in PyEval_EvalFrameEx () at /lib64/libpython2.7.so.1.0 #14 0x00007ffff668a3f8 in PyEval_EvalCodeEx () at /lib64/libpython2.7.so.1.0 #15 0x00007ffff65d97ee in function_call.lto_priv () at /lib64/libpython2.7.so.1.0 #16 0x00007ffff65a2a53 in PyObject_Call () at /lib64/libpython2.7.so.1.0 #17 0x00007ffff65a4e5f in PyObject_CallFunctionObjArgs () at /lib64/libpython2.7.so.1.0 #18 0x0000000000593940 in pyuw_sniffer(frame_unwind const*, frame_info*, void**) (self=<optimized out>, this_frame=0x2acd560, cache_ptr=0x2acd578) at ../../binutils-gdb/gdb/python/py-unwind.c:539 #19 0x00000000006b915d in frame_unwind_try_unwinder(frame_info*, void**, frame_unwind const*) (this_frame=0x2acd560, this_cache=0x2acd578, unwinder=0x34294b0) at ../../binutils-gdb/gdb/frame-unwind.c:106 #20 0x00000000006b951f in frame_unwind_find_by_frame(frame_info*, void**) (this_frame=0x2acd560, this_cache=0x2acd578) at ../../binutils-gdb/gdb/frame-unwind.c:164
Changing py-unwind.py (in the test suite) did not reproduce the failure, so more investigation needs to be done.
I am having the same issue: using GDB-8.1, installed a python unwinder I created and I get either an assertion failure or a crash (depending on the value of 'show debug frame'): with 1 I get a crash, with 0 I get the assertion failure. The root cause seems to be (when debug frame is 1): static void pyuw_this_id (struct frame_info *this_frame, void **cache_ptr, struct frame_id *this_id) { *this_id = ((cached_frame_info *) *cache_ptr)->frame_id; if (pyuw_debug >= 1) { fprintf_unfiltered (gdb_stdlog, "%s: frame_id: ", __FUNCTION__); fprint_frame_id (gdb_stdlog, *this_id); fprintf_unfiltered (gdb_stdlog, "\n"); } } cache_ptr is NULL hence the crash. The backtrace for the above: (gdb) bt #0 0x00000000006d6723 in pyuw_this_id (this_frame=0x5650d80, cache_ptr=0x5650d98, this_id=0x5650de0) at ../../gdb-8.1/gdb/python/py-unwind.c:461 #1 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x5650d80) at ../../gdb-8.1/gdb/frame.c:505 #2 0x00000000007e026a in get_frame_id (fi=0x5650d80) at ../../gdb-8.1/gdb/frame.c:537 #3 0x00000000007e3535 in get_prev_frame_id_by_id (id=...) at ../../gdb-8.1/gdb/frame.c:2368 #4 0x00000000008ffbe4 in value_fetch_lazy (val=val@entry=0x59550f0) at ../../gdb-8.1/gdb/value.c:3968 #5 0x00000000007de439 in value_of_register (regnum=16, frame=<optimised out>) at ../../gdb-8.1/gdb/findvar.c:275 #6 0x00000000006d64f8 in pending_framepy_read_register (self=0x57d04f0, args=<optimised out>) at ../../gdb-8.1/gdb/python/py-unwind.c:402 #7 0x0000000000ea4828 in call_function (oparg=<optimised out>, pp_stack=0x7fffa1325fe8) at ../Python-2.7.3/Python/ceval.c:4021 #8 PyEval_EvalFrameEx (f=f@entry=0x594f8d0, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #9 0x0000000000ea43e5 in fast_function (nk=0, na=<optimised out>, n=2, pp_stack=0x7fffa13260e8, func=0x58dd410) at ../Python-2.7.3/Python/ceval.c:4107 #10 call_function (oparg=<optimised out>, pp_stack=0x7fffa13260e8) at ../Python-2.7.3/Python/ceval.c:4042 #11 PyEval_EvalFrameEx (f=f@entry=0x5970750, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #12 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x57f6c38, argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python-2.7.3/Python/ceval.c:3253 #13 0x0000000000f14b0c in function_call (func=0x58dd398, arg=0x57f6c20, kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 #14 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x58dd398, arg=arg@entry=0x57f6c20, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #15 0x0000000000e2321f in instancemethod_call (func=0x58dd398, arg=0x57f6c20, kw=0x0) at ../Python-2.7.3/Objects/classobject.c:2578 #16 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x593ed20, arg=arg@entry=0x67a4dd0, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #17 0x0000000000e77935 in slot_tp_call (self=<optimised out>, args=0x67a4dd0, kwds=0x0) at ../Python-2.7.3/Objects/typeobject.c:5403 #18 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x57d60d0, arg=arg@entry=0x67a4dd0, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #19 0x0000000000ea27e5 in do_call (nk=0, na=<optimised out>, pp_stack=0x7fffa1326618, func=0x57d60d0) at ../Python-2.7.3/Python/ceval.c:4239 #20 call_function (oparg=<optimised out>, pp_stack=0x7fffa1326618) at ../Python-2.7.3/Python/ceval.c:4044 #21 PyEval_EvalFrameEx (f=f@entry=0x44af150, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #22 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x37d67e8, argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python-2.7.3/Python/ceval.c:3253 #23 0x0000000000f14b0c in function_call (func=0x3773b90, arg=0x37d67d0, kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 #24 0x0000000000e1afe5 in PyObject_Call (kw=0x0, arg=0x37d67d0, func=0x3773b90) at ../Python-2.7.3/Objects/abstract.c:2529 #25 PyObject_CallFunctionObjArgs (callable=0x3773b90) at ../Python-2.7.3/Objects/abstract.c:2760 #26 0x00000000006d7256 in pyuw_sniffer (self=<optimised out>, this_frame=0x5650d80, cache_ptr=0x5650d98) at ../../gdb-8.1/gdb/python/py-unwind.c:539 #27 0x00000000007e404d in frame_unwind_try_unwinder (this_frame=this_frame@entry=0x5650d80, this_cache=this_cache@entry=0x5650d98, unwinder=0x39aca00) at ../../gdb-8.1/gdb/frame-unwind.c:106 #28 0x00000000007e4427 in frame_unwind_find_by_frame (this_frame=this_frame@entry=0x5650d80, this_cache=this_cache@entry=0x5650d98) at ../../gdb-8.1/gdb/frame-unwind.c:164 #29 0x00000000007e01e3 in compute_frame_id (fi=fi@entry=0x5650d80) at ../../gdb-8.1/gdb/frame.c:501 #30 0x00000000007e026a in get_frame_id (fi=fi@entry=0x5650d80) at ../../gdb-8.1/gdb/frame.c:537 #31 0x00000000008ce65b in scoped_restore_current_thread::scoped_restore_current_thread (this=0x7fffa1326b10) at ../../gdb-8.1/gdb/thread.c:1573 #32 0x00000000008cf564 in print_thread_info_1 (uiout=0x391ff10, requested_threads=requested_threads@entry=0x0, global_ids=global_ids@entry=0, pid=pid@entry=-1, show_global_ids=show_global_ids@entry=0, this=<optimised out>, this=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1250 #33 0x00000000008d0049 in info_threads_command (arg=0x0, from_tty=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1390 #34 0x000000000069db89 in cmd_func (cmd=<optimised out>, args=<optimised out>, from_tty=<optimised out>) at ../../gdb-8.1/gdb/cli/cli-decode.c:1886 #35 0x00000000008d26b1 in execute_command (p=<optimised out>, p@entry=0x3591c20 "info threads ", from_tty=1) at ../../gdb-8.1/gdb/top.c:637 #36 0x00000000007d7a9c in command_handler (command=0x3591c20 "info threads ") at ../../gdb-8.1/gdb/event-top.c:583 #37 0x00000000007d7da8 in command_line_handler (rl=<optimised out>) at ../../gdb-8.1/gdb/event-top.c:774 With debug frame 0 I get an assertion failure: gdb_assert (fi->level == 0); inside get_frame_id() and the backtrace: (gdb) bt #0 0x00007f7aea353428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 #1 0x00007f7aea35502a in __GI_abort () at abort.c:89 #2 0x00000000008e9086 in dump_core () at ../../gdb-8.1/gdb/utils.c:284 #3 0x00000000008ed1dd in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (problem=problem@entry=0x20ff340 <internal_error_problem>, file=<optimised out>, line=<optimised out>, fmt=<optimised out>, ap=ap@entry=0x7ffff3d626b8) at ../../gdb-8.1/gdb/utils.c:493 #4 0x00000000008ed2e9 in internal_verror (file=<optimised out>, line=<optimised out>, fmt=<optimised out>, ap=ap@entry=0x7ffff3d626b8) at ../../gdb-8.1/gdb/utils.c:518 #5 0x000000000070f5f2 in internal_error (file=file@entry=0x10a67d7 "../../gdb-8.1/gdb/frame.c", line=line@entry=534, fmt=<optimised out>) at ../../gdb-8.1/gdb/common/errors.c:55 #6 0x00000000007e031b in get_frame_id (fi=0x4a88fa0) at ../../gdb-8.1/gdb/frame.c:534 #7 0x0000000000816dec in inline_frame_this_id (this_frame=0x4a88ee0, this_cache=<optimised out>, this_id=0x4a88f40) at ../../gdb-8.1/gdb/inline-frame.c:160 #8 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:505 #9 0x00000000007e026a in get_frame_id (fi=fi@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:537 #10 0x00000000007de2d8 in value_of_register_lazy (frame=frame@entry=0x4a88fa0, regnum=regnum@entry=16) at ../../gdb-8.1/gdb/findvar.c:298 #11 0x00000000007de42e in value_of_register (regnum=16, frame=0x4a88fa0) at ../../gdb-8.1/gdb/findvar.c:274 #12 0x00000000006d64f8 in pending_framepy_read_register (self=0x59494f0, args=<optimised out>) at ../../gdb-8.1/gdb/python/py-unwind.c:402 #13 0x0000000000ea4828 in call_function (oparg=<optimised out>, pp_stack=0x7ffff3d629b8) at ../Python-2.7.3/Python/ceval.c:4021 #14 PyEval_EvalFrameEx (f=f@entry=0x4a905e0, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #15 0x0000000000ea43e5 in fast_function (nk=0, na=<optimised out>, n=2, pp_stack=0x7ffff3d62ab8, func=0x4c19410) at ../Python-2.7.3/Python/ceval.c:4107 #16 call_function (oparg=<optimised out>, pp_stack=0x7ffff3d62ab8) at ../Python-2.7.3/Python/ceval.c:4042 #17 PyEval_EvalFrameEx (f=f@entry=0x3c0ef90, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #18 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x596fc80, argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python-2.7.3/Python/ceval.c:3253 #19 0x0000000000f14b0c in function_call (func=0x4c19398, arg=0x596fc68, kw=0x0) ---Type <return> to continue, or q <return> to quit--- :526 #20 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x4c19398, arg=arg@entry=0x596fc68, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #21 0x0000000000e2321f in instancemethod_call (func=0x4c19398, arg=0x596fc68, kw=0x0) at ../Python-2.7.3/Objects/classobject.c:2578 #22 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x4d77d20, arg=arg@entry=0x5bdfe50, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #23 0x0000000000e77935 in slot_tp_call (self=<optimised out>, args=0x5bdfe50, kwds=0x0) at ../Python-2.7.3/Objects/typeobject.c:5403 #24 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x5951150, arg=arg@entry=0x5bdfe50, kw=kw@entry=0x0) at ../Python-2.7.3/Objects/abstract.c:2529 #25 0x0000000000ea27e5 in do_call (nk=0, na=<optimised out>, pp_stack=0x7ffff3d62fe8, func=0x5951150) at ../Python-2.7.3/Python/ceval.c:4239 #26 call_function (oparg=<optimised out>, pp_stack=0x7ffff3d62fe8) at ../Python-2.7.3/Python/ceval.c:4044 #27 PyEval_EvalFrameEx (f=f@entry=0x3a9d380, throwflag=throwflag@entry=0) at ../Python-2.7.3/Python/ceval.c:2666 #28 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x2c067e8, argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at ../Python-2.7.3/Python/ceval.c:3253 #29 0x0000000000f14b0c in function_call (func=0x2ba3b90, arg=0x2c067d0, kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 #30 0x0000000000e1afe5 in PyObject_Call (kw=0x0, arg=0x2c067d0, func=0x2ba3b90) at ../Python-2.7.3/Objects/abstract.c:2529 #31 PyObject_CallFunctionObjArgs (callable=0x2ba3b90) at ../Python-2.7.3/Objects/abstract.c:2760 #32 0x00000000006d7256 in pyuw_sniffer (self=<optimised out>, this_frame=0x4a88fa0, cache_ptr=0x4a88fb8) at ../../gdb-8.1/gdb/python/py-unwind.c:539 #33 0x00000000007e404d in frame_unwind_try_unwinder (this_frame=this_frame@entry=0x4a88fa0, this_cache=this_cache@entry=0x4a88fb8, unwinder=0x2de4ae0) at ../../gdb-8.1/gdb/frame-unwind.c:106 #34 0x00000000007e4427 in frame_unwind_find_by_frame (this_frame=this_frame@entry=0x4a88fa0, this_cache=this_cache@entry=0x4a88fb8) at ../../gdb-8.1/gdb/frame-unwind.c:164 #35 0x00000000007e01e3 in compute_frame_id (fi=fi@entry=0x4a88fa0) at ../../gdb-8.1/gdb/frame.c:501 #36 0x00000000007e0738 in get_prev_frame_if_no_cycle (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:1913 #37 0x00000000007e2757 in get_prev_frame_always_1 (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:2087 #38 0x00000000007e2ccd in get_prev_frame_always (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:2103 #39 0x0000000000816de1 in inline_frame_this_id (this_frame=0x4a88ee0, this_cache=<optimised out>, this_id=0x4a88f40) at ../../gdb-8.1/gdb/inline-frame.c:160 #40 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:505 #41 0x00000000007e026a in get_frame_id (fi=fi@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:537 #42 0x00000000007de9f5 in value_from_register (type=type@entry=0x5acaee0, regnum=regnum@entry=6, frame=frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/findvar.c:938 #43 0x00000000007979fd in dwarf2_evaluate_loc_desc_full (type=0x5acaee0, frame=frame@entry=0x4a88ee0, data=<optimised out>, size=<optimised out>, per_cu=<optimised out>, subobj_type=0x5acaee0, subobj_type@entry=0x0, subobj_byte_offset=0) at ../../gdb-8.1/gdb/dwarf2loc.c:2418 #44 0x00000000007982d3 in dwarf2_evaluate_loc_desc (per_cu=<optimised out>, size=<optimised out>, data=<optimised out>, frame=0x4a88ee0, type=<optimised out>) at ../../gdb-8.1/gdb/dwarf2loc.c:2544 #45 loclist_read_variable (symbol=0x5acb140, frame=0x4a88ee0) at ../../gdb-8.1/gdb/dwarf2loc.c:4456 #46 0x00000000007debe7 in default_read_var_value (var=0x5acb140, var_block=0x0, frame=0x4a88ee0) at ../../gdb-8.1/gdb/findvar.c:612 #47 0x0000000000899637 in read_frame_arg (sym=sym@entry=0x5acb140, frame=frame@entry=0x4a88ee0, argp=argp@entry=0x7ffff3d637d0, entryargp=entryargp@entry=0x7ffff3d637f0) at ../../gdb-8.1/gdb/stack.c:349 #48 0x000000000089a1ad in print_frame_args (func=<optimised out>, frame=frame@entry=0x4a88ee0, num=num@entry=-1, stream=0x2d40090) at ../../gdb-8.1/gdb/stack.c:681 #49 0x000000000089ac65 in print_frame (print_args=<optimised out>, print_what=LOCATION, print_level=-1, frame=0x4a88ee0, sal=...) at ../../gdb-8.1/gdb/stack.c:1203 #50 print_frame_info (frame=frame@entry=0x4a88ee0, print_level=print_level@entry=0, print_what=print_what@entry=LOCATION, print_args=print_args@entry=1, set_current_sal=set_current_sal@entry=0) at ../../gdb-8.1/gdb/stack.c:860 #51 0x000000000089b0c6 in print_stack_frame (frame=0x4a88ee0, print_level=0, print_what=LOCATION, set_current_sal=0) at ../../gdb-8.1/gdb/stack.c:177 #52 0x00000000008cf810 in print_thread_info_1 (uiout=0x2d4ff10, requested_threads=requested_threads@entry=0x0, global_ids=global_ids@entry=0, pid=pid@entry=-1, show_global_ids=show_global_ids@entry=0, this=<optimised out>, this=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1321 #53 0x00000000008d0049 in info_threads_command (arg=0x0, from_tty=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1390 #54 0x000000000069db89 in cmd_func (cmd=<optimised out>, args=<optimised out>, from_tty=<optimised out>) at ../../gdb-8.1/gdb/cli/cli-decode.c:1886 #55 0x00000000008d26b1 in execute_command (p=<optimised out>, p@entry=0x29c1c20 "info threads ", from_tty=1) at ../../gdb-8.1/gdb/top.c:637 #56 0x00000000007d7a9c in command_handler (command=0x29c1c20 "info threads ") at ../../gdb-8.1/gdb/event-top.c:583 It is possible to reproduce the bug with a vanilla gdb-8.1 installation and the unwinder available at: https://github.com/tromey/spidermonkey-unwinder just launch gdb, attach to any running process and type (gdb) info threads
(In reply to Emiliano Testa from comment #2) > I am having the same issue: using GDB-8.1, installed a python unwinder I > created and I get either an assertion failure or a crash (depending on the > value of 'show debug frame'): with 1 I get a crash, with 0 I get the > assertion failure. > > The root cause seems to be (when debug frame is 1): > > > static void > pyuw_this_id (struct frame_info *this_frame, void **cache_ptr, > struct frame_id *this_id) > { > *this_id = ((cached_frame_info *) *cache_ptr)->frame_id; > if (pyuw_debug >= 1) > { > fprintf_unfiltered (gdb_stdlog, "%s: frame_id: ", __FUNCTION__); > fprint_frame_id (gdb_stdlog, *this_id); > fprintf_unfiltered (gdb_stdlog, "\n"); > } > } > > cache_ptr is NULL hence the crash. > > The backtrace for the above: > > (gdb) bt > #0 0x00000000006d6723 in pyuw_this_id (this_frame=0x5650d80, > cache_ptr=0x5650d98, this_id=0x5650de0) at > ../../gdb-8.1/gdb/python/py-unwind.c:461 > #1 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x5650d80) at > ../../gdb-8.1/gdb/frame.c:505 > #2 0x00000000007e026a in get_frame_id (fi=0x5650d80) at > ../../gdb-8.1/gdb/frame.c:537 > #3 0x00000000007e3535 in get_prev_frame_id_by_id (id=...) at > ../../gdb-8.1/gdb/frame.c:2368 > #4 0x00000000008ffbe4 in value_fetch_lazy (val=val@entry=0x59550f0) at > ../../gdb-8.1/gdb/value.c:3968 > #5 0x00000000007de439 in value_of_register (regnum=16, frame=<optimised > out>) at ../../gdb-8.1/gdb/findvar.c:275 > #6 0x00000000006d64f8 in pending_framepy_read_register (self=0x57d04f0, > args=<optimised out>) at ../../gdb-8.1/gdb/python/py-unwind.c:402 > #7 0x0000000000ea4828 in call_function (oparg=<optimised out>, > pp_stack=0x7fffa1325fe8) at ../Python-2.7.3/Python/ceval.c:4021 > #8 PyEval_EvalFrameEx (f=f@entry=0x594f8d0, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #9 0x0000000000ea43e5 in fast_function (nk=0, na=<optimised out>, n=2, > pp_stack=0x7fffa13260e8, func=0x58dd410) at > ../Python-2.7.3/Python/ceval.c:4107 > #10 call_function (oparg=<optimised out>, pp_stack=0x7fffa13260e8) at > ../Python-2.7.3/Python/ceval.c:4042 > #11 PyEval_EvalFrameEx (f=f@entry=0x5970750, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #12 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, > globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x57f6c38, > argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, > defcount=0, closure=0x0) > at ../Python-2.7.3/Python/ceval.c:3253 > #13 0x0000000000f14b0c in function_call (func=0x58dd398, arg=0x57f6c20, > kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 > #14 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x58dd398, > arg=arg@entry=0x57f6c20, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #15 0x0000000000e2321f in instancemethod_call (func=0x58dd398, > arg=0x57f6c20, kw=0x0) at ../Python-2.7.3/Objects/classobject.c:2578 > #16 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x593ed20, > arg=arg@entry=0x67a4dd0, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #17 0x0000000000e77935 in slot_tp_call (self=<optimised out>, > args=0x67a4dd0, kwds=0x0) at ../Python-2.7.3/Objects/typeobject.c:5403 > #18 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x57d60d0, > arg=arg@entry=0x67a4dd0, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #19 0x0000000000ea27e5 in do_call (nk=0, na=<optimised out>, > pp_stack=0x7fffa1326618, func=0x57d60d0) at > ../Python-2.7.3/Python/ceval.c:4239 > #20 call_function (oparg=<optimised out>, pp_stack=0x7fffa1326618) at > ../Python-2.7.3/Python/ceval.c:4044 > #21 PyEval_EvalFrameEx (f=f@entry=0x44af150, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #22 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, > globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x37d67e8, > argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, > defcount=0, closure=0x0) > at ../Python-2.7.3/Python/ceval.c:3253 > #23 0x0000000000f14b0c in function_call (func=0x3773b90, arg=0x37d67d0, > kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 > #24 0x0000000000e1afe5 in PyObject_Call (kw=0x0, arg=0x37d67d0, > func=0x3773b90) at ../Python-2.7.3/Objects/abstract.c:2529 > #25 PyObject_CallFunctionObjArgs (callable=0x3773b90) at > ../Python-2.7.3/Objects/abstract.c:2760 > #26 0x00000000006d7256 in pyuw_sniffer (self=<optimised out>, > this_frame=0x5650d80, cache_ptr=0x5650d98) at > ../../gdb-8.1/gdb/python/py-unwind.c:539 > #27 0x00000000007e404d in frame_unwind_try_unwinder > (this_frame=this_frame@entry=0x5650d80, > this_cache=this_cache@entry=0x5650d98, unwinder=0x39aca00) at > ../../gdb-8.1/gdb/frame-unwind.c:106 > #28 0x00000000007e4427 in frame_unwind_find_by_frame > (this_frame=this_frame@entry=0x5650d80, > this_cache=this_cache@entry=0x5650d98) at > ../../gdb-8.1/gdb/frame-unwind.c:164 > #29 0x00000000007e01e3 in compute_frame_id (fi=fi@entry=0x5650d80) at > ../../gdb-8.1/gdb/frame.c:501 > #30 0x00000000007e026a in get_frame_id (fi=fi@entry=0x5650d80) at > ../../gdb-8.1/gdb/frame.c:537 > #31 0x00000000008ce65b in > scoped_restore_current_thread::scoped_restore_current_thread > (this=0x7fffa1326b10) at ../../gdb-8.1/gdb/thread.c:1573 > #32 0x00000000008cf564 in print_thread_info_1 (uiout=0x391ff10, > requested_threads=requested_threads@entry=0x0, > global_ids=global_ids@entry=0, pid=pid@entry=-1, > show_global_ids=show_global_ids@entry=0, this=<optimised out>, > this=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1250 > #33 0x00000000008d0049 in info_threads_command (arg=0x0, from_tty=<optimised > out>) at ../../gdb-8.1/gdb/thread.c:1390 > #34 0x000000000069db89 in cmd_func (cmd=<optimised out>, args=<optimised > out>, from_tty=<optimised out>) at ../../gdb-8.1/gdb/cli/cli-decode.c:1886 > #35 0x00000000008d26b1 in execute_command (p=<optimised out>, > p@entry=0x3591c20 "info threads ", from_tty=1) at ../../gdb-8.1/gdb/top.c:637 > #36 0x00000000007d7a9c in command_handler (command=0x3591c20 "info threads > ") at ../../gdb-8.1/gdb/event-top.c:583 > #37 0x00000000007d7da8 in command_line_handler (rl=<optimised out>) at > ../../gdb-8.1/gdb/event-top.c:774 > > With debug frame 0 I get an assertion failure: > > gdb_assert (fi->level == 0); > > inside get_frame_id() > > and the backtrace: > > (gdb) bt > #0 0x00007f7aea353428 in __GI_raise (sig=sig@entry=6) at > ../sysdeps/unix/sysv/linux/raise.c:54 > #1 0x00007f7aea35502a in __GI_abort () at abort.c:89 > #2 0x00000000008e9086 in dump_core () at ../../gdb-8.1/gdb/utils.c:284 > #3 0x00000000008ed1dd in internal_vproblem(internal_problem *, const char > *, int, const char *, typedef __va_list_tag __va_list_tag *) > (problem=problem@entry=0x20ff340 <internal_error_problem>, file=<optimised > out>, > line=<optimised out>, fmt=<optimised out>, ap=ap@entry=0x7ffff3d626b8) > at ../../gdb-8.1/gdb/utils.c:493 > #4 0x00000000008ed2e9 in internal_verror (file=<optimised out>, > line=<optimised out>, fmt=<optimised out>, > ap=ap@entry=0x7ffff3d626b8) at ../../gdb-8.1/gdb/utils.c:518 > #5 0x000000000070f5f2 in internal_error (file=file@entry=0x10a67d7 > "../../gdb-8.1/gdb/frame.c", line=line@entry=534, > fmt=<optimised out>) at ../../gdb-8.1/gdb/common/errors.c:55 > #6 0x00000000007e031b in get_frame_id (fi=0x4a88fa0) at > ../../gdb-8.1/gdb/frame.c:534 > #7 0x0000000000816dec in inline_frame_this_id (this_frame=0x4a88ee0, > this_cache=<optimised out>, this_id=0x4a88f40) > at ../../gdb-8.1/gdb/inline-frame.c:160 > #8 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x4a88ee0) at > ../../gdb-8.1/gdb/frame.c:505 > #9 0x00000000007e026a in get_frame_id (fi=fi@entry=0x4a88ee0) at > ../../gdb-8.1/gdb/frame.c:537 > #10 0x00000000007de2d8 in value_of_register_lazy > (frame=frame@entry=0x4a88fa0, regnum=regnum@entry=16) > at ../../gdb-8.1/gdb/findvar.c:298 > #11 0x00000000007de42e in value_of_register (regnum=16, frame=0x4a88fa0) at > ../../gdb-8.1/gdb/findvar.c:274 > #12 0x00000000006d64f8 in pending_framepy_read_register (self=0x59494f0, > args=<optimised out>) > at ../../gdb-8.1/gdb/python/py-unwind.c:402 > #13 0x0000000000ea4828 in call_function (oparg=<optimised out>, > pp_stack=0x7ffff3d629b8) > at ../Python-2.7.3/Python/ceval.c:4021 > #14 PyEval_EvalFrameEx (f=f@entry=0x4a905e0, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #15 0x0000000000ea43e5 in fast_function (nk=0, na=<optimised out>, n=2, > pp_stack=0x7ffff3d62ab8, func=0x4c19410) > at ../Python-2.7.3/Python/ceval.c:4107 > #16 call_function (oparg=<optimised out>, pp_stack=0x7ffff3d62ab8) at > ../Python-2.7.3/Python/ceval.c:4042 > #17 PyEval_EvalFrameEx (f=f@entry=0x3c0ef90, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #18 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, > globals=<optimised out>, locals=locals@entry=0x0, > args=args@entry=0x596fc80, argcount=<optimised out>, kws=kws@entry=0x0, > kwcount=0, defs=0x0, defcount=0, > closure=0x0) at ../Python-2.7.3/Python/ceval.c:3253 > #19 0x0000000000f14b0c in function_call (func=0x4c19398, arg=0x596fc68, > kw=0x0) > ---Type <return> to continue, or q <return> to quit--- > :526 > #20 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x4c19398, > arg=arg@entry=0x596fc68, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #21 0x0000000000e2321f in instancemethod_call (func=0x4c19398, > arg=0x596fc68, kw=0x0) at ../Python-2.7.3/Objects/classobject.c:2578 > #22 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x4d77d20, > arg=arg@entry=0x5bdfe50, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #23 0x0000000000e77935 in slot_tp_call (self=<optimised out>, > args=0x5bdfe50, kwds=0x0) at ../Python-2.7.3/Objects/typeobject.c:5403 > #24 0x0000000000e1a37a in PyObject_Call (func=func@entry=0x5951150, > arg=arg@entry=0x5bdfe50, kw=kw@entry=0x0) at > ../Python-2.7.3/Objects/abstract.c:2529 > #25 0x0000000000ea27e5 in do_call (nk=0, na=<optimised out>, > pp_stack=0x7ffff3d62fe8, func=0x5951150) at > ../Python-2.7.3/Python/ceval.c:4239 > #26 call_function (oparg=<optimised out>, pp_stack=0x7ffff3d62fe8) at > ../Python-2.7.3/Python/ceval.c:4044 > #27 PyEval_EvalFrameEx (f=f@entry=0x3a9d380, throwflag=throwflag@entry=0) at > ../Python-2.7.3/Python/ceval.c:2666 > #28 0x0000000000ea5bbc in PyEval_EvalCodeEx (co=<optimised out>, > globals=<optimised out>, locals=locals@entry=0x0, args=args@entry=0x2c067e8, > argcount=<optimised out>, kws=kws@entry=0x0, kwcount=0, defs=0x0, > defcount=0, closure=0x0) > at ../Python-2.7.3/Python/ceval.c:3253 > #29 0x0000000000f14b0c in function_call (func=0x2ba3b90, arg=0x2c067d0, > kw=0x0) at ../Python-2.7.3/Objects/funcobject.c:526 > #30 0x0000000000e1afe5 in PyObject_Call (kw=0x0, arg=0x2c067d0, > func=0x2ba3b90) at ../Python-2.7.3/Objects/abstract.c:2529 > #31 PyObject_CallFunctionObjArgs (callable=0x2ba3b90) at > ../Python-2.7.3/Objects/abstract.c:2760 > #32 0x00000000006d7256 in pyuw_sniffer (self=<optimised out>, > this_frame=0x4a88fa0, cache_ptr=0x4a88fb8) at > ../../gdb-8.1/gdb/python/py-unwind.c:539 > #33 0x00000000007e404d in frame_unwind_try_unwinder > (this_frame=this_frame@entry=0x4a88fa0, > this_cache=this_cache@entry=0x4a88fb8, unwinder=0x2de4ae0) at > ../../gdb-8.1/gdb/frame-unwind.c:106 > #34 0x00000000007e4427 in frame_unwind_find_by_frame > (this_frame=this_frame@entry=0x4a88fa0, > this_cache=this_cache@entry=0x4a88fb8) at > ../../gdb-8.1/gdb/frame-unwind.c:164 > #35 0x00000000007e01e3 in compute_frame_id (fi=fi@entry=0x4a88fa0) at > ../../gdb-8.1/gdb/frame.c:501 > #36 0x00000000007e0738 in get_prev_frame_if_no_cycle > (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:1913 > #37 0x00000000007e2757 in get_prev_frame_always_1 > (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:2087 > #38 0x00000000007e2ccd in get_prev_frame_always > (this_frame=this_frame@entry=0x4a88ee0) at ../../gdb-8.1/gdb/frame.c:2103 > #39 0x0000000000816de1 in inline_frame_this_id (this_frame=0x4a88ee0, > this_cache=<optimised out>, this_id=0x4a88f40) at > ../../gdb-8.1/gdb/inline-frame.c:160 > #40 0x00000000007e012c in compute_frame_id (fi=fi@entry=0x4a88ee0) at > ../../gdb-8.1/gdb/frame.c:505 > #41 0x00000000007e026a in get_frame_id (fi=fi@entry=0x4a88ee0) at > ../../gdb-8.1/gdb/frame.c:537 > #42 0x00000000007de9f5 in value_from_register (type=type@entry=0x5acaee0, > regnum=regnum@entry=6, frame=frame@entry=0x4a88ee0) at > ../../gdb-8.1/gdb/findvar.c:938 > #43 0x00000000007979fd in dwarf2_evaluate_loc_desc_full (type=0x5acaee0, > frame=frame@entry=0x4a88ee0, data=<optimised out>, size=<optimised out>, > per_cu=<optimised out>, subobj_type=0x5acaee0, subobj_type@entry=0x0, > subobj_byte_offset=0) > at ../../gdb-8.1/gdb/dwarf2loc.c:2418 > #44 0x00000000007982d3 in dwarf2_evaluate_loc_desc (per_cu=<optimised out>, > size=<optimised out>, data=<optimised out>, frame=0x4a88ee0, type=<optimised > out>) at ../../gdb-8.1/gdb/dwarf2loc.c:2544 > #45 loclist_read_variable (symbol=0x5acb140, frame=0x4a88ee0) at > ../../gdb-8.1/gdb/dwarf2loc.c:4456 > #46 0x00000000007debe7 in default_read_var_value (var=0x5acb140, > var_block=0x0, frame=0x4a88ee0) at ../../gdb-8.1/gdb/findvar.c:612 > #47 0x0000000000899637 in read_frame_arg (sym=sym@entry=0x5acb140, > frame=frame@entry=0x4a88ee0, argp=argp@entry=0x7ffff3d637d0, > entryargp=entryargp@entry=0x7ffff3d637f0) at ../../gdb-8.1/gdb/stack.c:349 > #48 0x000000000089a1ad in print_frame_args (func=<optimised out>, > frame=frame@entry=0x4a88ee0, num=num@entry=-1, stream=0x2d40090) at > ../../gdb-8.1/gdb/stack.c:681 > #49 0x000000000089ac65 in print_frame (print_args=<optimised out>, > print_what=LOCATION, print_level=-1, frame=0x4a88ee0, sal=...) at > ../../gdb-8.1/gdb/stack.c:1203 > #50 print_frame_info (frame=frame@entry=0x4a88ee0, > print_level=print_level@entry=0, print_what=print_what@entry=LOCATION, > print_args=print_args@entry=1, set_current_sal=set_current_sal@entry=0) at > ../../gdb-8.1/gdb/stack.c:860 > #51 0x000000000089b0c6 in print_stack_frame (frame=0x4a88ee0, print_level=0, > print_what=LOCATION, set_current_sal=0) at ../../gdb-8.1/gdb/stack.c:177 > #52 0x00000000008cf810 in print_thread_info_1 (uiout=0x2d4ff10, > requested_threads=requested_threads@entry=0x0, > global_ids=global_ids@entry=0, pid=pid@entry=-1, > show_global_ids=show_global_ids@entry=0, this=<optimised out>, > this=<optimised out>) at ../../gdb-8.1/gdb/thread.c:1321 > #53 0x00000000008d0049 in info_threads_command (arg=0x0, from_tty=<optimised > out>) at ../../gdb-8.1/gdb/thread.c:1390 > #54 0x000000000069db89 in cmd_func (cmd=<optimised out>, args=<optimised > out>, from_tty=<optimised out>) at ../../gdb-8.1/gdb/cli/cli-decode.c:1886 > #55 0x00000000008d26b1 in execute_command (p=<optimised out>, > p@entry=0x29c1c20 "info threads ", from_tty=1) at ../../gdb-8.1/gdb/top.c:637 > #56 0x00000000007d7a9c in command_handler (command=0x29c1c20 "info threads > ") at ../../gdb-8.1/gdb/event-top.c:583 > > > It is possible to reproduce the bug with a vanilla gdb-8.1 installation and > the unwinder available at: https://github.com/tromey/spidermonkey-unwinder > > just launch gdb, attach to any running process and type > > (gdb) info threads I forgot to mention that reverting the commit as Tom did fixed the crash
We are seeing the same problem with GDB 8.2.1, with the same assertion. And we are working around it by reverting that 1-line patch. What is interesting is that I see no difference in the GDB test results with or without that patch. As noted by Tom, the changes to gdb/testsuite/gdb.python/py-recurse-unwind*, that were made at the same time as that one-line patch, don't seem to be affected by reverting this patch. Is there a test case that can be produced that fails when it is not present? I haven't found one yet.
I guess that this is the bug I see. I have a custom unwinder which causes this fault: /tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-775_20180622_1529687456/src/gdb/gdb/frame.c:534: internal-error: frame_ id get_frame_id(frame_info*): Assertion `fi->level == 0' failed. I get this error with a pre-built GDB for ARM from developer.arm.com with version 8.1, and a pre-built GDB from https://gnu-mcu-eclipse.github.io/blog/2019/05/24/arm-none-eabi-gcc-v8-2-1-1-7-released/ with version 8.3, but not with a pre-built GDB from developer.arm.com with version 7.10. The Python unwinder can be minimized to just this code: class MyUnwind( gdb.unwinder.Unwinder ): def __init__( self ): super( MyUnwind, self ).__init__( "MyUnwinder" ) def __call__( self, pending_frame ): # If the next line is removed, everything works as expected Pc = pending_frame.read_register( 'pc' ) return None If this unwinder is used to unwind a backtrace going through an inline stack frame, the above internal-error is shown. This bug unfortunately keeps us from going forward and use modern releases of GDB.
Created attachment 12206 [details] Fix for fi->level assert
Created attachment 12207 [details] c++ file to help repro the bug
Created attachment 12208 [details] python unwinder to help repro the bug
The bug happens because inline frames don't get a frame id until their caller does, but value_of_register_lazy needs a frame id so that value_fetch_lazy can find the frame again. But there's no need to do things lazily, so we can just fetch the value directly, bypassing the need for a frame id. To repro the bug: % g++ -O2 bug.cpp -o bug -g2 % gdb -ex "source bug.py" -ex "b printf" -ex run -ex bt bug GNU gdb (GDB) 10.0.50.20200114-git Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from bug... Breakpoint 1 at 0x400420 Starting program: /data/users/mwilliams/hphp-7/fbcode/foobar/bug Breakpoint 1, 0x00007ffff7242290 in printf () from /lib64/libc.so.6 ../../gdb/frame.c:579: internal-error: frame_id get_frame_id(frame_info*): Assertion `fi->level == 0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) y
The master branch has been updated by Andrew Burgess <aburgess@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=9fc501fdfe5dc82b5e5388cde4ac2ab70ed69d75 commit 9fc501fdfe5dc82b5e5388cde4ac2ab70ed69d75 Author: Andrew Burgess <andrew.burgess@embecosm.com> Date: Mon Jun 8 11:36:13 2020 +0100 gdb: Python unwinders, inline frames, and tail-call frames This started with me running into the bug described in python/22748, in summary, if the frame sniffing code accessed any registers within an inline frame then GDB would crash with this error: gdb/frame.c:579: internal-error: frame_id get_frame_id(frame_info*): Assertion `fi->level == 0' failed. The problem is that, when in the Python unwinder I write this: pending_frame.read_register ("register-name") This is translated internally into a call to `value_of_register', which in turn becomes a call to `value_of_register_lazy'. Usually this isn't a problem, `value_of_register_lazy' requires the next frame (more inner) to have a valid frame_id, which will be the case (if we're sniffing frame #1, then frame #0 will have had its frame-id figured out). Unfortunately if frame #0 is inline within frame #1, then the frame-id for frame #0 can't be computed until we have the frame-id for #1. As a result we can't create a lazy register for frame #1 when frame #0 is inline. Initially I proposed a solution inline with that proposed in bugzilla, changing value_of_register to avoid creating a lazy register value. However, when this was discussed on the mailing list I got this reply: https://sourceware.org/pipermail/gdb-patches/2020-June/169633.html Which led me to look at these two patches: [1] https://sourceware.org/pipermail/gdb-patches/2020-April/167612.html [2] https://sourceware.org/pipermail/gdb-patches/2020-April/167930.html When I considered patches [1] and [2] I saw that all of the issues being addressed here were related, and that there was a single solution that could address all of these issues. First I wrote the new test gdb.opt/inline-frame-tailcall.exp, which shows that [1] and [2] regress the inline tail-call unwinder, the reason for this is that these two patches replace a call to gdbarch_unwind_pc with a call to get_frame_register, however, this is not correct. The previous call to gdbarch_unwind_pc takes THIS_FRAME and returns the $pc value in the previous frame. In contrast get_frame_register takes THIS_FRAME and returns the value of the $pc in THIS_FRAME; these calls are not equivalent. The reason these patches appear (or do) fix the regressions listed in [1] is that the tail call sniffer depends on identifying the address of a caller and a callee, GDB then looks for a tail-call sequence that takes us from the caller address to the callee, if such a series is found then tail-call frames are added. The bug that was being hit, and which was address in patch [1] is that in order to find the address of the caller, GDB ended up creating a lazy register value for an inline frame with to frame-id. The solution in patch [1] is to instead take the address of the callee and treat this as the address of the caller. Getting the address of the callee works, but we then end up looking for a tail-call series from the callee to the callee, which obviously doesn't return any sane results, so we don't insert any tail call frames. The original patch [1] did cause some breakage, so patch [2] undid patch [1] in all cases except those where we had an inline frame with no frame-id. It just so happens that there were no tests that fitted this description _and_ which required tail-call frames to be successfully spotted, as a result patch [2] appeared to work. The new test inline-frame-tailcall.exp, exposes the flaw in patch [2]. This commit undoes patch [1] and [2], and replaces them with a new solution, which is also different to the solution proposed in the python/22748 bug report. In this solution I propose that we introduce some special case logic to value_of_register_lazy. To understand what this logic is we must first look at how inline frames unwind registers, this is very simple, they do this: static struct value * inline_frame_prev_register (struct frame_info *this_frame, void **this_cache, int regnum) { return get_frame_register_value (this_frame, regnum); } And remember: struct value * get_frame_register_value (struct frame_info *frame, int regnum) { return frame_unwind_register_value (frame->next, regnum); } So in all cases, unwinding a register in an inline frame just asks the next frame to unwind the register, this makes sense, as an inline frame doesn't really exist, when we unwind a register in an inline frame, we're really just asking the next frame for the value of the register in the previous, non-inline frame. So, if we assume that we only get into the missing frame-id situation when we try to unwind a register from an inline frame during the frame sniffing process, then we can change value_of_register_lazy to not create lazy register values for an inline frame. Imagine this stack setup, where #1 is inline within #2. #3 -> #2 -> #1 -> #0 \______/ inline Now when trying to figure out the frame-id for #1, we need to compute the frame-id for #2. If the frame sniffer for #2 causes a lazy register read in #2, either due to a Python Unwinder, or for the tail-call sniffer, then we call value_of_register_lazy passing in frame #2. In value_of_register_lazy, we grab the next frame, which is #1, and we used to then ask for the frame-id of #1, which was not computed, and this was our bug. Now, I propose we spot that #1 is an inline frame, and so lookup the next frame of #1, which is #0. As #0 is not inline it will have a valid frame-id, and so we create a lazy register value using #0 as the next-frame-id. This will give us the exact same result we had previously (thanks to the code we inspected above). Encoding into value_of_register_lazy the knowledge that reading an inline frame register will always just forward to the next frame feels.... not ideal, but this seems like the cleanest solution to this recursive frame-id computation/sniffing issue that appears to crop up. The following two commits are fully reverted with this commit, these correspond to patches [1] and [2] respectively: commit 5939967b355ba6a940887d19847b7893a4506067 Date: Tue Apr 14 17:26:22 2020 -0300 Fix inline frame unwinding breakage commit 991a3e2e9944a4b3a27bd989ac03c18285bd545d Date: Sat Apr 25 00:32:44 2020 -0300 Fix remaining inline/tailcall unwinding breakage for x86_64 gdb/ChangeLog: PR python/22748 * dwarf2/frame-tailcall.c (dwarf2_tailcall_sniffer_first): Remove special handling for inline frames. * findvar.c (value_of_register_lazy): Skip inline frames when creating lazy register values. * frame.c (frame_id_computed_p): Delete definition. * frame.h (frame_id_computed_p): Delete declaration. gdb/testsuite/ChangeLog: PR python/22748 * gdb.opt/inline-frame-tailcall.c: New file. * gdb.opt/inline-frame-tailcall.exp: New file. * gdb.python/py-unwind-inline.c: New file. * gdb.python/py-unwind-inline.exp: New file. * gdb.python/py-unwind-inline.py: New file.
Andrew, is this bug fixed? It seems to be, to me, but I wanted to double-check.
I'd also like to know if it has been fixed. Experienced this issue on 9.2 on Ubuntu.
Aha, Andrew wasn't CC'd on the bug last time around.
This issue should now be resolved. If anyone can still reproduce this issue, please feel free to reopen this bug.