aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
AgeCommit message (Collapse)AuthorFilesLines
2023-12-24gdb: remove VALUE_REGNUM, add value::regnumSimon Marchi1-4/+3
Remove VALUE_REGNUM, replace it with a method on struct value. Set `m_location.reg.regnum` directly from value::allocate_register_lazy, which is fine because allocate_register_lazy is a static creation function for struct value. Change-Id: Id632502357da971617d9dce1e2eab9b56dbcf52d
2023-12-14gdb: add gdbarch_pseudo_register_write that takes a frameSimon Marchi1-1/+8
Add a new variant of gdbarch_pseudo_register_write that takes a frame_info in order to write raw registers. Use this new method when available: - in put_frame_register, when trying to write a pseudo register to a given frame - in regcache::cooked_write No implementation is migrated to use this new method (that will come in subsequent patches), so no behavior change is expected here. The objective is to fix writing pseudo registers to non-current frames. See previous commit "gdb: read pseudo register through frame" for a more detailed explanation. Change-Id: Ie7fe364a15a4d86c2ecb09de2b4baa08c45555ac Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: read pseudo register through frameSimon Marchi1-3/+33
Change gdbarch_pseudo_register_read_value to take a frame instead of a regcache. The frame (and formerly the regcache) is used to read raw registers needed to make up the pseudo register value. The problem with using the regcache is that it always provides raw register values for the current frame (frame 0). Let's say the user wants to read the ebx register on amd64. ebx is a pseudo register, obtained by reading the bottom half (bottom 4 bytes) of the rbx register, which is a raw register. If the currently selected frame is frame 0, it works fine: (gdb) frame 0 #0 break_here_asm () at /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S:36 36 in /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S (gdb) p/x $ebx $1 = 0x24252627 (gdb) p/x $rbx $2 = 0x2021222324252627 But if the user is looking at another frame, and the raw register behind the pseudo register has been saved at some point in the call stack, then we get a wrong answer: (gdb) frame 1 #1 0x000055555555517d in caller () at /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S:56 56 in /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S (gdb) p/x $ebx $3 = 0x24252627 (gdb) p/x $rbx $4 = 0x1011121314151617 Here, the value of ebx was computed using the value of rbx in frame 0 (through the regcache), it should have been computed using the value of rbx in frame 1. In other to make this work properly, make the following changes: - Make dwarf2_frame_prev_register return nullptr if it doesn't know how to unwind a register and that register is a pseudo register. Previously, it returned `frame_unwind_got_register`, meaning, in our example, "the value of ebx in frame 1 is the same as the value of ebx in frame 0", which is obviously false. Return nullptr as a way to say "I don't know". - In frame_unwind_register_value, when prev_register (for instance dwarf2_frame_prev_register) returns nullptr, and we are trying to read a pseudo register, try to get the register value through gdbarch_pseudo_register_read_value or gdbarch_pseudo_register_read. If using gdbarch_pseudo_register_read, the behavior is known to be broken. Implementations should be migrated to use gdbarch_pseudo_register_read_value to fix that. - Change gdbarch_pseudo_register_read_value to take a frame_info instead of a regcache, update implementations (aarch64, amd64, i386). In i386-tdep.c, I made a copy of i386_mmx_regnum_to_fp_regnum that uses a frame instead of a regcache. The version using the regcache is still used by i386_pseudo_register_write. It will get removed in a subsequent patch. - Add some helpers in value.{c,h} to implement the common cases of pseudo registers: taking part of a raw register and concatenating multiple raw registers. - Update readable_regcache::{cooked_read,cooked_read_value} to pass the current frame to gdbarch_pseudo_register_read_value. Passing the current frame will give the same behavior as before: for frame 0, raw registers will be read from the current thread's regcache. Notes: - I do not plan on changing gdbarch_pseudo_register_read to receive a frame instead of a regcache. That method is considered deprecated. Instead, we should be working on migrating implementations to use gdbarch_pseudo_register_read_value instead. - In frame_unwind_register_value, we still ask the unwinder to try to unwind pseudo register values. It's apparently possible for the debug info to provide information about [1] pseudo registers, so we want to try that first, before falling back to computing them ourselves. [1] https://inbox.sourceware.org/gdb-patches/20180528174715.A954AD804AD@oc3748833570.ibm.com/ Change-Id: Id6ef1c64e19090a183dec050e4034d8c2394e7ca Reviewed-by: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: make get_frame_register_bytes take the next frameSimon Marchi1-10/+6
Similar to the previous patches, change get_frame_register_bytes to take the "next frame" instead of "this frame". Change-Id: Ie8f35042bfa6e93565fcefaee71b6b3903f0fe9f Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: make put_frame_register_bytes take the next frameSimon Marchi1-9/+5
Similar to the previous patches, change put_frame_register_bytes to take the "next frame" instead of "this frame". Change-Id: I27bcb26573686d99b231230823cff8db6405a788 Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: make put_frame_register take the next frameSimon Marchi1-7/+9
Similar to the previous patches, change put_frame_register to take the "next frame" instead of "this frame". Change-Id: I062fd4663b8f54f0fc7bbf39c860b7341363821b Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: remove frame_registerSimon Marchi1-31/+8
I was going to change frame_register to take the "next frame", but I realized that doing so would make it a useless wrapper around frame_register_unwind. So, just remove frame_register and replace uses with frame_register_unwind. Change-Id: I185868bc69f8e098124775d0550d069220a4678a Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: make put_frame_register take an array_viewSimon Marchi1-4/+7
Change put_frame_register to take an array_view instead of a raw pointer. Add an assertion to verify that the number of bytes we try to write matches the length of the register. Change-Id: Ib75a9c8a12b47e203097621643eaa2c1830591ae Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-12-14gdb: fix bugs in {get,put}_frame_register_bytesSimon Marchi1-40/+23
I found this only by inspection: the myaddr pointer in {get,put}_frame_register_bytes is reset to `buffer.data ()` at each iteration. This means that we will always use the bytes at the beginning of `buffer` to read or write to the registers, instead of progressing in `buffer`. Fix this by re-writing the functions to chip away the beginning of the buffer array_view as we progress in reading or writing the data. These bugs was introduced almost 3 years ago [1], and yet nobody complained. I'm wondering which architecture relies on that register "overflow" behavior (reading or writing multiple consecutive registers with one {get,put}_frame_register_bytes calls), and in which situation. I find these functions a bit dangerous, if a caller mis-calculates things, it could end up silently reading or writing to the next register, even if it's not the intent. If I could change it, I would prefer to have functions specifically made for that ({get,put}_frame_register_bytes_consecutive or something like that) and make {get,put}_frame_register_bytes only able to write within a single register (which I presume represents most of the use cases of the current {get,put}_frame_register_bytes). If a caller mis-calculates things and an overflow occurs while calling {get,put}_frame_register_bytes, it would hit an assert. The problem is knowing which callers rely on the overflow behavior and which don't. [1] https://gitlab.com/gnutools/binutils-gdb/-/commit/bdec2917b1e94c7198ba39919f45060067952f43 Change-Id: I43bd4a9f7fa8419d388a2b20bdc57d652688ddf8 Reviewed-By: John Baldwin <jhb@FreeBSD.org> Approved-By: Andrew Burgess <aburgess@redhat.com>
2023-12-14gdb: change regcache interface to use array_viewSimon Marchi1-2/+2
Change most of regcache (and base classes) to use array_view when possible, instead of raw pointers. By propagating the use of array_view further, it enables having some runtime checks to make sure the what we read from or write to regcaches has the expected length (such as the one in the `copy(array_view, array_view)` function. It also integrates well when connecting with other APIs already using gdb::array_view. Add some overloads of the methods using raw pointers to avoid having to change all call sites at once (which is both a lot of work and risky). I tried to do this change in small increments, but since many of these functions use each other, it ended up simpler to do it in one shot than having a lot of intermediary / transient changes. This change extends into gdbserver as well, because there is some part of the regcache interface that is shared. Changing the reg_buffer_common interface to use array_view caused some build failures in nat/aarch64-scalable-linux-ptrace.c. That file currently "takes advantage" of the fact that reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which IMO is dangerous. It uses raw_supply/raw_collect directly on uint64_t's, which I guess is fine because it is expected that native code will have the same endianness as the debugged process. To accomodate that, add some overloads of raw_collect and raw_supply that work on uint64_t. This file also uses raw_collect and raw_supply on `char` pointers. Change it to use `gdb_byte` pointers instead. Add overloads of raw_collect and raw_supply that work on `gdb_byte *` and make an array_view on the fly using the register's size. Those call sites could be converted to use array_view with not much work, in which case these overloads could be removed, but I didn't want to do it in this patch, to avoid starting to dig in arch-specific code. During development, I inadvertently changed reg_buffer::raw_compare's behavior to not accept an offset equal to the register size. This behavior (effectively comparing 0 bytes, returning true) change was caught by the AArch64 SME core tests. Add a selftest to make sure that this raw_compare behavior is preserved in the future. Change-Id: I9005f04114543ddff738949e12d85a31855304c2 Reviewed-By: John Baldwin <jhb@FreeBSD.org>
2023-11-28[gdb] Fix segfault in for_each_block, part 1Tom de Vries1-2/+3
When running test-case gdb.base/vfork-follow-parent.exp on powerpc64 (likewise on s390x), I run into: ... (gdb) PASS: gdb.base/vfork-follow-parent.exp: \ exec_file=vfork-follow-parent-exit: target-non-stop=on: non-stop=off: \ resolution_method=schedule-multiple: print unblock_parent = 1 continue^M Continuing.^M Reading symbols from vfork-follow-parent-exit...^M ^M ^M Fatal signal: Segmentation fault^M ----- Backtrace -----^M 0x1027d3e7 gdb_internal_backtrace_1^M src/gdb/bt-utils.c:122^M 0x1027d54f _Z22gdb_internal_backtracev^M src/gdb/bt-utils.c:168^M 0x1057643f handle_fatal_signal^M src/gdb/event-top.c:889^M 0x10576677 handle_sigsegv^M src/gdb/event-top.c:962^M 0x3fffa7610477 ???^M 0x103f2144 for_each_block^M src/gdb/dcache.c:199^M 0x103f235b _Z17dcache_invalidateP13dcache_struct^M src/gdb/dcache.c:251^M 0x10bde8c7 _Z24target_dcache_invalidatev^M src/gdb/target-dcache.c:50^M ... or similar. The root cause for the segmentation fault is that linux_is_uclinux gives an incorrect result: it should always return false, given that we're running on a regular linux system, but instead it returns first true, then false. In more detail, the segmentation fault happens as follows: - a program space with an address space is created - a second program space is about to be created. maybe_new_address_space is called, and because linux_is_uclinux returns true, maybe_new_address_space returns false, and no new address space is created - a second program space with the same address space is created - a program space is deleted. Because linux_is_uclinux now returns false, gdbarch_has_shared_address_space (current_inferior ()->arch ()) returns false, and the address space is deleted - when gdb uses the address space of the remaining program space, we run into the segfault, because the address space is deleted. Hardcoding linux_is_uclinux to false makes the test-case pass. We leave addressing the root cause for the following commit in this series. For now, prevent the segmentation fault by making the address space a refcounted object. This was already suggested here [1]: ... A better solution might be to have the address spaces be reference counted ... Tested on top of trunk on x86_64-linux and ppc64le-linux. Tested on top of gdb-14-branch on ppc64-linux. Co-Authored-By: Simon Marchi <simon.marchi@polymtl.ca> PR gdb/30547 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30547 [1] https://sourceware.org/pipermail/gdb-patches/2023-October/202928.html
2023-11-17gdb: remove get_current_regcacheSimon Marchi1-4/+5
Remove get_current_regcache, inlining the call to get_thread_regcache in callers. When possible, pass the right thread_info object known from the local context. Otherwise, fall back to passing `inferior_thread ()`. This makes the reference to global context bubble up one level, a small step towards the long term goal of reducing the number of references to global context (or rather, moving those references as close as possible to the top of the call tree). No behavior change expected. Change-Id: Ifa6980c88825d803ea586546b6b4c633c33be8d6
2023-11-17gdb: remove regcache's address spaceSimon Marchi1-5/+7
While looking at the regcache code, I noticed that the address space (passed to regcache when constructing it, and available through regcache::aspace) wasn't relevant for the regcache itself. Callers of regcache::aspace use that method because it appears to be a convenient way of getting the address space for a thread, if you already have the regcache. But there is always another way to get the address space, as the callers pretty much always know which thread they are dealing with. The regcache code itself doesn't use the address space. This patch removes anything related to address_space from the regcache code, and updates callers to get it from the thread in context. This removes a bit of unnecessary complexity from the regcache code. The current get_thread_arch_regcache function gets an address_space for the given thread using the target_thread_address_space function (which calls the target_ops::thread_address_space method). This suggest that there might have been the intention of supporting per-thread address spaces. But digging through the history, I did not find any such case. Maybe this method was just added because we needed a way to get an address space from a ptid (because constructing a regcache required an address space), and this seemed like the right way to do it, I don't know. The only implementations of thread_address_space and process_stratum_target::thread_address_space and linux_nat_target::thread_address_space, which essentially just return the inferior's address space. And thread_address_space is only used in the current get_thread_arch_regcache, which gets removed. So, I think that the thread_address_space target method can be removed, and we can assume that it's fine to use the inferior's address space everywhere. Callers of regcache::aspace are updated to get the address space from the relevant inferior, either using some context they already know about, or in last resort using the current global context. So, to summarize: - remove everything in regcache related to address spaces - in particular, remove get_thread_arch_regcache, and rename get_thread_arch_aspace_regcache to get_thread_arch_regcache - remove target_ops::thread_address_space, and target_thread_address_space - adjust all users of regcache::aspace to get the address space another way Change-Id: I04fd41b22c83fe486522af7851c75bcfb31c88c7
2023-11-14Move follow_static_link to frame.cTom Tromey1-0/+40
This moves the follow_static_link function to frame.c and exports it for use elsewhere. The API is changed slightly to make it more generically useful.
2023-09-20Remove explanatory comments from includesTom Tromey1-1/+1
I noticed a comment by an include and remembered that I think these don't really provide much value -- sometimes they are just editorial, and sometimes they are obsolete. I think it's better to just remove them. Tested by rebuilding. Approved-By: Andrew Burgess <aburgess@redhat.com>
2023-06-05[gdb] Fix more typosTom de Vries1-1/+1
Fix some more typos: - distinquish -> distinguish - actualy -> actually - singe -> single - frash -> frame - chid -> child - dissassembler -> disassembler - uninitalized -> uninitialized - precontidion -> precondition - regsiters -> registers - marge -> merge - sate -> state - garanteed -> guaranteed - explictly -> explicitly - prefices (nonstandard plural) -> prefixes - bondary -> boundary - formated -> formatted - ithe -> the - arrav -> array - coresponding -> corresponding - owend -> owned - fials -> fails - diasm -> disasm - ture -> true - tpye -> type There's one code change, the name of macro SIG_CODE_BONDARY_FAULT changed to SIG_CODE_BOUNDARY_FAULT. Tested on x86_64-linux.
2023-05-19Update documentation for Python Frame.older and Frame.newerTom Tromey1-1/+1
I noticed that Frame.older and Frame.newer don't document that they return None at the ends of the stack. This patch updates the documentation, and also fixes a somewhat related typo in a comment that I noticed while digging into this. Approved-By: Eli Zaretskii <eliz@gnu.org>
2023-05-03[gdb/build] Fix frame_list position in frame.cTom de Vries1-4/+7
In commit 995a34b1772 ("Guard against frame.c destructors running before frame-info.c's") the following problem was addressed. The frame_info_ptr destructor: ... ~frame_info_ptr () { frame_list.erase (frame_list.iterator_to (*this)); } ... uses frame_list, which is a static member of class frame_info_ptr, instantiated in frame-info.c: ... intrusive_list<frame_info_ptr> frame_info_ptr::frame_list; ... Then there's a static frame_info_pointer variable named selected_frame in frame.c: ... static frame_info_ptr selected_frame; ... Because the destructor of selected_frame uses frame_list, its destructor needs to be called before the destructor of frame_list. But because they're in different compilation units, the initialization order and consequently destruction order is not guarantueed. The commit fixed this by handling the case that the destructor of frame_list is called first, adding a check on is_linked (): ... ~frame_info_ptr () { - frame_list.erase (frame_list.iterator_to (*this)); + /* If this node has static storage, it may be deleted after + frame_list. Attempting to erase ourselves would then trigger + internal errors, so make sure we are still linked first. */ + if (is_linked ()) + frame_list.erase (frame_list.iterator_to (*this)); } ... However, since then frame_list has been moved into frame.c, and initialization/destruction order is guarantueed inside a compilation unit. Revert aforementioned commit, and fix the destruction order problem by moving frame_list before selected_frame. Reverting the commit is another way of fixing the already fixed Wdangling-pointer warning reported in PR build/30413, in a different way than commit 9b0ccb1ebae ("Pass const frame_info_ptr reference for skip_[language_]trampoline"). Approved-By: Simon Marchi <simon.marchi@efficios.com> Tested on x86_64-linux. PR build/30413 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30413
2023-03-31Fix maybe-uninitialized warning in frame.cTom Tromey1-3/+4
A recent patch caused my system gcc (Fedora 36, so gcc 12.2.1) to warn about sym_addr being possibly uninitialized in frame.c. It isn't, but the compiler can't tell. So, this patch initializes the variable. I also fixed a formatting buglet that I missed in review.
2023-03-31GDB: Favor full symbol main name for backtrace stopRichard Bunt1-10/+15
In the case where a Fortran program has a program name of "main" and there is also a minimal symbol called main, such as with programs built with GCC version 4.4.7 or below, the backtrace will erroneously stop at the minimal symbol rather than the user specified main, e.g.: (gdb) bt #0 bar () at .../gdb/testsuite/gdb.fortran/backtrace.f90:17 #1 0x0000000000402556 in foo () at .../gdb/testsuite/gdb.fortran/backtrace.f90:21 #2 0x0000000000402575 in main () at .../gdb/testsuite/gdb.fortran/backtrace.f90:31 #3 0x00000000004025aa in main () (gdb) This patch fixes this issue by increasing the precedence of the full symbol when the language of the current frame is Fortran. Newer versions of GCC transform the program name to "MAIN__" in this case, avoiding the problem. Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
2023-03-13Fix crash in inside_main_funcTom Tromey1-0/+8
gdb 13.1 crashes while running the rust compiler's debugger tests. The crash has a number of causes. First, the rust compiler still uses the C++-like _Z mangling, but with its own twist -- some hex digits added to the end of a symbol. So, while gdb finds the correct name of "main": (top-gdb) p name $13 = 0x292e0c0 "rustc_gdb_1031745::main" It isn't found in the minsyms, because C++ demangling yields: [99] t 0x90c0 _ZN17rustc_gdb_10317454main17h5b5be7fe16a97225E section .text rustc_gdb_1031745::main::h5b5be7fe16a97225 zko06yobckx336v This could perhaps be fixed. I also filed a new PR to suggest preferring the linkage name of the main program. Next, the rust compiler emits both a DW_TAG_subprogram and a DW_TAG_namespace for "main". This happens because the file is named "main.rs" -- i.e., the bug is specific to the source file name. The crash also seems to require the nested function inside of 'main', at least for me. The namespace always is generated, but perhaps this changes the ordering in the DWARF. When inside_main_func looks up the main symbol, it finds the namespace symbol rather than the function. (I filed a bug about fixing gdb's symbol tables -- long overdue.) Meanwhile, as I think it's important to fix this crash sooner rather than later, this patch changes inside_main_func to check that the symbol that is found is LOC_BLOCK. This perhaps should have been done in the first place, anyway. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30158
2023-02-19Convert contained_in to methodTom Tromey1-1/+1
This converts contained_in to be a method of block.
2023-02-15gdb: fix dealloc function not being called for frame 0Simon Marchi1-8/+21
Tom de Vries reported [1] a regression in gdb.btrace/record_goto.exp caused by 6d3717d4c4 ("gdb: call frame unwinders' dealloc_cache methods through destroying the frame cache"). This issue is caught by ASan. On a non-ASan build, it may or may not cause a crash or some other issue, I haven't tried. I managed to narrow it down to: $ ./gdb -nx -q --data-directory=data-directory testsuite/outputs/gdb.btrace/record_goto/record_goto -ex "start" -ex "record btrace" -ex "next" ... and then doing repeatedly "record goto 19" and "record goto 27". Eventually, I get: (gdb) record goto 27 ================================================================= ==1527735==ERROR: AddressSanitizer: heap-use-after-free on address 0x6210003392a8 at pc 0x55e4c26eef86 bp 0x7ffd229f24e0 sp 0x7ffd229f24d8 READ of size 8 at 0x6210003392a8 thread T0 #0 0x55e4c26eef85 in bfcache_eq /home/simark/src/binutils-gdb/gdb/record-btrace.c:1639 #1 0x55e4c37cdeff in htab_find_slot_with_hash /home/simark/src/binutils-gdb/libiberty/hashtab.c:659 #2 0x55e4c37ce24a in htab_find_slot /home/simark/src/binutils-gdb/libiberty/hashtab.c:703 #3 0x55e4c26ef0c6 in bfcache_new /home/simark/src/binutils-gdb/gdb/record-btrace.c:1653 #4 0x55e4c26f1242 in record_btrace_frame_sniffer /home/simark/src/binutils-gdb/gdb/record-btrace.c:1820 #5 0x55e4c1b926a1 in frame_unwind_try_unwinder /home/simark/src/binutils-gdb/gdb/frame-unwind.c:136 #6 0x55e4c1b930d7 in frame_unwind_find_by_frame(frame_info_ptr, void**) /home/simark/src/binutils-gdb/gdb/frame-unwind.c:196 #7 0x55e4c1bb867f in get_frame_type(frame_info_ptr) /home/simark/src/binutils-gdb/gdb/frame.c:2925 #8 0x55e4c2ae6798 in print_frame_info(frame_print_options const&, frame_info_ptr, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:1049 #9 0x55e4c2ade3e1 in print_stack_frame(frame_info_ptr, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:367 #10 0x55e4c26fda03 in record_btrace_set_replay /home/simark/src/binutils-gdb/gdb/record-btrace.c:2779 #11 0x55e4c26fddc3 in record_btrace_target::goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/record-btrace.c:2843 #12 0x55e4c2de2bb2 in target_goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/target.c:4169 #13 0x55e4c275ed98 in record_goto(char const*) /home/simark/src/binutils-gdb/gdb/record.c:372 #14 0x55e4c275edba in cmd_record_goto /home/simark/src/binutils-gdb/gdb/record.c:383 0x6210003392a8 is located 424 bytes inside of 4064-byte region [0x621000339100,0x62100033a0e0) freed by thread T0 here: #0 0x7f6ca34a5b6f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:123 #1 0x55e4c38a4c17 in rpl_free /home/simark/src/binutils-gdb/gnulib/import/free.c:44 #2 0x55e4c1bbd378 in xfree<void> /home/simark/src/binutils-gdb/gdb/../gdbsupport/gdb-xfree.h:37 #3 0x55e4c37d1b63 in call_freefun /home/simark/src/binutils-gdb/libiberty/obstack.c:103 #4 0x55e4c37d25a2 in _obstack_free /home/simark/src/binutils-gdb/libiberty/obstack.c:280 #5 0x55e4c1bad701 in reinit_frame_cache() /home/simark/src/binutils-gdb/gdb/frame.c:2112 #6 0x55e4c27705a3 in registers_changed_ptid(process_stratum_target*, ptid_t) /home/simark/src/binutils-gdb/gdb/regcache.c:564 #7 0x55e4c27708c7 in registers_changed_thread(thread_info*) /home/simark/src/binutils-gdb/gdb/regcache.c:573 #8 0x55e4c26fd922 in record_btrace_set_replay /home/simark/src/binutils-gdb/gdb/record-btrace.c:2772 #9 0x55e4c26fddc3 in record_btrace_target::goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/record-btrace.c:2843 #10 0x55e4c2de2bb2 in target_goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/target.c:4169 #11 0x55e4c275ed98 in record_goto(char const*) /home/simark/src/binutils-gdb/gdb/record.c:372 #12 0x55e4c275edba in cmd_record_goto /home/simark/src/binutils-gdb/gdb/record.c:383 previously allocated by thread T0 here: #0 0x7f6ca34a5e8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 #1 0x55e4c0b55c60 in xmalloc /home/simark/src/binutils-gdb/gdb/alloc.c:57 #2 0x55e4c37d1a6d in call_chunkfun /home/simark/src/binutils-gdb/libiberty/obstack.c:94 #3 0x55e4c37d1c20 in _obstack_begin_worker /home/simark/src/binutils-gdb/libiberty/obstack.c:141 #4 0x55e4c37d1ed7 in _obstack_begin /home/simark/src/binutils-gdb/libiberty/obstack.c:164 #5 0x55e4c1bad728 in reinit_frame_cache() /home/simark/src/binutils-gdb/gdb/frame.c:2113 #6 0x55e4c27705a3 in registers_changed_ptid(process_stratum_target*, ptid_t) /home/simark/src/binutils-gdb/gdb/regcache.c:564 #7 0x55e4c27708c7 in registers_changed_thread(thread_info*) /home/simark/src/binutils-gdb/gdb/regcache.c:573 #8 0x55e4c26fd922 in record_btrace_set_replay /home/simark/src/binutils-gdb/gdb/record-btrace.c:2772 #9 0x55e4c26fddc3 in record_btrace_target::goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/record-btrace.c:2843 #10 0x55e4c2de2bb2 in target_goto_record(unsigned long) /home/simark/src/binutils-gdb/gdb/target.c:4169 #11 0x55e4c275ed98 in record_goto(char const*) /home/simark/src/binutils-gdb/gdb/record.c:372 #12 0x55e4c275edba in cmd_record_goto /home/simark/src/binutils-gdb/gdb/record.c:383 The problem is a stale entry in the bfcache hash table (in record-btrace.c), left across a reinit_frame_cache. This entry points to something that used to be allocated on the frame obstack, that has since been wiped by reinit_frame_cache. Before the aforementioned, unwinder deallocation functions were called by iterating on the frame chain, starting with the sentinel frame, like so: /* Tear down all frame caches. */ for (frame_info *fi = sentinel_frame; fi != NULL; fi = fi->prev) { if (fi->prologue_cache && fi->unwind->dealloc_cache) fi->unwind->dealloc_cache (fi, fi->prologue_cache); if (fi->base_cache && fi->base->unwind->dealloc_cache) fi->base->unwind->dealloc_cache (fi, fi->base_cache); } After that patch, we relied on the fact that all frames are (supposedly) in the frame_stash. A deletion function was added to the frame_stash hash table, so that dealloc functions would be called when emptying the frame stash. There is one case, however, where a frame_info is not in the frame stash. That is when we create the frame_info for the current frame (level 0, unwound from the sentinel frame), but don't compute its frame id. The computation of the frame id for that frame (and only that frame, AFAIK) is done lazily. And putting a frame_info in the frame stash requires knowing its id. So a frame 0 whose frame id is not computed yet is necessarily not in the frame stash. When replaying with btrace, record_btrace_frame_sniffer insert entries corresponding to frames in the "bfcache" hash table. It then relies on record_btrace_frame_dealloc_cache being called for each frame to remove all those entries when the frames get invalidated. If a frame reinit happens while frame 0's id is not computed (and therefore that frame is not in frame_stash), record_btrace_frame_dealloc_cache does not get called for it, and it leaves a stale entry in bfcache. That then leads to a use-after-free when that entry is accessed later, which ASan catches. The proposed solution is to explicitly call frame_info_del on frame 0, if it exists, and if its frame id is not computed. If its frame id is computed, it is expected that it will be in the frame stash, so it will be "deleted" through that. [1] https://inbox.sourceware.org/gdb-patches/20230130200249.131155-1-simon.marchi@efficios.com/T/#mcf1340ce2906a72ec7ed535ec0c97dba11c3d977 Reported-By: Tom de Vries <tdevries@suse.de> Tested-By: Tom de Vries <tdevries@suse.de> Change-Id: I2351882dd511f3bbc01e4152e9db13b69b3ba384
2023-02-13Remove deprecated_lval_hackTom Tromey1-4/+4
This removes deprecated_lval_hack and the VALUE_LVAL macro, replacing all uses with a call to value::lval. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn many optimized-out value functions into methodsTom Tromey1-11/+11
This turns many functions that are related to optimized-out or availability-checking to be methods of value. The static function value_entirely_covered_by_range_vector is also converted to be a private method. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn remaining value_contents functions into methodsTom Tromey1-6/+6
This turns the remaining value_contents functions -- value_contents, value_contents_all, value_contents_for_printing, and value_contents_for_printing_const -- into methods of value. It also converts the static functions require_not_optimized_out and require_available to be private methods. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn some value_contents functions into methodsTom Tromey1-2/+2
This turns value_contents_raw, value_contents_writeable, and value_contents_all_raw into methods on value. The remaining functions will be changed later in the series; they were a bit trickier and so I didn't include them in this patch. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn value_address and set_value_address functions into methodsTom Tromey1-2/+2
This changes the value_address and set_value_address functions to be methods of value. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn value_lazy and set_value_lazy functions into methodsTom Tromey1-1/+1
This changes the value_lazy and set_value_lazy functions to be methods of value. Much of this patch was written by script. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-13Turn value_type into methodTom Tromey1-2/+2
This changes value_type to be a method of value. Much of this patch was written by script. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-02-10[gdb/cli] Add maint info frame-unwindersTom de Vries1-2/+2
Add a new command "maint info frame-unwinders": ... (gdb) help maint info frame-unwinders List the frame unwinders currently in effect, starting with the highest \ priority. ... Output for i386: ... $ gdb -q -batch -ex "set arch i386" -ex "maint info frame-unwinders" The target architecture is set to "i386". dummy DUMMY_FRAME dwarf2 tailcall TAILCALL_FRAME inline INLINE_FRAME i386 epilogue NORMAL_FRAME dwarf2 NORMAL_FRAME dwarf2 signal SIGTRAMP_FRAME i386 stack tramp NORMAL_FRAME i386 sigtramp SIGTRAMP_FRAME i386 prologue NORMAL_FRAME ... Output for x86_64: ... $ gdb -q -batch -ex "set arch i386:x86-64" -ex "maint info frame-unwinders" The target architecture is set to "i386:x86-64". dummy DUMMY_FRAME dwarf2 tailcall TAILCALL_FRAME inline INLINE_FRAME python NORMAL_FRAME amd64 epilogue NORMAL_FRAME i386 epilogue NORMAL_FRAME dwarf2 NORMAL_FRAME dwarf2 signal SIGTRAMP_FRAME amd64 sigtramp SIGTRAMP_FRAME amd64 prologue NORMAL_FRAME i386 stack tramp NORMAL_FRAME i386 sigtramp SIGTRAMP_FRAME i386 prologue NORMAL_FRAME ... Tested on x86_64-linux. Reviewed-By: Tom Tromey <tom@tromey.com> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
2023-02-08gdb: give sentinel for user frames distinct IDs, register sentinel frames to ↵Simon Marchi1-14/+49
the frame cache The test gdb.base/frame-view.exp fails like this on AArch64: frame^M #0 baz (z1=hahaha, /home/simark/src/binutils-gdb/gdb/value.c:4056: internal-error: value_fetch_lazy_register: Assertion `next_frame != NULL' failed.^M A problem internal to GDB has been detected,^M further debugging may prove unreliable.^M FAIL: gdb.base/frame-view.exp: with_pretty_printer=true: frame (GDB internal error) The sequence of events leading to this is the following: - When we create the user frame (the "select-frame view" command), we create a sentinel frame just for our user-created frame, in create_new_frame. This sentinel frame has the same id as the regular sentinel frame. - When printing the frame, after doing the "select-frame view" command, the argument's pretty printer is invoked, which does an inferior function call (this is the point of the test). This clears the frame cache, including the "real" sentinel frame, which sets the sentinel_frame global to nullptr. - Later in the frame-printing process (when printing the second argument), the auto-reinflation mechanism re-creates the user frame by calling create_new_frame again, creating its own special sentinel frame again. However, note that the "real" sentinel frame, the sentinel_frame global, is still nullptr. If the selected frame had been a regular frame, we would have called get_current_frame at some point during the reinflation, which would have re-created the "real" sentinel frame. But it's not the case when reinflating a user frame. - Deep down the stack, something wants to fill in the unwind stop reason for frame 0, which requires trying to unwind frame 1. This leads us to trying to unwind the PC of frame 1: #0 gdbarch_unwind_pc (gdbarch=0xffff8d010080, next_frame=...) at /home/simark/src/binutils-gdb/gdb/gdbarch.c:2955 #1 0x000000000134569c in dwarf2_tailcall_sniffer_first (this_frame=..., tailcall_cachep=0xffff773fcae0, entry_cfa_sp_offsetp=0xfffff7f7d450) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame-tailcall.c:390 #2 0x0000000001355d84 in dwarf2_frame_cache (this_frame=..., this_cache=0xffff773fc928) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1089 #3 0x00000000013562b0 in dwarf2_frame_unwind_stop_reason (this_frame=..., this_cache=0xffff773fc928) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1101 #4 0x0000000001990f64 in get_prev_frame_always_1 (this_frame=...) at /home/simark/src/binutils-gdb/gdb/frame.c:2281 #5 0x0000000001993034 in get_prev_frame_always (this_frame=...) at /home/simark/src/binutils-gdb/gdb/frame.c:2376 #6 0x000000000199b814 in get_frame_unwind_stop_reason (frame=...) at /home/simark/src/binutils-gdb/gdb/frame.c:3051 #7 0x0000000001359cd8 in dwarf2_frame_cfa (this_frame=...) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1356 #8 0x000000000132122c in dwarf_expr_context::execute_stack_op (this=0xfffff7f80170, op_ptr=0xffff8d8883ee "\217\002", op_end=0xffff8d8883ee "\217\002") at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:2110 #9 0x0000000001317b30 in dwarf_expr_context::eval (this=0xfffff7f80170, addr=0xffff8d8883ed "\234\217\002", len=1) at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1239 #10 0x000000000131d68c in dwarf_expr_context::execute_stack_op (this=0xfffff7f80170, op_ptr=0xffff8d88840e "", op_end=0xffff8d88840e "") at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1811 #11 0x0000000001317b30 in dwarf_expr_context::eval (this=0xfffff7f80170, addr=0xffff8d88840c "\221p", len=2) at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1239 #12 0x0000000001314c3c in dwarf_expr_context::evaluate (this=0xfffff7f80170, addr=0xffff8d88840c "\221p", len=2, as_lval=true, per_cu=0xffff90b03700, frame=..., addr_info=0x0, type=0xffff8f6c8400, subobj_type=0xffff8f6c8400, subobj_offset=0) at /home/simark/src/binutils-gdb/gdb/dwarf2/expr.c:1078 #13 0x000000000149f9e0 in dwarf2_evaluate_loc_desc_full (type=0xffff8f6c8400, frame=..., data=0xffff8d88840c "\221p", size=2, per_cu=0xffff90b03700, per_objfile=0xffff9070b980, subobj_type=0xffff8f6c8400, subobj_byte_offset=0, as_lval=true) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1513 #14 0x00000000014a0100 in dwarf2_evaluate_loc_desc (type=0xffff8f6c8400, frame=..., data=0xffff8d88840c "\221p", size=2, per_cu=0xffff90b03700, per_objfile=0xffff9070b980, as_lval=true) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:1557 #15 0x00000000014aa584 in locexpr_read_variable (symbol=0xffff8f6cd770, frame=...) at /home/simark/src/binutils-gdb/gdb/dwarf2/loc.c:3052 - AArch64 defines a special "prev register" function, aarch64_dwarf2_prev_register, to handle unwinding the PC. This function does frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM); - frame_unwind_register_unsigned ultimately creates a lazy register value, saving the frame id of this_frame->next. this_frame is the user-created frame, to this_frame->next is the special sentinel frame we created for it. So the saved ID is the sentinel frame ID. - When time comes to un-lazify the value, value_fetch_lazy_register calls frame_find_by_id, to find the frame with the ID we saved. - frame_find_by_id sees it's the sentinel frame ID, so returns the sentinel_frame global, which is, if you remember, nullptr. - We hit the `gdb_assert (next_frame != NULL)` assertion in value_fetch_lazy_register. The issues I see here are: - The ID of the sentinel frame created for the user-created frame is not distinguishable from the ID of the regular sentinel frame. So there's no way frame_find_by_id could find the right frame, in value_fetch_lazy_register. - Even if they had distinguishable IDs, sentinel frames created for user frames are not registered anywhere, so there's no easy way frame_find_by_id could find it. This patch addresses these two issues: - Give sentinel frames created for user frames their own distinct IDs - Register sentinel frames in the frame cache, so they can be found with frame_find_by_id. I initially had this split in two patches, but I then found that it was easier to explain as a single patch. Rergarding the first part of the change: with this patch, the sentinel frames created for user frames (in create_new_frame) still have stack_status == FID_STACK_SENTINEL, but their code_addr and stack_addr fields are now filled with the addresses used to create the user frame. This ensures this sentinel frame ID is different from the "target" sentinel frame ID, as well as any other "user" sentinel frame ID. If the user tries to create the same frame, with the same addresses, multiple times, create_sentinel_frame just reuses the existing frame. So we won't end up with multiple user sentinels with the same ID. Regular "target" sentinel frames remain with code_addr and stack_addr unset. The concrete changes for that part are: - Remove the sentinel_frame_id constant, since there isn't one "sentinel frame ID" now. Add the frame_id_build_sentinel function for building sentinel frame IDs and a is_sentinel_frame_id function to check if a frame id represents a sentinel frame. - Replace the sentinel_frame_id check in frame_find_by_id with a comparison to `frame_id_build_sentinel (0, 0)`. The sentinel_frame global is meant to contain a reference to the "target" sentinel, so the one with addresses (0, 0). - Add stack and code address parameters to create_sentinel_frame, to be able to create the various types of sentinel frames. - Adjust get_current_frame to create the regular "target" sentinel. - Adjust create_new_frame to create a sentinel with the ID specific to the created user frame. - Adjust sentinel_frame_prev_register to get the sentinel frame ID from the frame_info object, since there isn't a single "sentinel frame ID" now. - Change get_next_frame_sentinel_okay to check for a sentinel-frame-id-like frame ID, rather than for sentinel_frame specifically, since this function could be called with another sentinel frame (and we would want the assert to catch it). The rest of the change is about registering the sentinel frame in the frame cache: - Change frame_stash_add's assertion to allow sentinel frame levels (-1). - Make create_sentinel_frame add the frame to the frame cache. - Change the "sentinel_frame != NULL" check in reinit_frame_cache for a check that the frame stash is not empty. The idea is that if we only have some user-created frames in the cache when reinit_frame_cache is called, we probably want to emit the frames invalid annotation. The goal of that check is to avoid unnecessary repeated annotations, I suppose, so the "frame cache not empty" check should achieve that. After this change, I think we could theoritically get rid of the sentienl_frame global. That sentinel frame could always be found by looking up `frame_id_build_sentinel (0, 0)` in the frame cache. However, I left the global there to avoid slowing the typical case down for nothing. I however, noted in its comment that it is an optimization. With this fix applied, the gdb.base/frame-view.exp now passes for me on AArch64. value_of_register_lazy now saves the special sentinel frame ID in the value, and value_fetch_lazy_register is able to find that sentinel frame after the frame cache reinit and after the user-created frame was reinflated. Tested-By: Alexandra Petlanova Hajkova <ahajkova@redhat.com> Tested-By: Luis Machado <luis.machado@arm.com> Change-Id: I8b77b3448822c8aab3e1c3dda76ec434eb62704f
2023-02-08gdb: call frame unwinders' dealloc_cache methods through destroying the ↵Simon Marchi1-15/+24
frame cache Currently, some frame resources are deallocated by iterating on the frame chain (starting from the sentinel), calling dealloc_cache. The problem is that user-created frames are not part of that chain, so we never call dealloc_cache for them. I propose to make it so the dealloc_cache callbacks are called when the frames are removed from the frame_stash hash table, by registering a deletion function to the hash table. This happens when frame_stash_invalidate is called by reinit_frame_cache. This way, all frames registered in the cache will get their unwinder's dealloc_cache callbacks called. Note that at the moment, the sentinel frames are not registered in the cache, so we won't call dealloc_cache for them. However, it's just a theoritical problem, because the sentinel frame unwinder does not provide this callback. Also, a subsequent patch will change things so that sentinel frames are registered to the cache. I moved the obstack_free / obstack_init pair below the frame_stash_invalidate call in reinit_frame_cache, because I assumed that some dealloc_cache would need to access some data on that obstack, so it would be better to free it after clearing the hash table. Change-Id: If4f9b38266b458c4e2f7eb43e933090177c22190
2023-01-20gdb: make frame_info_ptr auto-reinflatableSimon Marchi1-3/+4
This is the second step of making frame_info_ptr automatic, reinflate on demand whenever trying to obtain the wrapper frame_info pointer, either through the get method or operator->. Make the reinflate method private, it is used as a convenience method in those two. Add an "is_null" method, because it is often needed to know whether the frame_info_ptr wraps an frame_info or is empty. Make m_ptr mutable, so that it's possible to reinflate const frame_info_ptr objects. Whether m_ptr is nullptr or not does not change the logical state of the object, because we re-create it on demand. I believe this is the right use case for mutable. Change-Id: Icb0552d0035e227f81eb3c121d8a9bb2f9d25794 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: make frame_info_ptr grab frame level and id on constructionSimon Marchi1-8/+11
This is the first step of making frame_info_ptr automatic. Remove the frame_info_ptr::prepare_reinflate method, move that code to the constructor. Change-Id: I85cdae3ab1c043c70e2702e7fb38e9a4a8a675d8 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: make user-created frames reinflatableSimon Marchi1-6/+16
This patch teaches frame_info_ptr to reinflate user-created frames (frames created through create_new_frame, with the "select-frame view" command). Before this patch, frame_info_ptr doesn't support reinflating user-created frames, because it currently reinflates by getting the current target frame (for frame 0) or frame_find_by_id (for other frames). To reinflate a user-created frame, we need to call create_new_frame, to make it lookup an existing user-created frame, or otherwise create one. So, in prepare_reinflate, get the frame id even if the frame has level 0, if it is user-created. In reinflate, if the saved frame id is user create it, call create_new_frame. In order to test this, I initially enhanced the gdb.base/frame-view.exp test added by the previous patch by setting a pretty-printer for the type of the function parameters, in which we do an inferior call. This causes print_frame_args to not reinflate its frame (which is a user-created one) properly. On one machine (my Arch Linux one), it properly catches the bug, as the frame is not correctly restored after printing the first parameter, so it messes up the second parameter: frame #0 baz (z1=hahaha, z2=<error reading variable: frame address is not available.>) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:40 40 return z1.m + z2.n; (gdb) FAIL: gdb.base/frame-view.exp: with_pretty_printer=true: frame frame #0 baz (z1=hahaha, z2=<error reading variable: frame address is not available.>) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:40 40 return z1.m + z2.n; (gdb) FAIL: gdb.base/frame-view.exp: with_pretty_printer=true: frame again However, on another machine (my Ubuntu 22.04 one), it just passes fine, without the appropriate fix. I then thought about writing a selftest for that, it's more reliable. I left the gdb.base/frame-view.exp pretty printer test there, it's already written, and we never know, it might catch some unrelated issue some day. Change-Id: I5849baf77991fc67a15bfce4b5e865a97265b386 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: make it possible to restore selected user-created framesSimon Marchi1-7/+23
I would like to improve frame_info_ptr to automatically grab the information needed to reinflate a frame, and automatically reinflate it as needed. One thing that is in the way is the fact that some frames can be created out of thin air by the create_new_frame function. These frames are not the fruit of unwinding from the target's current frame. These frames are created by the "select-frame view" command. These frames are not correctly handled by the frame save/restore functions, save_selected_frame, restore_selected_frame and lookup_selected_frame. This can be observed here, using the test included in this patch: $ ./gdb --data-directory=data-directory -nx -q testsuite/outputs/gdb.base/frame-view/frame-view Reading symbols from testsuite/outputs/gdb.base/frame-view/frame-view... (gdb) break thread_func Breakpoint 1 at 0x11a2: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c, line 42. (gdb) run Starting program: /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/frame-view/frame-view [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1". [New Thread 0x7ffff7cc46c0 (LWP 4171134)] [Switching to Thread 0x7ffff7cc46c0 (LWP 4171134)] Thread 2 "frame-view" hit Breakpoint 1, thread_func (p=0x0) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:42 42 foo (11); (gdb) info frame Stack level 0, frame at 0x7ffff7cc3ee0: rip = 0x5555555551a2 in thread_func (/home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:42); saved rip = 0x7ffff7d4e8fd called by frame at 0x7ffff7cc3f80 source language c. Arglist at 0x7ffff7cc3ed0, args: p=0x0 Locals at 0x7ffff7cc3ed0, Previous frame's sp is 0x7ffff7cc3ee0 Saved registers: rbp at 0x7ffff7cc3ed0, rip at 0x7ffff7cc3ed8 (gdb) thread 1 [Switching to thread 1 (Thread 0x7ffff7cc5740 (LWP 4171122))] #0 0x00007ffff7d4b4b6 in ?? () from /usr/lib/libc.so.6 Here, we create a custom frame for thread 1 (using the stack from thread 2, for convenience): (gdb) select-frame view 0x7ffff7cc3f80 0x5555555551a2 The first calls to "frame" looks good: (gdb) frame #0 thread_func (p=0x7ffff7d4e630) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:42 42 foo (11); But not the second one: (gdb) frame #0 0x00007ffff7d4b4b6 in ?? () from /usr/lib/libc.so.6 This second "frame" command shows the current target frame instead of the user-created frame. It's not totally clear how the "select-frame view" feature is expected to behave, especially since it's not tested. I heard accounts that it used to be possible to select a frame like this and do "up" and "down" to navigate the backtrace starting from that frame. The fact that create_new_frame calls frame_unwind_find_by_frame to install the right unwinder suggest that it used to be possible. But that doesn't work today: (gdb) select-frame view 0x7ffff7cc3f80 0x5555555551a2 (gdb) up Initial frame selected; you cannot go up. (gdb) down Bottom (innermost) frame selected; you cannot go down. and "backtrace" always shows the actual thread's backtrace, it ignores the user-created frame: (gdb) bt #0 0x00007ffff7d4b4b6 in ?? () from /usr/lib/libc.so.6 #1 0x00007ffff7d50403 in ?? () from /usr/lib/libc.so.6 #2 0x000055555555521a in main () at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/frame-view.c:56 I don't want to address all the `select-frame view` issues , but I think we can agree that the "frame" command changing the selected frame, as shown above, is a bug. I would expect that command to show the currently selected frame and not change it. This happens because of the scoped_restore_selected_frame object in print_frame_args. The frame information is saved in the constructor (the backtrace below), and restored in the destructor. #0 save_selected_frame (frame_id=0x7ffdc0020ad0, frame_level=0x7ffdc0020af0) at /home/simark/src/binutils-gdb/gdb/frame.c:1682 #1 0x00005631390242f0 in scoped_restore_selected_frame::scoped_restore_selected_frame (this=0x7ffdc0020ad0) at /home/simark/src/binutils-gdb/gdb/frame.c:324 #2 0x000056313993581e in print_frame_args (fp_opts=..., func=0x62100023bde0, frame=..., num=-1, stream=0x60b000000300) at /home/simark/src/binutils-gdb/gdb/stack.c:755 #3 0x000056313993ad49 in print_frame (fp_opts=..., frame=..., print_level=1, print_what=SRC_AND_LOC, print_args=1, sal=...) at /home/simark/src/binutils-gdb/gdb/stack.c:1401 #4 0x000056313993835d in print_frame_info (fp_opts=..., frame=..., print_level=1, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /home/simark/src/binutils-gdb/gdb/stack.c:1126 #5 0x0000563139932e0b in print_stack_frame (frame=..., print_level=1, print_what=SRC_AND_LOC, set_current_sal=1) at /home/simark/src/binutils-gdb/gdb/stack.c:368 #6 0x0000563139932bbe in print_stack_frame_to_uiout (uiout=0x611000016840, frame=..., print_level=1, print_what=SRC_AND_LOC, set_current_sal=1) at /home/simark/src/binutils-gdb/gdb/stack.c:346 #7 0x0000563139b0641e in print_selected_thread_frame (uiout=0x611000016840, selection=...) at /home/simark/src/binutils-gdb/gdb/thread.c:1993 #8 0x0000563139940b7f in frame_command_core (fi=..., ignored=true) at /home/simark/src/binutils-gdb/gdb/stack.c:1871 #9 0x000056313994db9e in frame_command_helper<frame_command_core>::base_command (arg=0x0, from_tty=1) at /home/simark/src/binutils-gdb/gdb/stack.c:1976 Since the user-created frame has level 0 (identified by the saved level -1), lookup_selected_frame just reselects the target's current frame, and the user-created frame is lost. My goal here is to fix this particular problem. Currently, select_frame does not set selected_frame_id and selected_frame_level for frames with level 0. It leaves them at null_frame_id / -1, indicating to restore_selected_frame to use the target's current frame. User-created frames also have level 0, so add a special case them such that select_frame saves their selected id and level. save_selected_frame does not need any change. Change the assertion in restore_selected_frame that checks `frame_level != 0` to account for the fact that we can restore user-created frames, which have level 0. Finally, change lookup_selected_frame to make it able to re-create user-created frame_info objects from selected_frame_level and selected_frame_id. Add a minimal test case for the case described above, that is the "select-frame view" command followed by the "frame" command twice. In order to have a known stack frame to switch to, the test spawns a second thread, and tells the first thread to use the other thread's top frame. Change-Id: Ifc77848dc465fbd21324b9d44670833e09fe98c7 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: add create_new_frame(frame_id) overloadSimon Marchi1-8/+18
The subsequent patches will need to call create_new_frame with an existing frame_id representing a user created frame. They could call the existing create_new_frame, passing both addresses, but it seems nicer to have a version of the function that takes a frame_id directly. Change-Id: If31025314fec0c3e644703e4391a5ef8079e1a32 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: add user-created frames to stashSimon Marchi1-2/+17
A subsequent patch makes it possible for frame_info_ptr to reinflate user-created frames. If two frame_info_ptr objects wrapping the same user-created frame_info need to do reinflation, we want them to end up pointing to the same frame_info instance, and not create two separate frame_infos. Otherwise, GDB gets confused down the line, as the state kept in one frame_info object starts differing from the other frame_info. Achieve this by making create_new_frame place the user-created frames in the frame stash. This way, when the second frame_info_ptr does reinflation, it will find the existing frame_info object, created by the other frame_info_ptr, in the frame stash. To make the frame stash differentiate between regular and user-created frame infos which would otherwise be equal, change frame_addr_hash and frame_id::operator== to account for frame_id::user_created_p. I made create_new_frame look up existing frames in the stash, and only create one if it doesn't find one. The goal is to avoid the "select-frame view"/"info frame view"/"frame view" commands from overriding existing entries into the stash, should the user specify the same frame more than once. This will also help in the subsequent patch that makes frame_info_ptr capable of reinflating user-created frames. It will be able to just call create_new_frame and it will do the right thing. Change-Id: I14ba5799012056c007b4992ecb5c7adafd0c2404 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: add frame_id::user_created_pSimon Marchi1-0/+1
Later in this series, we'll need to differentiate frame ids for regular frames (obtained from the target state and unwinding from it) vs frame ids for user-created frames (created with create_new_frame). Add the frame_id::user_created_p field to indicate a frame is user-created, and set it in create_new_frame. The field is otherwise not used yet, so not changes in behavior are expected. Change-Id: I60de3ce581ed01bf0fddb30dff9bd932840120c3 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-20gdb: move frame_info_ptr to frame.{c,h}Simon Marchi1-1/+42
A patch later in this series will make frame_info_ptr access some fields internal to frame_info, which we don't want to expose outside of frame.c. Move the frame_info_ptr class to frame.h, and the definitions to frame.c. Remove frame-info.c and frame-info.h. Change-Id: Ic5949759e6262ea0da6123858702d48fe5673fea Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2023-01-01Update copyright year range in header of all files managed by GDBJoel Brobecker1-1/+1
This commit is the result of running the gdb/copyright.py script, which automated the update of the copyright year range for all source files managed by the GDB project to be updated to include year 2023.
2022-12-07gdb: add invalidate_selected_frame functionSimon Marchi1-2/+14
Instead of using `select_frame (nullptr)` to invalidate the selected frame, introduce a function to do that. There is no change in behavior, but it makes the intent a bit clearer. It also allows adding an assert in select_frame that fi is not nullptr, so it avoids passing nullptr by mistake. Change-Id: I61643f46bc8eca428334513ebdaadab63997bdd0 Reviewed-By: Bruno Larsen <blarsen@redhat.com>
2022-12-01gdb: make frame_register staticSimon Marchi1-1/+6
It is only used inside frame.c. Change-Id: I44eb46a5992412f8f8b4954b2284b0ef3b549504
2022-11-10gdb: move frame_info_ptr method implementations to frame-info.cSimon Marchi1-3/+1
I don't see any particular reason why the implementations of the frame_info_ptr object are in the header file. It only seems to add some complexity. Since we can't include frame.h in frame-info.h, we have to add declarations of functions defined in frame.c, in frame-info.h. By moving the implementations to a new frame-info.c, we can avoid that. Change-Id: I435c828f81b8a3392c43ef018af31effddf6be9c Reviewed-By: Bruno Larsen <blarsen@redhat.com> Reviewed-By: Tom Tromey <tom@tromey.com>
2022-11-07gdb: make lookup_selected_frame staticSimon Marchi1-2/+6
Change-Id: Ide2749a34333110c7f0112b25852c78cace0d2b4
2022-10-28Convert compunit_language to a methodTom Tromey1-4/+4
This changes compunit_language to be a method on compunit_symtab. Approved-By: Simon Marchi <simon.marchi@efficios.com>
2022-10-25gdb: remove spurious spaces after frame_info_ptrSimon Marchi1-16/+16
Fix some whitespace issues introduced with the frame_info_ptr patch. Change-Id: I158d30d8108c97564276c647fc98283ff7b12163
2022-10-19internal_error: remove need to pass __FILE__/__LINE__Pedro Alves1-6/+3
Currently, every internal_error call must be passed __FILE__/__LINE__ explicitly, like: internal_error (__FILE__, __LINE__, "foo %d", var); The need to pass in explicit __FILE__/__LINE__ is there probably because the function predates widespread and portable variadic macros availability. We can use variadic macros nowadays, and in fact, we already use them in several places, including the related gdb_assert_not_reached. So this patch renames the internal_error function to something else, and then reimplements internal_error as a variadic macro that expands __FILE__/__LINE__ itself. The result is that we now should call internal_error like so: internal_error ("foo %d", var); Likewise for internal_warning. The patch adjusts all calls sites. 99% of the adjustments were done with a perl/sed script. The non-mechanical changes are in gdbsupport/errors.h, gdbsupport/gdb_assert.h, and gdb/gdbarch.py. Approved-By: Simon Marchi <simon.marchi@efficios.com> Change-Id: Ia6f372c11550ca876829e8fd85048f4502bdcf06
2022-10-10Change GDB to use frame_info_ptrTom Tromey1-146/+146
This changes GDB to use frame_info_ptr instead of frame_info * The substitution was done with multiple sequential `sed` commands: sed 's/^struct frame_info;/class frame_info_ptr;/' sed 's/struct frame_info \*/frame_info_ptr /g' - which left some issues in a few files, that were manually fixed. sed 's/\<frame_info \*/frame_info_ptr /g' sed 's/frame_info_ptr $/frame_info_ptr/g' - used to remove whitespace problems. The changed files were then manually checked and some 'sed' changes undone, some constructors and some gets were added, according to what made sense, and what Tromey originally did Co-Authored-By: Bruno Larsen <blarsen@redhat.com> Approved-by: Tom Tomey <tom@tromey.com>