On arm-linux, until this commit: ... commit bbb12eb9c84aa2b32480b7c022c494c2469ef717 Author: Thiago Jung Bauermann <thiago.bauermann@linaro.org> Date: Mon Feb 26 19:11:45 2024 -0300 gdb/arm: Remove tpidruro register from non-FreeBSD target descriptions ... I ran into: ... FAIL: gdb.base/inline-frame-cycle-unwind.exp: cycle at level 5: backtrace when the unwind is broken at frame 5 ... Because this was the only reported progression, I decided to investigate a bit further. I found that the python unwinder fails because this piece of code in pyuw_sniffer ignores the fact that value can be !entirely_available: ... /* Populate registers array. */ for (int i = 0; i < unwind_info->saved_regs->size (); ++i) { ... memcpy (cached->data.get (), value->contents ().data (), data_size); } } ... which throws an unavailable error, which is then caught by frame_unwind_try_unwinder: ... if (ex.error == NOT_AVAILABLE_ERROR) { /* This usually means that not even the PC is available, thus most unwinders aren't able to determine if they're the best fit. Keep trying. Fallback prologue unwinders should always accept the frame. */ return 0; } ...
With commit bbb12eb9c84aa2b32480b7c022c494c2469ef717 reverted, and this patch: ... diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c index 56f925bc57f..90f8ba4f293 100644 --- a/gdb/python/py-unwind.c +++ b/gdb/python/py-unwind.c @@ -916,6 +916,13 @@ pyuw_sniffer (const struct frame_unwind *self, const frame_info_ptr &this_frame, gdb_assert (data_size == value->type ()->length ()); cached_reg_t *cached = new (&cached_frame->reg[i]) cached_reg_t (); + + if (!value->entirely_available ()) + { + cached->num = -1; + continue; + } + cached->num = reg->number; cached->data.reset ((gdb_byte *) xmalloc (data_size)); memcpy (cached->data.get (), value->contents ().data (), data_size); ... the test-case still passes for me on arm-linux.
I realized it's cleaner to go with a fix in unwind_infopy_add_saved_register: ... diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c index 56f925bc57f..1c1289f7e7d 100644 --- a/gdb/python/py-unwind.c +++ b/gdb/python/py-unwind.c @@ -362,6 +362,18 @@ unwind_infopy_add_saved_register (PyObject *self, PyObject *args, PyObject *kw) return nullptr; } + if (value->optimized_out () || !value->entirely_available ()) + { + /* If we allow this value to be registered here, pyuw_sniffer is going + to run into an exception when trying to access its contents. + Throwing an exception here just puts a burden on the user to + implement the same checks on the user side. We could return False + here and True otherwise, but again that might require changes in user + code. So, handle this with minimal impact for the user, while + improving robustness: silently ignore the register/value pair. */ + Py_RETURN_NONE; + } + gdbpy_ref<> new_value = gdbpy_ref<>::new_reference (pyo_reg_value); bool found = false; for (saved_reg ® : *unwind_info->saved_regs) ... I'll test this and submit.
https://sourceware.org/pipermail/gdb-patches/2024-March/206965.html
The master branch has been updated by Tom de Vries <vries@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=306361f0687a60b06503a2df3c0ba949afca215f commit 306361f0687a60b06503a2df3c0ba949afca215f Author: Tom de Vries <tdevries@suse.de> Date: Tue Mar 19 10:30:36 2024 +0100 [gdb] Further fix "value is not available" with debug frame In commit 2aaba744467 ("[gdb] Fix "value is not available" with debug frame") I fixed a case in frame_unwind_register_value where using "set debug frame on" caused an "info frame" command to abort, reporting a "value is not available" error, due to the tpidruro register being unavailable. Subsequently, commit bbb12eb9c84 ("gdb/arm: Remove tpidruro register from non-FreeBSD target descriptions") removed the unavailable register, which caused a progression on test-case gdb.base/inline-frame-cycle-unwind.exp. While investigating the progression (see PR python/31437), I found that the "debug frame" output of the test-case (when reverting commit bbb12eb9c84) showed a smilar problem: ... Python Exception <class 'gdb.error'>: value is not available^M ... that was absent without "debug frame". Fix this likewise in fetch_lazy_register, and update the test-case to check for the exception. Furthermore, I realized that there's both value::entirely_available and value::entirely_unavailable, and that commit 2aaba744467 handled the case of !entirely_available by printing unavailable. Instead, print: - "unavailable" for entirely_unavailable, and - "partly unavailable" for !entirely_unavailable && !entirely_available. Tested on x86_64-linux and arm-linux.
This is probably a duplicate of PR30548.
The master branch has been updated by Tom de Vries <vries@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2236c5e384de20b0dd6b2fbc964a7269027cb2d9 commit 2236c5e384de20b0dd6b2fbc964a7269027cb2d9 Author: Tom de Vries <tdevries@suse.de> Date: Wed May 8 14:13:11 2024 +0200 [gdb/python] Make gdb.UnwindInfo.add_saved_register more robust On arm-linux, until commit bbb12eb9c84 ("gdb/arm: Remove tpidruro register from non-FreeBSD target descriptions") I ran into: ... FAIL: gdb.base/inline-frame-cycle-unwind.exp: cycle at level 5: \ backtrace when the unwind is broken at frame 5 ... What happens is the following: - the TestUnwinder from inline-frame-cycle-unwind.py calls gdb.UnwindInfo.add_saved_register with reg == tpidruro and value "<unavailable>", - pyuw_sniffer calls value->contents ().data () to access the value of the register, which throws an UNAVAILABLE_ERROR, - this causes the TestUnwinder unwinder to fail, after which another unwinder succeeds and returns the correct frame, and - the test-case fails because it's counting on the TestUnwinder to succeed and return an incorrect frame. Fix this by checking for !value::entirely_available as well as valued::optimized_out in unwind_infopy_add_saved_register. Tested on x86_64-linux and arm-linux. Approved-By: Andrew Burgess <aburgess@redhat.com> PR python/31437 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31437
Fixed.
*** Bug 30548 has been marked as a duplicate of this bug. ***