-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Assertion failed when interrupting/continuing multiple threads #6
Comments
palves
pushed a commit
that referenced
this issue
Jun 21, 2016
As reported in PR 19998, after type ctrl-c, GDB hang there and does not send interrupt. It causes a fail in gdb.base/interrupt.exp. All targets support remote fileio should be affected. When we type ctrc-c, SIGINT is handled by remote_fileio_sig_set, as shown below, #0 remote_fileio_sig_set (sigint_func=0x4495d0 <remote_fileio_ctrl_c_signal_handler(int)>) at /home/yao/SourceCode/gnu/gdb/git/gdb/remote-fileio.c:325 #1 0x00000000004495de in remote_fileio_ctrl_c_signal_handler (signo=<optimised out>) at /home/yao/SourceCode/gnu/gdb/git/gdb/remote-fileio.c:349 #2 <signal handler called> #3 0x00007ffff647ed83 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:81 #4 0x00000000005530ce in interruptible_select (n=10, readfds=readfds@entry=0x7fffffffd730, writefds=writefds@entry=0x0, exceptfds=exceptfds@entry=0x0, timeout=timeout@entry=0x0) at /home/yao/SourceCode/gnu/gdb/git/gdb/event-top.c:1017 #5 0x000000000061ab20 in stdio_file_read (file=<optimised out>, buf=0x12d02e0 "\n\022-\001", length_buf=16383) at /home/yao/SourceCode/gnu/gdb/git/gdb/ui-file.c:577 #6 0x000000000044a4dc in remote_fileio_func_read (buf=0x12c0360 "") at /home/yao/SourceCode/gnu/gdb/git/gdb/remote-fileio.c:583 #7 0x0000000000449598 in do_remote_fileio_request (uiout=<optimised out>, buf_arg=buf_arg@entry=0x12c0340) at /home/yao/SourceCode/gnu/gdb/git/gdb/remote-fileio.c:1179 we don't set quit_serial_event, do { res = gdb_select (n, readfds, writefds, exceptfds, timeout); } while (res == -1 && errno == EINTR); if (res == 1 && FD_ISSET (fd, readfds)) { errno = EINTR; return -1; } return res; we can't go out of the loop above, and that is why GDB can't send interrupt. Recently, we stop throwing exception from SIGINT handler (remote_fileio_ctrl_c_signal_handler) https://sourceware.org/ml/gdb-patches/2016-03/msg00372.html, which is correct, because gdb_select is interruptible. However, in the same patch series, we add interruptible_select later as a wrapper to gdb_select, https://sourceware.org/ml/gdb-patches/2016-03/msg00375.html and it is not interruptible (because of the loop in it) unless select/poll-able file descriptors are marked. This fix in this patch is to call quit_serial_event_set, so that we can go out of the loop above, return -1 and set errno to EINTR. 2016-06-01 Yao Qi <[email protected]> PR remote/19998 * remote-fileio.c (remote_fileio_ctrl_c_signal_handler): Call quit_serial_event_set.
palves
pushed a commit
that referenced
this issue
Jun 21, 2016
This patch adds some sanity check that reinsert breakpoints must be there when doing step-over on software single step target. The check triggers an assert when running forking-threads-plus-breakpoint.exp on arm-linux target, gdb/gdbserver/linux-low.c:4714: A problem internal to GDBserver has been detected.^M int finish_step_over(lwp_info*): Assertion `has_reinsert_breakpoints ()' failed. the error happens when GDBserver has already resumed a thread of process A for step-over (and wait for it hitting reinsert breakpoint), but receives detach request for process B from GDB, which is shown in the backtrace below, (gdb) bt #2 0x000228aa in finish_step_over (lwp=0x12bbd98) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/linux-low.c:4703 #3 0x00025a50 in finish_step_over (lwp=0x12bbd98) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/linux-low.c:4749 #4 complete_ongoing_step_over () at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/linux-low.c:4760 #5 linux_detach (pid=25228) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/linux-low.c:1503 #6 0x00012bae in process_serial_event () at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/server.c:3974 #7 handle_serial_event (err=<optimized out>, client_data=<optimized out>) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/server.c:4347 #8 0x00016d68 in handle_file_event (event_file_desc=<optimized out>) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/event-loop.c:429 #9 0x000173ea in process_event () at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/event-loop.c:184 #10 start_event_loop () at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/event-loop.c:547 #11 0x0000aa2c in captured_main (argv=<optimized out>, argc=<optimized out>) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/server.c:3719 #12 main (argc=<optimized out>, argv=<optimized out>) at /home/yao/SourceCode/gnu/gdb/git/gdb/gdbserver/server.c:3804 the sanity check tries to find the reinsert breakpoint from process B, but nothing is found. It is wrong, we need to search in process A, since we started step-over of a thread of process A. (gdb) p lwp->thread->entry.id $3 = {pid = 25120, lwp = 25131, tid = 0} (gdb) p current_thread->entry.id $4 = {pid = 25228, lwp = 25228, tid = 0} This patch switched current_thread to the thread we are doing step-over in finish_step_over. gdb/gdbserver: 2016-06-17 Yao Qi <[email protected]> * linux-low.c (maybe_hw_step): New function. (linux_resume_one_lwp_throw): Call maybe_hw_step. (finish_step_over): Switch current_thread to lwp temporarily, and assert has_reinsert_breakpoints returns true. (proceed_one_lwp): Call maybe_hw_step. * mem-break.c (has_reinsert_breakpoints): New function. * mem-break.h (has_reinsert_breakpoints): Declare.
palves
pushed a commit
that referenced
this issue
Aug 25, 2016
If I build gdb with -fsanitize=address and run tests, I get error, malformed linespec error: unexpected colon^M (gdb) PASS: gdb.linespec/ls-errs.exp: lang=C: break : break :=================================================================^M ==3266==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000051451 at pc 0x2b5797a972a8 bp 0x7fffd8e0f3c0 sp 0x7fffd8e0f398^M READ of size 2 at 0x602000051451 thread T0 #0 0x2b5797a972a7 in __interceptor_strlen (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x322a7)^M #1 0x7bd004 in compare_filenames_for_search(char const*, char const*) /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:316^M #2 0x7bd310 in iterate_over_some_symtabs(char const*, char const*, int (*)(symtab*, void*), void*, compunit_symtab*, compunit_symtab*) /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:411^M #3 0x7bd775 in iterate_over_symtabs(char const*, int (*)(symtab*, void*), void*) /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:481^M #4 0x7bda15 in lookup_symtab(char const*) /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:527^M #5 0x7d5e2a in make_file_symbol_completion_list_1 /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:5635^M #6 0x7d61e1 in make_file_symbol_completion_list(char const*, char const*, char const*) /home/yao/SourceCode/gnu/gdb/git/gdb/symtab.c:5684^M #7 0x88dc06 in linespec_location_completer /home/yao/SourceCode/gnu/gdb/git/gdb/completer.c:288 .... 0x602000051451 is located 0 bytes to the right of 1-byte region [0x602000051450,0x602000051451)^M mallocated by thread T0 here: #0 0x2b5797ab97ef in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x547ef)^M #1 0xbbfb8d in xmalloc /home/yao/SourceCode/gnu/gdb/git/gdb/common/common-utils.c:43^M #2 0x88dabd in linespec_location_completer /home/yao/SourceCode/gnu/gdb/git/gdb/completer.c:273^M #3 0x88e5ef in location_completer(cmd_list_element*, char const*, char const*) /home/yao/SourceCode/gnu/gdb/git/gdb/completer.c:531^M #4 0x8902e7 in complete_line_internal /home/yao/SourceCode/gnu/gdb/git/gdb/completer.c:964^ The code in question is here file_to_match = (char *) xmalloc (colon - text + 1); strncpy (file_to_match, text, colon - text + 1); it is likely that file_to_match is not null-terminated. The patch is to strncpy 'colon - text' bytes and explicitly set '\0'. gdb: 2016-08-19 Yao Qi <[email protected]> * completer.c (linespec_location_completer): Make file_to_match null-terminated.
palves
pushed a commit
that referenced
this issue
Nov 7, 2016
Most of the time, the trace should be in one piece. This case is handled fine by GDB. In some cases, however, there may be gaps in the trace. They result from trace decode errors or from overflows. A gap in the trace means we lost an unknown amount of trace. Gaps can be very small, such as a few instructions in the same function, or they can be rather big. We may, for example, lose a few function calls or returns. The trace may continue in a different function and we likely don't know how we got there. Even though we can't say how the program executed across a gap, higher levels may not be impacted too much by it. Let's assume we have functions a-e and a trace that looks roughly like this: a \ b b \ / c <gap> c / d d \ / e Even though we can't say for sure, it is likely that b and c are the same function instance before and after the gap. This patch is trying to connect the c and b function segments across the gap. This will add a to the back trace of b on the right hand side. The changes are reflected in GDB's internal representation of the trace and will improve: - the output of "record function-call-history /c" - the output of "backtrace" in replay mode - source stepping in replay mode will be improved indirectly via the improved back trace I don't have an automated test for this patch; decode errors will be fixed and overflows occur sporadically and are quite rare. I tested it by hacking GDB to provoke a decode error and on the expected gap in the gdb.btrace/dlopen.exp test. The issue is that we can't predict where we will be able to re-sync in case of errors. For the expected decode error in gdb.btrace/dlopen.exp, for example, we may be able to re-sync somewhere in dlclose, in test, in main, or not at all. Here's one example run of gdb.btrace/dlopen.exp with and without this patch. (gdb) info record Active record target: record-btrace Recording format: Intel Processor Trace. Buffer size: 16kB. warning: Non-contiguous trace at instruction 66608 (offset = 0xa83, pc = 0xb7fdcc31). warning: Non-contiguous trace at instruction 66652 (offset = 0xa9b, pc = 0xb7fdcc31). warning: Non-contiguous trace at instruction 66770 (offset = 0xacb, pc = 0xb7fdcc31). warning: Non-contiguous trace at instruction 66966 (offset = 0xb60, pc = 0xb7ff5ee4). warning: Non-contiguous trace at instruction 66994 (offset = 0xb74, pc = 0xb7ff5f24). warning: Non-contiguous trace at instruction 67334 (offset = 0xbac, pc = 0xb7ff5e6d). warning: Non-contiguous trace at instruction 69022 (offset = 0xc04, pc = 0xb7ff60b3). warning: Non-contiguous trace at instruction 69116 (offset = 0xc1c, pc = 0xb7ff60b3). warning: Non-contiguous trace at instruction 69504 (offset = 0xc74, pc = 0xb7ff605d). warning: Non-contiguous trace at instruction 83648 (offset = 0xecc, pc = 0xb7ff6134). warning: Decode error (-13) at instruction 83876 (offset = 0xf48, pc = 0xb7fd6380): no memory mapped at this address. warning: Non-contiguous trace at instruction 83876 (offset = 0x11b7, pc = 0xb7ff1c70). Recorded 83948 instructions in 912 functions (12 gaps) for thread 1 (process 12996). (gdb) record instruction-history 83876, +2 83876 => 0xb7fec46f <call_init.part.0+95>: call *%eax [decode error (-13): no memory mapped at this address] [disabled] 83877 0xb7ff1c70 <_dl_close_worker.part.0+1584>: nop Without the patch, the trace is disconnected and the backtrace is short: (gdb) record goto 83876 #0 0xb7fec46f in call_init.part () from /lib/ld-linux.so.2 (gdb) backtrace #0 0xb7fec46f in call_init.part () from /lib/ld-linux.so.2 #1 0xb7fec5d0 in _dl_init () from /lib/ld-linux.so.2 #2 0xb7ff0fe3 in dl_open_worker () from /lib/ld-linux.so.2 Backtrace stopped: not enough registers or memory available to unwind further (gdb) record goto 83877 #0 0xb7ff1c70 in _dl_close_worker.part.0 () from /lib/ld-linux.so.2 (gdb) backtrace #0 0xb7ff1c70 in _dl_close_worker.part.0 () from /lib/ld-linux.so.2 #1 0xb7ff287a in _dl_close () from /lib/ld-linux.so.2 #2 0xb7fc3d5d in dlclose_doit () from /lib/libdl.so.2 #3 0xb7fec354 in _dl_catch_error () from /lib/ld-linux.so.2 #4 0xb7fc43dd in _dlerror_run () from /lib/libdl.so.2 #5 0xb7fc3d98 in dlclose () from /lib/libdl.so.2 #6 0x0804860a in test () #7 0x08048628 in main () With the patch, GDB is able to connect the trace pieces and we get a full backtrace. (gdb) record goto 83876 #0 0xb7fec46f in call_init.part () from /lib/ld-linux.so.2 (gdb) backtrace #0 0xb7fec46f in call_init.part () from /lib/ld-linux.so.2 #1 0xb7fec5d0 in _dl_init () from /lib/ld-linux.so.2 #2 0xb7ff0fe3 in dl_open_worker () from /lib/ld-linux.so.2 #3 0xb7fec354 in _dl_catch_error () from /lib/ld-linux.so.2 #4 0xb7ff02e2 in _dl_open () from /lib/ld-linux.so.2 #5 0xb7fc3c65 in dlopen_doit () from /lib/libdl.so.2 #6 0xb7fec354 in _dl_catch_error () from /lib/ld-linux.so.2 #7 0xb7fc43dd in _dlerror_run () from /lib/libdl.so.2 #8 0xb7fc3d0e in dlopen@@GLIBC_2.1 () from /lib/libdl.so.2 #9 0xb7ff28ee in _dl_runtime_resolve () from /lib/ld-linux.so.2 #10 0x0804841c in ?? () #11 0x08048470 in dlopen@plt () #12 0x080485a3 in test () #13 0x08048628 in main () (gdb) record goto 83877 #0 0xb7ff1c70 in _dl_close_worker.part.0 () from /lib/ld-linux.so.2 (gdb) backtrace #0 0xb7ff1c70 in _dl_close_worker.part.0 () from /lib/ld-linux.so.2 #1 0xb7ff287a in _dl_close () from /lib/ld-linux.so.2 #2 0xb7fc3d5d in dlclose_doit () from /lib/libdl.so.2 #3 0xb7fec354 in _dl_catch_error () from /lib/ld-linux.so.2 #4 0xb7fc43dd in _dlerror_run () from /lib/libdl.so.2 #5 0xb7fc3d98 in dlclose () from /lib/libdl.so.2 #6 0x0804860a in test () #7 0x08048628 in main () It worked nicely in this case but it may, of course, also lead to weird connections; it is a heuristic, after all. It works best when the gap is small and the trace pieces are long. gdb/ * btrace.c (bfun_s): New typedef. (ftrace_update_caller): Print caller in debug dump. (ftrace_get_caller, ftrace_match_backtrace, ftrace_fixup_level) (ftrace_compute_global_level_offset, ftrace_connect_bfun) (ftrace_connect_backtrace, ftrace_bridge_gap, btrace_bridge_gaps): New. (btrace_compute_ftrace_bts): Pass vector of gaps. Collect gaps. (btrace_compute_ftrace_pt): Likewise. (btrace_compute_ftrace): Split into this, ... (btrace_compute_ftrace_1): ... this, and ... (btrace_finalize_ftrace): ... this. Call btrace_bridge_gaps.
palves
pushed a commit
that referenced
this issue
Dec 2, 2016
… frame This patch ensures that the frame id for the current frame is stashed before that of the previous frame (to the current frame). First, it should be noted that the frame id for the current frame is not stashed by get_current_frame(). The current frame's frame id is lazily computed and stashed via calls to get_frame_id(). However, it's possible for get_prev_frame() to be called without first stashing the current frame. The frame stash is used not only to speed up frame lookups, but also to detect cycles. When attempting to compute the frame id for a "previous" frame (in get_prev_frame_if_no_cycle), a cycle is detected if the computed frame id is already in the stash. If it should happen that a previous frame id is stashed which should represent a cycle for the current frame, then an assertion failure will trigger should get_frame_id() be later called to determine the frame id for the current frame. As of late 2016, with the "Tweak meaning of VALUE_FRAME_ID" patch in place, this actually occurs when running the gdb.dwarf2/dw2-dup-frame.exp test. While attempting to generate a backtrace, the python frame filter code is invoked, leading to frame_info_to_frame_object() (in python/py-frame.c) being called. That function will potentially call get_prev_frame() before get_frame_id() is called. The call to get_prev_frame() can eventually end up in get_prev_frame_if_no_cycle() which, in turn, calls compute_frame_id(), after which the frame id is stashed for the previous frame. If the frame id for the current frame is stashed, the cycle detection code (which relies on the frame stash) in get_prev_frame_if_no_cycle() will be triggered for a cycle starting with the current frame. If the current frame's id is not stashed, the cycle detecting code can't operate as designed. Instead, when get_frame_id() is called on the current frame at some later point, the current frame's id will found to be already in the stash, triggering an assertion failure. Below is an in depth examination of the failure which lead to this change. I've shortened pathnames for brevity and readability. Here's the portion of the log file showing the failure/internal error: (gdb) break stop_frame Breakpoint 1 at 0x40059a: file dw2-dup-frame.c, line 22. (gdb) run Starting program: testsuite/outputs/gdb.dwarf2/dw2-dup-frame/dw2-dup-frame Breakpoint 1, stop_frame () at dw2-dup-frame.c:22 22 } (gdb) bt gdb/frame.c:544: internal-error: frame_id get_frame_id(frame_info*): Assertion `stashed' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) FAIL: gdb.dwarf2/dw2-dup-frame.exp: backtrace from stop_frame (GDB internal error) Here's a partial backtrace from the internal error, showing the frames which I think are relevant, plus several extra to provide context: #0 internal_error ( file=0x932b98 "gdb/frame.c", line=544, fmt=0x932b20 "%s: Assertion `%s' failed.") at gdb/common/errors.c:54 #1 0x000000000072207e in get_frame_id (fi=0xe5a760) at gdb/frame.c:544 #2 0x00000000004eb50d in frame_info_to_frame_object (frame=0xe5a760) at gdb/python/py-frame.c:390 #3 0x00000000004ef5be in bootstrap_python_frame_filters (frame=0xe5a760, frame_low=0, frame_high=-1) at gdb/python/py-framefilter.c:1453 #4 0x00000000004ef7a9 in gdbpy_apply_frame_filter ( extlang=0x8857e0 <extension_language_python>, frame=0xe5a760, flags=7, args_type=CLI_SCALAR_VALUES, out=0xf6def0, frame_low=0, frame_high=-1) at gdb/python/py-framefilter.c:1548 #5 0x00000000005f2c5a in apply_ext_lang_frame_filter (frame=0xe5a760, flags=7, args_type=CLI_SCALAR_VALUES, out=0xf6def0, frame_low=0, frame_high=-1) at gdb/extension.c:572 #6 0x00000000005ea896 in backtrace_command_1 (count_exp=0x0, show_locals=0, no_filters=0, from_tty=1) at gdb/stack.c:1834 Examination of the code in frame_info_to_frame_object(), which is in python/py-frame.c, is key to understanding this problem: if (get_prev_frame (frame) == NULL && get_frame_unwind_stop_reason (frame) != UNWIND_NO_REASON && get_next_frame (frame) != NULL) { frame_obj->frame_id = get_frame_id (get_next_frame (frame)); frame_obj->frame_id_is_next = 1; } else { frame_obj->frame_id = get_frame_id (frame); frame_obj->frame_id_is_next = 0; } I will first note that the frame id for frame has not been computed yet. (This was verified by placing a breakpoint on compute_frame_id().) The call to get_prev_frame() causes the the frame id to (eventually) be computed for the previous frame. Here's a backtrace showing how we get there: #0 compute_frame_id (fi=0x10e2810) at gdb/frame.c:496 #1 0x0000000000724a67 in get_prev_frame_if_no_cycle (this_frame=0xe5a760) at gdb/frame.c:1871 #2 0x0000000000725136 in get_prev_frame_always_1 (this_frame=0xe5a760) at gdb/frame.c:2045 #3 0x000000000072516b in get_prev_frame_always (this_frame=0xe5a760) at gdb/frame.c:2061 #4 0x000000000072570f in get_prev_frame (this_frame=0xe5a760) at gdb/frame.c:2303 #5 0x00000000004eb471 in frame_info_to_frame_object (frame=0xe5a760) at gdb/python/py-frame.c:381 For this particular case, we end up in the else clause of the code above which calls get_frame_id (frame). It's at this point that the frame id for frame is computed. Again, here's a backtrace: #0 compute_frame_id (fi=0xe5a760) at gdb/frame.c:496 #1 0x000000000072203d in get_frame_id (fi=0xe5a760) at gdb/frame.c:539 #2 0x00000000004eb50d in frame_info_to_frame_object (frame=0xe5a760) at gdb/python/py-frame.c:390 The test in question, dw2-dup-frame.exp, deliberately creates a broken (cyclic) stack. So, in this instance, the frame id for the prev `frame' will be the same as that for `frame'. But that particular frame id ended up in the stash during the previous frame operation. When, just a few lines later, we compute the frame id for `frame', the id in question is already in the stash, thus triggering the assertion failure. I considered two other solutions to solving this problem: We could prevent get_prev_frame() from being called before get_frame_id() in frame_info_to_frame_object(). (See above for the snippet of code where this happens.) A call to get_frame_id (frame) could be placed ahead of that code snippet above. I have tested this approach and, while it does work, I can't be certain that get_prev_frame() isn't called ahead of stashing the current frame somewhere else in GDB, but in a less obvious way. Another approach is to stash the current frame's id by calling get_frame_id() in get_current_frame(). This approach is conceptually simpler, but when importing a python unwinder, has the unwelcome side effect of causing the unwinder to be called during import. A cleaner looking fix would be to place this code after code corresponding to the "Don't compute the frame id of the current frame yet..." comment in get_prev_frame_if_no_cycle(). Sadly, this does not work though; by the time we get to this point, the frame state for the prev frame has been modified just enough to cause an internal error to occur when attempting to compute the (current) frame id for inline frames. (The unexpected failure count increases by roughly 130 failures.) Therefore, I decided to place it as early as possible in get_prev_frame(). gdb/ChangeLog: * frame.c (get_prev_frame): Stash frame id for current frame prior to computing frame id for previous frame.
palves
added a commit
that referenced
this issue
Jan 3, 2017
…binations This adds a test that exposes several problems fixed by earlier patches: #1 - Buffer overrun when host/target formats match, but sizes don't. https://sourceware.org/ml/gdb-patches/2016-03/msg00125.html #2 - Missing handling for FR-V FR300. https://sourceware.org/ml/gdb-patches/2016-03/msg00117.html #3 - BFD architectures with spaces in their names (v850). https://sourceware.org/ml/binutils/2016-03/msg00108.html #4 - The OS ABI names with spaces issue. https://sourceware.org/ml/gdb-patches/2016-03/msg00116.html #5 - Bogus HP/PA long double format. https://sourceware.org/ml/gdb-patches/2016-03/msg00122.html #6 - Cris big endian internal error. https://sourceware.org/ml/gdb-patches/2016-03/msg00126.html #7 - Several PowerPC bfd archs/machines not handled by gdb. https://sourceware.org/bugzilla/show_bug.cgi?id=19797 And hopefully helps catch others in the future. This started out as a test that simply did, gdb -ex "print 1.0L" to exercise #1 above. Then to cover both 32-bit target / 64-bit host and the converse, I thought of having the testcase print the floats twice, once with the architecture set to "i386" and then to "i386:x86-64". This way it wouldn't matter whether gdb was built as 32-bit or a 64-bit program. Then I thought that other archs might have similar host/target floatformat conversion issues as well. Instead of hardcoding some architectures in the test file, I thought we could just iterate over all bfd architectures and OS ABIs supported by the gdb build being tested. This is what then exposed all the other problems listed above... With an --enable-targets=all, this exercises over 14 thousand combinations. If left in a single test file, it all consistenly runs in under a minute on my machine (An Intel i7-4810MQ @ 2.8 MHZ running Fedora 23). Split in 8 chunks, as in this commit, it runs in around 25 seconds, with make -j8. To avoid flooding the gdb.sum file, it avoids calling "pass" on each tested combination/iteration. I'm explicitly not implementing that by passing an empty message to gdb_test / gdb_test_multiple, because I still want a FAIL to be logged in gdb.sum. So instead this puts the internal passes in the gdb.log file, only, prefixed "IPASS:", for internal pass. TBC, if some iteration fails, it'll still show up as FAIL in gdb.sum. If this is an approach that takes on, I can see us extending the common bits to support it for all testcases. gdb/testsuite/ChangeLog: 2016-12-09 Pedro Alves <[email protected]> * gdb.base/all-architectures-0.exp: New file. * gdb.base/all-architectures-1.exp: New file. * gdb.base/all-architectures-2.exp: New file. * gdb.base/all-architectures-3.exp: New file. * gdb.base/all-architectures-4.exp: New file. * gdb.base/all-architectures-5.exp: New file. * gdb.base/all-architectures-6.exp: New file. * gdb.base/all-architectures-7.exp: New file. * gdb.base/all-architectures.exp.in: New file.
palves
pushed a commit
that referenced
this issue
Jan 3, 2017
I build GDB for all targets enabled. When I "set architecture rl78", GDB crashes, (gdb) set architecture rl78 Program received signal SIGSEGV, Segmentation fault. append_flags_type_flag (type=0x20cc0e0, bitpos=bitpos@entry=0, name=name@entry=0x11dba3f "CY") at ../../binutils-gdb/gdb/gdbtypes.c:4926 4926 name); (gdb) bt 10 #0 append_flags_type_flag (type=0x20cc0e0, bitpos=bitpos@entry=0, name=name@entry=0x11dba3f "CY") at ../../binutils-gdb/gdb/gdbtypes.c:4926 #1 0x00000000004aaca8 in rl78_gdbarch_init (info=..., arches=<optimized out>) at ../../binutils-gdb/gdb/rl78-tdep.c:1410 #2 0x00000000006b05a4 in gdbarch_find_by_info (info=...) at ../../binutils-gdb/gdb/gdbarch.c:5269 #3 0x000000000060eee4 in gdbarch_update_p (info=...) at ../../binutils-gdb/gdb/arch-utils.c:557 #4 0x000000000060f8a8 in set_architecture (ignore_args=<optimized out>, from_tty=1, c=<optimized out>) at ../../binutils-gdb/gdb/arch-utils.c:531 #5 0x0000000000593d0b in do_set_command (arg=<optimized out>, arg@entry=0x20be851 "rl78", from_tty=from_tty@entry=1, c=c@entry=0x20b1540) at ../../binutils-gdb/gdb/cli/cli-setshow.c:455 #6 0x00000000007665c3 in execute_command (p=<optimized out>, p@entry=0x20be840 "set architecture rl78", from_tty=1) at ../../binutils-gdb/gdb/top.c:666 #7 0x00000000006935f4 in command_handler (command=0x20be840 "set architecture rl78") at ../../binutils-gdb/gdb/event-top.c:577 #8 0x00000000006938d8 in command_line_handler (rl=<optimized out>) at ../../binutils-gdb/gdb/event-top.c:767 #9 0x0000000000692c2c in gdb_rl_callback_handler (rl=0x20be890 "") at ../../binutils-gdb/gdb/event-top.c:200 The cause is that we want to access some builtin types in gdbarch init, but it is not initialized yet. I fix it by creating the type when it is to be used. We've already done this in sparc, sparc64 and m68k. gdb: 2016-12-09 Yao Qi <[email protected]> PR tdep/20953 * rl78-tdep.c (rl78_psw_type): New function. (rl78_register_type): Call rl78_psw_type. (rl78_gdbarch_init): Move code to rl78_psw_type. gdb/testsuite: 2016-12-09 Yao Qi <[email protected]> * gdb.base/all-architectures.exp.in: Remove kfail for rl78.
palves
pushed a commit
that referenced
this issue
Jan 3, 2017
I build GDB with all targets enabled, and "set architecture rx", GDB crashes, (gdb) set architecture rx Program received signal SIGSEGV, Segmentation fault. append_flags_type_flag (type=0x20cc360, bitpos=bitpos@entry=0, name=name@entry=0xd27529 "C") at ../../binutils-gdb/gdb/gdbtypes.c:4926 4926 name); (gdb) bt 10 #0 append_flags_type_flag (type=0x20cc360, bitpos=bitpos@entry=0, name=name@entry=0xd27529 "C") at ../../binutils-gdb/gdb/gdbtypes.c:4926 #1 0x00000000004ce725 in rx_gdbarch_init (info=..., arches=<optimized out>) at ../../binutils-gdb/gdb/rx-tdep.c:1051 #2 0x00000000006b05a4 in gdbarch_find_by_info (info=...) at ../../binutils-gdb/gdb/gdbarch.c:5269 #3 0x000000000060eee4 in gdbarch_update_p (info=...) at ../../binutils-gdb/gdb/arch-utils.c:557 #4 0x000000000060f8a8 in set_architecture (ignore_args=<optimized out>, from_tty=1, c=<optimized out>) at ../../binutils-gdb/gdb/arch-utils.c:531 #5 0x0000000000593d0b in do_set_command (arg=<optimized out>, arg@entry=0x20bee81 "rx ", from_tty=from_tty@entry=1, c=c@entry=0x20b1540) at ../../binutils-gdb/gdb/cli/cli-setshow.c:455 #6 0x00000000007665c3 in execute_command (p=<optimized out>, p@entry=0x20bee70 "set architecture rx ", from_tty=1) at ../../binutils-gdb/gdb/top.c:666 #7 0x00000000006935f4 in command_handler (command=0x20bee70 "set architecture rx ") at ../../binutils-gdb/gdb/event-top.c:577 #8 0x00000000006938d8 in command_line_handler (rl=<optimized out>) at ../../binutils-gdb/gdb/event-top.c:767 #9 0x0000000000692c2c in gdb_rl_callback_handler (rl=0x20be7f0 "") at ../../binutils-gdb/gdb/event-top.c:200 The cause is that we want to access some builtin types in gdbarch init, but it is not initialized yet. I fix it by creating the type when it is to be used. We've already done this in sparc, sparc64 and m68k. gdb: 2016-12-09 Yao Qi <[email protected]> PR tdep/20954 * rx-tdep.c (rx_psw_type): New function. (rx_fpsw_type): New function. (rx_register_type): Call rx_psw_type and rx_fpsw_type. (rx_gdbarch_init): Move code to rx_psw_type and rx_fpsw_type. gdb/testsuite: 2016-12-09 Yao Qi <[email protected]> * gdb.base/all-architectures.exp.in: Remove kfail for "rx".
palves
added a commit
that referenced
this issue
Jan 3, 2017
Nowadays, GDB propagates C++ exceptions across readline using setjmp/longjmp 8952576 ("Propagate GDB/C++ exceptions across readline using sj/lj-based TRY/CATCH") because DWARF-based unwinding can't cross C functions compiled without -fexceptions (see details from the commit above). Unfortunately, toolchains that use SjLj-based C++ exceptions got broken with that fix, because _Unwind_SjLj_Unregister, which is put at the exit of a function, is not executed due to the longjmp added by that commit. (gdb) [New Thread 2936.0xb80] kill Thread 1 received signal SIGSEGV, Segmentation fault. 0x03ff662b in ?? () top?bt 15 #0 0x03ff662b in ?? () #1 0x00526b92 in stdin_event_handler (error=0, client_data=0x172ed8) at ../../binutils-gdb/gdb/event-top.c:555 #2 0x00525a94 in handle_file_event (ready_mask=<optimized out>, file_ptr=0x3ff5cb8) at ../../binutils-gdb/gdb/event-loop.c:733 #3 gdb_wait_for_event (block=block@entry=1) at ../../binutils-gdb/gdb/event-loop.c:884 #4 0x00525bfb in gdb_do_one_event () at ../../binutils-gdb/gdb/event-loop.c:347 #5 0x00525ce5 in start_event_loop () at ../../binutils-gdb/gdb/event-loop.c:371 #6 0x0051fada in captured_command_loop (data=0x0) at ../../binutils-gdb/gdb/main.c:324 #7 0x0051cf5d in catch_errors ( func=func@entry=0x51fab0 <captured_command_loop(void*)>, func_args=func_args@entry=0x0, errstring=errstring@entry=0x7922bf <VEC_interp_factory_p_quick_push(VEC_inte rp_factory_p*, interp_factory*, char const*, unsigned int)::__PRETTY_FUNCTION__+351> "", mask=mask@entry=RETURN_MASK_ALL) at ../../binutils-gdb/gdb/exceptions.c:236 #8 0x00520f0c in captured_main (data=0x328feb4) at ../../binutils-gdb/gdb/main.c:1149 #9 gdb_main (args=args@entry=0x328feb4) at ../../binutils-gdb/gdb/main.c:1159 #10 0x0071e400 in main (argc=1, argv=0x171220) at ../../binutils-gdb/gdb/gdb.c:32 Fix this by making the functions involved in setjmp/longjmp as noexcept, so that the compiler knows it doesn't need to emit the _Unwind_SjLj_Register / _Unwind_SjLj_Unregister calls for C++ exceptions. Tested on x86_64 Fedora 23 with: - GCC 5.3.1 w/ DWARF-based exceptions. - GCC 7 built with --enable-sjlj-exceptions. gdb/ChangeLog: 2016-12-20 Pedro Alves <[email protected]> Yao Qi <[email protected]> PR gdb/20977 * event-top.c (gdb_rl_callback_read_char_wrapper_noexcept): New noexcept function, factored out from ... (gdb_rl_callback_read_char_wrapper): ... this. (gdb_rl_callback_handler): Mark noexcept.
palves
pushed a commit
that referenced
this issue
Jan 24, 2017
New in v2: - Define PyMem_RawMalloc as PyMem_Malloc for Python < 3.4 and use PyMem_RawMalloc in the code. Since Python 3.4, the callback installed in PyOS_ReadlineFunctionPointer should return a value allocated with PyMem_RawMalloc instead of PyMem_Malloc. The reason is that PyMem_Malloc must be called with the Python Global Interpreter Lock (GIL) held, which is not the case in the context where this function is called. PyMem_RawMalloc was introduced for cases like this. In Python 3.6, it looks like they added an assert to verify that PyMem_Malloc was not called without the GIL. The consequence is that typing anything in the python-interactive mode of gdb crashes the process. The same behavior was observed with the official package on Arch Linux as well as with a manual Python build on Ubuntu 14.04. This is what is shown with a debug build of Python 3.6 (the error with a non-debug build is far less clear): (gdb) pi >>> print(1) Fatal Python error: Python memory allocator called without holding the GIL Current thread 0x00007f1459af8780 (most recent call first): [1] 21326 abort ./gdb and the backtrace: #0 0x00007ffff618bc37 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007ffff618f028 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007ffff6b104d6 in Py_FatalError (msg=msg@entry=0x7ffff6ba15b8 "Python memory allocator called without holding the GIL") at Python/pylifecycle.c:1457 #3 0x00007ffff6a37a68 in _PyMem_DebugCheckGIL () at Objects/obmalloc.c:1972 #4 0x00007ffff6a3804e in _PyMem_DebugFree (ctx=0x7ffff6e65290 <_PyMem_Debug+48>, ptr=0x24f8830) at Objects/obmalloc.c:1994 #5 0x00007ffff6a38e1d in PyMem_Free (ptr=<optimized out>) at Objects/obmalloc.c:442 #6 0x00007ffff6b866c6 in _PyFaulthandler_Fini () at ./Modules/faulthandler.c:1369 #7 0x00007ffff6b104bd in Py_FatalError (msg=msg@entry=0x7ffff6ba15b8 "Python memory allocator called without holding the GIL") at Python/pylifecycle.c:1431 #8 0x00007ffff6a37a68 in _PyMem_DebugCheckGIL () at Objects/obmalloc.c:1972 #9 0x00007ffff6a37aa3 in _PyMem_DebugMalloc (ctx=0x7ffff6e65290 <_PyMem_Debug+48>, nbytes=5) at Objects/obmalloc.c:1980 #10 0x00007ffff6a38d91 in PyMem_Malloc (size=<optimized out>) at Objects/obmalloc.c:418 #11 0x000000000064dbe2 in gdbpy_readline_wrapper (sys_stdin=0x7ffff6514640 <_IO_2_1_stdin_>, sys_stdout=0x7ffff6514400 <_IO_2_1_stdout_>, prompt=0x7ffff4d4f7d0 ">>> ") at /home/emaisin/src/binutils-gdb/gdb/python/py-gdb-readline.c:75 The documentation is very clear about it [1] and it was also mentioned in the "What's New In Python 3.4" page [2]. [1] https://docs.python.org/3/c-api/veryhigh.html#c.PyOS_ReadlineFunctionPointer [2] https://docs.python.org/3/whatsnew/3.4.html#changes-in-the-c-api gdb/ChangeLog: * python/python-internal.h (PyMem_RawMalloc): Define for Python < 3.4. * python/py-gdb-readline.c (gdbpy_readline_wrapper): Use PyMem_RawMalloc instead of PyMem_Malloc.
palves
pushed a commit
that referenced
this issue
Jan 24, 2017
When the gdbpy_ref objects get destroyed, they call Py_DECREF to decrement the reference counter of the python object they hold a reference to. Any time we call into the Python API, we should be holding the GIL. The gdbpy_enter object does that for us in an RAII-fashion. However, if gdbpy_enter is declared after a gdbpy_ref object in a function, gdbpy_enter's destructor will be called (and the GIL will be released) before gdbpy_ref's destructor is called. Therefore, we will end up calling Py_DECREF without holding the GIL. This became obvious with Python 3.6, where memory management functions have asserts to make sure that the GIL is held. This was exposed by tests py-as-string.exp, py-function.exp and py-xmethods. For example: (gdb) p $_as_string(enum_valid) Fatal Python error: Python memory allocator called without holding the GIL Current thread 0x00007f7f7b21c780 (most recent call first): [1] 18678 abort (core dumped) ./gdb -nx testsuite/outputs/gdb.python/py-as-string/py-as-string #0 0x00007ffff618bc37 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007ffff618f028 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007ffff6b104d6 in Py_FatalError (msg=msg@entry=0x7ffff6ba15b8 "Python memory allocator called without holding the GIL") at Python/pylifecycle.c:1457 #3 0x00007ffff6a37a68 in _PyMem_DebugCheckGIL () at Objects/obmalloc.c:1972 #4 0x00007ffff6a3804e in _PyMem_DebugFree (ctx=0x7ffff6e65290 <_PyMem_Debug+48>, ptr=0x24f8830) at Objects/obmalloc.c:1994 #5 0x00007ffff6a38e1d in PyMem_Free (ptr=<optimized out>) at Objects/obmalloc.c:442 #6 0x00007ffff6b866c6 in _PyFaulthandler_Fini () at ./Modules/faulthandler.c:1369 #7 0x00007ffff6b104bd in Py_FatalError (msg=msg@entry=0x7ffff6ba15b8 "Python memory allocator called without holding the GIL") at Python/pylifecycle.c:1431 #8 0x00007ffff6a37a68 in _PyMem_DebugCheckGIL () at Objects/obmalloc.c:1972 #9 0x00007ffff6a3804e in _PyMem_DebugFree (ctx=0x7ffff6e652c0 <_PyMem_Debug+96>, ptr=0x7ffff46b6040) at Objects/obmalloc.c:1994 #10 0x00007ffff6a38f55 in PyObject_Free (ptr=<optimized out>) at Objects/obmalloc.c:503 #11 0x00007ffff6a5f27e in unicode_dealloc (unicode=unicode@entry=0x7ffff46b6040) at Objects/unicodeobject.c:1794 #12 0x00007ffff6a352a9 in _Py_Dealloc (op=0x7ffff46b6040) at Objects/object.c:1786 #13 0x000000000063f28b in gdb_Py_DECREF (op=0x7ffff46b6040) at /home/emaisin/src/binutils-gdb/gdb/python/python-internal.h:192 #14 0x000000000063fa33 in gdbpy_ref_policy::decref (ptr=0x7ffff46b6040) at /home/emaisin/src/binutils-gdb/gdb/python/py-ref.h:35 #15 0x000000000063fa77 in gdb::ref_ptr<_object, gdbpy_ref_policy>::~ref_ptr (this=0x7fffffffcdf0, __in_chrg=<optimized out>) at /home/emaisin/src/binutils-gdb/gdb/common/gdb_ref_ptr.h:91 #16 0x000000000064d8b8 in fnpy_call (gdbarch=0x2b50010, language=0x115d2c0 <c_language_defn>, cookie=0x7ffff46b7468, argc=1, argv=0x7fffffffcf48) at /home/emaisin/src/binutils-gdb/gdb/python/py-function.c:145 The fix is to place the gdbpy_enter first in the function. I also cleaned up the comments a bit and removed the unnecessary initialization of the value variable. gdb/ChangeLog: * python/py-function.c (fnpy_call): Reorder declarations to have the gdbpy_enter object declared first. * python/py-xmethods.c (gdbpy_get_xmethod_arg_types): Likewise.
palves
added a commit
that referenced
this issue
Feb 9, 2017
This commit fixes a "-gdb-set logging redirect on" crash by not handling "logging redirect on" on the fly. Previous discussion here: https://sourceware.org/ml/gdb-patches/2017-01/msg00467.html Code for handling "logging redirect on" on the fly was added here: https://sourceware.org/ml/gdb-patches/2010-08/msg00202.html Meanwhile, MI gained support for logging, but flipping redirect "on" on the fly was not considered. The result is that this sequence of commands crashes GDB: -gdb-set logging on -gdb-set logging redirect on Program received signal SIGSEGV, Segmentation fault. 0x00000000008dd7bc in gdb_flush (file=0x2a097f0) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/ui-file.c:95 194 file->to_flush (file); (top-gdb) bt #0 0x00000000008dd7bc in gdb_flush(ui_file*) (file=0x2a097f0) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/ui-file.c:95 #1 0x00000000007b5f34 in gdb_wait_for_event(int) (block=0) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/event-loop.c:752 #2 0x00000000007b52b6 in gdb_do_one_event() () at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/event-loop.c:322 #3 0x00000000007b5362 in start_event_loop() () at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/event-loop.c:371 #4 0x000000000082704a in captured_command_loop(void*) (data=0x0) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/main.c:325 #5 0x00000000007b8d7c in catch_errors(int (*)(void*), void*, char*, return_mask) (func=0x827008 <captured_command_loop(void*)>, func_args=0x0, errstring=0x11dee51 "", mask=RETURN_MASK_ALL) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/exceptions.c:236 #6 0x000000000082839b in captured_main(void*) (data=0x7fffffffd820) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/main.c:1148 During symbol reading, cannot get low and high bounds for subprogram DIE at 24065. #7 0x00000000008283c4 in gdb_main(captured_main_args*) (args=0x7fffffffd820) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/main.c:1158 #8 0x0000000000412d4d in main(int, char**) (argc=4, argv=0x7fffffffd928) at /home/pedro/gdb/mygit/cxx-convertion/src/gdb/gdb.c:32 The handling of redirect on the fly is not really a use case we need to handle, IMO. Its inconsistent (other "set logging foo" commands aren't handled on the fly), and complicates the code significantly. Instead of complicating it further for MI, go back to the original idea of warning, only: https://sourceware.org/ml/gdb-patches/2010-08/msg00083.html New test included. gdb/ChangeLog: 2017-02-02 Pedro Alves <[email protected]> * cli/cli-logging.c (maybe_warn_already_logging): New factored out from ... (set_logging_overwrite): ... here. (logging_no_redirect_file): Delete. (set_logging_redirect): Don't handle redirection on the fly. Instead warn that "logging off" / "logging on" is necessary. (pop_output_files): Delete references to logging_no_redirect_file. (show_logging_command): Always speak in terms of what will happen once logging is reenabled. gdb/testsuite/ChangeLog: 2017-02-02 Pedro Alves <[email protected]> * gdb.mi/mi-logging.exp: Add "redirect while already logging" tests.
palves
pushed a commit
that referenced
this issue
Feb 24, 2017
In commit 2f408ec (Use ui_file_as_string throughout more), we start to new varobj_item, > - vitem = XNEW (struct varobj_item); > + vitem = new varobj_item (); but we still use xfree. This causes some ASAN errors, -var-update container^M =================================================================^M ^[[1m^[[31m==20660==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new vs free) on 0x602000090c10^M ^[[1m^[[0m #0 0x2baa77d03631 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x54631)^M #1 0x80e0c8 in xfree(void*) /home/yao/SourceCode/gnu/gdb/git/gdb/common/common-utils.c:100^M #2 0xc13670 in varobj_clear_saved_item /home/yao/SourceCode/gnu/gdb/git/gdb/varobj.c:727^M #3 0xc13957 in update_dynamic_varobj_children /home/yao/SourceCode/gnu/gdb/git/gdb/varobj.c:752^M #4 0xc1841c in varobj_update(varobj**, int) /home/yao/SourceCode/gnu/gdb/git/gdb/varobj.c:1699^M #5 0x5a2bf7 in varobj_update_one /home/yao/SourceCode/gnu/gdb/git/gdb/mi/mi-cmd-var.c:712^M #6 0x5a2a41 in mi_cmd_var_update(char*, char**, int) /home/yao/SourceCode/gnu/gdb/git/gdb/mi/mi-cmd-var.c:695^ ........ ^M ^[[1m^[[32m0x602000090c10 is located 0 bytes inside of 16-byte region [0x602000090c10,0x602000090c20)^M ^[[1m^[[0m^[[1m^[[35mallocated by thread T0 here:^[[1m^[[0m^M #0 0x2baa77d0415f in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5515f)^M #1 0x63613e in py_varobj_iter_next /home/yao/SourceCode/gnu/gdb/git/gdb/python/py-varobj.c:112^M #2 0xc13b89 in update_dynamic_varobj_children /home/yao/SourceCode/gnu/gdb/git/gdb/varobj.c:776^M #3 0xc1841c in varobj_update(varobj**, int) /home/yao/SourceCode/gnu/gdb/git/gdb/varobj.c:1699^M #4 0x5a2bf7 in varobj_update_one /home/yao/SourceCode/gnu/gdb/git/gdb/mi/mi-cmd-var.c:712^M #5 0x5a2a41 in mi_cmd_var_update(char*, char**, int) /home/yao/SourceCode/gnu/gdb/git/gdb/mi/mi-cmd-var.c:695^M gdb: 2017-02-23 Yao Qi <[email protected]> * varobj.c (varobj_clear_saved_item): Use delete instead of xfree. (update_dynamic_varobj_children): Likewise.
palves
pushed a commit
that referenced
this issue
Feb 24, 2017
ASAN reports an error, -var-create container @ c^M =================================================================^M ^[[1m^[[31m==21639==ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x6030000805c0^M ^[[1m^[[0m #0 0x7f2449b01b2a in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99b2a)^M #1 0xbb601d in update_dynamic_varobj_children ../../binutils-gdb/gdb/varobj.c:794^M #2 0xbb6556 in varobj_get_num_children(varobj*) ../../binutils-gdb/gdb/varobj.c:854^M #3 0x580cb4 in print_varobj ../../binutils-gdb/gdb/mi/mi-cmd-var.c:61^M #4 0x58138b in mi_cmd_var_create(char*, char**, int) ../../binutils-gdb/gdb/mi/mi-cmd-var.c:145^M #5 0x5967ce in mi_cmd_execute ../../binutils-gdb/gdb/mi/mi-main.c:2301^M #6 0x594b05 in captured_mi_execute_command ../../binutils-gdb/gdb/mi/mi-main.c:2001 .... ^M ^[[1m^[[32m0x6030000805c0 is located 0 bytes inside of 32-byte region [0x6030000805c0,0x6030000805e0)^M ^[[1m^[[0m^[[1m^[[35mallocated by thread T0 here:^[[1m^[[0m^M #0 0x7f2449b00602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)^M #1 0x7d1596 in xmalloc ../../binutils-gdb/gdb/common/common-utils.c:43^M #2 0x604176 in py_varobj_iter_new ../../binutils-gdb/gdb/python/py-varobj.c:159^M #3 0x6042da in py_varobj_get_iterator(varobj*, _object*) ../../binutils-gdb/gdb/python/py-varobj.c:198^M #4 0xbb5806 in varobj_get_iterator ../../binutils-gdb/gdb/varobj.c:720^M #5 0xbb5b9b in update_dynamic_varobj_children ../../binutils-gdb/gdb/varobj.c:758^M gdb: 2017-02-23 Yao Qi <[email protected]> * varobj-iter.h (varobj_iter_delete): Call xfree instead of delete.
palves
pushed a commit
that referenced
this issue
Mar 7, 2017
ASAN reports the following error, (gdb) PASS: gdb.fortran/vla-ptr-info.exp: continue to breakpoint: pvla-associated print &pvla^M =================================================================^M ^[[1m^[[31m==14331==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000ea569f at pc 0x0000008eb546 bp 0x7ffde0c1dc70 sp 0x7ffde0c1dc60^M ^[[1m^[[0m^[[1m^[[34mREAD of size 1 at 0x000000ea569f thread T0^[[1m^[[0m^M #0 0x8eb545 in f_print_type(type*, char const*, ui_file*, int, int, type_print_options const*) ../../binutils-gdb/gdb/f-typeprint.c:89^M #1 0xb611e2 in type_print(type*, char const*, ui_file*, int) ../../binutils-gdb/gdb/typeprint.c:365^M #2 0x7b3471 in c_value_print(value*, ui_file*, value_print_options const*) ../../binutils-gdb/gdb/c-valprint.c:650^M #3 0xb99517 in value_print(value*, ui_file*, value_print_options const*) ../../binutils-gdb/gdb/valprint.c:1233^M #4 0xa42be8 in print_formatted ../../binutils-gdb/gdb/printcmd.c:321^M #5 0xa46ac9 in print_value(value*, format_data const*) ../../binutils-gdb/gdb/printcmd.c:1233^M #6 0xa46d82 in print_command_1 ../../binutils-gdb/gdb/printcmd.c:1261^M #7 0xa46e3e in print_command ../../binutils-gdb/gdb/printcmd.c:1267 on this line of code demangled_args = varstring[strlen (varstring) - 1] == ')'; because varstring is an empty string and strlen () is 0, so "strlen () - 1" is definitely out of the bound of "varstring", (gdb) bt 10 at /home/yao/SourceCode/gnu/gdb/git/gdb/f-typeprint.c:56 at /home/yao/SourceCode/gnu/gdb/git/gdb/typeprint.c:365 at /home/yao/SourceCode/gnu/gdb/git/gdb/c-valprint.c:650 at /home/yao/SourceCode/gnu/gdb/git/gdb/valprint.c:1236 This patch adds a pre-check that varstring is empty or not. gdb: 2017-02-27 Yao Qi <[email protected]> * f-typeprint.c (f_print_type): Check "varstring" is empty first.
palves
added a commit
that referenced
this issue
Apr 4, 2017
Commit d7e7473 ("Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy") introduced a problem when using "layout regs", that leads gdb to crash when issuing: ./gdb ./a.out -ex 'layout regs' -ex start From the backtrace, it's caused by this 'delete' on tui_restore_gdbout(): (gdb) bt #0 0x00007ffff6b962b2 in free () from /lib64/libc.so.6 #1 0x000000000059fa47 in tui_restore_gdbout (ui=0x22997b0) at ../../gdb/tui/tui-regs.c:714 #2 0x0000000000619996 in do_my_cleanups (pmy_chain=pmy_chain@entry=0x1e08320 <cleanup_chain>, old_chain=old_chain@entry=0x235b4b0) at ../../gdb/common/cleanups.c:154 #3 0x0000000000619b1d in do_cleanups (old_chain=old_chain@entry=0x235b4b0) at ../../gdb/common/cleanups.c:176 #4 0x000000000059fb0d in tui_register_format (frame=frame@entry=0x22564e0, regnum=regnum@entry=0) at ../../gdb/tui/tui-regs.c:747 #5 0x000000000059ffeb in tui_get_register (data=0x2434d18, changedp=0x0, regnum=0, frame=0x22564e0) at ../../gdb/tui/tui-regs.c:768 #6 tui_show_register_group (refresh_values_only=<optimized out>, frame=0x22564e0, group=0x1e09250 <general_group>) at ../../gdb/tui/tui-regs.c:287 #7 tui_show_registers (group=0x1e09250 <general_group>) at ../../gdb/tui/tui-regs.c:156 #8 0x00000000005a07cf in tui_check_register_values (frame=frame@entry=0x22564e0) at ../../gdb/tui/tui-regs.c:496 #9 0x00000000005a3e65 in tui_check_data_values (frame=frame@entry=0x22564e0) at ../../gdb/tui/tui-windata.c:232 #10 0x000000000059cf65 in tui_refresh_frame_and_register_information (registers_too_p=1) at ../../gdb/tui/tui-hooks.c:156 #11 0x00000000006d5c05 in generic_observer_notify (args=0x7fffffffdbe0, subject=<optimized out>) at ../../gdb/observer.c:167 #12 observer_notify_normal_stop (bs=<optimized out>, print_frame=print_frame@entry=1) at ./observer.inc:61 #13 0x00000000006a6409 in normal_stop () at ../../gdb/infrun.c:8364 #14 0x00000000006af8f5 in fetch_inferior_event (client_data=<optimized out>) at ../../gdb/infrun.c:3990 #15 0x000000000066f0fd in gdb_wait_for_event (block=block@entry=0) at ../../gdb/event-loop.c:859 #16 0x000000000066f237 in gdb_do_one_event () at ../../gdb/event-loop.c:322 #17 0x000000000066f386 in gdb_do_one_event () at ../../gdb/event-loop.c:353 #18 0x00000000007411bc in wait_sync_command_done () at ../../gdb/top.c:570 #19 0x0000000000741426 in maybe_wait_sync_command_done (was_sync=0) at ../../gdb/top.c:587 #20 execute_command (p=<optimized out>, p@entry=0x7fffffffe43a "start", from_tty=from_tty@entry=1) at ../../gdb/top.c:676 #21 0x00000000006c2048 in catch_command_errors (command=0x741200 <execute_command(char*, int)>, arg=0x7fffffffe43a "start", from_tty=1) at ../../gdb/main.c:376 #22 0x00000000006c2b60 in captured_main_1 (context=0x7fffffffde70) at ../../gdb/main.c:1119 #23 captured_main (data=0x7fffffffde70) at ../../gdb/main.c:1140 #24 gdb_main (args=args@entry=0x7fffffffdf90) at ../../gdb/main.c:1158 #25 0x0000000000408cf5 in main (argc=<optimized out>, argv=<optimized out>) at ../../gdb/gdb.c:32 (gdb) f 1 #1 0x000000000059fa47 in tui_restore_gdbout (ui=0x22997b0) at ../../gdb/tui/tui-regs.c:714 714 delete gdb_stdout; The problem is simply that the commit mentioned above made the ui_file that gdb_stdout is temporarily set to be a stack-allocated string_file, while before it used to be a heap-allocated ui_file. The fix is simply to remove the now-incorrect delete. New test included, which exercises enabling all TUI layouts, with and without execution. (This particular crash only triggers with execution.) gdb/ChangeLog: 2017-03-07 Pedro Alves <[email protected]> * tui/tui-regs.c (tui_restore_gdbout): Don't delete gdb_stdout. gdb/testsuite/ChangeLog: 2017-03-07 Pedro Alves <[email protected]> * gdb.base/tui-layout.c: New file. * gdb.base/tui-layout.exp: New file.
palves
added a commit
that referenced
this issue
Aug 31, 2017
Ref: https://sourceware.org/ml/gdb-patches/2017-07/msg00162.html Debugging x86-64 GNU/Linux programs currently crashes GDB in tdesc_use_registers during gdbarch initialization: Program received signal SIGSEGV, Segmentation fault. 0x0000000001093eaf in htab_remove_elt_with_hash (htab=0x2ef9fa0, element=0x26af960, hash=557151073) at src/libiberty/hashtab.c:728 728 if (*slot == HTAB_EMPTY_ENTRY) (top-gdb) p slot $1 = (void **) 0x0 (top-gdb) bt #0 0x0000000001093eaf in htab_remove_elt_with_hash (htab=0x2ef9fa0, element=0x26af960, hash=557151073) at src/libiberty/hashtab.c:728 #1 0x0000000001093e79 in htab_remove_elt (htab=0x2ef9fa0, element=0x26af960) at src/libiberty/hashtab.c:714 #2 0x00000000009121b0 in tdesc_use_registers (gdbarch=0x3001240, target_desc=0x2659cb0, early_data=0x2881cb0) at src/gdb/target-descriptions.c:1328 #3 0x000000000047c93e in i386_gdbarch_init (info=..., arches=0x0) at src/gdb/i386-tdep.c:8634 #4 0x0000000000818d5f in gdbarch_find_by_info (info=...) at src/gdb/gdbarch.c:5394 #5 0x00000000007198a8 in set_gdbarch_from_file (abfd=0x2f48250) at src/gdb/arch-utils.c:618 #6 0x00000000007f21cb in exec_file_attach (filename=0x7fffffffddb0 "/home/pedro/gdb/tests/threads", from_tty=1) at src/gdb/exec.c:380 #7 0x0000000000865c18 in catch_command_errors_const (command=0x7f1d83 <exec_file_attach(char const*, int)>, arg=0x7fffffffddb0 "/home/pedro/gdb/tests/threads", from_tty=1) at src/gdb/main.c:403 #8 0x00000000008669cf in captured_main_1 (context=0x7fffffffd860) at src/gdb/main.c:1035 #9 0x0000000000866de2 in captured_main (data=0x7fffffffd860) at src/gdb/main.c:1142 #10 0x0000000000866e24 in gdb_main (args=0x7fffffffd860) at src/gdb/main.c:1160 #11 0x000000000041312d in main (argc=3, argv=0x7fffffffd968) at src/gdb/gdb.c:32 The direct cause of the crash is that we tried to remove an element from the hash which supposedly exists, but does not. (htab_remove_elt shouldn't really crash in this case, but that's secondary.) The real problem is that early_data passed to tdesc_use_registers includes regs from a target description that is not the target_desc, which violates its assumptions. The registers in question are the fs_base/gs_base registers, added by amd64_init_abi: tdesc_numbered_register (feature, tdesc_data_segments, AMD64_FSBASE_REGNUM, "fs_base"); tdesc_numbered_register (feature, tdesc_data_segments, AMD64_GSBASE_REGNUM, "gs_base"); and that happens because amd64_linux_init_abi uses amd64_init_abi as helper, but they don't coordinate on which fallback tdesc to use. amd64_init_abi does: if (! tdesc_has_registers (tdesc)) tdesc = tdesc_amd64; and then adds the fs_base/gs_base registers of the "tdesc_amd64" tdesc to the tdesc_arch_data. After amd64_init_abi returns, amd64_linux_init_abi does: if (! tdesc_has_registers (tdesc)) tdesc = tdesc_amd64_linux; tdep->tdesc = tdesc; and we end up tdesc_amd64_linux installed in tdep->tdesc. The fix is to make sure that amd64_linux_init_abi and amd64_init_abi agree on default tdesc, by adding a "default tdesc" parameter to amd64_init_abi, instead of having amd64_init_abi hardcode a default. With this, amd64_init_abi creates the fs_base/gs_base registers using the tdesc_amd64_linux tdesc. Tested on x86-64 GNU/Linux, -m64. I don't have an x32 setup handy. Thanks to John Baldwin, Yao Qi and Simon Marchi for the investigation. gdb/ChangeLog: 2017-07-13 Pedro Alves <[email protected]> * amd64-darwin-tdep.c (x86_darwin_init_abi_64): Pass tdesc_amd64 as default tdesc. * amd64-dicos-tdep.c (amd64_dicos_init_abi): * amd64-fbsd-tdep.c (amd64fbsd_init_abi): * amd64-linux-tdep.c (amd64_linux_init_abi): Pass tdesc_amd64_linux as default tdesc. Get final tdesc from the tdep. (amd64_x32_linux_init_abi): Pass tdesc_x32_linux as default tdesc. Get final tdesc from the tdep. * amd64-nbsd-tdep.c (amd64nbsd_init_abi): Pass tdesc_amd64 as default tdesc. * amd64-obsd-tdep.c (amd64obsd_init_abi): Likewise. * amd64-sol2-tdep.c (amd64_sol2_init_abi): Likewise. * amd64-tdep.c (amd64_init_abi): Add 'default_tdesc' parameter. Use it as default tdesc. (amd64_x32_init_abi): Add 'default_tdesc' parameter, and pass it down to amd_init_abi. No longer handle fallback tdesc here. * amd64-tdep.h (tdesc_x32): Declare. (amd64_init_abi, amd64_x32_init_abi): Add 'default_tdesc' parameter. * amd64-windows-tdep.c (amd64_windows_init_abi): Pass tdesc_amd64 as default tdesc.
palves
pushed a commit
that referenced
this issue
Aug 31, 2017
PR 21555 is caused by the exception during the prologue analysis when re-set a breakpoint. (gdb) bt #0 memory_error_message (err=TARGET_XFER_E_IO, gdbarch=0x153db50, memaddr=93824992233232) at ../../binutils-gdb/gdb/corefile.c:192 #1 0x00000000005718ed in memory_error (err=TARGET_XFER_E_IO, memaddr=memaddr@entry=93824992233232) at ../../binutils-gdb/gdb/corefile.c:220 #2 0x00000000005719d6 in read_memory_object (object=object@entry=TARGET_OBJECT_CODE_MEMORY, memaddr=93824992233232, memaddr@entry=1, myaddr=myaddr@entry=0x7fffffffd0a0 "P\333S\001", len=len@entry=1) at ../../binutils-gdb/gdb/corefile.c:259 #3 0x0000000000571c6e in read_code (len=1, myaddr=0x7fffffffd0a0 "P\333S\001", memaddr=<optimized out>) at ../../binutils-gdb/gdb/corefile.c:287 #4 read_code_unsigned_integer (memaddr=memaddr@entry=93824992233232, len=len@entry=1, byte_order=byte_order@entry=BFD_ENDIAN_LITTLE) at ../../binutils-gdb/gdb/corefile.c:362 #5 0x000000000041d4a0 in amd64_analyze_prologue (gdbarch=gdbarch@entry=0x153db50, pc=pc@entry=93824992233232, current_pc=current_pc@entry=18446744073709551615, cache=cache@entry=0x7fffffffd1e0) at ../../binutils-gdb/gdb/amd64-tdep.c:2310 #6 0x000000000041e404 in amd64_skip_prologue (gdbarch=0x153db50, start_pc=93824992233232) at ../../binutils-gdb/gdb/amd64-tdep.c:2459 #7 0x000000000067bfb0 in skip_prologue_sal (sal=sal@entry=0x7fffffffd4e0) at ../../binutils-gdb/gdb/symtab.c:3628 #8 0x000000000067c4d8 in find_function_start_sal (sym=sym@entry=0x1549960, funfirstline=1) at ../../binutils-gdb/gdb/symtab.c:3501 #9 0x000000000060999d in symbol_to_sal (result=result@entry=0x7fffffffd5f0, funfirstline=<optimized out>, sym=sym@entry=0x1549960) at ../../binutils-gdb/gdb/linespec.c:3860 .... #16 0x000000000054b733 in location_to_sals (b=b@entry=0x15792d0, location=0x157c230, search_pspace=search_pspace@entry=0x1148120, found=found@entry=0x7fffffffdc64) at ../../binutils-gdb/gdb/breakpoint.c:14211 #17 0x000000000054c1f5 in breakpoint_re_set_default (b=0x15792d0) at ../../binutils-gdb/gdb/breakpoint.c:14301 #18 0x00000000005412a9 in breakpoint_re_set_one (bint=bint@entry=0x15792d0) at ../../binutils-gdb/gdb/breakpoint.c:14412 This problem can be fixed by - either each prologue analyzer doesn't throw exception, - or catch the exception thrown from gdbarch_skip_prologue, I choose the latter because the former needs to fix *every* prologue analyzer to not throw exception. This error can be reproduced by changing reread.exp. The test reread.exp has already test that breakpoint can be reset correctly after the executable is re-read. This patch extends this test by compiling test c file with and without -fPIE. (gdb) run ^M The program being debugged has been started already.^M Start it from the beginning? (y or n) y^M x86_64/gdb/testsuite/outputs/gdb.base/reread/reread' has changed; re-reading symbols. Error in re-setting breakpoint 1: Cannot access memory at address 0x555555554790^M Error in re-setting breakpoint 2: Cannot access memory at address 0x555555554790^M Starting program: /scratch/yao/gdb/build-git/x86_64/gdb/testsuite/outputs/gdb.base/reread/reread ^M This is foo^M [Inferior 1 (process 27720) exited normally]^M (gdb) FAIL: gdb.base/reread.exp: opts= "-fPIE" "ldflags=-pie" : run to foo() second time (the program exited) This patch doesn't re-indent the code, to keep the patch simple. gdb: 2017-07-25 Yao Qi <[email protected]> PR gdb/21555 * arch-utils.c (gdbarch_skip_prologue_noexcept): New function. * arch-utils.h (gdbarch_skip_prologue_noexcept): Declare. * infrun.c: Include arch-utils.h (handle_step_into_function): Call gdbarch_skip_prologue_noexcept. (handle_step_into_function_backward): Likewise. * symtab.c (skip_prologue_sal): Likewise. gdb/testsuite: 2017-07-25 Yao Qi <[email protected]> PR gdb/21555 * gdb.base/reread.exp: Wrap the whole test with two kinds of compilation flags, with -fPIE and without -fPIE.
palves
added a commit
that referenced
this issue
Oct 6, 2017
…ior yet A following patch will change the default target_thread_architecture method, like this: struct gdbarch * default_thread_architecture (struct target_ops *ops, ptid_t ptid) { - return target_gdbarch (); + inferior *inf = find_inferior_ptid (ptid); + gdb_assert (inf != NULL); + return inf->gdbarch; } This is because target_gdbarch is really just current_inferior()->gdbarch, and it's wrong to return that architecture when the inferior of the passed in PTID is NOT the current inferior -- the inferior for PTID may be running a different architecture. E.g., a mix of 64-bit and 32-bit inferiors in the same debug session. Doing that change above however exposes a problem in "maint print registers", caught be the testsuite: -PASS: gdb.base/maint.exp: maint print registers +FAIL: gdb.base/maint.exp: maint print registers (GDB internal error) ... gdb/inferior.c:309: internal-error: inferior* find_inferior_pid(int): Assertion `pid != 0' failed. A problem internal to GDB has been detected, The call stack looks like this: #0 0x000000000068b707 in internal_error(char const*, int, char const*, ...) (file=0xa9b958 "gdb/inferior.c", line=309, fmt=0xa9b8e0 "%s: Assertion `%s' failed.") at gdb/common/errors.c:54 #1 0x00000000006e1c40 in find_inferior_pid(int) (pid=0) at gdb/inferior.c:309 #2 0x00000000006e1c8d in find_inferior_ptid(ptid_t) (ptid=...) at gdb/inferior.c:323 #3 0x00000000007c18dc in default_thread_architecture(target_ops*, ptid_t) (ops=0xf86d60 <dummy_target>, ptid=...) at gdb/target.c:3134 #4 0x00000000007b5414 in delegate_thread_architecture(target_ops*, ptid_t) (self=0xf86d60 <dummy_target>, arg1=...) at gdb/target-delegates.c:2527 #5 0x00000000007647b3 in get_thread_regcache(ptid_t) (ptid=...) at gdb/regcache.c:466 #6 0x00000000007647ff in get_current_regcache() () at gdb/regcache.c:475 #7 0x0000000000767495 in regcache_print(char const*, regcache_dump_what) (args=0x0, what_to_dump=regcache_dump_none) at gdb/regcache.c:1599 #8 0x0000000000767550 in maintenance_print_registers(char const*, int) (args=0x0, from_tty=1) at gdb/regcache.c:1613 I.e., the test does "maint print registers" while the inferior is not running yet. This is expected to work, and there's already a hack in get_thread_arch_regcache to make it work. Instead of pilling on hacks in the internal of regcache and target_ops, this commit moves the null_ptid special casing to where it belongs -- higher up in the call chain in the implementation of "maint print registers" & co directly. gdb/ChangeLog: 2017-10-04 Pedro Alves <[email protected]> * regcache.c (get_thread_arch_regcache): Remove null_ptid special case. (regcache_print): Handle !target_has_registers here instead.
palves
added a commit
that referenced
this issue
Nov 16, 2017
If you have a breakpoint command that re-resumes the target, like: break foo commands > c > end and then let the inferior run, hitting the breakpoint, and then press Ctrl-C at just the right time, between GDB processing the stop at "foo", and re-resuming the target, you'll hit the QUIT call in infrun.c:resume. With this hack, we can reproduce the bad case consistently: --- a/gdb/inf-loop.c +++ b/gdb/inf-loop.c @@ -31,6 +31,8 @@ #include "top.h" #include "observer.h" +bool continue_hack; + /* General function to handle events in the inferior. */ void @@ -64,6 +66,8 @@ inferior_event_handler (enum inferior_event_type event_type, { check_frame_language_change (); + continue_hack = true; + /* Don't propagate breakpoint commands errors. Either we're stopping or some command resumes the inferior. The user will be informed. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index d425664..c74b14c 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2403,6 +2403,10 @@ resume (enum gdb_signal sig) gdb_assert (!tp->stop_requested); gdb_assert (!thread_is_in_step_over_chain (tp)); + extern bool continue_hack; + + if (continue_hack) + set_quit_flag (); QUIT; The GDB backtrace looks like this: (top-gdb) bt ... #3 0x0000000000612e8b in throw_quit(char const*, ...) (fmt=0xaf84a1 "Quit") at src/gdb/common/common-exceptions.c:408 #4 0x00000000007fc104 in quit() () at src/gdb/utils.c:748 #5 0x00000000006a79d2 in default_quit_handler() () at src/gdb/event-top.c:954 #6 0x00000000007fc134 in maybe_quit() () at src/gdb/utils.c:762 #7 0x00000000006f66a3 in resume(gdb_signal) (sig=GDB_SIGNAL_0) at src/gdb/infrun.c:2406 #8 0x0000000000700c3d in keep_going_pass_signal(execution_control_state*) (ecs=0x7ffcf3744e60) at src/gdb/infrun.c:7793 #9 0x00000000006f5fcd in start_step_over() () at src/gdb/infrun.c:2145 #10 0x00000000006f7b1f in proceed(unsigned long, gdb_signal) (addr=18446744073709551615, siggnal=GDB_SIGNAL_DEFAULT) at src/gdb/infrun.c:3135 #11 0x00000000006ebdd4 in continue_1(int) (all_threads=0) at src/gdb/infcmd.c:842 #12 0x00000000006ec097 in continue_command(char*, int) (args=0x0, from_tty=0) at src/gdb/infcmd.c:938 #13 0x00000000004b5140 in do_cfunc(cmd_list_element*, char*, int) (c=0x2d18570, args=0x0, from_tty=0) at src/gdb/cli/cli-decode.c:106 #14 0x00000000004b8219 in cmd_func(cmd_list_element*, char*, int) (cmd=0x2d18570, args=0x0, from_tty=0) at src/gdb/cli/cli-decode.c:1952 #15 0x00000000007f1532 in execute_command(char*, int) (p=0x7ffcf37452b1 "", from_tty=0) at src/gdb/top.c:608 #16 0x00000000004bd127 in execute_control_command(command_line*) (cmd=0x3a88ef0) at src/gdb/cli/cli-script.c:485 #17 0x00000000005cae0c in bpstat_do_actions_1(bpstat*) (bsp=0x37edcf0) at src/gdb/breakpoint.c:4513 #18 0x00000000005caf67 in bpstat_do_actions() () at src/gdb/breakpoint.c:4563 #19 0x00000000006e8798 in inferior_event_handler(inferior_event_type, void*) (event_type=INF_EXEC_COMPLETE, client_data=0x0) at src/gdb/inf-loop.c:72 #20 0x00000000006f9447 in fetch_inferior_event(void*) (client_data=0x0) at src/gdb/infrun.c:3970 #21 0x00000000006e870e in inferior_event_handler(inferior_event_type, void*) (event_type=INF_REG_EVENT, client_data=0x0) at src/gdb/inf-loop.c:43 #22 0x0000000000494d58 in remote_async_serial_handler(serial*, void*) (scb=0x3585ca0, context=0x2cd1b80) at src/gdb/remote.c:13820 #23 0x000000000044d682 in run_async_handler_and_reschedule(serial*) (scb=0x3585ca0) at src/gdb/ser-base.c:137 #24 0x000000000044d767 in fd_event(int, void*) (error=0, context=0x3585ca0) at src/gdb/ser-base.c:188 #25 0x00000000006a5686 in handle_file_event(file_handler*, int) (file_ptr=0x45997d0, ready_mask=1) at src/gdb/event-loop.c:733 #26 0x00000000006a5c29 in gdb_wait_for_event(int) (block=1) at src/gdb/event-loop.c:859 #27 0x00000000006a4aa6 in gdb_do_one_event() () at src/gdb/event-loop.c:347 #28 0x00000000006a4ade in start_event_loop() () at src/gdb/event-loop.c:371 and when that happens, you end up with GDB's run control in quite a messed up state. Something like this: thread_function1 (arg=0x1) at threads.c:107 107 usleep (SLEEP); /* Loop increment. */ Quit (gdb) c Continuing. ** nothing happens, time passes..., press ctrl-c again ** ^CQuit (gdb) info threads Id Target Id Frame 1 Thread 1462.1462 "threads" (running) * 2 Thread 1462.1466 "threads" (running) 3 Thread 1462.1465 "function0" (running) (gdb) c Cannot execute this command while the selected thread is running. (gdb) The first "Quit" above is thrown from within "resume", and cancels run control while GDB is in the middle of stepping over a breakpoint. with step_over_info_valid_p() true. The next "c" didn't actually resume anything, because GDB throught that the step-over was still in progress. It wasn't, because the thread that was supposed to be stepping over the breakpoint wasn't actually resumed. So at this point, we press Ctrl-C again, and this time, the default quit handler is called directly from the event loop (event-top.c:default_quit_handler -> quit()), because gdb was left owning the terminal (because the previous resume was cancelled before we reach target_resume -> target_terminal::inferior()). Note that the exception called from within resume ends up calling normal_stop via resume_cleanups. That's very borked though, because normal_stop is going to re-handle whatever was the last reported event, possibly even re-running a hook stop... I think that the only sane way to safely cancel the run control state machinery is to push an event via handle_inferior_event like all other events. The fix here does two things, and either alone would fix the problem at hand: #1 - passes the terminal to the inferior earlier, so that any QUIT call from the point we declare the target as running goes to the inferior directly, protecting run control from unsafe QUIT calls. #2 - gets rid of this QUIT call in resume and of its related unsafe resume_cleanups. Aboout #2, the comment describing resume says: /* Resume the inferior, but allow a QUIT. This is useful if the user wants to interrupt some lengthy single-stepping operation (for child processes, the SIGINT goes to the inferior, and so we get a SIGINT random_signal, but for remote debugging and perhaps other targets, that's not true). but that's a really old comment that predates a lot of fixes to Ctrl-C handling throughout both GDB core and the remote target, that made sure that a Ctrl-C isn't ever lost. In any case, if some target depended on this, a much better fix would be to make the target return a SIGINT stop out of target_wait the next time that is called. This was exposed by the new gdb.base/bp-cmds-continue-ctrl-c.exp testcase added later in the series. gdb/ChangeLog: 2017-11-16 Pedro Alves <[email protected]> * infrun.c (resume_cleanups): Delete. (resume): No longer install a resume_cleanups cleanup nor call QUIT. (proceed): Pass the terminal to the inferior. (keep_going_pass_signal): No longer install a resume_cleanups cleanup.
palves
pushed a commit
that referenced
this issue
Dec 13, 2017
Target descriptions are allocated lazily, that is fine in GDBserver, but it is not safe to call malloc in gdb_collect in IPA, because we can set a fast tracepoint in malloc, and when the tracepoint is hit, gdb_collect/malloc is called, deadlock or memory corruption may be triggered. #0 0xf7cfc200 in malloc () #1 0xf7efdc07 in operator new(unsigned int) () #2 0xf7ef7636 in allocate_target_description() () #3 0xf7efcbe1 in i386_create_target_description(unsigned long long, bool) () #4 0xf7efb474 in i386_linux_read_description(unsigned long long) () #5 0xf7efb190 in get_ipa_tdesc(int) () #6 0xf7ef9baa in gdb_collect () The fix is to initialize all target descriptions earlier, when the IPA is loaded. In order to guarantee malloc is not called in IPA in gdb_collect, I change the test to set a breakpoint on malloc, if IPA gdb_collect calls malloc, program will hit the breakpoint, and test fail. continue Continuing. Thread 1 "" hit Breakpoint 5, 0xf7cfc200 in malloc () (gdb) FAIL: gdb.trace/ftrace.exp: advance through tracing gdb/gdbserver: 2017-12-07 Yao Qi <[email protected]> * linux-aarch64-ipa.c (initialize_low_tracepoint): Call aarch64_linux_read_description. * linux-amd64-ipa.c (idx2mask): New array. (get_ipa_tdesc): Move idx2mask out. (initialize_low_tracepoint): Initialize target descriptions. * linux-i386-ipa.c (idx2mask): New array. (get_ipa_tdesc): Move idx2mask out. (initialize_low_tracepoint): Initialize target descriptions. gdb/testsuite: 2017-12-07 Yao Qi <[email protected]> * gdb.trace/ftrace.exp (run_trace_experiment): Set breakpoint on malloc and catch syscall.
palves
added a commit
that referenced
this issue
Feb 16, 2018
At <https://sourceware.org/ml/gdb-patches/2017-12/msg00285.html>, Maciej reported that commit: commit 5cd63fd Date: Wed Oct 4 18:21:10 2017 +0100 Subject: Fix "Remote 'g' packet reply is too long" problems with multiple inferiors made GDB stop working with older stubs. Any attempt to continue execution after the initial connection fails with: [...] Process .../gdb/testsuite/outputs/gdb.base/advance/advance created; pid = 2670 Listening on port 2346 target remote [...]:2346 Remote debugging using [...]:2346 Reading symbols from .../lib64/ld.so.1...done. [Switching to Thread <main>] (gdb) continue Cannot execute this command without a live selected thread. (gdb) The problem is: (gdb) c Cannot execute this command without a live selected thread. (gdb) info threads Id Target Id Frame 1 Thread 14917 0x00007f341cd98ed0 in _start () from /lib64/ld-linux-x86-64.so.2 The current thread <Thread ID 2> has terminated. See `help thread'. ^^^^^^^^^^^ (gdb) Note, thread _2_. There's really only one thread in the inferior (it's still at the entry point), but still GDB added a bogus second thread. The reason GDB started adding a second thread after 5cd63fd is this hunk: + if (event->ptid == null_ptid) + { + const char *thr = strstr (p1 + 1, ";thread:"); + if (thr != NULL) + event->ptid = read_ptid (thr + strlen (";thread:"), + NULL); + else + event->ptid = magic_null_ptid; + } Note the else branch that falls back to magic_null_ptid. We reach that when we process the initial stop reply sent back in response to the the "?" (status) packet early in the connection setup: Sending packet: $?#3f...Ack Packet received: T0506:0000000000000000;07:40a510f4fd7f0000;10:d0fe1201577f0000; And note that that response does not include a ";thread:XXX" part. This stop reply is processed after listing threads with qfThreadInfo / qsThreadInfo : Sending packet: $qfThreadInfo#bb...Ack Packet received: m3915 Sending packet: $qsThreadInfo#c8...Ack Packet received: l meaning, when we process that stop reply, we treat the event as coming from a thread with ptid == magic_null_ptid, which is not yet in the thread list, so we add it then: (top-gdb) p ptid $1 = {m_pid = 42000, m_lwp = -1, m_tid = 1} (top-gdb) bt #0 0x0000000000840a8c in add_thread_silent(ptid_t) (ptid=...) at src/gdb/thread.c:269 #1 0x00000000007ad61d in remote_add_thread(ptid_t, int, int) (ptid=..., running=0, executing=0) at src/gdb/remote.c:1838 #2 0x00000000007ad8de in remote_notice_new_inferior(ptid_t, int) (currthread=..., executing=0) at src/gdb/remote.c:1921 #3 0x00000000007b758b in process_stop_reply(stop_reply*, target_waitstatus*) (stop_reply=0x1158860, status=0x7fffffffcc00) at src/gdb/remote.c:7217 #4 0x00000000007b7a38 in remote_wait_as(ptid_t, target_waitstatus*, int) (ptid=..., status=0x7fffffffcc00, options=0) at src/gdb/remote.c:7380 #5 0x00000000007b7cd1 in remote_wait(target_ops*, ptid_t, target_waitstatus*, int) (ops=0x102fac0 <remote_ops>, ptid=..., status=0x7fffffffcc00, options=0) at src/gdb/remote.c:7446 #6 0x000000000081587b in delegate_wait(target_ops*, ptid_t, target_waitstatus*, int) (self=0x102fac0 <remote_ops>, arg1=..., arg2=0x7fffffffcc00, arg3=0) at src/gdb/target-delegates.c:138 #7 0x0000000000827d77 in target_wait(ptid_t, target_waitstatus*, int) (ptid=..., status=0x7fffffffcc00, options=0) at src/gdb/target.c:2179 #8 0x0000000000715fda in do_target_wait(ptid_t, target_waitstatus*, int) (ptid=..., status=0x7fffffffcc00, options=0) at src/gdb/infrun.c:3589 #9 0x0000000000716351 in wait_for_inferior() () at src/gdb/infrun.c:3707 #10 0x0000000000715435 in start_remote(int) (from_tty=1) at src/gdb/infrun.c:3212 things go downhill from this. We don't see the problem with current master gdbserver, because that version always sends the ";thread:" part in the initial stop reply: Sending packet: $?#3f...Packet received: T0506:0000000000000000;07:a0d4ffffff7f0000;10:d05eddf7ff7f0000;thread:p3cea.3cea;core:3; Years ago I had added a "--disable-packet=" command line option to gdbserver which comes in handy for testing this, since the existing "--disable-packet=Tthread" precisely makes gdbserver not send that ";thread:" part in stop replies. The testcase added by this commit emulates old gdbserver making use of that. I've compared a testrun at 5cd63fd^ (before regression) with 'current master+patch', against old gdbserver at f8b73d1^. I hacked out --once, and "monitor exit" to be able to test. The results are a bit too unstable to tell accurately, but it looked like there were no regressions. Maciej confirmed this worked for him as well. No regressions on master (against master gdbserver). gdb/ChangeLog: 2018-01-11 Pedro Alves <[email protected]> PR remote/22597 * remote.c (remote_parse_stop_reply): Default to the last-set general thread instead of to 'magic_null_ptid'. gdb/testsuite/ChangeLog: 2018-01-11 Pedro Alves <[email protected]> PR remote/22597 * gdb.server/stop-reply-no-thread.c: New file. * gdb.server/stop-reply-no-thread.exp: New file.
palves
pushed a commit
that referenced
this issue
Feb 16, 2018
When running the test gdb.dwarf2/dw2-bad-parameter-type.exp under valgrind, I see the following issue reported (on x86-64 Fedora): (gdb) ptype f ==5203== Invalid read of size 1 ==5203== at 0x6931FE: process_die_scope::~process_die_scope() (dwarf2read.c:10642) ==5203== by 0x66818F: process_die(die_info*, dwarf2_cu*) (dwarf2read.c:10664) ==5203== by 0x66A01F: read_file_scope(die_info*, dwarf2_cu*) (dwarf2read.c:11650) ==5203== by 0x667F2D: process_die(die_info*, dwarf2_cu*) (dwarf2read.c:10672) ==5203== by 0x6677B6: process_full_comp_unit(dwarf2_per_cu_data*, language) (dwarf2read.c:10445) ==5203== by 0x66657A: process_queue(dwarf2_per_objfile*) (dwarf2read.c:9945) ==5203== by 0x6559B4: dw2_do_instantiate_symtab(dwarf2_per_cu_data*) (dwarf2read.c:3163) ==5203== by 0x66683D: psymtab_to_symtab_1(partial_symtab*) (dwarf2read.c:10034) ==5203== by 0x66622A: dwarf2_read_symtab(partial_symtab*, objfile*) (dwarf2read.c:9811) ==5203== by 0x787984: psymtab_to_symtab(objfile*, partial_symtab*) (psymtab.c:792) ==5203== by 0x786E3E: psym_lookup_symbol(objfile*, int, char const*, domain_enum_tag) (psymtab.c:522) ==5203== by 0x804BD0: lookup_symbol_via_quick_fns(objfile*, int, char const*, domain_enum_tag) (symtab.c:2383) ==5203== Address 0x147ed063 is 291 bytes inside a block of size 4,064 free'd ==5203== at 0x4C2CD5A: free (vg_replace_malloc.c:530) ==5203== by 0x444415: void xfree<void>(void*) (common-utils.h:60) ==5203== by 0x9DA8C2: call_freefun (obstack.c:103) ==5203== by 0x9DAD35: _obstack_free (obstack.c:280) ==5203== by 0x44464C: auto_obstack::~auto_obstack() (gdb_obstack.h:73) ==5203== by 0x68AFB0: dwarf2_cu::~dwarf2_cu() (dwarf2read.c:25080) ==5203== by 0x68B204: free_one_cached_comp_unit(dwarf2_per_cu_data*) (dwarf2read.c:25174) ==5203== by 0x66668C: dwarf2_release_queue(void*) (dwarf2read.c:9982) ==5203== by 0x563A4C: do_my_cleanups(cleanup**, cleanup*) (cleanups.c:154) ==5203== by 0x563AA7: do_cleanups(cleanup*) (cleanups.c:176) ==5203== by 0x5646CE: throw_exception_cxx(gdb_exception) (common-exceptions.c:289) ==5203== by 0x5647B7: throw_exception(gdb_exception) (common-exceptions.c:317) ==5203== Block was alloc'd at ==5203== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) ==5203== by 0x564BE8: xmalloc (common-utils.c:44) ==5203== by 0x9DA872: call_chunkfun (obstack.c:94) ==5203== by 0x9DA935: _obstack_begin_worker (obstack.c:141) ==5203== by 0x9DAA3C: _obstack_begin (obstack.c:164) ==5203== by 0x4445E0: auto_obstack::auto_obstack() (gdb_obstack.h:70) ==5203== by 0x68AE07: dwarf2_cu::dwarf2_cu(dwarf2_per_cu_data*) (dwarf2read.c:25073) ==5203== by 0x661A8A: init_cutu_and_read_dies(dwarf2_per_cu_data*, abbrev_table*, int, int, void (*)(die_reader_specs const*, unsigned char const*, die_info*, int, void*), void*) (dwarf2read.c:7869) ==5203== by 0x666A29: load_full_comp_unit(dwarf2_per_cu_data*, language) (dwarf2read.c:10108) ==5203== by 0x655847: load_cu(dwarf2_per_cu_data*) (dwarf2read.c:3120) ==5203== by 0x655928: dw2_do_instantiate_symtab(dwarf2_per_cu_data*) (dwarf2read.c:3148) ==5203== by 0x66683D: psymtab_to_symtab_1(partial_symtab*) (dwarf2read.c:10034) There's actually a series of three issues reported, but it turns out they're all related, so we can consider on the first one. The invalid read is triggered from a destructor which is being invoked as part of a stack unwind after throwing an error. At the time the error is thrown, the stack looks like this: #0 0x00000000009f4ecd in __cxa_throw () #1 0x0000000000564761 in throw_exception_cxx (exception=...) at ../../src/gdb/common/common-exceptions.c:303 #2 0x00000000005647b8 in throw_exception (exception=...) at ../../src/gdb/common/common-exceptions.c:317 #3 0x00000000005648ff in throw_it(return_reason, errors, const char *, typedef __va_list_tag __va_list_tag *) (reason=RETURN_ERROR, error=GENERIC_ERROR, fmt=0xb33020 "Dwarf Error: Cannot find DIE at 0x%x referenced from DIE at 0x%x [in module %s]", ap=0x7fff387f2d68) at ../../src/gdb/common/common-exceptions.c:373 #4 0x0000000000564929 in throw_verror (error=GENERIC_ERROR, fmt=0xb33020 "Dwarf Error: Cannot find DIE at 0x%x referenced from DIE at 0x%x [in module %s]", ap=0x7fff387f2d68) at ../../src/gdb/common/common-exceptions.c:379 #5 0x0000000000867be4 in verror (string=0xb33020 "Dwarf Error: Cannot find DIE at 0x%x referenced from DIE at 0x%x [in module %s]", args=0x7fff387f2d68) at ../../src/gdb/utils.c:251 #6 0x000000000056879d in error (fmt=0xb33020 "Dwarf Error: Cannot find DIE at 0x%x referenced from DIE at 0x%x [in module %s]") at ../../src/gdb/common/errors.c:43 #7 0x0000000000686875 in follow_die_ref (src_die=0x30bc8a0, attr=0x30bc8c8, ref_cu=0x7fff387f2ed0) at ../../src/gdb/dwarf2read.c:22969 #8 0x00000000006844cd in lookup_die_type (die=0x30bc8a0, attr=0x30bc8c8, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:21976 #9 0x0000000000683f27 in die_type (die=0x30bc8a0, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:21832 #10 0x0000000000679b39 in read_subroutine_type (die=0x30bc830, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:17343 #11 0x00000000006845fb in read_type_die_1 (die=0x30bc830, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:22035 #12 0x0000000000684576 in read_type_die (die=0x30bc830, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:22010 #13 0x000000000067003f in read_func_scope (die=0x30bc830, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:13822 #14 0x0000000000667f5e in process_die (die=0x30bc830, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:10679 #15 0x000000000066a020 in read_file_scope (die=0x30bc720, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:11650 #16 0x0000000000667f2e in process_die (die=0x30bc720, cu=0x30bc5d0) at ../../src/gdb/dwarf2read.c:10672 #17 0x00000000006677b7 in process_full_comp_unit (per_cu=0x3089b80, pretend_language=language_minimal) at ../../src/gdb/dwarf2read.c:10445 #18 0x000000000066657b in process_queue (dwarf2_per_objfile=0x30897d0) at ../../src/gdb/dwarf2read.c:9945 #19 0x00000000006559b5 in dw2_do_instantiate_symtab (per_cu=0x3089b80) at ../../src/gdb/dwarf2read.c:3163 #20 0x000000000066683e in psymtab_to_symtab_1 (pst=0x3089bd0) at ../../src/gdb/dwarf2read.c:10034 #21 0x000000000066622b in dwarf2_read_symtab (self=0x3089bd0, objfile=0x3073f40) at ../../src/gdb/dwarf2read.c:9811 #22 0x0000000000787985 in psymtab_to_symtab (objfile=0x3073f40, pst=0x3089bd0) at ../../src/gdb/psymtab.c:792 #23 0x0000000000786e3f in psym_lookup_symbol (objfile=0x3073f40, block_index=1, name=0x30b2e30 "f", domain=VAR_DOMAIN) at ../../src/gdb/psymtab.c:522 #24 0x0000000000804bd1 in lookup_symbol_via_quick_fns (objfile=0x3073f40, block_index=1, name=0x30b2e30 "f", domain=VAR_DOMAIN) at ../../src/gdb/symtab.c:2383 #25 0x0000000000804fe4 in lookup_symbol_in_objfile (objfile=0x3073f40, block_index=1, name=0x30b2e30 "f", domain=VAR_DOMAIN) at ../../src/gdb/symtab.c:2558 #26 0x0000000000805125 in lookup_static_symbol (name=0x30b2e30 "f", domain=VAR_DOMAIN) at ../../src/gdb/symtab.c:2595 #27 0x0000000000804357 in lookup_symbol_aux (name=0x30b2e30 "f", match_type=symbol_name_match_type::FULL, block=0x0, domain=VAR_DOMAIN, language=language_c, is_a_field_of_this=0x0) at ../../src/gdb/symtab.c:2105 #28 0x0000000000803ad9 in lookup_symbol_in_language (name=0x30b2e30 "f", block=0x0, domain=VAR_DOMAIN, lang=language_c, is_a_field_of_this=0x0) at ../../src/gdb/symtab.c:1887 #29 0x0000000000803b53 in lookup_symbol (name=0x30b2e30 "f", block=0x0, domain=VAR_DOMAIN, is_a_field_of_this=0x0) at ../../src/gdb/symtab.c:1899 #30 0x000000000053b246 in classify_name (par_state=0x7fff387f6090, block=0x0, is_quoted_name=false, is_after_structop=false) at ../../src/gdb/c-exp.y:2879 #31 0x000000000053b7e9 in c_yylex () at ../../src/gdb/c-exp.y:3083 #32 0x000000000053414a in c_yyparse () at c-exp.c:1903 #33 0x000000000053c2e7 in c_parse (par_state=0x7fff387f6090) at ../../src/gdb/c-exp.y:3255 #34 0x0000000000774a02 in parse_exp_in_context_1 (stringptr=0x7fff387f61c0, pc=0, block=0x0, comma=0, void_context_p=0, out_subexp=0x0) at ../../src/gdb/parse.c:1213 #35 0x000000000077476a in parse_exp_in_context (stringptr=0x7fff387f61c0, pc=0, block=0x0, comma=0, void_context_p=0, out_subexp=0x0) at ../../src/gdb/parse.c:1115 #36 0x0000000000774714 in parse_exp_1 (stringptr=0x7fff387f61c0, pc=0, block=0x0, comma=0) at ../../src/gdb/parse.c:1106 #37 0x0000000000774c53 in parse_expression (string=0x27ff996 "f") at ../../src/gdb/parse.c:1253 #38 0x0000000000861dc4 in whatis_exp (exp=0x27ff996 "f", show=1) at ../../src/gdb/typeprint.c:472 #39 0x00000000008620d8 in ptype_command (type_name=0x27ff996 "f", from_tty=1) at ../../src/gdb/typeprint.c:561 #40 0x000000000047430b in do_const_cfunc (c=0x3012010, args=0x27ff996 "f", from_tty=1) at ../../src/gdb/cli/cli-decode.c:106 #41 0x000000000047715e in cmd_func (cmd=0x3012010, args=0x27ff996 "f", from_tty=1) at ../../src/gdb/cli/cli-decode.c:1886 #42 0x00000000008431bb in execute_command (p=0x27ff996 "f", from_tty=1) at ../../src/gdb/top.c:630 #43 0x00000000006bf946 in command_handler (command=0x27ff990 "ptype f") at ../../src/gdb/event-top.c:583 #44 0x00000000006bfd12 in command_line_handler (rl=0x30bb3a0 "\240\305\v\003") at ../../src/gdb/event-top.c:774 The problem is that in `process_die` (frames 14 and 16) we create a `process_die_scope` object, that takes a copy of the `struct dwarf2_cu *` passed into the frame. The destructor of the `process_die_scope` dereferences the stored pointer. This wouldn't be an issue, except... ... in dw2_do_instantiate_symtab (frame 19) a clean up was registered that clears the dwarf2_queue in case of an error. Part of this clean up involves deleting the `struct dwarf2_cu`s referenced from the queue.. The problem then, is that cleanups are processed at the site of the throw, while, class destructors are invoked as we unwind their frame. The result is that we process the frame 19 cleanup (and delete the struct dwarf2_cu) before we process the destructors in frames 14 and 16. When we do get back to frames 14 and 16 the objects being references have already been deleted. The solution is to remove the cleanup from dw2_do_instantiate_symtab, and instead use a destructor to release the dwarf2_queue instead. With this patch in place, the valgrind errors are now resolved. gdb/ChangeLog: * dwarf2read.c (dwarf2_release_queue): Delete function, move body into... (class dwarf2_queue_guard): ...the destructor of this new class. (dw2_do_instantiate_symtab): Create instance of the new class dwarf2_queue_guard, remove cleanup.
palves
added a commit
that referenced
this issue
Apr 14, 2018
A future patch will propose making the remote target's target_ops be heap-allocated (to make it possible to have multiple instances of remote targets, for multiple simultaneous connections), and will delete/destroy the remote target at target_close time. That change trips on a latent problem, though. File I/O handles remain open even after the target is gone, with a dangling pointer to a target that no longer exists. This results in GDB crashing when it calls the target_ops backend associated with the file handle: (gdb) Disconnect Ending remote debugging. * GDB crashes deferencing a dangling pointer Backtrace: #0 0x00007f79338570a0 in main_arena () at /lib64/libc.so.6 #1 0x0000000000858bfe in target_fileio_close(int, int*) (fd=1, target_errno=0x7ffe0499a4c8) at src/gdb/target.c:2980 #2 0x00000000007088bd in gdb_bfd_iovec_fileio_close(bfd*, void*) (abfd=0x1a631b0, stream=0x223c9d0) at src/gdb/gdb_bfd.c:353 #3 0x0000000000930906 in opncls_bclose (abfd=0x1a631b0) at src/bfd/opncls.c:528 #4 0x0000000000930cf9 in bfd_close_all_done (abfd=0x1a631b0) at src/bfd/opncls.c:768 #5 0x0000000000930cb3 in bfd_close (abfd=0x1a631b0) at src/bfd/opncls.c:735 #6 0x0000000000708dc5 in gdb_bfd_close_or_warn(bfd*) (abfd=0x1a631b0) at src/gdb/gdb_bfd.c:511 #7 0x00000000007091a2 in gdb_bfd_unref(bfd*) (abfd=0x1a631b0) at src/gdb/gdb_bfd.c:615 #8 0x000000000079ed8e in objfile::~objfile() (this=0x2154730, __in_chrg=<optimized out>) at src/gdb/objfiles.c:682 #9 0x000000000079fd1a in objfile_purge_solibs() () at src/gdb/objfiles.c:1065 #10 0x00000000008162ca in no_shared_libraries(char const*, int) (ignored=0x0, from_tty=1) at src/gdb/solib.c:1251 #11 0x000000000073b89b in disconnect_command(char const*, int) (args=0x0, from_tty=1) at src/gdb/infcmd.c:3035 This goes unnoticed in current master, because the current remote target's target_ops is never destroyed nowadays, so we end up calling: remote_hostio_close -> remote_hostio_send_command which gracefully fails with FILEIO_ENOSYS if remote_desc is NULL (because the target is closed). Fix this by invalidating a target's file I/O handles when the target is closed. With this change, remote_hostio_send_command no longer needs to handle the case of being called with a closed remote target, originally added here: <https://sourceware.org/ml/gdb-patches/2008-08/msg00359.html>. gdb/ChangeLog: 2018-04-11 Pedro Alves <[email protected]> * target.c (fileio_fh_t::t): Add comment. (target_fileio_pwrite, target_fileio_pread, target_fileio_fstat) (target_fileio_close): Handle a NULL target. (invalidate_fileio_fh): New. (target_close): Call it. * remote.c (remote_hostio_send_command): No longer check whether remote_desc is open.
palves
added a commit
that referenced
this issue
Sep 20, 2018
…b/23379) This commit fixes a 8.1->8.2 regression exposed by gdb.python/py-evthreads.exp when testing with --target_board=native-gdbserver. gdb.log shows: src/gdb/thread.c:93: internal-error: thread_info* inferior_thread(): Assertion `tp' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) FAIL: gdb.python/py-evthreads.exp: run to breakpoint 1 (GDB internal error) A backtrace shows (frames #2 and #10 highlighted) that the assertion fails when GDB is setting up the connection to the remote target, in non-stop mode: #0 0x0000000000622ff0 in internal_error(char const*, int, char const*, ...) (file=0xc1ad98 "src/gdb/thread.c", line=93, fmt=0xc1ad20 "%s: Assertion `%s' failed.") at src/gdb/common/errors.c:54 #1 0x000000000089567e in inferior_thread() () at src/gdb/thread.c:93 = #2 0x00000000004da91d in get_event_thread() () at src/gdb/python/py-threadevent.c:38 #3 0x00000000004da9b7 in create_thread_event_object(_typeobject*, _object*) (py_type=0x11574c0 <continue_event_object_type>, thread=0x0) at src/gdb/python/py-threadevent.c:60 #4 0x00000000004bf6fe in create_continue_event_object() () at src/gdb/python/py-continueevent.c:27 #5 0x00000000004bf738 in emit_continue_event(ptid_t) (ptid=...) at src/gdb/python/py-continueevent.c:40 #6 0x00000000004c7d47 in python_on_resume(ptid_t) (ptid=...) at src/gdb/python/py-inferior.c:108 #7 0x0000000000485bfb in std::_Function_handler<void (ptid_t), void (*)(ptid_t)>::_M_invoke(std::_Any_data const&, ptid_t&&) (__functor=..., __args#0=...) at /usr/include/c++/7/bits/std_function.h:316 #8 0x000000000089b416 in std::function<void (ptid_t)>::operator()(ptid_t) const (this=0x12aa600, __args#0=...) at /usr/include/c++/7/bits/std_function.h:706 #9 0x000000000089aa0e in gdb::observers::observable<ptid_t>::notify(ptid_t) const (this=0x118a7a0 <gdb::observers::target_resumed>, args#0=...) at src/gdb/common/observable.h:106 = #10 0x0000000000896fbe in set_running(ptid_t, int) (ptid=..., running=1) at src/gdb/thread.c:880 #11 0x00000000007f750f in remote_target::remote_add_thread(ptid_t, bool, bool) (this=0x12c5440, ptid=..., running=true, executing=true) at src/gdb/remote.c:2434 #12 0x00000000007f779d in remote_target::remote_notice_new_inferior(ptid_t, int) (this=0x12c5440, currthread=..., executing=1) at src/gdb/remote.c:2515 #13 0x00000000007f9c44 in remote_target::update_thread_list() (this=0x12c5440) at src/gdb/remote.c:3831 #14 0x00000000007fb922 in remote_target::start_remote(int, int) (this=0x12c5440, from_tty=0, extended_p=0) at src/gdb/remote.c:4655 #15 0x00000000007fd102 in remote_target::open_1(char const*, int, int) (name=0x1a4f45e "localhost:2346", from_tty=0, extended_p=0) at src/gdb/remote.c:5638 #16 0x00000000007fbec1 in remote_target::open(char const*, int) (name=0x1a4f45e "localhost:2346", from_tty=0) at src/gdb/remote.c:4862 So on frame #10, we're marking a newly-discovered thread as running, and that causes the Python API to emit a gdb.ContinueEvent. gdb.ContinueEvent is a gdb.ThreadEvent, and as such includes the event thread as the "inferior_thread" attribute. The problem is that when we get to frame #3/#4, we lost all references to the thread that is being marked as running. create_continue_event_object assumes that it is the current thread, which is not true in this case. Fix this by passing down the right thread in create_continue_event_object. Also remove create_thread_event_object's default argument and have the only other caller left pass down the right thread explicitly too. gdb/ChangeLog: 2018-08-24 Pedro Alves <[email protected]> Simon Marchi <[email protected]> PR gdb/23379 * python/py-continueevent.c: Include "gdbthread.h". (create_continue_event_object): Add intro comment. Add 'ptid' parameter. Use it to find thread to pass to create_thread_event_object. (emit_continue_event): Pass PTID down to create_continue_event_object. * python/py-event.h (py_get_event_thread): Declare. (create_thread_event_object): Remove default from 'thread' parameter. * python/py-stopevent.c (create_stop_event_object): Use py_get_event_thread. * python/py-threadevent.c (get_event_thread): Rename to ... (py_get_event_thread): ... this, make extern, add 'ptid' parameter and use it to find the thread. (create_thread_event_object): Assert that THREAD isn't null. Don't find the event thread here.
palves
added a commit
that referenced
this issue
Nov 30, 2018
A following commit to make each inferior have its own thread list exposes a problem with bf93d7b ("Add thread after updating gdbarch when exec'ing"), which is that we can't defer adding the thread because that breaks try_open_exec_file which deep inside ends up calling inferior_thread(): #5 0x0000000000637c78 in internal_error(char const*, int, char const*, ...) (file=0xc151f8 "src/gdb/thread.c", line=165, fmt=0xc15180 "%s: Assertion `%s' failed.") at src/gdb/common/errors.c:55 #6 0x00000000008a3d80 in inferior_thread() () at src/gdb/thread.c:165 #7 0x0000000000456f91 in try_thread_db_load_1(thread_db_info*) (info=0x277eb00) at src/gdb/linux-thread-db.c:830 #8 0x0000000000457554 in try_thread_db_load(char const*, int) (library=0xb01a4f "libthread_db.so.1", check_auto_load_safe=0) at src/gdb/linux-thread-db.c:1002 #9 0x0000000000457861 in try_thread_db_load_from_sdir() () at src/gdb/linux-thread-db.c:1079 #10 0x0000000000457b72 in thread_db_load_search() () at src/gdb/linux-thread-db.c:1134 #11 0x0000000000457d29 in thread_db_load() () at src/gdb/linux-thread-db.c:1192 #12 0x0000000000457e51 in check_for_thread_db() () at src/gdb/linux-thread-db.c:1244 #13 0x0000000000457ed2 in thread_db_new_objfile(objfile*) (objfile=0x270ff60) at src/gdb/linux-thread-db.c:1273 #14 0x000000000045a92e in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7ffef3efe140: 0x270ff60) at /usr/include/c++/7/bits/std_function.h:316 #15 0x00000000007bbebf in std::function<void (objfile*)>::operator()(objfile*) const (this=0x24e1d18, __args#0=0x270ff60) at /usr/include/c++/7/bits/std_function.h:706 #16 0x00000000007bba86 in gdb::observers::observable<objfile*>::notify(objfile*) const (this=0x117ce80 <gdb::observers::new_objfile>, args#0=0x270ff60) at src/gdb/common/observable.h:106 #17 0x0000000000856000 in symbol_file_add_with_addrs(bfd*, char const*, symfile_add_flags, section_addr_info*, objfile_flags, objfile*) (abfd=0x1d7dae0, name=0x254bfc0 "/ho The problem is latent currently because inferior_thread() at that point manages to return a thread, even though it's the wrong one (of the old inferior). The problem originally fixed by bf93d7b was: (...) we should avoid doing register reads after a process does an exec and before we've updated that inferior's gdbarch. Otherwise, we may interpret the registers using the wrong architecture. (...) The call to "add_thread" done just after adding the inferior is problematic, because it ends up reading the registers (because the ptid is re-used, we end up doing a switch_to_thread to it, which tries to update stop_pc). (...) The register-reading issue is no longer a problem nowadays, ever since switch_to_thread stopped reading the stop_pc in git commit f2ffa92 ("gdb: Eliminate the 'stop_pc' global"). So this commit basically reverts bf93d7b. gdb/ChangeLog: 2018-11-22 Pedro Alves <[email protected]> * infrun.c (follow_exec) <set follow-exec new>: Add thread and switch to it before calling into try_open_exec_file.
palves
pushed a commit
that referenced
this issue
Mar 12, 2019
Errors that happen in nested sourced files (when a sourced file sources another file) lead to a wrong error message, or use-after-free. For example, if I put this in "a.gdb": command_that_doesnt_exist and this in "b.gdb": source a.gdb and try to "source b.gdb" in GDB, the result may look like this: (gdb) source b.gdb b.gdb:1: Error in sourced command file: _that_doesnt_exist:1: Error in sourced command file: Undefined command: "command_that_doesnt_exist". Try "help". Notice the wrong file name where "a.gdb" should be. The exact result may differ, depending on the feelings of the memory allocator. What happens is: - The "source a.gdb" command is saved by command_line_append_input_line in command_line_input's static buffer. - Since we are sourcing a file, the script_from_file function stores the script name (a.gdb) in the source_file_name global. However, it doesn't do a copy, it just saves a pointer to command_line_input's static buffer. - The "command_that_doesnt_exist" command is saved by command_line_append_input_line in command_line_input's static buffer. Depending on what xrealloc does, source_file_name may now point to freed memory, or at the minimum the data it was pointing to was overwritten. - When the error is handled in script_from_file, we dererence source_file_name to print the name of the file in which the error occured. To fix it, I made source_file_name an std::string, so that keeps a copy of the file name instead of pointing to a buffer with a too small lifetime. With this patch, the expected filename is printed, and no use-after-free occurs: (gdb) source b.gdb b.gdb:1: Error in sourced command file: a.gdb:1: Error in sourced command file: Undefined command: "command_that_doesnt_exist". Try "help". I passed explicit template parameters to make_scoped_restore (<std::string, const std::string &>), so that the second parameter is passed by reference and avoid a copy. It was not as obvious as I first thought to change gdb.base/source.exp to test this, because source commands inside sourced files are interpreted relative to GDB's current working directory, not the directory of the currently sourced file. As a workaround, I moved the snippet that tests errors after the snippet that adds the source directory to the search path. This way, the "source source-error-1.gdb" line in source-error.exp manages to find the file. For reference, here is what ASAN reports when use-after-free occurs: (gdb) source b.gdb ================================================================= ==18498==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c000019847 at pc 0x7f1d3645de8e bp 0x7ffdcb892e50 sp 0x7ffdcb8925c8 READ of size 6 at 0x60c000019847 thread T0 #0 0x7f1d3645de8d in printf_common /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:546 #1 0x7f1d36477175 in __interceptor_vasprintf /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1525 #2 0x5632eaffa277 in xstrvprintf(char const*, __va_list_tag*) /home/simark/src/binutils-gdb/gdb/common/common-utils.c:122 #3 0x5632eaff96d1 in throw_it /home/simark/src/binutils-gdb/gdb/common/common-exceptions.c:351 #4 0x5632eaff98df in throw_verror(errors, char const*, __va_list_tag*) /home/simark/src/binutils-gdb/gdb/common/common-exceptions.c:379 #5 0x5632eaff9a2a in throw_error(errors, char const*, ...) /home/simark/src/binutils-gdb/gdb/common/common-exceptions.c:394 #6 0x5632eafca21a in script_from_file(_IO_FILE*, char const*) /home/simark/src/binutils-gdb/gdb/cli/cli-script.c:1553 #7 0x5632eaf8a500 in source_script_from_stream /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:569 #8 0x5632eaf8a735 in source_script_with_search /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:605 #9 0x5632eaf8ab20 in source_command /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:664 #10 0x5632eafa8b4a in do_const_cfunc /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:106 #11 0x5632eafb0687 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:1892 #12 0x5632ebf3dd87 in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:630 #13 0x5632eb3b25d3 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:583 #14 0x5632ebf3cf09 in read_command_file(_IO_FILE*) /home/simark/src/binutils-gdb/gdb/top.c:425 #15 0x5632eafca054 in script_from_file(_IO_FILE*, char const*) /home/simark/src/binutils-gdb/gdb/cli/cli-script.c:1547 #16 0x5632eaf8a500 in source_script_from_stream /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:569 #17 0x5632eaf8a735 in source_script_with_search /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:605 #18 0x5632eaf8ab20 in source_command /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:664 #19 0x5632eafa8b4a in do_const_cfunc /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:106 #20 0x5632eafb0687 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:1892 #21 0x5632ebf3dd87 in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:630 #22 0x5632eb3b25d3 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:583 #23 0x5632eb3b2f87 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/simark/src/binutils-gdb/gdb/event-top.c:770 #24 0x5632eb3b0fe1 in gdb_rl_callback_handler /home/simark/src/binutils-gdb/gdb/event-top.c:213 #25 0x5632ec1c8729 in rl_callback_read_char /home/simark/src/binutils-gdb/readline/callback.c:220 #26 0x5632eb3b0b8f in gdb_rl_callback_read_char_wrapper_noexcept /home/simark/src/binutils-gdb/gdb/event-top.c:175 #27 0x5632eb3b0da1 in gdb_rl_callback_read_char_wrapper /home/simark/src/binutils-gdb/gdb/event-top.c:192 #28 0x5632eb3b2186 in stdin_event_handler(int, void*) /home/simark/src/binutils-gdb/gdb/event-top.c:511 #29 0x5632eb3aa6a9 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 #30 0x5632eb3aaf41 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 #31 0x5632eb3a88ea in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:347 #32 0x5632eb3a89bf in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 #33 0x5632eb76fbfc in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:330 #34 0x5632eb772ea8 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1176 #35 0x5632eb773071 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1192 #36 0x5632eabfe7f9 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 #37 0x7f1d3554f222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) #38 0x5632eabfe5dd in _start (/home/simark/build/binutils-gdb/gdb/gdb+0x195d5dd) 0x60c000019847 is located 7 bytes inside of 128-byte region [0x60c000019840,0x60c0000198c0) freed by thread T0 here: #0 0x7f1d36502491 in __interceptor_realloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:105 #1 0x5632eaff9f47 in xrealloc /home/simark/src/binutils-gdb/gdb/common/common-utils.c:62 #2 0x5632eaff6b44 in buffer_grow(buffer*, char const*, unsigned long) /home/simark/src/binutils-gdb/gdb/common/buffer.c:40 #3 0x5632eb3b271d in command_line_append_input_line /home/simark/src/binutils-gdb/gdb/event-top.c:614 #4 0x5632eb3b28c6 in handle_line_of_input(buffer*, char const*, int, char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:654 #5 0x5632ebf402a6 in command_line_input(char const*, char const*) /home/simark/src/binutils-gdb/gdb/top.c:1252 #6 0x5632ebf3cee9 in read_command_file(_IO_FILE*) /home/simark/src/binutils-gdb/gdb/top.c:422 #7 0x5632eafca054 in script_from_file(_IO_FILE*, char const*) /home/simark/src/binutils-gdb/gdb/cli/cli-script.c:1547 #8 0x5632eaf8a500 in source_script_from_stream /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:569 #9 0x5632eaf8a735 in source_script_with_search /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:605 #10 0x5632eaf8ab20 in source_command /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:664 #11 0x5632eafa8b4a in do_const_cfunc /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:106 #12 0x5632eafb0687 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:1892 #13 0x5632ebf3dd87 in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:630 #14 0x5632eb3b25d3 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:583 #15 0x5632ebf3cf09 in read_command_file(_IO_FILE*) /home/simark/src/binutils-gdb/gdb/top.c:425 #16 0x5632eafca054 in script_from_file(_IO_FILE*, char const*) /home/simark/src/binutils-gdb/gdb/cli/cli-script.c:1547 #17 0x5632eaf8a500 in source_script_from_stream /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:569 #18 0x5632eaf8a735 in source_script_with_search /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:605 #19 0x5632eaf8ab20 in source_command /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:664 #20 0x5632eafa8b4a in do_const_cfunc /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:106 #21 0x5632eafb0687 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:1892 #22 0x5632ebf3dd87 in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:630 #23 0x5632eb3b25d3 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:583 #24 0x5632eb3b2f87 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/simark/src/binutils-gdb/gdb/event-top.c:770 #25 0x5632eb3b0fe1 in gdb_rl_callback_handler /home/simark/src/binutils-gdb/gdb/event-top.c:213 #26 0x5632ec1c8729 in rl_callback_read_char /home/simark/src/binutils-gdb/readline/callback.c:220 #27 0x5632eb3b0b8f in gdb_rl_callback_read_char_wrapper_noexcept /home/simark/src/binutils-gdb/gdb/event-top.c:175 #28 0x5632eb3b0da1 in gdb_rl_callback_read_char_wrapper /home/simark/src/binutils-gdb/gdb/event-top.c:192 #29 0x5632eb3b2186 in stdin_event_handler(int, void*) /home/simark/src/binutils-gdb/gdb/event-top.c:511 previously allocated by thread T0 here: #0 0x7f1d36502491 in __interceptor_realloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:105 #1 0x5632eaff9f47 in xrealloc /home/simark/src/binutils-gdb/gdb/common/common-utils.c:62 #2 0x5632eaff6b44 in buffer_grow(buffer*, char const*, unsigned long) /home/simark/src/binutils-gdb/gdb/common/buffer.c:40 #3 0x5632eb3b271d in command_line_append_input_line /home/simark/src/binutils-gdb/gdb/event-top.c:614 #4 0x5632eb3b28c6 in handle_line_of_input(buffer*, char const*, int, char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:654 #5 0x5632ebf402a6 in command_line_input(char const*, char const*) /home/simark/src/binutils-gdb/gdb/top.c:1252 #6 0x5632ebf3cee9 in read_command_file(_IO_FILE*) /home/simark/src/binutils-gdb/gdb/top.c:422 #7 0x5632eafca054 in script_from_file(_IO_FILE*, char const*) /home/simark/src/binutils-gdb/gdb/cli/cli-script.c:1547 #8 0x5632eaf8a500 in source_script_from_stream /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:569 #9 0x5632eaf8a735 in source_script_with_search /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:605 #10 0x5632eaf8ab20 in source_command /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:664 #11 0x5632eafa8b4a in do_const_cfunc /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:106 #12 0x5632eafb0687 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:1892 #13 0x5632ebf3dd87 in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:630 #14 0x5632eb3b25d3 in command_handler(char const*) /home/simark/src/binutils-gdb/gdb/event-top.c:583 #15 0x5632eb3b2f87 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/simark/src/binutils-gdb/gdb/event-top.c:770 #16 0x5632eb3b0fe1 in gdb_rl_callback_handler /home/simark/src/binutils-gdb/gdb/event-top.c:213 #17 0x5632ec1c8729 in rl_callback_read_char /home/simark/src/binutils-gdb/readline/callback.c:220 #18 0x5632eb3b0b8f in gdb_rl_callback_read_char_wrapper_noexcept /home/simark/src/binutils-gdb/gdb/event-top.c:175 #19 0x5632eb3b0da1 in gdb_rl_callback_read_char_wrapper /home/simark/src/binutils-gdb/gdb/event-top.c:192 #20 0x5632eb3b2186 in stdin_event_handler(int, void*) /home/simark/src/binutils-gdb/gdb/event-top.c:511 #21 0x5632eb3aa6a9 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 #22 0x5632eb3aaf41 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 #23 0x5632eb3a88ea in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:347 #24 0x5632eb3a89bf in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 #25 0x5632eb76fbfc in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:330 #26 0x5632eb772ea8 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1176 #27 0x5632eb773071 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1192 #28 0x5632eabfe7f9 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 #29 0x7f1d3554f222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) SUMMARY: AddressSanitizer: heap-use-after-free /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:546 in printf_common gdb/ChangeLog: * top.h (source_file_name): Change to std::string. * top.c (source_file_name): Likewise. (command_line_input): Adjust. * cli/cli-script.c (script_from_file): Adjust. gdb/testsuite/ChangeLog: * gdb.base/source.exp: Move "error in sourced script" code to the end. * gdb.base/source-error.gdb: Move contents to source-error-1.gdb. Add new code to source source-error-1.gdb. * gdb.base/source-error-1.gdb: New file, from previous source-error.gdb.
palves
pushed a commit
that referenced
this issue
Jul 16, 2019
Commit ab42892 ("Fix vertical scrolling of TUI source window") introduced a use-after-free in source_cache::get_source_lines. At the beginning of the method, we get the fullname of the symtab: const char *fullname = symtab_to_fullname (s); fullname points to the string owned by the symtab (s.fullname). When we later do scoped_fd desc = open_source_file (s); s.fullname gets reallocated (even though the string contents may not change). The fullname local variable now points to freed memory. To avoid it, refresh the value of fullname after calling open_source_file. Here is the ASan report: $ ./gdb -nx --data-directory=data-directory ./a.out (gdb) start Temporary breakpoint 1 at 0x1130: file test.cpp, line 12. Starting program: /home/simark/build/binutils-gdb/gdb/a.out Temporary breakpoint 1, main () at test.cpp:12 ================================================================= ==26068==ERROR: AddressSanitizer: heap-use-after-free on address 0x6210003d4100 at pc 0x7fed89a34681 bp 0x7ffd8d185d80 sp 0x7ffd8d185528 READ of size 2 at 0x6210003d4100 thread T0 #0 0x7fed89a34680 in __interceptor_strlen /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:301 #1 0x55b6edf6c2f7 in std::char_traits<char>::length(char const*) /usr/include/c++/8.2.1/bits/char_traits.h:320 #2 0x55b6edf6c9b2 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) /usr/include/c++/8.2.1/bits/basic_string.h:516 #3 0x55b6ef09121b in source_cache::get_source_lines(symtab*, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) /home/simark/src/binutils-gdb/gdb/source-cache.c:214 #4 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 #5 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 #6 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 #7 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 #8 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 #9 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 #10 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 #11 0x55b6ee01a14d in std::_Function_handler<void (bpstats*, int), void (*)(bpstats*, int)>::_M_invoke(std::_Any_data const&, bpstats*&&, int&&) /usr/include/c++/8.2.1/bits/std_function.h:297 #12 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 #13 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 #14 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 #15 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 #16 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 #17 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 #18 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 #19 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 #20 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 #21 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 #22 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 #23 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 #24 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 #25 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 #26 0x7fed88ad8222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) #27 0x55b6edf4f86d in _start (/home/simark/build/binutils-gdb/gdb/gdb+0x197186d) 0x6210003d4100 is located 0 bytes inside of 4096-byte region [0x6210003d4100,0x6210003d5100) freed by thread T0 here: #0 0x7fed89a8ac19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:66 #1 0x55b6edfe12df in xfree<char> /home/simark/src/binutils-gdb/gdb/common/common-utils.h:60 #2 0x55b6edfea675 in gdb::xfree_deleter<char>::operator()(char*) const /home/simark/src/binutils-gdb/gdb/common/gdb_unique_ptr.h:34 #3 0x55b6edfe532c in std::unique_ptr<char, gdb::xfree_deleter<char> >::reset(char*) /usr/include/c++/8.2.1/bits/unique_ptr.h:382 #4 0x55b6edfe7329 in std::unique_ptr<char, gdb::xfree_deleter<char> >::operator=(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /usr/include/c++/8.2.1/bits/unique_ptr.h:289 #5 0x55b6ef09ec2b in find_and_open_source(char const*, char const*, std::unique_ptr<char, gdb::xfree_deleter<char> >*) /home/simark/src/binutils-gdb/gdb/source.c:990 #6 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 #7 0x55b6ef090f78 in source_cache::get_source_lines(symtab*, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) /home/simark/src/binutils-gdb/gdb/source-cache.c:205 #8 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 #9 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 #10 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 #11 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 #12 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 #13 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 #14 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 #15 0x55b6ee01a14d in std::_Function_handler<void (bpstats*, int), void (*)(bpstats*, int)>::_M_invoke(std::_Any_data const&, bpstats*&&, int&&) /usr/include/c++/8.2.1/bits/std_function.h:297 #16 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 #17 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 #18 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 #19 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 #20 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 #21 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 #22 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 #23 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 #24 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 #25 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 #26 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 #27 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 #28 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 #29 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 previously allocated by thread T0 here: #0 0x7fed89a8b019 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:86 #1 0x7fed88af983f in realpath@@GLIBC_2.3 (/usr/lib/libc.so.6+0x4583f) #2 0x7fed899dbbbc in __interceptor_canonicalize_file_name /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:3297 #3 0x55b6ee376a03 in gdb_realpath(char const*) /home/simark/src/binutils-gdb/gdb/common/pathstuff.c:72 #4 0x55b6ef09ec12 in find_and_open_source(char const*, char const*, std::unique_ptr<char, gdb::xfree_deleter<char> >*) /home/simark/src/binutils-gdb/gdb/source.c:990 #5 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 #6 0x55b6ef0a0f12 in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1270 #7 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 #8 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 #9 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 #10 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 #11 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 #12 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 #13 0x55b6ee01a14d in std::_Function_handler<void (bpstats*, int), void (*)(bpstats*, int)>::_M_invoke(std::_Any_data const&, bpstats*&&, int&&) /usr/include/c++/8.2.1/bits/std_function.h:297 #14 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 #15 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 #16 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 #17 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 #18 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 #19 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 #20 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 #21 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 #22 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 #23 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 #24 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 #25 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 #26 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 #27 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 #28 0x7fed88ad8222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) gdb/ChangeLog: * source-cache.c (source_cache::get_source_lines): Re-read fullname after calling open_source_file.
palves
pushed a commit
that referenced
this issue
Jul 16, 2019
…trace The test gdb.threads/watchthreads-reorder.exp verifies that the 'set debug infrun 1' debug output does not crash GDB. Under high load, the test can still cause a GDB internal error (see details below). This patch fixes this crash, and improves/factorises some wait kind traces. Tested on debian/amd64 + run one test with 'set debug infrun 1'. Changes compared to the first version: * Handles the suggestions of Kevin to trace the relevant elements of the wait status (this is done by calling target_waitstatus_to_string). * Some other changes to factorise wait status tracing. Note that using target_waitstatus_to_string instead of the 'locally printed' status kind strings means that debug trace that was using strings such as: "EXITED" or "TARGET_WAITKIND_EXITED" will now use what is printed by target_waitstatus_to_string e.g. "exited". gdb/ChangeLog 2019-04-01 Philippe Waroquiers <[email protected]> * infrun.c (stop_all_threads): If debug_infrun, always trace the wait status after wait_one, using target_waitstatus_to_string and target_pid_to_str. (handle_inferior_event): Replace various trace of wait status kind by a single trace. * gdb/gnu-nat.c (gnu_nat_target::wait): Replace local wait status kind image by target_waitstatus_to_string. * target/waitstatus.c (target_waitstatus_to_string): Fix obsolete comment. (top-gdb) bt #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 #1 0x00007f3d54a0642a in __GI_abort () at abort.c:89 #2 0x0000555c24c60e66 in dump_core () at ../../fixleaks/gdb/utils.c:201 #3 0x0000555c24c63d49 in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (problem=problem@entry=0x555c25338d40 <internal_error_problem>, file=<optimized out>, line=287, fmt=<optimized out>, ap=<optimized out>) at ../../fixleaks/gdb/utils.c:411 #4 0x0000555c24c63eab in internal_verror (file=<optimized out>, line=<optimized out>, fmt=<optimized out>, ap=<optimized out>) at ../../fixleaks/gdb/utils.c:436 #5 0x0000555c249e8c22 in internal_error (file=file@entry=0x555c24e0f2ad "../../fixleaks/gdb/inferior.c", line=line@entry=287, fmt=<optimized out>) at ../../fixleaks/gdb/common/errors.c:55 #6 0x0000555c247d3f5c in find_inferior_pid (pid=<optimized out>) at ../../fixleaks/gdb/inferior.c:287 #7 0x0000555c24ad2248 in find_inferior_pid (pid=<optimized out>) at ../../fixleaks/gdb/inferior.c:302 #8 find_inferior_ptid (ptid=...) at ../../fixleaks/gdb/inferior.c:301 #9 0x0000555c24c35f25 in find_thread_ptid (ptid=...) at ../../fixleaks/gdb/thread.c:522 #10 0x0000555c24b0ab4d in thread_db_target::pid_to_str[abi:cxx11](ptid_t) ( this=0x555c2532e3e0 <the_thread_db_target>, ptid=...) at ../../fixleaks/gdb/linux-thread-db.c:1637 #11 0x0000555c24c2f420 in target_pid_to_str[abi:cxx11](ptid_t) (ptid=...) at ../../fixleaks/gdb/target.c:2083 #12 0x0000555c24ad9cab in stop_all_threads () at ../../fixleaks/gdb/infrun.c:4373 #13 0x0000555c24ada00f in stop_waiting (ecs=<optimized out>) at ../../fixleaks/gdb/infrun.c:7464 #14 0x0000555c24adc401 in process_event_stop_test (ecs=ecs@entry=0x7ffc9402d9d0) at ../../fixleaks/gdb/infrun.c:6181 ... (top-gdb) fr 12 #12 0x0000555c24ad9cab in stop_all_threads () at ../../fixleaks/gdb/infrun.c:4373 (top-gdb) p event_ptid $5 = {m_pid = 25419, m_lwp = 25427, m_tid = 0} (top-gdb) p ptid $6 = {m_pid = 0, m_lwp = 0, m_tid = 0} (top-gdb) p ws $7 = {kind = TARGET_WAITKIND_THREAD_EXITED, value = {integer = 0, sig = GDB_SIGNAL_0, related_pid = {m_pid = 0, m_lwp = 0, m_tid = 0}, execd_pathname = 0x0, syscall_number = 0}} (top-gdb) The gdb.log corresponding to the above crash is: (gdb) PASS: gdb.threads/watchthreads-reorder.exp: reorder1: set debug infrun 1 continue Continuing. infrun: clear_proceed_status_thread (Thread 0x7ffff7fcfb40 (LWP 25419)) infrun: clear_proceed_status_thread (Thread 0x7ffff7310700 (LWP 25427)) infrun: clear_proceed_status_thread (Thread 0x7ffff6b0f700 (LWP 25428)) infrun: proceed (addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT) infrun: proceed: resuming Thread 0x7ffff7fcfb40 (LWP 25419) infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7fcfb40 (LWP 25419)] at 0x7ffff7344317 infrun: infrun_async(1) infrun: prepare_to_wait infrun: proceed: resuming Thread 0x7ffff7310700 (LWP 25427) infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7310700 (LWP 25427)] at 0x5555555553d7 infrun: prepare_to_wait infrun: proceed: resuming Thread 0x7ffff6b0f700 (LWP 25428) infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff6b0f700 (LWP 25428)] at 0x5555555554c8 infrun: prepare_to_wait infrun: target_wait (-1.0.0, status) = infrun: -1.0.0 [process -1], infrun: status->kind = ignore infrun: TARGET_WAITKIND_IGNORE infrun: prepare_to_wait Joining the threads. [Thread 0x7ffff6b0f700 (LWP 25428) exited] infrun: target_wait (-1.0.0, status) = infrun: -1.0.0 [process -1], infrun: status->kind = ignore infrun: TARGET_WAITKIND_IGNORE infrun: prepare_to_wait infrun: target_wait (-1.0.0, status) = infrun: 25419.25419.0 [Thread 0x7ffff7fcfb40 (LWP 25419)], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x555555555e50 infrun: context switch infrun: Switching context from Thread 0x7ffff6b0f700 (LWP 25428) to Thread 0x7ffff7fcfb40 (LWP 25419) infrun: BPSTAT_WHAT_STOP_NOISY infrun: stop_waiting infrun: stop_all_threads infrun: stop_all_threads, pass=0, iterations=0 infrun: Thread 0x7ffff7fcfb40 (LWP 25419) not executing infrun: Thread 0x7ffff7310700 (LWP 25427) executing, need stop [Thread 0x7ffff7310700 (LWP 25427) exited] infrun: target_wait (-1.0.0, status) = infrun: 25419.25427.0 [LWP 25427], infrun: status->kind = thread exited, status = 0 infrun: infrun_async(0) ../../fixleaks/gdb/inferior.c:287: internal-error: inferior* find_inferior_pid(int): Assertion `pid != 0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) FAIL: gdb.threads/watchthreads-reorder.exp: reorder1: continue to breakpoint: break-at-exit (GDB internal error) Resyncing due to internal error. n infrun: infrun_async(1) This is a bug, please report it. For instructions, see: <http://www.gnu.org/software/gdb/bugs/>. infrun: infrun_async(0) ../../fixleaks/gdb/inferior.c:287: internal-error: inferior* find_inferior_pid(int): Assertion `pid != 0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Create a core file of GDB? (y or n) y
palves
pushed a commit
that referenced
this issue
Jul 16, 2019
When running gdb using AddressSanitizer, and loading a cc1plus binary built with profiledbootstrap and -flto, we run into a heap-use-after-free error: ... $ LD_PRELOAD=/usr/lib64/libasan.so.3 ./gdb -batch cc1plus ==26855==ERROR: AddressSanitizer: heap-use-after-free on address \ 0x62100ad8a8b0 at pc 0x7f13803cc9e3 bp 0x7ffe55b0d090 sp 0x7ffe55b0c840 READ of size 47 at 0x62100ad8a8b0 thread T0 #0 0x7f13803cc9e2 (/usr/lib64/libasan.so.3+0x3e9e2) #1 0x5e7a0d in typename_concat gdb/dwarf2read.c:22661 #2 0x5c6437 in partial_die_full_name gdb/dwarf2read.c:8876 #3 0x5c6555 in add_partial_symbol gdb/dwarf2read.c:8893 #4 0x5c6ecf in add_partial_subprogram gdb/dwarf2read.c:9156 #5 0x5c5e90 in scan_partial_symbols gdb/dwarf2read.c:8668 #6 0x5c6c0a in add_partial_namespace gdb/dwarf2read.c:9081 #7 0x5c5f99 in scan_partial_symbols gdb/dwarf2read.c:8702 #8 0x5c48b6 in process_psymtab_comp_unit_reader gdb/dwarf2read.c:8056 #9 0x5c3c1f in init_cutu_and_read_dies gdb/dwarf2read.c:7689 #10 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 #11 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 #12 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 #13 0x612359 in read_psyms gdb/elfread.c:1311 #14 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 #15 0x867d7b in read_symbols gdb/symfile.c:821 #16 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 #17 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 #18 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 #19 0x868b0a in symbol_file_add_from_bfd(bfd*, char const*, \ enum_flags<symfile_add_flag>, std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>, objfile*) gdb/symfile.c:1204 #20 0x868b64 in symbol_file_add(char const*, \ enum_flags<symfile_add_flag>, \ std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>) gdb/symfile.c:1217 #21 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 #22 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 #23 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 #24 0x71f10e in catch_command_errors gdb/main.c:372 #25 0x71ff5f in captured_main_1 gdb/main.c:1043 #26 0x72045d in captured_main gdb/main.c:1163 #27 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 #28 0x40fd7d in main gdb/gdb.c:32 #29 0x7f137e300f49 in __libc_start_main (/lib64/libc.so.6+0x20f49) #30 0x40fc89 in _start (/data/gdb_versions/devel/build/gdb/gdb+0x40fc89) 0x62100ad8a8b0 is located 944 bytes inside of 4064-byte region \ [0x62100ad8a500,0x62100ad8b4e0) freed by thread T0 here: #0 0x7f13804523a0 in __interceptor_free (/usr/lib64/libasan.so.3+0xc43a0) #1 0x435e44 in xfree<void> gdb/common/common-utils.h:60 #2 0xa82c25 in call_freefun libiberty/obstack.c:103 #3 0xa83098 in _obstack_free libiberty/obstack.c:280 #4 0x4367da in auto_obstack::~auto_obstack() gdb/gdb_obstack.h:101 #5 0x5ed72c in dwarf2_cu::~dwarf2_cu() gdb/dwarf2read.c:25341 #6 0x5fb5bb in std::default_delete<dwarf2_cu>::operator()(dwarf2_cu*) const \ /usr/include/c++/7/bits/unique_ptr.h:78 #7 0x5f7334 in std::unique_ptr<dwarf2_cu, \ std::default_delete<dwarf2_cu> >::~unique_ptr() \ /usr/include/c++/7/bits/unique_ptr.h:268 #8 0x5c3ce5 in init_cutu_and_read_dies gdb/dwarf2read.c:7624 #9 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 #10 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 #11 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 #12 0x612359 in read_psyms gdb/elfread.c:1311 #13 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 #14 0x867d7b in read_symbols gdb/symfile.c:821 #15 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 #16 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 #17 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 #18 0x868b0a in symbol_file_add_from_bfd(bfd*, char const*, \ enum_flags<symfile_add_flag>, std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>, objfile*) gdb/symfile.c:1204 #19 0x868b64 in symbol_file_add(char const*, \ enum_flags<symfile_add_flag>, std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>) gdb/symfile.c:1217 #20 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 #21 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 #22 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 #23 0x71f10e in catch_command_errors gdb/main.c:372 #24 0x71ff5f in captured_main_1 gdb/main.c:1043 #25 0x72045d in captured_main gdb/main.c:1163 #26 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 #27 0x40fd7d in main gdb/gdb.c:32 #28 0x7f137e300f49 in __libc_start_main (/lib64/libc.so.6+0x20f49) previously allocated by thread T0 here: #0 0x7f13804526b8 in __interceptor_malloc (/usr/lib64/libasan.so.3+0xc46b8) #1 0x5114b5 in xmalloc gdb/common/common-utils.c:44 #2 0xa82bd5 in call_chunkfun libiberty/obstack.c:94 #3 0xa82eda in _obstack_newchunk libiberty/obstack.c:206 #4 0x477310 in allocate_on_obstack::operator new(unsigned long, obstack*) \ gdb/gdb_obstack.h:117 #5 0x5dea8c in load_partial_dies gdb/dwarf2read.c:18571 #6 0x5c487f in process_psymtab_comp_unit_reader gdb/dwarf2read.c:8054 #7 0x5c3c1f in init_cutu_and_read_dies gdb/dwarf2read.c:7689 #8 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 #9 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 #10 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 #11 0x612359 in read_psyms gdb/elfread.c:1311 #12 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 #13 0x867d7b in read_symbols gdb/symfile.c:821 #14 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 #15 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 #16 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 #17 0x868b0a in symbol_file_add_from_bfd(bfd*, char const*, \ enum_flags<symfile_add_flag>, \ std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>, objfile*) gdb/symfile.c:1204 #18 0x868b64 in symbol_file_add(char const*, enum_flags<symfile_add_flag>, \ std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>) gdb/symfile.c:1217 #19 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 #20 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 #21 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 #22 0x71f10e in catch_command_errors gdb/main.c:372 #23 0x71ff5f in captured_main_1 gdb/main.c:1043 #24 0x72045d in captured_main gdb/main.c:1163 #25 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 #26 0x40fd7d in main gdb/gdb.c:32 #27 0x7f137e300f49 in __libc_start_main (/lib64/libc.so.6+0x20f49) ... This error happens as follows. The function find_partial_die has a cu argument, but returns a pdi which may or may not be from that cu: ... /* Find a partial DIE at OFFSET, which may or may not be in CU, except in the case of .debug_types DIEs which do not reference outside their CU (they do however referencing other types via DW_FORM_ref_sig8). */ static struct partial_die_info * find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu) ... So the pdi returned by find_partial_die here in partial_die_parent_scope may be from another cu: ... partial_die_parent_scope (struct partial_die_info *pdi, struct dwarf2_cu *cu) { const char *grandparent_scope; struct partial_die_info *parent, *real_pdi; /* We need to look at our parent DIE; if we have a DW_AT_specification, then this means the parent of the specification DIE. */ real_pdi = pdi; while (real_pdi->has_specification) real_pdi = find_partial_die (real_pdi->spec_offset, real_pdi->spec_is_dwz, cu); parent = real_pdi->die_parent; ... in which case both real_pdi and parent will be not from cu, but from another one, say cu2. Subsequently, cu's comp_unit_obstack is used to set parent->scope: ... parent->scope = typename_concat (&cu->comp_unit_obstack, grandparent_scope, parent->name, 0, cu); ... So, we use cu->comp_unit_obstack to assign a value to the scope field of a pdi belonging to cu2, and when cu is deleted, the scope field points to a freed value. Fix this by making find_partial_die return the cu corresponding to the returned pdi, and handling this at the call sites. Tested on x86_64-linux. gdb/ChangeLog: 2019-05-17 Tom de Vries <[email protected]> PR gdb/24094 * dwarf2read.c (struct cu_partial_die_info): New struct. (find_partial_die): Return cu_partial_die_info. (partial_die_parent_scope, guess_partial_die_structure_name) (partial_die_info::fixup): Handle new return type of find_partial_die.
palves
added a commit
that referenced
this issue
Apr 30, 2021
When testing with "maint set target-non-stop on", gdb.server/bkpt-other-inferior.exp sometimes fails like so: (gdb) inferior 2 [Switching to inferior 2 [process 368191] (<noexec>)] [Switching to thread 2.1 (Thread 368191.368191)] [remote] Sending packet: $m7ffff7fd0100,1#5b [remote] Packet received: 48 [remote] Sending packet: $m7ffff7fd0100,1#5b [remote] Packet received: 48 [remote] Sending packet: $m7ffff7fd0100,9#63 [remote] Packet received: 4889e7e8e80c000049 #0 0x00007ffff7fd0100 in ?? () (gdb) PASS: gdb.server/bkpt-other-inferior.exp: inf 2: switch to inferior break -q main Breakpoint 2 at 0x1138: file /home/pedro/gdb/binutils-gdb/src/gdb/testsuite/gdb.server/server.c, line 21. (gdb) PASS: gdb.server/bkpt-other-inferior.exp: inf 2: set breakpoint delete breakpoints Delete all breakpoints? (y or n) y (gdb) [remote] wait: enter [remote] wait: exit FAIL: gdb.server/bkpt-other-inferior.exp: inf 2: delete all breakpoints in delete_breakpoints (timeout) ERROR: breakpoints not deleted Remote debugging from host ::1, port 55876 monitor exit The problem is here: (gdb) [remote] wait: enter The testcase isn't expecting any output after the prompt. Why is that "[remote] wait" output? What happens is that "delete breakpoints" queries the user, and `query` disables/reenables target async, which results in the remote target's async event handler ending up marked: (top-gdb) bt #0 mark_async_event_handler (async_handler_ptr=0x556bffffffff) at ../../src/gdb/async-event.c:295 #1 0x0000556bf71b711f in infrun_async (enable=1) at ../../src/gdb/infrun.c:119 #2 0x0000556bf7471387 in target_async (enable=1) at ../../src/gdb/target.c:3684 #3 0x0000556bf748a0bd in gdb_readline_wrapper_cleanup::~gdb_readline_wrapper_cleanup (this=0x7ffe3cf30eb0, __in_chrg=<optimized out>) at ../../src/gdb/top.c:1074 #4 0x0000556bf74874e2 in gdb_readline_wrapper (prompt=0x556bfa17da60 "Delete all breakpoints? (y or n) ") at ../../src/gdb/top.c:1096 #5 0x0000556bf75111c5 in defaulted_query(const char *, char, typedef __va_list_tag __va_list_tag *) (ctlstr=0x556bf7717f34 "Delete all breakpoints? ", defchar=0 '\000', args=0x7ffe3cf31020) at ../../src/gdb/utils.c:893 #6 0x0000556bf751166f in query (ctlstr=0x556bf7717f34 "Delete all breakpoints? ") at ../../src/gdb/utils.c:985 #7 0x0000556bf6f11404 in delete_command (arg=0x0, from_tty=1) at ../../src/gdb/breakpoint.c:13500 ... ... which then later results in a target_wait call: (top-gdb) bt #0 remote_target::wait_ns (this=0x7ffe3cf30f80, ptid=..., status=0xde530314f0802800, options=...) at ../../src/gdb/remote.c:7937 #1 0x0000556bf7369dcb in remote_target::wait (this=0x556bfa0b2180, ptid=..., status=0x7ffe3cf31568, options=...) at ../../src/gdb/remote.c:8173 #2 0x0000556bf745e527 in target_wait (ptid=..., status=0x7ffe3cf31568, options=...) at ../../src/gdb/target.c:2000 #3 0x0000556bf71be686 in do_target_wait_1 (inf=0x556bfa1573d0, ptid=..., status=0x7ffe3cf31568, options=...) at ../../src/gdb/infrun.c:3463 #4 0x0000556bf71be88b in <lambda(inferior*)>::operator()(inferior *) const (__closure=0x7ffe3cf31320, inf=0x556bfa1573d0) at ../../src/gdb/infrun.c:3526 #5 0x0000556bf71bebcd in do_target_wait (wait_ptid=..., ecs=0x7ffe3cf31540, options=...) at ../../src/gdb/infrun.c:3539 #6 0x0000556bf71bf97b in fetch_inferior_event () at ../../src/gdb/infrun.c:3879 #7 0x0000556bf71a27f8 in inferior_event_handler (event_type=INF_REG_EVENT) at ../../src/gdb/inf-loop.c:42 #8 0x0000556bf71cc8b7 in infrun_async_inferior_event_handler (data=0x0) at ../../src/gdb/infrun.c:9220 #9 0x0000556bf6ecb80f in check_async_event_handlers () at ../../src/gdb/async-event.c:327 #10 0x0000556bf76b011a in gdb_do_one_event () at ../../src/gdbsupport/event-loop.cc:216 ... ... which returns TARGET_WAITKIND_IGNORE. Fix this by only enabling remote output around setting the breakpoint. gdb/testsuite/ChangeLog: * gdb.server/bkpt-other-inferior.exp: Only enable remote output around setting the breakpoint. Change-Id: I2fd152fd9c46b1c5e7fa678cc4d4054dac0b2bd4
palves
added a commit
that referenced
this issue
May 25, 2021
$ make check RUNTESTFLAGS="--target_board=native-extended-gdbserver" TESTS="gdb.base/signest.exp" make[1]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' Nothing to be done for all... make check-single make[2]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' rootme=`pwd`; export rootme; srcdir=/home/pedro/gdb/mygit/src/gdb/testsuite ; export srcdir ; EXPECT=`if [ "${READ1}" != "" ] ; then echo ${rootme}/expect-read1; elif [ -f ${rootme}/../../expect/expect ] ; then echo ${rootme}/../../expect/expect ; else echo expect ; fi` ; export EXPECT ; EXEEXT= ; export EXEEXT ; LD_LIBRARY_PATH=$rootme/../../expect:$rootme/../../libstdc++:$rootme/../../tk/unix:$rootme/../../tcl/unix:$rootme/../../bfd:$rootme/../../opcodes:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; if [ -f ${rootme}/../../expect/expect ] ; then TCL_LIBRARY=${srcdir}/../../tcl/library ; export TCL_LIBRARY ; fi ; runtest --status --target_board=native-extended-gdbserver gdb.base/signest.exp Using /home/pedro/gdb/mygit/src/gdb/testsuite/lib/gdb.exp as tool init file. NOTE: Dejagnu's default_target_compile is missing support for Go, using local override NOTE: Dejagnu's default_target_compile is missing support for Rust, using local override Test run by pedro on Wed May 19 00:00:39 2021 Native configuration is x86_64-pc-linux-gnu === gdb tests === Schedule of variations: native-extended-gdbserver Running target native-extended-gdbserver Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/native-extended-gdbserver.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/gdbserver-base.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/local-board.exp as board description file for target. configuring for gdbserver local testing (extended-remote) Using /home/pedro/gdb/mygit/src/gdb/testsuite/config/extended-gdbserver.exp as tool-and-target-specific interface file. Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/signest.exp ... ERROR: GDB process no longer exists === gdb Summary === # of expected passes 4 # of unresolved testcases 1 Infinite recursion: (top-gdb) bt 20 #0 0x0000561d6a1bfeff in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #1 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #2 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #3 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #4 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #5 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #6 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #7 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #8 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #9 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #10 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #11 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #12 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #13 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #14 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #15 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #16 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #17 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #18 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #19 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 (More stack frames follow...) (top-gdb) bt -30 #157054 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157055 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157056 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157057 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157058 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157059 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157060 0x0000561d6a1bbc65 in frame_unwind_pc (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:970 #157061 0x0000561d6a1bf54c in get_frame_pc (frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2625 #157062 0x0000561d6a1bf63e in get_frame_address_in_block (this_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2655 #157063 0x0000561d6a0cae7f in dwarf2_frame_cache (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1010 #157064 0x0000561d6a0cb928 in dwarf2_frame_this_id (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8, this_id=0x561d6b19faf0) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1227 #157065 0x0000561d6a1baf72 in compute_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:588 #157066 0x0000561d6a1bb16e in get_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:636 #157067 0x0000561d6a1bb224 in get_stack_frame_id (next_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:650 #157068 0x0000561d6a26ecd0 in insert_hp_step_resume_breakpoint_at_frame (return_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/infrun.c:7809 #157069 0x0000561d6a26b88a in handle_signal_stop (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:6428 #157070 0x0000561d6a269d81 in handle_inferior_event (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:5741 #157071 0x0000561d6a265bd0 in fetch_inferior_event () at /home/pedro/gdb/mygit/src/gdb/infrun.c:4120 #157072 0x0000561d6a244c24 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/mygit/src/gdb/inf-loop.c:41 #157073 0x0000561d6a435cc4 in remote_async_serial_handler (scb=0x561d6b4a8990, context=0x561d6b4a4c48) at /home/pedro/gdb/mygit/src/gdb/remote.c:14403 #157074 0x0000561d6a460bc5 in run_async_handler_and_reschedule (scb=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:138 #157075 0x0000561d6a460cae in fd_event (error=0, context=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:189 #157076 0x0000561d6a76a191 in handle_file_event (file_ptr=0x561d6b233ae0, ready_mask=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:575 #157077 0x0000561d6a76a743 in gdb_wait_for_event (block=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:701 #157078 0x0000561d6a7694ee in gdb_do_one_event () at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:237 #157079 0x0000561d6a2df16b in start_event_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:421 #157080 0x0000561d6a2df2b6 in captured_command_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:481 #157081 0x0000561d6a2e0d16 in captured_main (data=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1353 #157082 0x0000561d6a2e0da8 in gdb_main (args=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1370 #157083 0x0000561d69eb3d82 in main (argc=13, argv=0x7ffc67022cf8, envp=0x7ffc67022d68) at /home/pedro/gdb/mygit/src/gdb/gdb.c:33 The annota1.exp change is necessary because we'd get a regression otherwise: @@ -238,8 +238,6 @@ Continuing. ▒▒breakpoints-invalid -▒▒frames-invalid - ▒▒breakpoint 3 Breakpoint 3, @@ -276,7 +274,7 @@ printf.c ▒▒pre-prompt (gdb) ▒▒prompt -PASS: gdb.base/annota1.exp: continue to printf +FAIL: gdb.base/annota1.exp: continue to printf ... before this patch avoids flushing the frame cache. We still need to match frames-invalid because against gdbserver + "maint set target non-stop on", some other code path flushes the frame cache resulting in the annotation being emitted anyway.
palves
added a commit
that referenced
this issue
May 26, 2021
$ make check RUNTESTFLAGS="--target_board=native-extended-gdbserver" TESTS="gdb.base/signest.exp" make[1]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' Nothing to be done for all... make check-single make[2]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' rootme=`pwd`; export rootme; srcdir=/home/pedro/gdb/mygit/src/gdb/testsuite ; export srcdir ; EXPECT=`if [ "${READ1}" != "" ] ; then echo ${rootme}/expect-read1; elif [ -f ${rootme}/../../expect/expect ] ; then echo ${rootme}/../../expect/expect ; else echo expect ; fi` ; export EXPECT ; EXEEXT= ; export EXEEXT ; LD_LIBRARY_PATH=$rootme/../../expect:$rootme/../../libstdc++:$rootme/../../tk/unix:$rootme/../../tcl/unix:$rootme/../../bfd:$rootme/../../opcodes:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; if [ -f ${rootme}/../../expect/expect ] ; then TCL_LIBRARY=${srcdir}/../../tcl/library ; export TCL_LIBRARY ; fi ; runtest --status --target_board=native-extended-gdbserver gdb.base/signest.exp Using /home/pedro/gdb/mygit/src/gdb/testsuite/lib/gdb.exp as tool init file. NOTE: Dejagnu's default_target_compile is missing support for Go, using local override NOTE: Dejagnu's default_target_compile is missing support for Rust, using local override Test run by pedro on Wed May 19 00:00:39 2021 Native configuration is x86_64-pc-linux-gnu === gdb tests === Schedule of variations: native-extended-gdbserver Running target native-extended-gdbserver Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/native-extended-gdbserver.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/gdbserver-base.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/local-board.exp as board description file for target. configuring for gdbserver local testing (extended-remote) Using /home/pedro/gdb/mygit/src/gdb/testsuite/config/extended-gdbserver.exp as tool-and-target-specific interface file. Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/signest.exp ... ERROR: GDB process no longer exists === gdb Summary === # of expected passes 4 # of unresolved testcases 1 Infinite recursion: (top-gdb) bt 20 #0 0x0000561d6a1bfeff in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #1 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #2 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #3 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #4 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #5 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #6 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #7 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #8 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #9 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #10 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #11 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #12 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #13 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #14 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #15 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #16 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #17 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #18 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #19 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 (More stack frames follow...) (top-gdb) bt -30 #157054 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157055 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157056 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157057 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157058 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157059 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157060 0x0000561d6a1bbc65 in frame_unwind_pc (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:970 #157061 0x0000561d6a1bf54c in get_frame_pc (frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2625 #157062 0x0000561d6a1bf63e in get_frame_address_in_block (this_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2655 #157063 0x0000561d6a0cae7f in dwarf2_frame_cache (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1010 #157064 0x0000561d6a0cb928 in dwarf2_frame_this_id (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8, this_id=0x561d6b19faf0) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1227 #157065 0x0000561d6a1baf72 in compute_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:588 #157066 0x0000561d6a1bb16e in get_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:636 #157067 0x0000561d6a1bb224 in get_stack_frame_id (next_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:650 #157068 0x0000561d6a26ecd0 in insert_hp_step_resume_breakpoint_at_frame (return_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/infrun.c:7809 #157069 0x0000561d6a26b88a in handle_signal_stop (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:6428 #157070 0x0000561d6a269d81 in handle_inferior_event (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:5741 #157071 0x0000561d6a265bd0 in fetch_inferior_event () at /home/pedro/gdb/mygit/src/gdb/infrun.c:4120 #157072 0x0000561d6a244c24 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/mygit/src/gdb/inf-loop.c:41 #157073 0x0000561d6a435cc4 in remote_async_serial_handler (scb=0x561d6b4a8990, context=0x561d6b4a4c48) at /home/pedro/gdb/mygit/src/gdb/remote.c:14403 #157074 0x0000561d6a460bc5 in run_async_handler_and_reschedule (scb=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:138 #157075 0x0000561d6a460cae in fd_event (error=0, context=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:189 #157076 0x0000561d6a76a191 in handle_file_event (file_ptr=0x561d6b233ae0, ready_mask=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:575 #157077 0x0000561d6a76a743 in gdb_wait_for_event (block=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:701 #157078 0x0000561d6a7694ee in gdb_do_one_event () at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:237 #157079 0x0000561d6a2df16b in start_event_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:421 #157080 0x0000561d6a2df2b6 in captured_command_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:481 #157081 0x0000561d6a2e0d16 in captured_main (data=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1353 #157082 0x0000561d6a2e0da8 in gdb_main (args=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1370 #157083 0x0000561d69eb3d82 in main (argc=13, argv=0x7ffc67022cf8, envp=0x7ffc67022d68) at /home/pedro/gdb/mygit/src/gdb/gdb.c:33 The annota1.exp change is necessary because we'd get a regression otherwise: @@ -238,8 +238,6 @@ Continuing. ▒▒breakpoints-invalid -▒▒frames-invalid - ▒▒breakpoint 3 Breakpoint 3, @@ -276,7 +274,7 @@ printf.c ▒▒pre-prompt (gdb) ▒▒prompt -PASS: gdb.base/annota1.exp: continue to printf +FAIL: gdb.base/annota1.exp: continue to printf ... before this patch avoids flushing the frame cache. We still need to match frames-invalid because against gdbserver + "maint set target non-stop on", some other code path flushes the frame cache resulting in the annotation being emitted anyway.
palves
added a commit
that referenced
this issue
May 31, 2021
$ make check RUNTESTFLAGS="--target_board=native-extended-gdbserver" TESTS="gdb.base/signest.exp" make[1]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' Nothing to be done for all... make check-single make[2]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' rootme=`pwd`; export rootme; srcdir=/home/pedro/gdb/mygit/src/gdb/testsuite ; export srcdir ; EXPECT=`if [ "${READ1}" != "" ] ; then echo ${rootme}/expect-read1; elif [ -f ${rootme}/../../expect/expect ] ; then echo ${rootme}/../../expect/expect ; else echo expect ; fi` ; export EXPECT ; EXEEXT= ; export EXEEXT ; LD_LIBRARY_PATH=$rootme/../../expect:$rootme/../../libstdc++:$rootme/../../tk/unix:$rootme/../../tcl/unix:$rootme/../../bfd:$rootme/../../opcodes:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; if [ -f ${rootme}/../../expect/expect ] ; then TCL_LIBRARY=${srcdir}/../../tcl/library ; export TCL_LIBRARY ; fi ; runtest --status --target_board=native-extended-gdbserver gdb.base/signest.exp Using /home/pedro/gdb/mygit/src/gdb/testsuite/lib/gdb.exp as tool init file. NOTE: Dejagnu's default_target_compile is missing support for Go, using local override NOTE: Dejagnu's default_target_compile is missing support for Rust, using local override Test run by pedro on Wed May 19 00:00:39 2021 Native configuration is x86_64-pc-linux-gnu === gdb tests === Schedule of variations: native-extended-gdbserver Running target native-extended-gdbserver Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/native-extended-gdbserver.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/gdbserver-base.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/local-board.exp as board description file for target. configuring for gdbserver local testing (extended-remote) Using /home/pedro/gdb/mygit/src/gdb/testsuite/config/extended-gdbserver.exp as tool-and-target-specific interface file. Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/signest.exp ... ERROR: GDB process no longer exists === gdb Summary === # of expected passes 4 # of unresolved testcases 1 Infinite recursion: (top-gdb) bt 20 #0 0x0000561d6a1bfeff in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #1 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #2 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #3 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #4 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #5 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #6 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #7 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #8 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #9 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #10 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #11 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #12 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #13 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #14 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #15 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #16 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #17 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #18 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #19 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 (More stack frames follow...) (top-gdb) bt -30 #157054 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157055 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157056 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157057 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157058 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157059 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157060 0x0000561d6a1bbc65 in frame_unwind_pc (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:970 #157061 0x0000561d6a1bf54c in get_frame_pc (frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2625 #157062 0x0000561d6a1bf63e in get_frame_address_in_block (this_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2655 #157063 0x0000561d6a0cae7f in dwarf2_frame_cache (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1010 #157064 0x0000561d6a0cb928 in dwarf2_frame_this_id (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8, this_id=0x561d6b19faf0) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1227 #157065 0x0000561d6a1baf72 in compute_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:588 #157066 0x0000561d6a1bb16e in get_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:636 #157067 0x0000561d6a1bb224 in get_stack_frame_id (next_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:650 #157068 0x0000561d6a26ecd0 in insert_hp_step_resume_breakpoint_at_frame (return_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/infrun.c:7809 #157069 0x0000561d6a26b88a in handle_signal_stop (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:6428 #157070 0x0000561d6a269d81 in handle_inferior_event (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:5741 #157071 0x0000561d6a265bd0 in fetch_inferior_event () at /home/pedro/gdb/mygit/src/gdb/infrun.c:4120 #157072 0x0000561d6a244c24 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/mygit/src/gdb/inf-loop.c:41 #157073 0x0000561d6a435cc4 in remote_async_serial_handler (scb=0x561d6b4a8990, context=0x561d6b4a4c48) at /home/pedro/gdb/mygit/src/gdb/remote.c:14403 #157074 0x0000561d6a460bc5 in run_async_handler_and_reschedule (scb=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:138 #157075 0x0000561d6a460cae in fd_event (error=0, context=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:189 #157076 0x0000561d6a76a191 in handle_file_event (file_ptr=0x561d6b233ae0, ready_mask=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:575 #157077 0x0000561d6a76a743 in gdb_wait_for_event (block=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:701 #157078 0x0000561d6a7694ee in gdb_do_one_event () at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:237 #157079 0x0000561d6a2df16b in start_event_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:421 #157080 0x0000561d6a2df2b6 in captured_command_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:481 #157081 0x0000561d6a2e0d16 in captured_main (data=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1353 #157082 0x0000561d6a2e0da8 in gdb_main (args=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1370 #157083 0x0000561d69eb3d82 in main (argc=13, argv=0x7ffc67022cf8, envp=0x7ffc67022d68) at /home/pedro/gdb/mygit/src/gdb/gdb.c:33 The annota1.exp change is necessary because we'd get a regression otherwise: @@ -238,8 +238,6 @@ Continuing. ▒▒breakpoints-invalid -▒▒frames-invalid - ▒▒breakpoint 3 Breakpoint 3, @@ -276,7 +274,7 @@ printf.c ▒▒pre-prompt (gdb) ▒▒prompt -PASS: gdb.base/annota1.exp: continue to printf +FAIL: gdb.base/annota1.exp: continue to printf ... before this patch avoids flushing the frame cache. We still need to match frames-invalid because against gdbserver + "maint set target non-stop on", some other code path flushes the frame cache resulting in the annotation being emitted anyway.
palves
added a commit
that referenced
this issue
Jun 1, 2021
$ make check RUNTESTFLAGS="--target_board=native-extended-gdbserver" TESTS="gdb.base/signest.exp" make[1]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' Nothing to be done for all... make check-single make[2]: Entering directory '/home/pedro/gdb/mygit/build/gdb/testsuite' rootme=`pwd`; export rootme; srcdir=/home/pedro/gdb/mygit/src/gdb/testsuite ; export srcdir ; EXPECT=`if [ "${READ1}" != "" ] ; then echo ${rootme}/expect-read1; elif [ -f ${rootme}/../../expect/expect ] ; then echo ${rootme}/../../expect/expect ; else echo expect ; fi` ; export EXPECT ; EXEEXT= ; export EXEEXT ; LD_LIBRARY_PATH=$rootme/../../expect:$rootme/../../libstdc++:$rootme/../../tk/unix:$rootme/../../tcl/unix:$rootme/../../bfd:$rootme/../../opcodes:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; if [ -f ${rootme}/../../expect/expect ] ; then TCL_LIBRARY=${srcdir}/../../tcl/library ; export TCL_LIBRARY ; fi ; runtest --status --target_board=native-extended-gdbserver gdb.base/signest.exp Using /home/pedro/gdb/mygit/src/gdb/testsuite/lib/gdb.exp as tool init file. NOTE: Dejagnu's default_target_compile is missing support for Go, using local override NOTE: Dejagnu's default_target_compile is missing support for Rust, using local override Test run by pedro on Wed May 19 00:00:39 2021 Native configuration is x86_64-pc-linux-gnu === gdb tests === Schedule of variations: native-extended-gdbserver Running target native-extended-gdbserver Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/native-extended-gdbserver.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/gdbserver-base.exp as board description file for target. Using /home/pedro/gdb/mygit/src/gdb/testsuite/boards/../boards/local-board.exp as board description file for target. configuring for gdbserver local testing (extended-remote) Using /home/pedro/gdb/mygit/src/gdb/testsuite/config/extended-gdbserver.exp as tool-and-target-specific interface file. Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/signest.exp ... ERROR: GDB process no longer exists === gdb Summary === # of expected passes 4 # of unresolved testcases 1 Infinite recursion: (top-gdb) bt 20 #0 0x0000561d6a1bfeff in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #1 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #2 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #3 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #4 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #5 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #6 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #7 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #8 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #9 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #10 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #11 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #12 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #13 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #14 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #15 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #16 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #17 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #18 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #19 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 (More stack frames follow...) (top-gdb) bt -30 #157054 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157055 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157056 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157057 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157058 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157059 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157060 0x0000561d6a1bbc65 in frame_unwind_pc (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:970 #157061 0x0000561d6a1bf54c in get_frame_pc (frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2625 #157062 0x0000561d6a1bf63e in get_frame_address_in_block (this_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2655 #157063 0x0000561d6a0cae7f in dwarf2_frame_cache (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1010 #157064 0x0000561d6a0cb928 in dwarf2_frame_this_id (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8, this_id=0x561d6b19faf0) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1227 #157065 0x0000561d6a1baf72 in compute_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:588 #157066 0x0000561d6a1bb16e in get_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:636 #157067 0x0000561d6a1bb224 in get_stack_frame_id (next_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:650 #157068 0x0000561d6a26ecd0 in insert_hp_step_resume_breakpoint_at_frame (return_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/infrun.c:7809 #157069 0x0000561d6a26b88a in handle_signal_stop (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:6428 #157070 0x0000561d6a269d81 in handle_inferior_event (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:5741 #157071 0x0000561d6a265bd0 in fetch_inferior_event () at /home/pedro/gdb/mygit/src/gdb/infrun.c:4120 #157072 0x0000561d6a244c24 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/mygit/src/gdb/inf-loop.c:41 #157073 0x0000561d6a435cc4 in remote_async_serial_handler (scb=0x561d6b4a8990, context=0x561d6b4a4c48) at /home/pedro/gdb/mygit/src/gdb/remote.c:14403 #157074 0x0000561d6a460bc5 in run_async_handler_and_reschedule (scb=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:138 #157075 0x0000561d6a460cae in fd_event (error=0, context=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:189 #157076 0x0000561d6a76a191 in handle_file_event (file_ptr=0x561d6b233ae0, ready_mask=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:575 #157077 0x0000561d6a76a743 in gdb_wait_for_event (block=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:701 #157078 0x0000561d6a7694ee in gdb_do_one_event () at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:237 #157079 0x0000561d6a2df16b in start_event_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:421 #157080 0x0000561d6a2df2b6 in captured_command_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:481 #157081 0x0000561d6a2e0d16 in captured_main (data=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1353 #157082 0x0000561d6a2e0da8 in gdb_main (args=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1370 #157083 0x0000561d69eb3d82 in main (argc=13, argv=0x7ffc67022cf8, envp=0x7ffc67022d68) at /home/pedro/gdb/mygit/src/gdb/gdb.c:33 The annota1.exp change is necessary because we'd get a regression otherwise: @@ -238,8 +238,6 @@ Continuing. ▒▒breakpoints-invalid -▒▒frames-invalid - ▒▒breakpoint 3 Breakpoint 3, @@ -276,7 +274,7 @@ printf.c ▒▒pre-prompt (gdb) ▒▒prompt -PASS: gdb.base/annota1.exp: continue to printf +FAIL: gdb.base/annota1.exp: continue to printf ... before this patch avoids flushing the frame cache. We still need to match frames-invalid because against gdbserver + "maint set target non-stop on", some other code path flushes the frame cache resulting in the annotation being emitted anyway.
palves
added a commit
that referenced
this issue
Jun 2, 2021
A following patch adds a exists_non_stop_target call in the target_terminal routines, and that surprisingly caused a weird regression / GDB crash: $ make check RUNTESTFLAGS="--target_board=native-extended-gdbserver" TESTS="gdb.base/signest.exp" ... configuring for gdbserver local testing (extended-remote) Using /home/pedro/gdb/mygit/src/gdb/testsuite/config/extended-gdbserver.exp as tool-and-target-specific interface file. Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.base/signest.exp ... ERROR: GDB process no longer exists Debugging the core, we see infinite recursion: (top-gdb) bt 20 #0 0x0000561d6a1bfeff in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #1 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #2 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #3 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #4 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #5 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #6 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #7 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #8 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #9 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #10 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #11 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #12 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #13 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #14 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #15 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #16 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #17 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #18 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #19 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 (More stack frames follow...) (top-gdb) bt -30 #157054 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157055 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157056 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157057 0x0000561d6a1bfeb8 in get_frame_arch (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2939 #157058 0x0000561d6a1b989f in frame_unwind_find_by_frame (this_frame=0x561d6b19f9c0, this_cache=0x561d6b19f9d8) at /home/pedro/gdb/mygit/src/gdb/frame-unwind.c:174 #157059 0x0000561d6a1bff04 in frame_unwind_arch (next_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:2950 #157060 0x0000561d6a1bbc65 in frame_unwind_pc (this_frame=0x561d6b19f9c0) at /home/pedro/gdb/mygit/src/gdb/frame.c:970 #157061 0x0000561d6a1bf54c in get_frame_pc (frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2625 #157062 0x0000561d6a1bf63e in get_frame_address_in_block (this_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:2655 #157063 0x0000561d6a0cae7f in dwarf2_frame_cache (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1010 #157064 0x0000561d6a0cb928 in dwarf2_frame_this_id (this_frame=0x561d6b19fa90, this_cache=0x561d6b19faa8, this_id=0x561d6b19faf0) at /home/pedro/gdb/mygit/src/gdb/dwarf2/frame.c:1227 #157065 0x0000561d6a1baf72 in compute_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:588 #157066 0x0000561d6a1bb16e in get_frame_id (fi=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:636 #157067 0x0000561d6a1bb224 in get_stack_frame_id (next_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/frame.c:650 #157068 0x0000561d6a26ecd0 in insert_hp_step_resume_breakpoint_at_frame (return_frame=0x561d6b19fa90) at /home/pedro/gdb/mygit/src/gdb/infrun.c:7809 #157069 0x0000561d6a26b88a in handle_signal_stop (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:6428 #157070 0x0000561d6a269d81 in handle_inferior_event (ecs=0x7ffc67022830) at /home/pedro/gdb/mygit/src/gdb/infrun.c:5741 #157071 0x0000561d6a265bd0 in fetch_inferior_event () at /home/pedro/gdb/mygit/src/gdb/infrun.c:4120 #157072 0x0000561d6a244c24 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/pedro/gdb/mygit/src/gdb/inf-loop.c:41 #157073 0x0000561d6a435cc4 in remote_async_serial_handler (scb=0x561d6b4a8990, context=0x561d6b4a4c48) at /home/pedro/gdb/mygit/src/gdb/remote.c:14403 #157074 0x0000561d6a460bc5 in run_async_handler_and_reschedule (scb=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:138 #157075 0x0000561d6a460cae in fd_event (error=0, context=0x561d6b4a8990) at /home/pedro/gdb/mygit/src/gdb/ser-base.c:189 #157076 0x0000561d6a76a191 in handle_file_event (file_ptr=0x561d6b233ae0, ready_mask=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:575 #157077 0x0000561d6a76a743 in gdb_wait_for_event (block=1) at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:701 #157078 0x0000561d6a7694ee in gdb_do_one_event () at /home/pedro/gdb/mygit/src/gdbsupport/event-loop.cc:237 #157079 0x0000561d6a2df16b in start_event_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:421 #157080 0x0000561d6a2df2b6 in captured_command_loop () at /home/pedro/gdb/mygit/src/gdb/main.c:481 #157081 0x0000561d6a2e0d16 in captured_main (data=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1353 #157082 0x0000561d6a2e0da8 in gdb_main (args=0x7ffc67022bd0) at /home/pedro/gdb/mygit/src/gdb/main.c:1370 #157083 0x0000561d69eb3d82 in main (argc=13, argv=0x7ffc67022cf8, envp=0x7ffc67022d68) at /home/pedro/gdb/mygit/src/gdb/gdb.c:33 This was caused by exists_non_stop_target flushing the frame cache via scoped_restore_current_thread/switch_to_thread, while we're in the middle of unwinding. Fix this by making exists_non_stop_target only switch the inferior, like done in target_pass_ctrlc. The annota1.exp change is necessary because we'd get a regression otherwise: @@ -238,8 +238,6 @@ Continuing. ▒▒breakpoints-invalid -▒▒frames-invalid - ▒▒breakpoint 3 Breakpoint 3, @@ -276,7 +274,7 @@ printf.c ▒▒pre-prompt (gdb) ▒▒prompt -PASS: gdb.base/annota1.exp: continue to printf +FAIL: gdb.base/annota1.exp: continue to printf ... because this patch avoids flushing the frame cache that lead to that missing frames-invalid. We still need to match frames-invalid because against gdbserver + "maint set target non-stop on", some other code path flushes the frame cache resulting in the annotation being emitted anyway. gdb/ChangeLog: yyyy-mm-dd Pedro Alves <[email protected]> * target.c (exists_non_stop_target): Use scoped_restore_current_inferior and set_current_inferior instead of scoped_restore_current_thread / switch_to_inferior_no_thread.
palves
pushed a commit
that referenced
this issue
Jun 17, 2021
When loading the debug info package libLLVM.so.10-10.0.1-lp152.30.4.x86_64.debug from openSUSE Leap 15.2, we run into a dwarf error: ... $ gdb -q -batch libLLVM.so.10-10.0.1-lp152.30.4.x86_64.debug Dwarf Error: Cannot not find DIE at 0x18a936e7 \ [from module libLLVM.so.10-10.0.1-lp152.30.4.x86_64.debug] ... The DIE @ 0x18a936e7 does in fact exist, and is part of a CU @ 0x18a23e52. No error message is printed when using -readnow. What happens is the following: - a dwarf2_per_cu_data P is created for the CU. - a dwarf2_cu A is created for the same CU. - another dwarf2_cu B is created for the same CU. - the dwarf2_cu B is set in per_objfile->m_dwarf2_cus, such that per_objfile->get_cu (P) returns B. - P->load_all_dies is set to 1. - all dies are read into the A->partial_dies htab - dwarf2_cu A is destroyed. - we try to find the partial_die for the DIE @ 0x18a936e7 in B->partial_dies. We can't find it, but do not try to load all dies, because P->load_all_dies is already set to 1. - an error message is generated. The question is why we're creating dwarf2_cu A and B for the same CU. The dwarf2_cu A is created here: ... (gdb) bt #0 dwarf2_cu::dwarf2_cu (this=0x79a9660, per_cu=0x23c0b30, per_objfile=0x1ad01b0) at dwarf2/cu.c:38 #1 0x0000000000675799 in cutu_reader::cutu_reader (this=0x7fffffffd040, this_cu=0x23c0b30, per_objfile=0x1ad01b0, abbrev_table=0x0, existing_cu=0x0, skip_partial=false) at dwarf2/read.c:6487 #2 0x0000000000676eb3 in process_psymtab_comp_unit (this_cu=0x23c0b30, per_objfile=0x1ad01b0, want_partial_unit=false, pretend_language=language_minimal) at dwarf2/read.c:7028 ... And the dwarf2_cu B is created here: ... (gdb) bt #0 dwarf2_cu::dwarf2_cu (this=0x885e8c0, per_cu=0x23c0b30, per_objfile=0x1ad01b0) at dwarf2/cu.c:38 #1 0x0000000000675799 in cutu_reader::cutu_reader (this=0x7fffffffcc50, this_cu=0x23c0b30, per_objfile=0x1ad01b0, abbrev_table=0x0, existing_cu=0x0, skip_partial=false) at dwarf2/read.c:6487 #2 0x0000000000678118 in load_partial_comp_unit (this_cu=0x23c0b30, per_objfile=0x1ad01b0, existing_cu=0x0) at dwarf2/read.c:7436 #3 0x000000000069721d in find_partial_die (sect_off=(unknown: 0x18a55054), offset_in_dwz=0, cu=0x0) at dwarf2/read.c:19391 #4 0x000000000069755b in partial_die_info::fixup (this=0x9096900, cu=0xa6a85f0) at dwarf2/read.c:19512 #5 0x0000000000697586 in partial_die_info::fixup (this=0x8629bb0, cu=0xa6a85f0) at dwarf2/read.c:19516 #6 0x00000000006787b1 in scan_partial_symbols (first_die=0x8629b40, lowpc=0x7fffffffcf58, highpc=0x7fffffffcf50, set_addrmap=0, cu=0x79a9660) at dwarf2/read.c:7563 #7 0x0000000000678878 in scan_partial_symbols (first_die=0x796ebf0, lowpc=0x7fffffffcf58, highpc=0x7fffffffcf50, set_addrmap=0, cu=0x79a9660) at dwarf2/read.c:7580 #8 0x0000000000676b82 in process_psymtab_comp_unit_reader (reader=0x7fffffffd040, info_ptr=0x7fffc1b3f29b, comp_unit_die=0x6ea90f0, pretend_language=language_minimal) at dwarf2/read.c:6954 #9 0x0000000000676ffd in process_psymtab_comp_unit (this_cu=0x23c0b30, per_objfile=0x1ad01b0, want_partial_unit=false, pretend_language=language_minimal) at dwarf2/read.c:7057 ... So in frame #9, a cutu_reader is created with dwarf2_cu A. Then a fixup takes us to the following CU @ 0x18aa33d6, in frame #5. And a similar fixup in frame #4 takes us back to CU @ 0x18a23e52. At that point, there's no information available that we're already trying to read that CU, and we end up creating another cutu_reader with dwarf2_cu B. It seems that there are two related problems: - creating two dwarf2_cu's is not optimal - the unoptimal case is not handled correctly This patch addresses the last problem, by moving the load_all_dies flag from dwarf2_per_cu_data to dwarf2_cu, such that it is paired with the partial_dies field, which ensures that the two can be kept in sync. Tested on x86_64-linux. gdb/ChangeLog: 2021-05-27 Tom de Vries <[email protected]> PR symtab/27898 * dwarf2/cu.c (dwarf2_cu::dwarf2_cu): Add load_all_dies init. * dwarf2/cu.h (dwarf2_cu): Add load_all_dies field. * dwarf2/read.c (load_partial_dies, find_partial_die): Update. * dwarf2/read.h (dwarf2_per_cu_data::dwarf2_per_cu_data): Remove load_all_dies init. (dwarf2_per_cu_data): Remove load_all_dies field.
palves
pushed a commit
that referenced
this issue
Jun 17, 2021
… when attaching / handling a fork child When trying to attach to a pthread process on a Linux system with glibc 2.33, we get: $ ./gdb -q -nx --data-directory=data-directory -p 1472010 Attaching to process 1472010 [New LWP 1472013] [New LWP 1472014] [New LWP 1472015] Error while reading shared library symbols for /usr/lib/libpthread.so.0: Cannot find user-level thread for LWP 1472015: generic error 0x00007ffff6d3637f in poll () from /usr/lib/libc.so.6 (gdb) When attaching to a process (or handling a fork child, an operation very similar to attaching), GDB reads the shared library list from the process. For each shared library (if "set auto-solib-add" is on), it reads its symbols and calls the "new_objfile" observable. The libthread-db code monitors this observable, and if it sees an objfile named somewhat like "libpthread.so" go by, it tries to load libthread_db.so in the GDB process itself. libthread_db knows how to navigate libpthread's data structures to get information about the existing threads. To locate these data structures, libthread_db calls ps_pglobal_lookup (implemented in proc-service.c), passing in a symbol name and expecting an address in return. Before glibc 2.33, libthread_db always asked for symbols found in libpthread. There was no ordering problem: since we were always trying to load libthread_db in reaction to processing libpthread (and reading in its symbols) and libthread_db only asked symbols from libpthread, the requested symbols could always be found. Starting with glibc 2.33, libthread_db now asks for a symbol name that can be found in /lib/ld-linux-x86-64.so.2 (_rtld_global). And the ordering in which GDB reads the shared libraries from the inferior when attaching is unfortunate, in that libpthread is processed before ld-linux. So when loading libthread_db in reaction to processing libpthread, and libthread_db requests the symbol that is from ld-linux, GDB is not yet able to supply it. That problematic symbol lookup happens in the thread_from_lwp function, when we call td_ta_map_lwp2thr_p, and an exception is thrown at this point: #0 0x00007ffff6681012 in __cxxabiv1::__cxa_throw (obj=0x60e000006100, tinfo=0x555560033b50 <typeinfo for gdb_exception_error>, dest=0x55555d9404bc <gdb_exception_error::~gdb_exception_error()>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_throw.cc:78 #1 0x000055555e5d3734 in throw_it(return_reason, errors, const char *, typedef __va_list_tag __va_list_tag *) (reason=RETURN_ERROR, error=GENERIC_ERROR, fmt=0x55555f0c5360 "Cannot find user-level thread for LWP %ld: %s", ap=0x7fffffffaae0) at /home/simark/src/binutils-gdb/gdbsupport/common-exceptions.cc:200 #2 0x000055555e5d37d4 in throw_verror (error=GENERIC_ERROR, fmt=0x55555f0c5360 "Cannot find user-level thread for LWP %ld: %s", ap=0x7fffffffaae0) at /home/simark/src/binutils-gdb/gdbsupport/common-exceptions.cc:208 #3 0x000055555e0b0ed2 in verror (string=0x55555f0c5360 "Cannot find user-level thread for LWP %ld: %s", args=0x7fffffffaae0) at /home/simark/src/binutils-gdb/gdb/utils.c:171 #4 0x000055555e5e898a in error (fmt=0x55555f0c5360 "Cannot find user-level thread for LWP %ld: %s") at /home/simark/src/binutils-gdb/gdbsupport/errors.cc:43 #5 0x000055555d06b4bc in thread_from_lwp (stopped=0x617000035d80, ptid=...) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:418 #6 0x000055555d07040d in try_thread_db_load_1 (info=0x60c000011140) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:912 #7 0x000055555d071103 in try_thread_db_load (library=0x55555f0c62a0 "libthread_db.so.1", check_auto_load_safe=false) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1014 #8 0x000055555d072168 in try_thread_db_load_from_sdir () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1091 #9 0x000055555d072d1c in thread_db_load_search () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1146 #10 0x000055555d07365c in thread_db_load () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1203 #11 0x000055555d07373e in check_for_thread_db () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1246 #12 0x000055555d0738ab in thread_db_new_objfile (objfile=0x61300000c0c0) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1275 #13 0x000055555bd10740 in std::__invoke_impl<void, void (*&)(objfile*), objfile*> (__f=@0x616000068d88: 0x55555d073745 <thread_db_new_objfile(objfile*)>) at /usr/include/c++/10.2.0/bits/invoke.h:60 #14 0x000055555bd02096 in std::__invoke_r<void, void (*&)(objfile*), objfile*> (__fn=@0x616000068d88: 0x55555d073745 <thread_db_new_objfile(objfile*)>) at /usr/include/c++/10.2.0/bits/invoke.h:153 #15 0x000055555bce0392 in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7fffffffb4a0: 0x61300000c0c0) at /usr/include/c++/10.2.0/bits/std_function.h:291 #16 0x000055555d3595c0 in std::function<void (objfile*)>::operator()(objfile*) const (this=0x616000068d88, __args#0=0x61300000c0c0) at /usr/include/c++/10.2.0/bits/std_function.h:622 #17 0x000055555d356b7f in gdb::observers::observable<objfile*>::notify (this=0x555566727020 <gdb::observers::new_objfile>, args#0=0x61300000c0c0) at /home/simark/src/binutils-gdb/gdb/../gdbsupport/observable.h:106 #18 0x000055555da3f228 in symbol_file_add_with_addrs (abfd=0x61200001ccc0, name=0x6190000d9090 "/usr/lib/libpthread.so.0", add_flags=..., addrs=0x7fffffffbc10, flags=..., parent=0x0) at /home/simark/src/binutils-gdb/gdb/symfile.c:1131 #19 0x000055555da3f763 in symbol_file_add_from_bfd (abfd=0x61200001ccc0, name=0x6190000d9090 "/usr/lib/libpthread.so.0", add_flags=<error reading variable: Cannot access memory at address 0xffffffffffffffb0>, addrs=0x7fffffffbc10, flags=<error reading variable: Cannot access memory at address 0xffffffffffffffc0>, parent=0x0) at /home/simark/src/binutils-gdb/gdb/symfile.c:1167 #20 0x000055555d95f9fa in solib_read_symbols (so=0x6190000d8e80, flags=...) at /home/simark/src/binutils-gdb/gdb/solib.c:681 #21 0x000055555d96233d in solib_add (pattern=0x0, from_tty=0, readsyms=1) at /home/simark/src/binutils-gdb/gdb/solib.c:987 #22 0x000055555d93646e in enable_break (info=0x608000008f20, from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:2238 #23 0x000055555d93cfc0 in svr4_solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:3049 #24 0x000055555d96610d in solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib.c:1195 #25 0x000055555cdee318 in post_create_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:318 #26 0x000055555ce00e6e in setup_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:2439 #27 0x000055555ce59c34 in handle_one (event=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:4887 #28 0x000055555ce5cd00 in stop_all_threads () at /home/simark/src/binutils-gdb/gdb/infrun.c:5064 #29 0x000055555ce7f0da in stop_waiting (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:8006 #30 0x000055555ce67f5c in handle_signal_stop (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:6062 #31 0x000055555ce63653 in handle_inferior_event (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:5727 #32 0x000055555ce4f297 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:4105 #33 0x000055555cdbe3bf in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 #34 0x000055555d018047 in handle_target_event (error=0, client_data=0x0) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:4060 #35 0x000055555e5ea77e in handle_file_event (file_ptr=0x60600008b1c0, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:575 #36 0x000055555e5eb09c in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:701 #37 0x000055555e5e8d19 in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 #38 0x000055555dd6e0d4 in wait_sync_command_done () at /home/simark/src/binutils-gdb/gdb/top.c:528 #39 0x000055555dd6e372 in maybe_wait_sync_command_done (was_sync=0) at /home/simark/src/binutils-gdb/gdb/top.c:545 #40 0x000055555d0ec7c8 in catch_command_errors (command=0x55555ce01bb8 <attach_command(char const*, int)>, arg=0x7fffffffe28d "1472010", from_tty=1, do_bp_actions=false) at /home/simark/src/binutils-gdb/gdb/main.c:452 #41 0x000055555d0f03ad in captured_main_1 (context=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1149 #42 0x000055555d0f1239 in captured_main (data=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1232 #43 0x000055555d0f1315 in gdb_main (args=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1257 #44 0x000055555bb70cf9 in main (argc=7, argv=0x7fffffffde88) at /home/simark/src/binutils-gdb/gdb/gdb.c:32 The exception is caught here: #0 __cxxabiv1::__cxa_begin_catch (exc_obj_in=0x60e0000060e0) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_catch.cc:84 #1 0x000055555d95fded in solib_read_symbols (so=0x6190000d8e80, flags=...) at /home/simark/src/binutils-gdb/gdb/solib.c:689 #2 0x000055555d96233d in solib_add (pattern=0x0, from_tty=0, readsyms=1) at /home/simark/src/binutils-gdb/gdb/solib.c:987 #3 0x000055555d93646e in enable_break (info=0x608000008f20, from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:2238 #4 0x000055555d93cfc0 in svr4_solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:3049 #5 0x000055555d96610d in solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib.c:1195 #6 0x000055555cdee318 in post_create_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:318 #7 0x000055555ce00e6e in setup_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:2439 #8 0x000055555ce59c34 in handle_one (event=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:4887 #9 0x000055555ce5cd00 in stop_all_threads () at /home/simark/src/binutils-gdb/gdb/infrun.c:5064 #10 0x000055555ce7f0da in stop_waiting (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:8006 #11 0x000055555ce67f5c in handle_signal_stop (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:6062 #12 0x000055555ce63653 in handle_inferior_event (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:5727 #13 0x000055555ce4f297 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:4105 #14 0x000055555cdbe3bf in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 #15 0x000055555d018047 in handle_target_event (error=0, client_data=0x0) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:4060 #16 0x000055555e5ea77e in handle_file_event (file_ptr=0x60600008b1c0, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:575 #17 0x000055555e5eb09c in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:701 #18 0x000055555e5e8d19 in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 #19 0x000055555dd6e0d4 in wait_sync_command_done () at /home/simark/src/binutils-gdb/gdb/top.c:528 #20 0x000055555dd6e372 in maybe_wait_sync_command_done (was_sync=0) at /home/simark/src/binutils-gdb/gdb/top.c:545 #21 0x000055555d0ec7c8 in catch_command_errors (command=0x55555ce01bb8 <attach_command(char const*, int)>, arg=0x7fffffffe28d "1472010", from_tty=1, do_bp_actions=false) at /home/simark/src/binutils-gdb/gdb/main.c:452 #22 0x000055555d0f03ad in captured_main_1 (context=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1149 #23 0x000055555d0f1239 in captured_main (data=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1232 #24 0x000055555d0f1315 in gdb_main (args=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1257 #25 0x000055555bb70cf9 in main (argc=7, argv=0x7fffffffde88) at /home/simark/src/binutils-gdb/gdb/gdb.c:32 Catching the exception at this point means that the thread_db_info object for this inferior will be left in place, despite the failure to load libthread_db. This means that there won't be further attempts at loading libthread_db, because thread_db_load will think that libthread_db is already loaded for this inferior and will always exit early. To fix this, add a try/catch around calling try_thread_db_load_1 in try_thread_db_load, such that if some exception is thrown while trying to load libthread_db, we reset / delete the thread_db_info for that inferior. That alone makes attach work fine again, because check_for_thread_db is called again in the thread_db_inferior_created observer (that happens after we learned about all shared libraries and their symbols), and libthread_db is successfully loaded then. When attaching, I think that the inferior_created observer is a good place to try to load libthread_db: it is called once everything has stabilized, when we learned about all shared libraries. The only problem then is that when we first try (and fail) to load libthread_db, in reaction to learning about libpthread, we show this warning: warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available. This is misleading, because we do succeed in loading it later. So when attaching, I think we shouldn't try to load libthread_db in reaction to the new_objfile events, we should wait until we have learned about all shared libraries (using the inferior_created observable). To do so, add an `in_initial_library_scan` flag to struct inferior. This flag is used to postpone loading libthread_db if we are attaching or handling a fork child. When debugging remotely with GDBserver, the same problem happens, except that the qSymbol mechanism (allowing the remote side to ask GDB for symbols values) is involved. The fix there is the same idea, we make GDB wait until all shared libraries and their symbols are known before sending out a qSymbol packet. This way, we never present the remote side a state where libpthread.so's symbols are known but ld-linux's symbols aren't. gdb/ChangeLog: * inferior.h (class inferior) <in_initial_library_scan>: New. * infcmd.c (post_create_inferior): Set in_initial_library_scan. * infrun.c (follow_fork_inferior): Likewise. * linux-thread-db.c (try_thread_db_load): Catch exception thrown by try_thread_db_load_1 (thread_db_load): Return early if in_initial_library_scan is set. * remote.c (remote_new_objfile): Return early if in_initial_library_scan is set. Change-Id: I7a279836cfbb2b362b4fde11b196b4aab82f5efb
palves
pushed a commit
that referenced
this issue
Jul 2, 2021
When loading a mach-o (macOS) executable and trying to set a breakpoint, a GDB built with ASan or -D_GLIBCXX_DEBUG will crash with an out-of-bound vector access. This can be reproduced on Linux using the repro files in bug 28017 [1]: $ ./gdb -nx --data-directory=data-directory -q repro/test -ex "b main" -batch /usr/include/c++/11.1.0/debug/vector:445: In function: std::__debug::vector<_Tp, _Allocator>::const_reference std::__debug::vector<_Tp, _Allocator>::operator[](std::__debug::vector<_Tp, _Allocator>::size_type) const [with _Tp = long unsigned int; _Allocator = std::allocator<long unsigned int>; std::__debug::vector<_Tp, _Allocator>::const_reference = const long unsigned int&; std::__debug::vector<_Tp, _Allocator>::size_type = long unsigned int] Error: attempt to subscript container with out-of-bounds index 13, but container only holds 13 elements. Objects involved in the operation: sequence "this" @ 0x0x61300000a590 { type = std::__debug::vector<unsigned long, std::allocator<unsigned long> >; } The out-of-bound access happens here: #0 0x00007ffff6405d22 in raise () from /usr/lib/libc.so.6 #1 0x00007ffff63ef862 in abort () from /usr/lib/libc.so.6 #2 0x00007ffff664e21e in __gnu_debug::_Error_formatter::_M_error() const [clone .cold] from /usr/lib/libstdc++.so.6 #3 0x000055555699e5ff in std::__debug::vector<unsigned long, std::allocator<unsigned long> >::operator[] (this=0x61300000a590, __n=13) at /usr/include/c++/11.1.0/debug/vector:445 #4 0x0000555556a58c17 in objfile::section_offset (this=0x61300000a4c0, section=0x55555bbe4ac0 <_bfd_std_section>) at /home/simark/src/binutils-gdb/gdb/objfiles.h:644 #5 0x0000555556a58cac in obj_section::offset (this=0x62100016d2a8) at /home/simark/src/binutils-gdb/gdb/objfiles.h:838 #6 0x0000555556a58cfa in obj_section::addr (this=0x62100016d2a8) at /home/simark/src/binutils-gdb/gdb/objfiles.h:850 #7 0x000055555779f5f7 in sort_cmp (sect1=0x62100016d2a8, sect2=0x62100016d170) at /home/simark/src/binutils-gdb/gdb/objfiles.c:902 #8 0x00005555577aae35 in __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(obj_section const*, obj_section const*)>::operator()<obj_section**, obj_section**> (this=0x7fffffffa9e0, __it1=0x60c000015970, __it2=0x60c000015940) at /usr/include/c++/11.1.0/bits/predefined_ops.h:158 #9 0x00005555577aa2b8 in std::__insertion_sort<obj_section**, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(obj_section const*, obj_section const*)> > (__first=0x60c000015940, __last=0x60c0000159c0, __comp=...) at /usr/include/c++/11.1.0/bits/stl_algo.h:1826 #10 0x00005555577a8e26 in std::__final_insertion_sort<obj_section**, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(obj_section const*, obj_section const*)> > (__first=0x60c000015940, __last=0x60c0000159c0, __comp=...) at /usr/include/c++/11.1.0/bits/stl_algo.h:1871 #11 0x00005555577a723c in std::__sort<obj_section**, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(obj_section const*, obj_section const*)> > (__first=0x60c000015940, __last=0x60c0000159c0, __comp=...) at /usr/include/c++/11.1.0/bits/stl_algo.h:1957 #12 0x00005555577a50f4 in std::sort<obj_section**, bool (*)(obj_section const*, obj_section const*)> (__first=0x60c000015940, __last=0x60c0000159c0, __comp=0x55555779f4e7 <sort_cmp(obj_section const*, obj_section const*)>) at /usr/include/c++/11.1.0/bits/stl_algo.h:4875 #13 0x00005555577a147e in update_section_map (pspace=0x61200001d2c0, pmap=0x6030000d40b0, pmap_size=0x6030000d40b8) at /home/simark/src/binutils-gdb/gdb/objfiles.c:1165 #14 0x00005555577a19a0 in find_pc_section (pc=0x100003fa0) at /home/simark/src/binutils-gdb/gdb/objfiles.c:1212 #15 0x00005555576dd39e in lookup_minimal_symbol_by_pc_section (pc_in=0x100003fa0, section=0x0, prefer=lookup_msym_prefer::TEXT, previous=0x0) at /home/simark/src/binutils-gdb/gdb/minsyms.c:750 #16 0x00005555576de552 in lookup_minimal_symbol_by_pc (pc=0x100003fa0) at /home/simark/src/binutils-gdb/gdb/minsyms.c:986 #17 0x0000555557d44b54 in find_pc_sect_line (pc=0x100003fa0, section=0x62100016d170, notcurrent=0) at /home/simark/src/binutils-gdb/gdb/symtab.c:3163 #18 0x0000555557d489fa in find_function_start_sal_1 (func_addr=0x100003fa0, section=0x62100016d170, funfirstline=true) at /home/simark/src/binutils-gdb/gdb/symtab.c:3650 #19 0x0000555557d49015 in find_function_start_sal (sym=0x621000191670, funfirstline=true) at /home/simark/src/binutils-gdb/gdb/symtab.c:3706 #20 0x0000555557485283 in symbol_to_sal (result=0x7fffffffbb30, funfirstline=1, sym=0x621000191670) at /home/simark/src/binutils-gdb/gdb/linespec.c:4460 #21 0x00005555574728c2 in convert_linespec_to_sals (state=0x7fffffffc390, ls=0x7fffffffc3e0) at /home/simark/src/binutils-gdb/gdb/linespec.c:2335 #22 0x0000555557475a8e in parse_linespec (parser=0x7fffffffc360, arg=0x60200007a550 "main", match_type=symbol_name_match_type::WILD) at /home/simark/src/binutils-gdb/gdb/linespec.c:2716 #23 0x0000555557479027 in event_location_to_sals (parser=0x7fffffffc360, location=0x606000097be0) at /home/simark/src/binutils-gdb/gdb/linespec.c:3173 #24 0x00005555574798f7 in decode_line_full (location=0x606000097be0, flags=1, search_pspace=0x0, default_symtab=0x0, default_line=0, canonical=0x7fffffffcca0, select_mode=0x0, filter=0x0) at /home/simark/src/binutils-gdb/gdb/linespec.c:3253 #25 0x0000555556b4949f in parse_breakpoint_sals (location=0x606000097be0, canonical=0x7fffffffcca0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9134 #26 0x0000555556b6ce95 in create_sals_from_location_default (location=0x606000097be0, canonical=0x7fffffffcca0, type_wanted=bp_breakpoint) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:13819 #27 0x0000555556b645a6 in bkpt_create_sals_from_location (location=0x606000097be0, canonical=0x7fffffffcca0, type_wanted=bp_breakpoint) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:12631 #28 0x0000555556b4badf in create_breakpoint (gdbarch=0x621000152d10, location=0x606000097be0, cond_string=0x0, thread=0, extra_string=0x0, force_condition=false, parse_extra=1, tempflag=0, type_wanted=bp_breakpoint, ignore_count=0, pending_break_support=AUTO_BOOLEAN_AUTO, ops=0x55555bd728a0 <bkpt_breakpoint_ops>, from_tty=0, enabled=1, internal=0, flags=0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9410 #29 0x0000555556b4d3b1 in break_command_1 (arg=0x7fffffffe291 "", flag=0, from_tty=0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9590 #30 0x0000555556b4dc1b in break_command (arg=0x7fffffffe28d "main", from_tty=0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9660 #31 0x0000555556d24ca9 in do_const_cfunc (c=0x61100003a240, args=0x7fffffffe28d "main", from_tty=0) at /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:102 #32 0x0000555556d2fcd3 in cmd_func (cmd=0x61100003a240, args=0x7fffffffe28d "main", from_tty=0) at /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2160 #33 0x0000555557e84e93 in execute_command (p=0x7fffffffe290 "n", from_tty=0) at /home/simark/src/binutils-gdb/gdb/top.c:674 #34 0x00005555575a9933 in catch_command_errors (command=0x555557e84043 <execute_command(char const*, int)>, arg=0x7fffffffe28b "b main", from_tty=0, do_bp_actions=true) at /home/simark/src/binutils-gdb/gdb/main.c:523 #35 0x00005555575a9fdb in execute_cmdargs (cmdarg_vec=0x7fffffffd910, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffd5b0) at /home/simark/src/binutils-gdb/gdb/main.c:618 #36 0x00005555575ad48a in captured_main_1 (context=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1322 #37 0x00005555575ada9c in captured_main (data=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1343 #38 0x00005555575adb31 in gdb_main (args=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1368 #39 0x000055555681e179 in main (argc=8, argv=0x7fffffffde78) at /home/simark/src/binutils-gdb/gdb/gdb.c:32 The section being dealt with at that moment is the special *COM* section: (top-gdb) p section.name $1 = 0x55555a1bbe60 "*COM*" (top-gdb) p section $2 = (bfd_section *) 0x55555bbe4ac0 <_bfd_std_section> I'm not too sure what this section is for, but this is one of four special BFD sections that GDB puts after the regular sections in the objfile::sections and objfile::section_offsets lists. You can check gdb_bfd_section_index to see how they are handled. gdb_bfd_count_sections returns "+ 4" to account for those sections. The problem is that macho_symfile_offsets uses bfd_count_sections instead of gdb_bfd_count_sections when allocating the objfile::section_offsets vector. The vector will therefore contain, say, 13 elements instead of 17. When trying to access the section offset of the *COM* section, the first after the regular sections, we access section_offsets[13], which is out of bounds. Fix that by using gdb_bfd_count_sections instead of bfd_count_sections. I'm fairly confident that this is correct, as this is what default_symfile_offsets does. With this patch, the command shown above terminates normally: $ ./gdb -nx --data-directory=data-directory -q repro/test -ex "b main" -batch Breakpoint 1 at 0x100003fad: file test.c, line 2. [1] https://sourceware.org/bugzilla/show_bug.cgi?id=28017 gdb/ChangeLog: PR gdb/28017 * machoread.c (macho_symfile_offsets): Use gdb_bfd_count_sections to allocate objfile::section_offsets. Change-Id: Ic3a56f46f7232e9f24581f8255fc1ab981935450
palves
added a commit
that referenced
this issue
Jul 2, 2021
Running the gdb.threads/interrupt-while-step-over.exp testcase added later in the series against gdbserver, after the TARGET_WAITKIND_NO_RESUMED fix from the following patch would run into an infinite loop in stop_all_threads. I added a hacky gdb_assert to catch the loop, and it looked like this: [infrun] stop_all_threads: Thread 3492141.3492141 not executing [infrun] stop_all_threads: Thread 3492141.3492716 not executing [infrun] stop_all_threads: Thread 3492141.3492717 not executing [infrun] stop_all_threads: Thread 3492141.3492718 not executing [infrun] stop_all_threads: Thread 3492141.3492719 not executing [infrun] stop_all_threads: Thread 3492141.3492720 executing, need stop [remote] stop: enter [remote] remote_stop_ns: Enqueueing phony stop reply for thread pending vCont-resume (3492141, 3492720, 0) [remote] stop: exit [infrun] stop_all_threads: Thread 3492141.3492721 not executing [infrun] stop_all_threads: Thread 3492141.3492722 not executing [infrun] stop_all_threads: Thread 3492141.3492723 not executing [infrun] stop_all_threads: Thread 3492141.3492724 not executing [infrun] stop_all_threads: Thread 3492141.3492725 not executing [infrun] stop_all_threads: Thread 3492141.3492726 not executing [infrun] stop_all_threads: Thread 3492141.3492727 not executing [infrun] stop_all_threads: Thread 3492141.3492728 not executing [infrun] stop_all_threads: Thread 3492141.3492729 not executing [infrun] stop_all_threads: Thread 3492141.3492730 not executing [infrun] stop_all_threads: Thread 3492141.3492731 not executing [infrun] stop_all_threads: Thread 3492141.3492732 not executing [infrun] stop_all_threads: Thread 3492141.3492733 not executing [infrun] stop_all_threads: Thread 3492141.3492734 not executing [infrun] stop_all_threads: Thread 3492141.3492735 not executing [remote] wait: enter [remote] wait: exit [infrun] print_target_wait_results: target_wait (-1.0.0 [process -1], status) = [infrun] print_target_wait_results: -1.0.0 [process -1], [infrun] print_target_wait_results: status->kind = no-resumed [infrun] infrun_async: enable=0 [infrun] handle_one: status->kind = no-resumed process -1 [remote] Sending packet: $qXfer:threads:read::0,1000#92 [remote] Packet received: l<threads>\n<thread id="p35492d.35492d" core="16" name="interrupt-while" handle="40d7d8f7ff7f0000"/>\n<thread id="p35492d.354b6c" core="12" name="interrupt-while" handle="00c7d8f7ff7f0000"/>\n<thread id="p35492d.354b6d" core="5" name="interrupt-while" handle="00b758f7ff7f0000"/>\n<thread id="p35492d.354b6e" core="19" name="interrupt-while" handle="00a7d8f6ff7f0000"/>\n<thread id="p35492d.354b6f" core="15" name="interrupt-while" handle="009758f6ff7f0000"/>\n<thread id="p35492d.354b70" core="6" name="interrupt-whil [1370 bytes omitted] [infrun] stop_all_threads: Thread 3492141.3492141 not executing [infrun] stop_all_threads: Thread 3492141.3492716 not executing [infrun] stop_all_threads: Thread 3492141.3492717 not executing [infrun] stop_all_threads: Thread 3492141.3492718 not executing [infrun] stop_all_threads: Thread 3492141.3492719 not executing [infrun] stop_all_threads: Thread 3492141.3492720 executing, already stopping [infrun] stop_all_threads: Thread 3492141.3492721 not executing [infrun] stop_all_threads: Thread 3492141.3492722 not executing [infrun] stop_all_threads: Thread 3492141.3492723 not executing [infrun] stop_all_threads: Thread 3492141.3492724 not executing [infrun] stop_all_threads: Thread 3492141.3492725 not executing [infrun] stop_all_threads: Thread 3492141.3492726 not executing [infrun] stop_all_threads: Thread 3492141.3492727 not executing [infrun] stop_all_threads: Thread 3492141.3492728 not executing [infrun] stop_all_threads: Thread 3492141.3492729 not executing [infrun] stop_all_threads: Thread 3492141.3492730 not executing [infrun] stop_all_threads: Thread 3492141.3492731 not executing [infrun] stop_all_threads: Thread 3492141.3492732 not executing [infrun] stop_all_threads: Thread 3492141.3492733 not executing [infrun] stop_all_threads: Thread 3492141.3492734 not executing [infrun] stop_all_threads: Thread 3492141.3492735 not executing ../../src/gdb/infrun.c:5066: internal-error: void stop_all_threads(): Assertion `0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) What happened above was that gdbserver had sent a TARGET_WAITKIND_NO_RESUMED stop reply (N) to GDB already, and that event was still in transit, held in remote.c's stop reply queue, not yet seen by infrun. In stop_all_threads, GDB told remote.c to stop thread 3492141.3492720. That thread had a pending vCont resume, so remote.c queued a phony stop. This event is queued _after_ the TARGET_WAITKIND_NO_RESUMED stop reply that was already there. stop_all_threads calls wait_one to collect one event and gets back that TARGET_WAITKIND_NO_RESUMED. Seeing TARGET_WAITKIND_NO_RESUMED, wait_one disables target_async for that target to stop listing to events from that target. No other unresumed target has async active, so wait_one returns TARGET_WAITKIND_NO_RESUMED. stop_all_threads still hasn't seen the stop for 3492141.3492720, so we go for another iteration. But since the target is not async, wait_one returns TARGET_WAITKIND_NO_RESUMED without calling target_wait. The queued event for 3492141.3492720 remains pending forever, and stop_all_threads keeps iterating forever. The comment in the patch describes a different scenario that does not involve the phony stop: /* wait_one waits for events until it sees a TARGET_WAITKIND_NO_RESUMED. When it sees one, it disables target_async for the target and no longer waits for events from that target. TARGET_WAITKIND_NO_RESUMED can be delayed though, consider: #1 - threads 2-5 are stopped, thread 1 is running #2 - target reports breakpoint hit for thread 1, event is queued. #3 - target reports no-resumed left, event is queued #4 - user resumes all threads #5 - gdb decides to stop all threads, stops threads 1-5 #6 - wait_one returns the queued breakpoint hit for thread 1 #7 - wait_one returns the queued no-resumed event, wait_one stops waiting for events from target. #8 - we still haven't seen the stops for threads 2-5, so we do another pass. #9 - if the target is not async wait_one doesn't wait on the target, so it won't see the stops. #a - we'd loop forever with WAITS_NEEDED > 0. Fix this by explicitly enabling target async on each iteration, before starting the wait_one loop. gdb/ChangeLog: yyyy-mm-dd Pedro Alves <[email protected]> PR gdb/27338 * infrun.c (reenable_target_async): New. (stop_all_threads): Enable/re-enable async on targets that can async before waiting for stops. Change-Id: Ie3ffb0df89635585a6631aa842689cecc989e33f
palves
pushed a commit
that referenced
this issue
Jul 18, 2021
When loading a file using the file command on macOS, we get: $ ./gdb -nx --data-directory=data-directory -q -ex "file ./test" Reading symbols from ./test... Reading symbols from /Users/smarchi/build/binutils-gdb/gdb/test.dSYM/Contents/Resources/DWARF/test... /Users/smarchi/src/binutils-gdb/gdb/thread.c:72: internal-error: struct thread_info *inferior_thread(): Assertion `current_thread_ != nullptr' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) The backtrace is: * frame #0: 0x0000000101fcb826 gdb`internal_error(file="/Users/smarchi/src/binutils-gdb/gdb/thread.c", line=72, fmt="%s: Assertion `%s' failed.") at errors.cc:52:3 frame #1: 0x00000001018a2584 gdb`inferior_thread() at thread.c:72:3 frame #2: 0x0000000101469c09 gdb`get_current_regcache() at regcache.c:421:31 frame #3: 0x00000001015f9812 gdb`darwin_solib_get_all_image_info_addr_at_init(info=0x0000603000006d00) at solib-darwin.c:464:34 frame #4: 0x00000001015f7a04 gdb`darwin_solib_create_inferior_hook(from_tty=1) at solib-darwin.c:515:5 frame #5: 0x000000010161205e gdb`solib_create_inferior_hook(from_tty=1) at solib.c:1200:3 frame #6: 0x00000001016d8f76 gdb`symbol_file_command(args="./test", from_tty=1) at symfile.c:1650:7 frame #7: 0x0000000100abab17 gdb`file_command(arg="./test", from_tty=1) at exec.c:555:3 frame #8: 0x00000001004dc799 gdb`do_const_cfunc(c=0x000061100000c340, args="./test", from_tty=1) at cli-decode.c:102:3 frame #9: 0x00000001004ea042 gdb`cmd_func(cmd=0x000061100000c340, args="./test", from_tty=1) at cli-decode.c:2160:7 frame #10: 0x00000001018d4f59 gdb`execute_command(p="t", from_tty=1) at top.c:674:2 frame #11: 0x0000000100eee430 gdb`catch_command_errors(command=(gdb`execute_command(char const*, int) at top.c:561), arg="file ./test", from_tty=1, do_bp_actions=true)(char const*, int), char const*, int, bool) at main.c:523:7 frame #12: 0x0000000100eee902 gdb`execute_cmdargs(cmdarg_vec=0x00007ffeefbfeba0 size=1, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x00007ffeefbfec20) at main.c:618:9 frame #13: 0x0000000100eed3a4 gdb`captured_main_1(context=0x00007ffeefbff780) at main.c:1322:3 frame #14: 0x0000000100ee810d gdb`captured_main(data=0x00007ffeefbff780) at main.c:1343:3 frame #15: 0x0000000100ee8025 gdb`gdb_main(args=0x00007ffeefbff780) at main.c:1368:7 frame #16: 0x00000001000044f1 gdb`main(argc=6, argv=0x00007ffeefbff8a0) at gdb.c:32:10 frame #17: 0x00007fff20558f5d libdyld.dylib`start + 1 The solib_create_inferior_hook call in symbol_file_command was added by commit ea142fb ("Fix breakpoints on file reloads for PIE binaries"). It causes solib_create_inferior_hook to be called while the inferior is not running, which darwin_solib_create_inferior_hook does not expect. darwin_solib_get_all_image_info_addr_at_init, in particular, assumes that there is a current thread, as it tries to get the current thread's regcache. Fix it by adding a target_has_execution check and returning early. Note that there is a similar check in svr4_solib_create_inferior_hook. gdb/ChangeLog: * solib-darwin.c (darwin_solib_create_inferior_hook): Return early if no execution. Change-Id: Ia11dd983a1e29786e5ce663d0fcaa6846dc611bb
palves
added a commit
that referenced
this issue
Jul 18, 2021
Commit 408f668 ("detach in all-stop with threads running") regressed "detach" with "target remote": (gdb) detach Detaching from program: target:/any/program, process 3671843 Detaching from process 3671843 Ending remote debugging. [Inferior 1 (process 3671843) detached] In main terminate called after throwing an instance of 'gdb_exception_error' Aborted (core dumped) Here's the exception above being thrown: (top-gdb) bt #0 throw_error (error=TARGET_CLOSE_ERROR, fmt=0x555556035588 "Remote connection closed") at src/gdbsupport/common-exceptions.cc:222 #1 0x0000555555bbaa46 in remote_target::readchar (this=0x555556a11040, timeout=10000) at src/gdb/remote.c:9440 #2 0x0000555555bbb9e5 in remote_target::getpkt_or_notif_sane_1 (this=0x555556a11040, buf=0x555556a11058, forever=0, expecting_notif=0, is_notif=0x0) at src/gdb/remote.c:9928 #3 0x0000555555bbbda9 in remote_target::getpkt_sane (this=0x555556a11040, buf=0x555556a11058, forever=0) at src/gdb/remote.c:10030 #4 0x0000555555bc0e75 in remote_target::remote_hostio_send_command (this=0x555556a11040, command_bytes=13, which_packet=14, remote_errno=0x7fffffffcfd0, attachment=0x0, attachment_len=0x0) at src/gdb/remote.c:12137 #5 0x0000555555bc1b6c in remote_target::remote_hostio_close (this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12455 #6 0x0000555555bc1bb4 in remote_target::fileio_close (During symbol reading: .debug_line address at offset 0x64f417 is 0 [in module build/gdb/gdb] this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12462 #7 0x0000555555c9274c in target_fileio_close (fd=3, target_errno=0x7fffffffcfd0) at src/gdb/target.c:3365 #8 0x000055555595a19d in gdb_bfd_iovec_fileio_close (abfd=0x555556b9f8a0, stream=0x555556b11530) at src/gdb/gdb_bfd.c:439 #9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556b9f8a0) at src/bfd/opncls.c:599 #10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556b9f8a0) at src/bfd/opncls.c:847 #11 0x0000555555e0a27a in bfd_close (abfd=0x555556b9f8a0) at src/bfd/opncls.c:814 #12 0x000055555595a9d3 in gdb_bfd_close_or_warn (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:626 #13 0x000055555595ad29 in gdb_bfd_unref (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:715 #14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 #15 0x0000555555ae955a in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x555556c20db0) at /usr/include/c++/9/bits/shared_ptr_base.h:377 #16 0x000055555572b7c8 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x555556c20db0) at /usr/include/c++/9/bits/shared_ptr_base.h:155 #17 0x00005555557263c3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x555556bf0588, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:730 #18 0x0000555555ae745e in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x555556bf0580, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:1169 #19 0x0000555555ae747e in std::shared_ptr<objfile>::~shared_ptr (this=0x555556bf0580, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr.h:103 #20 0x0000555555b1c1dc in __gnu_cxx::new_allocator<std::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> > (this=0x5555564cdd60, __p=0x555556bf0580) at /usr/include/c++/9/ext/new_allocator.h:153 #21 0x0000555555b1bb1d in std::allocator_traits<std::allocator<std::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> > (__a=..., __p=0x555556bf0580) at /usr/include/c++/9/bits/alloc_traits.h:497 #22 0x0000555555b1b73e in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase (this=0x5555564cdd60, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556515540}) at /usr/include/c++/9/bits/stl_list.h:1921 #23 0x0000555555b1afeb in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase (this=0x5555564cdd60, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556515540}) at /usr/include/c++/9/bits/list.tcc:158 #24 0x0000555555b19576 in program_space::remove_objfile (this=0x5555564cdd20, objfile=0x555556515540) at src/gdb/progspace.c:210 #25 0x0000555555ae4502 in objfile::unlink (this=0x555556515540) at src/gdb/objfiles.c:487 #26 0x0000555555ae5a12 in objfile_purge_solibs () at src/gdb/objfiles.c:875 #27 0x0000555555c09686 in no_shared_libraries (ignored=0x0, from_tty=1) at src/gdb/solib.c:1236 #28 0x00005555559e3f5f in detach_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:2769 So frame #28 already detached the remote process, and then we're purging the shared libraries. GDB had opened remote shared libraries via the target: sysroot, so it tries closing them. GDBserver is tearing down already, so remote communication breaks down and we close the remote target and throw TARGET_CLOSE_ERROR. Note frame #14: #14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 That's a dtor, thus noexcept. That's the reason for the std::terminate. Stepping back a bit, why do we still have open remote files if we've managed to detach already, and, we're debugging with "target remote"? The reason is that commit 408f668 makes detach_command hold a reference to the target, so the remote target won't be finally closed until frame #28 returns. It's closing the target that invalidates target file I/O handles. This commit fixes the issue by not relying on target_close to invalidate the target file I/O handles, instead invalidate them immediately in remote_unpush_target. So when GDB purges the solibs, and we end up in target_fileio_close (frame #7 above), there's nothing to do, and we don't try to talk with the remote target anymore. The regression isn't seen when testing with --target_board=native-gdbserver, because that does "set sysroot" to disable the "target:" sysroot, for test run speed reasons. So this commit adds a testcase that explicitly tests detach with "set sysroot target:". gdb/ChangeLog: yyyy-mm-dd Pedro Alves <[email protected]> PR gdb/28080 * remote.c (remote_unpush_target): Invalidate file I/O target handles. * target.c (fileio_handles_invalidate_target): Make extern. * target.h (fileio_handles_invalidate_target): Declare. gdb/testsuite/ChangeLog: yyyy-mm-dd Pedro Alves <[email protected]> PR gdb/28080 * gdb.base/detach-sysroot-target.exp: New. * gdb.base/detach-sysroot-target.c: New. Reported-By: Jonah Graham <[email protected]> Change-Id: I851234910172f42a1b30e731161376c344d2727d
palves
added a commit
that referenced
this issue
Jul 18, 2021
…080) Before PR gdb/28080 was fixed by the previous patch, GDB was crashing like this: (gdb) detach Detaching from program: target:/any/program, process 3671843 Detaching from process 3671843 Ending remote debugging. [Inferior 1 (process 3671843) detached] In main terminate called after throwing an instance of 'gdb_exception_error' Aborted (core dumped) Here's the exception above being thrown: (top-gdb) bt #0 throw_error (error=TARGET_CLOSE_ERROR, fmt=0x555556035588 "Remote connection closed") at src/gdbsupport/common-exceptions.cc:222 #1 0x0000555555bbaa46 in remote_target::readchar (this=0x555556a11040, timeout=10000) at src/gdb/remote.c:9440 #2 0x0000555555bbb9e5 in remote_target::getpkt_or_notif_sane_1 (this=0x555556a11040, buf=0x555556a11058, forever=0, expecting_notif=0, is_notif=0x0) at src/gdb/remote.c:9928 #3 0x0000555555bbbda9 in remote_target::getpkt_sane (this=0x555556a11040, buf=0x555556a11058, forever=0) at src/gdb/remote.c:10030 #4 0x0000555555bc0e75 in remote_target::remote_hostio_send_command (this=0x555556a11040, command_bytes=13, which_packet=14, remote_errno=0x7fffffffcfd0, attachment=0x0, attachment_len=0x0) at src/gdb/remote.c:12137 #5 0x0000555555bc1b6c in remote_target::remote_hostio_close (this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12455 #6 0x0000555555bc1bb4 in remote_target::fileio_close (During symbol reading: .debug_line address at offset 0x64f417 is 0 [in module build/gdb/gdb] this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12462 #7 0x0000555555c9274c in target_fileio_close (fd=3, target_errno=0x7fffffffcfd0) at src/gdb/target.c:3365 #8 0x000055555595a19d in gdb_bfd_iovec_fileio_close (abfd=0x555556b9f8a0, stream=0x555556b11530) at src/gdb/gdb_bfd.c:439 #9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556b9f8a0) at src/bfd/opncls.c:599 #10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556b9f8a0) at src/bfd/opncls.c:847 #11 0x0000555555e0a27a in bfd_close (abfd=0x555556b9f8a0) at src/bfd/opncls.c:814 #12 0x000055555595a9d3 in gdb_bfd_close_or_warn (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:626 #13 0x000055555595ad29 in gdb_bfd_unref (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:715 #14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 #15 0x0000555555ae955a in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x555556c20db0) at /usr/include/c++/9/bits/shared_ptr_base.h:377 #16 0x000055555572b7c8 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x555556c20db0) at /usr/include/c++/9/bits/shared_ptr_base.h:155 #17 0x00005555557263c3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x555556bf0588, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:730 #18 0x0000555555ae745e in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x555556bf0580, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:1169 #19 0x0000555555ae747e in std::shared_ptr<objfile>::~shared_ptr (this=0x555556bf0580, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr.h:103 #20 0x0000555555b1c1dc in __gnu_cxx::new_allocator<std::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> > (this=0x5555564cdd60, __p=0x555556bf0580) at /usr/include/c++/9/ext/new_allocator.h:153 #21 0x0000555555b1bb1d in std::allocator_traits<std::allocator<std::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> > (__a=..., __p=0x555556bf0580) at /usr/include/c++/9/bits/alloc_traits.h:497 #22 0x0000555555b1b73e in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase (this=0x5555564cdd60, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556515540}) at /usr/include/c++/9/bits/stl_list.h:1921 #23 0x0000555555b1afeb in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase (this=0x5555564cdd60, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556515540}) at /usr/include/c++/9/bits/list.tcc:158 #24 0x0000555555b19576 in program_space::remove_objfile (this=0x5555564cdd20, objfile=0x555556515540) at src/gdb/progspace.c:210 #25 0x0000555555ae4502 in objfile::unlink (this=0x555556515540) at src/gdb/objfiles.c:487 #26 0x0000555555ae5a12 in objfile_purge_solibs () at src/gdb/objfiles.c:875 #27 0x0000555555c09686 in no_shared_libraries (ignored=0x0, from_tty=1) at src/gdb/solib.c:1236 #28 0x00005555559e3f5f in detach_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:2769 Note frame #14: #14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 That's a dtor, thus noexcept. That's the reason for the std::terminate. The previous patch fixed things such that the exception above isn't thrown anymore. However, it's possible that e.g., the remote connection drops just while a user types "nosharedlibrary", or some other reason that leads to objfile::~objfile, and then we end up the same std::terminate problem. Also notice that frames #9-#11 are BFD frames: #9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556bc27e0) at src/bfd/opncls.c:599 #10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556bc27e0) at src/bfd/opncls.c:847 #11 0x0000555555e0a27a in bfd_close (abfd=0x555556bc27e0) at src/bfd/opncls.c:814 BFD is written in C and thus throwing exceptions over such frames may either not clean up properly, or, may abort if bfd is not compiled with -fasynchronous-unwind-tables (x86-64 defaults that on, but not all GCC ports do). Thus frame #8 seems like a good place to swallow exceptions. More so since in this spot we already ignore target_fileio_close return errors. That's what this commit does. Without the previous fix, we'd see: (gdb) detach Detaching from program: target:/any/program, process 2197701 Ending remote debugging. [Inferior 1 (process 2197701) detached] warning: cannot close "target:/lib64/ld-linux-x86-64.so.2": Remote connection closed Note it prints a warning, which would still be a regression compared to GDB 10, if it weren't for the previous fix. gdb/ChangeLog: yyyy-mm-dd Pedro Alves <[email protected]> PR gdb/28080 * gdb_bfd.c (gdb_bfd_close_warning): New. (gdb_bfd_iovec_fileio_close): Wrap target_fileio_close in try/catch and print warning on exception. (gdb_bfd_close_or_warn): Use gdb_bfd_close_warning. Change-Id: Ic7a26ddba0a4444e3377b0e7c1c89934a84545d7
palves
added a commit
that referenced
this issue
Jun 7, 2023
After running a number of programs under gdb and detaching them, I typed run in gdb, and got a hang, here: (top-gdb) bt #0 sharing_input_terminal (pid=4672) at /home/pedro/rocm/gdb/src/gdb/mingw-hdep.c:388 #1 0x00007ff71a2d8678 in sharing_input_terminal (inf=0x23bf23dafb0) at /home/pedro/rocm/gdb/src/gdb/inflow.c:269 #2 0x00007ff71a2d887b in child_terminal_save_inferior (self=0x23bf23de060) at /home/pedro/rocm/gdb/src/gdb/inflow.c:423 #3 0x00007ff71a2c80c0 in inf_child_target::terminal_save_inferior (this=0x23bf23de060) at /home/pedro/rocm/gdb/src/gdb/inf-child.c:111 #4 0x00007ff71a429c0f in target_terminal_is_ours_kind (desired_state=target_terminal_state::is_ours_for_output) at /home/pedro/rocm/gdb/src/gdb/target.c:1037 #5 0x00007ff71a429e02 in target_terminal::ours_for_output () at /home/pedro/rocm/gdb/src/gdb/target.c:1094 #6 0x00007ff71a2ccc8e in post_create_inferior (from_tty=0) at /home/pedro/rocm/gdb/src/gdb/infcmd.c:245 #7 0x00007ff71a2cd431 in run_command_1 (args=0x0, from_tty=0, run_how=RUN_NORMAL) at /home/pedro/rocm/gdb/src/gdb/infcmd.c:502 #8 0x00007ff71a2cd58b in run_command (args=0x0, from_tty=0) at /home/pedro/rocm/gdb/src/gdb/infcmd.c:527 The problem is that the loop around GetConsoleProcessList looped forever, because there were exactly 10 processes to return. GetConsoleProcessList's documentation says: If the buffer is too small to hold all the valid process identifiers, the return value is the required number of array elements. The function will have stored no identifiers in the buffer. In this situation, use the return value to allocate a buffer that is large enough to store the entire list and call the function again. In this case, the buffer wasn't too small, it was exactly the right size, so we should have broken out of the loop. We didn't due to a "<" check that should have been "<=". That is fixed by this patch. Change-Id: I14e4909f2ac2fa83d0d9b6e64418b5831ac4e4e3
palves
pushed a commit
that referenced
this issue
Jun 7, 2023
In some cases GDB will fail when attempting to complete a command that involves a rust symbol, the failure can manifest as a crash. The problem is caused by the completion_match_for_lcd object being left containing invalid data during calls to cp_symbol_name_matches_1. The first question to address is why we are calling a C++ support function when handling a rust symbol. That's due to GDB's auto language detection for msymbols, in some cases GDB can't tell if a symbol is a rust symbol, or a C++ symbol. The test application contains symbols for functions which are statically linked in from various rust support libraries. There's no DWARF for these symbols, so all GDB has is the msymbols built from the ELF symbol table. Here's the problematic symbol that leads to our crash: mangled: _ZN4core3str21_$LT$impl$u20$str$GT$5parse17h5111d2d6a50d22bdE demangled: core::str::<impl str>::parse As an msymbol this is initially created with language auto, then GDB eventually calls symbol_find_demangled_name, which loops over all languages calling language_defn::sniff_from_mangled_name, the first language that can demangle the symbol gets assigned as the language for that symbol. Unfortunately, there's overlap in the mangled symbol names, some (legacy) rust symbols can be demangled as both rust and C++, see cplus_demangle in libiberty/cplus-dem.c where this is mentioned. And so, because we check the C++ language before we check for rust, then the msymbol is (incorrectly) given the C++ language. Now it's true that is some cases we might be able to figure out that a demangled symbol is not actually a valid C++ symbol, for example, in our case, the construct '::<impl str>::' is not, I believe, valid in a C++ symbol, we could look for ':<' and '>:' and refuse to accept this as a C++ symbol. However, I'm not sure it is always possible to tell that a demangled symbol is rust or C++, so, I think, we have to accept that some times we will get this language detection wrong. If we accept that we can't fix the symbol language detection 100% of the time, then we should make sure that GDB doesn't crash when it gets the language wrong, that is what this commit addresses. In our test case the user tries to complete a symbol name like this: (gdb) complete break pars This results in GDB trying to find all symbols that match 'pars', eventually we consider our problematic symbol, and we end up with a call stack that looks like this: #0 0x0000000000f3c6bd in strncmp_iw_with_mode #1 0x0000000000706d8d in cp_symbol_name_matches_1 #2 0x0000000000706fa4 in cp_symbol_name_matches #3 0x0000000000df3c45 in compare_symbol_name #4 0x0000000000df3c91 in completion_list_add_name #5 0x0000000000df3f1d in completion_list_add_msymbol #6 0x0000000000df4c94 in default_collect_symbol_completion_matches_break_on #7 0x0000000000658c08 in language_defn::collect_symbol_completion_matches #8 0x0000000000df54c9 in collect_symbol_completion_matches #9 0x00000000009d98fb in linespec_complete_function #10 0x00000000009d99f0 in complete_linespec_component #11 0x00000000009da200 in linespec_complete #12 0x00000000006e4132 in complete_address_and_linespec_locations #13 0x00000000006e4ac3 in location_completer In cp_symbol_name_matches_1 we enter a loop, this loop repeatedly tries to match the demangled problematic symbol name against the user supplied text ('pars'). Each time around the loop another component of the symbol name is stripped off, thus, we check 'pars' against these options: core::str::<impl str>::parse str::<impl str>::parse <impl str>::parse parse As soon as we get a match the cp_symbol_name_matches_1 exits its loop and returns. In our case, when we're looking for 'pars', the match occurs on the last iteration of the loop, when we are comparing to 'parse'. Now the problem here is that cp_symbol_name_matches_1 uses the strncmp_iw_with_mode, and inside strncmp_iw_with_mode we allow for skipping over template parameters. This allows GDB to match the symbol name 'foo<int>(int,int)' if the user supplies 'foo(int,'. Inside strncmp_iw_with_mode GDB will record any template arguments that it has skipped over inside the completion_match_for_lcd object that is passed in as an argument. And so, when GDB tries to match against '<impl str>::parse', the first thing it sees is '<impl str>', GDB assumes this is a template argument and records this as a skipped region within the completion_match_for_lcd object. After '<impl str>' GDB sees a ':' character, which doesn't match with the 'pars' the user supplied, so strncmp_iw_with_mode returns a value indicating a non-match. GDB then removes the '<impl str>' component from the symbol name and tries again, this time comparing to 'parse', which does match. Having found a match, then in cp_symbol_name_matches_1 we record the match string, and the full symbol name within the completion_match_result object, and return. The problem here is that the skipped region, the '<impl str>' that we recorded in the penultimate loop iteration was never discarded, its still there in our returned result. If we look at what the pointers held in the completion_match_result that cp_symbol_name_matches_1 returns, this is what we see: core::str::<impl str>::parse | \________/ | | | '--- completion match string | '---skip range '--- full symbol name When GDB calls completion_match_for_lcd::finish, GDB tries to create a string using the completion match string (parse), but excluding the skip range, as the stored skip range is before the start of the completion match string, then GDB tries to do some weird string creation, which will cause GDB to crash. The reason we don't often see this problem in C++ is that for C++ symbols there is always some non-template text before the template argument. This non-template text means GDB is likely to either match the symbol, or reject the symbol without storing a skip range. However, notice, I did say, we don't often see this problem. Once I understood the issue, I was able to reproduce the crash using a pure C++ example: template<typename S> struct foo { template<typename T> foo (int p1, T a) { s = 0; } S s; }; int main () { foo<int> obj (2.3, 0); return 0; } Then in GDB: (gdb) complete break foo(int The problem here is that the C++ symbol for the constructor looks like this: foo<int>::foo<double>(int, double) When GDB enters cp_symbol_name_matches_1 the symbols it examines are: foo<int>::foo<double>(int, double) foo<double>(int, double) The first iteration of the loop will match the 'foo', then add the '<int>' template argument will be added as a skip range. When GDB find the ':' after the '<int>' the first iteration of the loop fails to match, GDB removes the 'foo<int>::' component, and starts the second iteration of the loop. Again, GDB matches the 'foo', and now adds '<double>' as a skip region. After that the '(int' successfully matches, and so the second iteration of the loop succeeds, but, once again we left the '<int>' in place as a skip region, even though this occurs before the start of our match string, and this will cause GDB to crash. This problem was reported to the mailing list, and a solution discussed in this thread: https://sourceware.org/pipermail/gdb-patches/2023-January/195166.html The solution proposed here is similar to one proposed by the original bug reported, but implemented in a different location within GDB. Instead of placing the fix in strncmp_iw_with_mode, I place the fix in cp_symbol_name_matches_1. I believe this is a better location as it is this function that implements the loop, and it is this loop, which repeatedly calls strncmp_iw_with_mode, that should be resetting the result object state (I believe). What I have done is add an assert to strncmp_iw_with_mode that the incoming result object is empty. I've also added some other asserts in related code, in completion_match_for_lcd::mark_ignored_range, I make some basic assertions about the incoming range pointers, and in completion_match_for_lcd::finish I also make some assertions about how the skip ranges relate to the match pointer. There's two new tests. The original rust example that was used in the initial bug report, and a C++ test. The rust example depends on which symbols are pulled in from the rust libraries, so it is possible that, at some future date, the problematic symbol will disappear from this test program. The C++ test should be more reliable, as this only depends on symbols from within the C++ source code. Since I originally posted this patch to the mailing list, the following patch has been merged: commit 6e7eef7 Date: Sun Mar 19 09:13:10 2023 -0600 Use rust_demangle to fix a crash This solves the problem of a rust symbol ending up in the C++ specific code by changing the order languages are sorted. However, this new commit doesn't address the issue in the C++ code which was fixed with this commit. Given that the C++ issue is real, and has a reproducer, I'm still going to merge this fix. I've left the discussion of rust in this commit message as I originally wrote it, but it should be read within the context of GDB prior to commit 6e7eef7. Co-Authored-By: Zheng Zhan <[email protected]>
palves
pushed a commit
that referenced
this issue
Jun 7, 2023
Commit 7a8de0c ("Remove ALL_BREAKPOINTS_SAFE") introduced a use-after-free in the breakpoints iterations (see below for full ASan report). This makes gdb.base/stale-infcall.exp fail when GDB is build with ASan. check_longjmp_breakpoint_for_call_dummy iterates on all breakpoints, possibly deleting the current breakpoint as well as related breakpoints. The problem arises when a breakpoint in the B->related_breakpoint chain is also B->next. In that case, deleting that related breakpoint frees the breakpoint that all_breakpoints_safe has saved. The old code worked around that by manually changing B_TMP, which was the next breakpoint saved by the "safe iterator": while (b->related_breakpoint != b) { if (b_tmp == b->related_breakpoint) b_tmp = b->related_breakpoint->next; delete_breakpoint (b->related_breakpoint); } (Note that this seemed to assume that b->related_breakpoint->next was the same as b->next->next, not sure this is guaranteed.) The new code kept the B_TMP variable, but it's not useful in that context. We can't go change the next breakpoint as saved by the safe iterator, like we did before. I suggest fixing that by saving the breakpoints to delete in a map and deleting them all at the end. Here's the full ASan report: (gdb) PASS: gdb.base/stale-infcall.exp: continue to breakpoint: break-run1 print infcall () ================================================================= ==47472==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000034980 at pc 0x563f7012c7bc bp 0x7ffdf3804d70 sp 0x7ffdf3804d60 READ of size 8 at 0x611000034980 thread T0 #0 0x563f7012c7bb in next_iterator<breakpoint>::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/next-iterator.h:66 #1 0x563f702ce8c0 in basic_safe_iterator<next_iterator<breakpoint> >::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/safe-iterator.h:84 #2 0x563f7021522a in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7611 #3 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881 #4 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769 #5 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023 #6 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387 #7 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42 #8 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219 #9 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 #10 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 #11 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217 #12 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426 #13 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650 #14 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332 #15 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 #16 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 #17 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 #18 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 #19 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 #20 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 #21 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 #22 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 #23 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 #24 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 #25 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 #26 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 #27 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 #28 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 #29 0x563f7101014b in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779 #30 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104 #31 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250 #32 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) #33 0x563f7100ca06 in gdb_rl_callback_read_char_wrapper_noexcept /home/smarchi/src/binutils-gdb/gdb/event-top.c:192 #34 0x563f7100cc5e in gdb_rl_callback_read_char_wrapper /home/smarchi/src/binutils-gdb/gdb/event-top.c:225 #35 0x563f728c70db in stdin_event_handler /home/smarchi/src/binutils-gdb/gdb/ui.c:155 #36 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 #37 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 #38 0x563f72fcb15c in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:264 #39 0x563f7177ec1c in start_event_loop /home/smarchi/src/binutils-gdb/gdb/main.c:412 #40 0x563f7177f12e in captured_command_loop /home/smarchi/src/binutils-gdb/gdb/main.c:476 #41 0x563f717846e4 in captured_main /home/smarchi/src/binutils-gdb/gdb/main.c:1320 #42 0x563f71784821 in gdb_main(captured_main_args*) /home/smarchi/src/binutils-gdb/gdb/main.c:1339 #43 0x563f6fcedfbd in main /home/smarchi/src/binutils-gdb/gdb/gdb.c:32 #44 0x7f5a7e43984f (/usr/lib/libc.so.6+0x2384f) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) #45 0x7f5a7e439909 in __libc_start_main (/usr/lib/libc.so.6+0x23909) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) #46 0x563f6fcedd84 in _start (/home/smarchi/build/binutils-gdb/gdb/gdb+0xafb0d84) (BuildId: 50bd32e6e9d5e84543e9897b8faca34858ca3995) 0x611000034980 is located 0 bytes inside of 208-byte region [0x611000034980,0x611000034a50) freed by thread T0 here: #0 0x7f5a7fce312a in operator delete(void*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:164 #1 0x563f702bd1fa in momentary_breakpoint::~momentary_breakpoint() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:304 #2 0x563f702771c5 in delete_breakpoint(breakpoint*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:12404 #3 0x563f702150a7 in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7673 #4 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881 #5 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769 #6 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023 #7 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387 #8 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42 #9 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219 #10 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 #11 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 #12 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217 #13 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426 #14 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650 #15 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332 #16 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 #17 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 #18 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 #19 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 #20 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 #21 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 #22 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 #23 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 #24 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 #25 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 #26 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 #27 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 #28 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 #29 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 previously allocated by thread T0 here: #0 0x7f5a7fce2012 in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:95 #1 0x563f7029a9a3 in new_momentary_breakpoint<program_space*&, frame_id&, int&> /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8129 #2 0x563f702212f6 in momentary_breakpoint_from_master /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8169 #3 0x563f70212db1 in set_longjmp_breakpoint_for_call_dummy() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7582 #4 0x563f713804db in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1260 #5 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 #6 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 #7 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 #8 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 #9 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 #10 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 #11 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 #12 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 #13 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 #14 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 #15 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 #16 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 #17 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 #18 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 #19 0x563f7101014b in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779 #20 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104 #21 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250 #22 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) Change-Id: Id00c17ab677f847fbf4efdf0f4038373668d3d88 Approved-By: Tom Tromey <[email protected]>
palves
pushed a commit
that referenced
this issue
Jun 7, 2023
Commit b5661ff ("gdb: fix possible use-after-free when executing commands") attempted to fix possible use-after-free in case command redefines itself. Commit 37e5833 ("gdb: fix command lookup in execute_command ()") updated the previous fix to handle subcommands as well by using the original command string to lookup the command again after its execution. This fixed the test in gdb.base/define.exp but it turned out that it does not work (at least) for "target remote" and "target extended-remote". The problem is that the command buffer P passed to execute_command () gets overwritten in dont_repeat () while executing "target remote" command itself: #0 dont_repeat () at top.c:822 #1 0x000055555730982a in target_preopen (from_tty=1) at target.c:2483 #2 0x000055555711e911 in remote_target::open_1 (name=0x55555881c7fe ":1234", from_tty=1, extended_p=0) at remote.c:5946 #3 0x000055555711d577 in remote_target::open (name=0x55555881c7fe ":1234", from_tty=1) at remote.c:5272 #4 0x00005555573062f2 in open_target (args=0x55555881c7fe ":1234", from_tty=1, command=0x5555589d0490) at target.c:853 #5 0x0000555556ad22fa in cmd_func (cmd=0x5555589d0490, args=0x55555881c7fe ":1234", from_tty=1) at cli/cli-decode.c:2737 #6 0x00005555573487fd in execute_command (p=0x55555881c802 "4", from_tty=1) at top.c:688 Therefore the second call to lookup_cmd () at line 697 fails to find command because the original command string is gone. This commit addresses this particular problem by creating a *copy* of original command string for the sole purpose of using it after command execution to lookup the command again. It may not be the most efficient way but it's safer given that command buffer is shared and overwritten in hard-to-foresee situations. Tested on x86_64-linux. PR 30249 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30249 Approved-By: Tom Tromey <[email protected]>
palves
pushed a commit
that referenced
this issue
Jul 19, 2023
After this commit: commit baab375 Date: Tue Jul 13 14:44:27 2021 -0400 gdb: building inferior strings from within GDB It was pointed out that a new ASan failure had been introduced which was triggered by gdb.base/internal-string-values.exp: (gdb) PASS: gdb.base/internal-string-values.exp: test_setting: all langs: lang=ada: ptype "foo" print $_gdb_maint_setting("test-settings string") ================================================================= ==80377==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000068034 at pc 0x564785cba682 bp 0x7ffd20644620 sp 0x7ffd20644610 READ of size 1 at 0x603000068034 thread T0 #0 0x564785cba681 in find_command_name_length(char const*) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2129 #1 0x564785cbacb2 in lookup_cmd_1(char const**, cmd_list_element*, cmd_list_element**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, int, bool) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2186 #2 0x564785cbb539 in lookup_cmd_1(char const**, cmd_list_element*, cmd_list_element**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, int, bool) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2248 #3 0x564785cbbcf3 in lookup_cmd(char const**, cmd_list_element*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, int, int) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2339 #4 0x564785c82df2 in setting_cmd /tmp/src/binutils-gdb/gdb/cli/cli-cmds.c:2219 #5 0x564785c84274 in gdb_maint_setting_internal_fn /tmp/src/binutils-gdb/gdb/cli/cli-cmds.c:2348 #6 0x564788167b3b in call_internal_function(gdbarch*, language_defn const*, value*, int, value**) /tmp/src/binutils-gdb/gdb/value.c:2321 #7 0x5647854b6ebd in expr::ada_funcall_operation::evaluate(type*, expression*, noside) /tmp/src/binutils-gdb/gdb/ada-lang.c:11254 #8 0x564786658266 in expression::evaluate(type*, noside) /tmp/src/binutils-gdb/gdb/eval.c:111 #9 0x5647871242d6 in process_print_command_args /tmp/src/binutils-gdb/gdb/printcmd.c:1322 #10 0x5647871244b3 in print_command_1 /tmp/src/binutils-gdb/gdb/printcmd.c:1335 #11 0x564787125384 in print_command /tmp/src/binutils-gdb/gdb/printcmd.c:1468 #12 0x564785caac44 in do_simple_func /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:95 #13 0x564785cc18f0 in cmd_func(cmd_list_element*, char const*, int) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2735 #14 0x564787c70c68 in execute_command(char const*, int) /tmp/src/binutils-gdb/gdb/top.c:574 #15 0x564786686180 in command_handler(char const*) /tmp/src/binutils-gdb/gdb/event-top.c:543 #16 0x56478668752f in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /tmp/src/binutils-gdb/gdb/event-top.c:779 #17 0x564787dcb29a in tui_command_line_handler /tmp/src/binutils-gdb/gdb/tui/tui-interp.c:104 #18 0x56478668443d in gdb_rl_callback_handler /tmp/src/binutils-gdb/gdb/event-top.c:250 #19 0x7f4efd506246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) #20 0x564786683dea in gdb_rl_callback_read_char_wrapper_noexcept /tmp/src/binutils-gdb/gdb/event-top.c:192 #21 0x564786684042 in gdb_rl_callback_read_char_wrapper /tmp/src/binutils-gdb/gdb/event-top.c:225 #22 0x564787f1b119 in stdin_event_handler /tmp/src/binutils-gdb/gdb/ui.c:155 #23 0x56478862438d in handle_file_event /tmp/src/binutils-gdb/gdbsupport/event-loop.cc:573 #24 0x564788624d23 in gdb_wait_for_event /tmp/src/binutils-gdb/gdbsupport/event-loop.cc:694 #25 0x56478862297c in gdb_do_one_event(int) /tmp/src/binutils-gdb/gdbsupport/event-loop.cc:264 #26 0x564786df99f0 in start_event_loop /tmp/src/binutils-gdb/gdb/main.c:412 #27 0x564786dfa069 in captured_command_loop /tmp/src/binutils-gdb/gdb/main.c:476 #28 0x564786dff61f in captured_main /tmp/src/binutils-gdb/gdb/main.c:1320 #29 0x564786dff75c in gdb_main(captured_main_args*) /tmp/src/binutils-gdb/gdb/main.c:1339 #30 0x564785381b6d in main /tmp/src/binutils-gdb/gdb/gdb.c:32 #31 0x7f4efbc3984f (/usr/lib/libc.so.6+0x2384f) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) #32 0x7f4efbc39909 in __libc_start_main (/usr/lib/libc.so.6+0x23909) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) #33 0x564785381934 in _start (/tmp/build/binutils-gdb/gdb/gdb+0xabc5934) (BuildId: 90de353ac158646e7dab501b76a18a76628fca33) 0x603000068034 is located 0 bytes after 20-byte region [0x603000068020,0x603000068034) allocated by thread T0 here: #0 0x7f4efcee0cd1 in __interceptor_calloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:77 #1 0x5647856265d8 in xcalloc /tmp/src/binutils-gdb/gdb/alloc.c:97 #2 0x564788610c6b in xzalloc(unsigned long) /tmp/src/binutils-gdb/gdbsupport/common-utils.cc:29 #3 0x56478815721a in value::allocate_contents(bool) /tmp/src/binutils-gdb/gdb/value.c:929 #4 0x564788157285 in value::allocate(type*, bool) /tmp/src/binutils-gdb/gdb/value.c:941 #5 0x56478815733a in value::allocate(type*) /tmp/src/binutils-gdb/gdb/value.c:951 #6 0x5647854ae81c in expr::ada_string_operation::evaluate(type*, expression*, noside) /tmp/src/binutils-gdb/gdb/ada-lang.c:10675 #7 0x5647854b63b8 in expr::ada_funcall_operation::evaluate(type*, expression*, noside) /tmp/src/binutils-gdb/gdb/ada-lang.c:11184 #8 0x564786658266 in expression::evaluate(type*, noside) /tmp/src/binutils-gdb/gdb/eval.c:111 #9 0x5647871242d6 in process_print_command_args /tmp/src/binutils-gdb/gdb/printcmd.c:1322 #10 0x5647871244b3 in print_command_1 /tmp/src/binutils-gdb/gdb/printcmd.c:1335 #11 0x564787125384 in print_command /tmp/src/binutils-gdb/gdb/printcmd.c:1468 #12 0x564785caac44 in do_simple_func /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:95 #13 0x564785cc18f0 in cmd_func(cmd_list_element*, char const*, int) /tmp/src/binutils-gdb/gdb/cli/cli-decode.c:2735 #14 0x564787c70c68 in execute_command(char const*, int) /tmp/src/binutils-gdb/gdb/top.c:574 #15 0x564786686180 in command_handler(char const*) /tmp/src/binutils-gdb/gdb/event-top.c:543 #16 0x56478668752f in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /tmp/src/binutils-gdb/gdb/event-top.c:779 #17 0x564787dcb29a in tui_command_line_handler /tmp/src/binutils-gdb/gdb/tui/tui-interp.c:104 #18 0x56478668443d in gdb_rl_callback_handler /tmp/src/binutils-gdb/gdb/event-top.c:250 #19 0x7f4efd506246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) The problem is in cli/cli-cmds.c, in the function setting_cmd, where we do this: const char *a0 = (const char *) argv[0]->contents ().data (); Here argv[0] is a value* which we know is either a TYPE_CODE_ARRAY or a TYPE_CODE_STRING. The problem is that the above line is casting the value contents directly to a C-string, i.e. one that is assumed to have a null-terminator at the end. After the above commit this can no longer be assumed to be true. A string value will be represented just as it would be in the current language, so for Ada and Fortran the string will be an array of characters with no null-terminator at the end. My proposed solution is to copy the string contents into a std::string object, and then use the std::string::c_str() value, this will ensure that a null-terminator has been added. I had a check through GDB at places TYPE_CODE_STRING was used and couldn't see any other obvious places where this type of assumption was being made, so hopefully this is the only offender. Running the above test with ASan compiled in no longer gives an error. Reviewed-By: Tom Tromey <[email protected]>
palves
pushed a commit
that referenced
this issue
Jul 19, 2023
While working on a later patch, which changes gdb.base/foll-vfork.exp, I noticed that sometimes I would hit this assert: x86_linux_update_debug_registers: Assertion `lwp_is_stopped (lwp)' failed. I eventually tracked it down to a combination of schedule-multiple mode being on, target-non-stop being off, follow-fork-mode being set to child, and some bad timing. The failing case is pretty simple, a single threaded application performs a vfork, the child process then execs some other application while the parent process (once the vfork child has completed its exec) just exits. As best I understand things, here's what happens when things go wrong: 1. The parent process performs a vfork, GDB sees the VFORKED event and creates an inferior and thread for the vfork child, 2. GDB resumes the vfork child process. As schedule-multiple is on and target-non-stop is off, this is translated into a request to start all processes (see user_visible_resume_ptid), 3. In the linux-nat layer we spot that one of the threads we are about to start is a vfork parent, and so don't start that thread (see resume_lwp), the vfork child thread is resumed, 4. GDB waits for the next event, eventually entering linux_nat_target::wait, which in turn calls linux_nat_wait_1, 5. In linux_nat_wait_1 we eventually call resume_stopped_resumed_lwps, this should restart threads that have stopped but don't actually have anything interesting to report. 6. Unfortunately, resume_stopped_resumed_lwps doesn't check for vfork parents like resume_lwp does, so at this point the vfork parent is resumed. This feels like the start of the bug, and this is where I'm proposing to fix things, but, resuming the vfork parent isn't the worst thing in the world because.... 7. As the vfork child is still alive the kernel holds the vfork parent stopped, 8. Eventually the child performs its exec and GDB is sent and EXECD event. However, because the parent is resumed, as soon as the child performs its exec the vfork parent also sends a VFORK_DONE event to GDB, 9. Depending on timing both of these events might seem to arrive in GDB at the same time. Normally GDB expects to see the EXECD or EXITED/SIGNALED event from the vfork child before getting the VFORK_DONE in the parent. We know this because it is as a result of the EXECD/EXITED/SIGNALED that GDB detaches from the parent (see handle_vfork_child_exec_or_exit for details). Further the comment in target/waitstatus.h on TARGET_WAITKIND_VFORK_DONE indicates that when we remain attached to the child (not the parent) we should not expect to see a VFORK_DONE, 10. If both events arrive at the same time then GDB will randomly choose one event to handle first, in some cases this will be the VFORK_DONE. As described above, upon seeing a VFORK_DONE GDB expects that (a) the vfork child has finished, however, in this case this is not completely true, the child has finished, but GDB has not processed the event associated with the completion yet, and (b) upon seeing a VFORK_DONE GDB assumes we are remaining attached to the parent, and so resumes the parent process, 11. GDB now handles the EXECD event. In our case we are detaching from the parent, so GDB calls target_detach (see handle_vfork_child_exec_or_exit), 12. While this has been going on the vfork parent is executing, and might even exit, 13. In linux_nat_target::detach the first thing we do is stop all threads in the process we're detaching from, the result of the stop request will be cached on the lwp_info object, 14. In our case the vfork parent has exited though, so when GDB waits for the thread, instead of a stop due to signal, we instead get a thread exited status, 15. Later in the detach process we try to resume the threads just prior to making the ptrace call to actually detach (see detach_one_lwp), as part of the process to resume a thread we try to touch some registers within the thread, and before doing this GDB asserts that the thread is stopped, 16. An exited thread is not classified as stopped, and so the assert triggers! So there's two bugs I see here. The first, and most critical one here is in step #6. I think that resume_stopped_resumed_lwps should not resume a vfork parent, just like resume_lwp doesn't resume a vfork parent. With this change in place the vfork parent will remain stopped in step instead GDB will only see the EXECD/EXITED/SIGNALLED event. The problems in #9 and #10 are therefore skipped and we arrive at #11, handling the EXECD event. As the parent is still stopped #12 doesn't apply, and in #13 when we try to stop the process we will see that it is already stopped, there's no risk of the vfork parent exiting before we get to this point. And finally, in #15 we are safe to poke the process registers because it will not have exited by this point. However, I did mention two bugs. The second bug I've not yet managed to actually trigger, but I'm convinced it must exist: if we forget vforks for a moment, in step #13 above, when linux_nat_target::detach is called, we first try to stop all threads in the process GDB is detaching from. If we imagine a multi-threaded inferior with many threads, and GDB running in non-stop mode, then, if the user tries to detach there is a chance that thread could exit just as linux_nat_target::detach is entered, in which case we should be able to trigger the same assert. But, like I said, I've not (yet) managed to trigger this second bug, and even if I could, the fix would not belong in this commit, so I'm pointing this out just for completeness. There's no test included in this commit. In a couple of commits time I will expand gdb.base/foll-vfork.exp which is when this bug would be exposed. Unfortunately there are at least two other bugs (separate from the ones discussed above) that need fixing first, these will be fixed in the next commits before the gdb.base/foll-vfork.exp test is expanded. If you do want to reproduce this failure then you will for certainly need to run the gdb.base/foll-vfork.exp test in a loop as the failures are all very timing sensitive. I've found that running multiple copies in parallel makes the failure more likely to appear, I usually run ~6 copies in parallel and expect to see a failure after within 10mins.
palves
pushed a commit
that referenced
this issue
Jul 19, 2023
Like the last few commit, this fixes yet another vfork related issue. Like the commit titled: gdb: don't restart vfork parent while waiting for child to finish which addressed a case in linux-nat where we would try to resume a vfork parent, this commit addresses a very similar case, but this time occurring in infrun.c. Just like with that previous commit, this bug results in the assert: x86-linux-dregs.c:146: internal-error: x86_linux_update_debug_registers: Assertion `lwp_is_stopped (lwp)' failed. In this case the issue occurs when target-non-stop is on, but non-stop is off, and again, schedule-multiple is on. As with the previous commit, GDB is in follow-fork-mode child. If you have not done so, it is worth reading the earlier commit as many of the problems leading to the failure are the same, they just appear in a different part of GDB. Here are the steps leading to the assertion failure: 1. The user performs a 'next' over a vfork, GDB stop in the vfork child, 2. As we are planning to follow the child GDB sets the vfork_parent and vfork_child member variables in the two inferiors, the thread_waiting_for_vfork_done member is left as nullptr, that member is only used when GDB is planning to follow the parent inferior, 3. The user does 'continue', our expectation is that the vfork child should resume, and once that process has exited or execd, GDB should detach from the vfork parent. As a result of the 'continue' GDB eventually enters the proceed function, 4. In proceed we selected a ptid_t to resume, because schedule-multiple is on we select minus_one_ptid (see user_visible_resume_ptid), 5. As GDB is running in all-stop on top of non-stop mode, in the proceed function we iterate over all threads that match the resume ptid, which turns out to be all threads, and call proceed_resume_thread_checked. One of the threads we iterate over is the vfork parent thread, 6. As the thread passed to proceed_resume_thread_checked doesn't match any of the early return conditions, GDB will set the thread resumed, 7. As we are resuming one thread at a time, this thread is seen by the lower layers (e.g. linux-nat) as the "event thread", which means we don't apply any of the checks, e.g. is this thread a vfork parent, instead we assume that GDB core knows what it's doing, and linux-nat will resume the thread, we have now incorrectly set running the vfork parent thread when this thread should be waiting for the vfork child to complete, 8. Back in the proceed function GDB continues to iterate over all threads, and now (correctly) resumes the vfork child thread, 8. As the vfork child is still alive the kernel holds the vfork parent stopped, 9. Eventually the child performs its exec and GDB is sent and EXECD event. However, because the parent is resumed, as soon as the child performs its exec the vfork parent also sends a VFORK_DONE event to GDB, 10. Depending on timing both of these events might seem to arrive in GDB at the same time. Normally GDB expects to see the EXECD or EXITED/SIGNALED event from the vfork child before getting the VFORK_DONE in the parent. We know this because it is as a result of the EXECD/EXITED/SIGNALED that GDB detaches from the parent (see handle_vfork_child_exec_or_exit for details). Further the comment in target/waitstatus.h on TARGET_WAITKIND_VFORK_DONE indicates that when we remain attached to the child (not the parent) we should not expect to see a VFORK_DONE, 11. If both events arrive at the same time then GDB will randomly choose one event to handle first, in some cases this will be the VFORK_DONE. As described above, upon seeing a VFORK_DONE GDB expects that (a) the vfork child has finished, however, in this case this is not completely true, the child has finished, but GDB has not processed the event associated with the completion yet, and (b) upon seeing a VFORK_DONE GDB assumes we are remaining attached to the parent, and so resumes the parent process, 12. GDB now handles the EXECD event. In our case we are detaching from the parent, so GDB calls target_detach (see handle_vfork_child_exec_or_exit), 13. While this has been going on the vfork parent is executing, and might even exit, 14. In linux_nat_target::detach the first thing we do is stop all threads in the process we're detaching from, the result of the stop request will be cached on the lwp_info object, 15. In our case the vfork parent has exited though, so when GDB waits for the thread, instead of a stop due to signal, we instead get a thread exited status, 16. Later in the detach process we try to resume the threads just prior to making the ptrace call to actually detach (see detach_one_lwp), as part of the process to resume a thread we try to touch some registers within the thread, and before doing this GDB asserts that the thread is stopped, 17. An exited thread is not classified as stopped, and so the assert triggers! Just like with the earlier commit, the fix is to spot the vfork parent status of the thread, and not resume such threads. Where the earlier commit fixed this in linux-nat, in this case I think the fix should live in infrun.c, in proceed_resume_thread_checked. This function already has a similar check to not resume the vfork parent in the case where we are planning to follow the vfork parent, I propose adding a similar case that checks for the vfork parent when we plan to follow the vfork child. This new check will mean that at step #6 above GDB doesn't try to resume the vfork parent thread, which prevents the VFORK_DONE from ever arriving. Once GDB sees the EXECD/EXITED/SIGNALLED event from the vfork child GDB will detach from the parent. There's no test included in this commit. In a subsequent commit I will expand gdb.base/foll-vfork.exp which is when this bug would be exposed. If you do want to reproduce this failure then you will for certainly need to run the gdb.base/foll-vfork.exp test in a loop as the failures are all very timing sensitive. I've found that running multiple copies in parallel makes the failure more likely to appear, I usually run ~6 copies in parallel and expect to see a failure after within 10mins.
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
Expect a `.MIPS.options' section alternatively to `.reginfo' and ignore contents of either as irrelevant for all the affected compact EH tests, removing these regressions: mips64-openbsd -FAIL: Compact EH EB #1 with personality ID and FDE data mips64-openbsd -FAIL: Compact EH EB #2 with personality routine and FDE data mips64-openbsd -FAIL: Compact EH EB #3 with personality id and large FDE data mips64-openbsd -FAIL: Compact EH EB #4 with personality id, FDE data and LSDA mips64-openbsd -FAIL: Compact EH EB #5 with personality routine, FDE data and LSDA mips64-openbsd -FAIL: Compact EH EB #6 with personality id, LSDA and large FDE data mips64-openbsd -FAIL: Compact EH EL #1 with personality ID and FDE data mips64-openbsd -FAIL: Compact EH EL #2 with personality routine and FDE data mips64-openbsd -FAIL: Compact EH EL #3 with personality id and large FDE data mips64-openbsd -FAIL: Compact EH EL #4 with personality id, FDE data and LSDA mips64-openbsd -FAIL: Compact EH EL #5 with personality routine, FDE data and LSDA mips64-openbsd -FAIL: Compact EH EL #6 with personality id, LSDA and large FDE data mips64el-openbsd -FAIL: Compact EH EB #1 with personality ID and FDE data mips64el-openbsd -FAIL: Compact EH EB #2 with personality routine and FDE data mips64el-openbsd -FAIL: Compact EH EB #3 with personality id and large FDE data mips64el-openbsd -FAIL: Compact EH EB #4 with personality id, FDE data and LSDA mips64el-openbsd -FAIL: Compact EH EB #5 with personality routine, FDE data and LSDA mips64el-openbsd -FAIL: Compact EH EB #6 with personality id, LSDA and large FDE data mips64el-openbsd -FAIL: Compact EH EL #1 with personality ID and FDE data mips64el-openbsd -FAIL: Compact EH EL #2 with personality routine and FDE data mips64el-openbsd -FAIL: Compact EH EL #3 with personality id and large FDE data mips64el-openbsd -FAIL: Compact EH EL #4 with personality id, FDE data and LSDA mips64el-openbsd -FAIL: Compact EH EL #5 with personality routine, FDE data and LSDA mips64el-openbsd -FAIL: Compact EH EL #6 with personality id, LSDA and large FDE data Co-Authored-By: Maciej W. Rozycki <[email protected]> gas/ * testsuite/gas/mips/compact-eh-eb-1.d: Accept `.MIPS.options' section as an alternative to `.reginfo' and ignore contents of either. * testsuite/gas/mips/compact-eh-eb-2.d: Likewise. * testsuite/gas/mips/compact-eh-eb-3.d: Likewise. * testsuite/gas/mips/compact-eh-eb-4.d: Likewise. * testsuite/gas/mips/compact-eh-eb-5.d: Likewise. * testsuite/gas/mips/compact-eh-eb-6.d: Likewise. * testsuite/gas/mips/compact-eh-el-1.d: Likewise. * testsuite/gas/mips/compact-eh-el-2.d: Likewise. * testsuite/gas/mips/compact-eh-el-3.d: Likewise. * testsuite/gas/mips/compact-eh-el-4.d: Likewise. * testsuite/gas/mips/compact-eh-el-5.d: Likewise. * testsuite/gas/mips/compact-eh-el-6.d: Likewise.
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I run into: ... (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache... (gdb) show index-cache enabled The index cache is off. (gdb) PASS: gdb.base/index-cache.exp: test_basic_stuff: index-cache is disabled by default set index-cache enabled on ================== WARNING: ThreadSanitizer: data race (pid=32248) Write of size 1 at 0x00000321f540 by main thread: #0 index_cache::enable() gdb/dwarf2/index-cache.c:76 (gdb+0x82cfdd) #1 set_index_cache_enabled_command gdb/dwarf2/index-cache.c:270 (gdb+0x82d9af) #2 bool setting::set<bool>(bool const&) gdb/command.h:353 (gdb+0x6fe5f2) #3 do_set_command(char const*, int, cmd_list_element*) gdb/cli/cli-setshow.c:414 (gdb+0x6fcd21) #4 execute_command(char const*, int) gdb/top.c:567 (gdb+0xff2e64) #5 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94acc0) #6 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b37d) #7 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103467e) #8 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a265) #9 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdd3f) #10 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a064) #11 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a125) #12 stdin_event_handler gdb/ui.c:155 (gdb+0x1074922) #13 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94de4) #14 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9551c) #15 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93908) #16 start_event_loop gdb/main.c:412 (gdb+0xb5a256) #17 captured_command_loop gdb/main.c:476 (gdb+0xb5a445) #18 captured_main gdb/main.c:1320 (gdb+0xb5c5c5) #19 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c674) #20 main gdb/gdb.c:32 (gdb+0x416776) Previous read of size 1 at 0x00000321f540 by thread T12: #0 index_cache::enabled() const gdb/dwarf2/index-cache.h:48 (gdb+0x82e1a6) #1 index_cache::store(dwarf2_per_bfd*) gdb/dwarf2/index-cache.c:94 (gdb+0x82d0bc) #2 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:638 (gdb+0x7f1b97) #3 operator() gdb/dwarf2/cooked-index.c:468 (gdb+0x7f0f24) #4 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f285b) #5 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952) #6 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0) #7 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91) #8 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59) #9 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660) #10 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c) #11 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623) #12 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf) #13 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f) #14 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5) #15 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d) #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2) #18 pthread_once <null> (libtsan.so.0+0x4457c) #19 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd) #20 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224) #21 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852) #22 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef) #23 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac492) #24 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabdb4) #25 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dace63) #26 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac294) #27 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf5c6) #28 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf551) #29 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf506) #30 <null> <null> (libstdc++.so.6+0xdcac2) Location is global 'global_index_cache' of size 48 at 0x00000321f520 (gdb+0x00000321f540) ... SUMMARY: ThreadSanitizer: data race gdb/dwarf2/index-cache.c:76 in index_cache::enable() ... The race happens when issuing a "file $exec" command followed by a "set index-cache enabled on" command. The race is between: - a worker thread reading index_cache::m_enabled to determine whether an index-cache entry for $exec needs to be written (due to command "file $exec"), and - the main thread setting index_cache::m_enabled (due to command "set index-cache enabled on"). Fix this by capturing the value of index_cache::m_enabled in the main thread, and using the captured value in the worker thread. Tested on x86_64-linux. PR symtab/30392 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I run into: ... (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache... ================== WARNING: ThreadSanitizer: data race (pid=12261) Write of size 4 at 0x7b4400097d08 by main thread: #0 bfd_open_file bfd/cache.c:584 (gdb+0x148bb92) #1 bfd_cache_lookup_worker bfd/cache.c:261 (gdb+0x148b12a) #2 cache_bseek bfd/cache.c:289 (gdb+0x148b324) #3 bfd_seek bfd/bfdio.c:459 (gdb+0x1489c31) #4 _bfd_generic_get_section_contents bfd/libbfd.c:1069 (gdb+0x14977a4) #5 bfd_get_section_contents bfd/section.c:1606 (gdb+0x149cc7c) #6 gdb_bfd_scan_elf_dyntag(int, bfd*, unsigned long*, unsigned long*) gdb/solib.c:1601 (gdb+0xed8eca) #7 elf_locate_base gdb/solib-svr4.c:705 (gdb+0xec28ac) #8 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3430 (gdb+0xeca55d) #9 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad) #10 find_main_name gdb/symtab.c:6270 (gdb+0xf743a5) #11 main_language() gdb/symtab.c:6313 (gdb+0xf74499) #12 set_initial_language() gdb/symfile.c:1700 (gdb+0xf4285c) #13 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40e2a) #14 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf427d1) #15 file_command gdb/exec.c:554 (gdb+0x94f74b) #16 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528) #17 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69) #18 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff303c) #19 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94adde) #20 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b49b) #21 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x103479c) #22 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a383) #23 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bde5d) #24 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a182) #25 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a243) #26 stdin_event_handler gdb/ui.c:155 (gdb+0x1074a40) #27 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d94f02) #28 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d9563a) #29 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93a26) #30 start_event_loop gdb/main.c:412 (gdb+0xb5a374) #31 captured_command_loop gdb/main.c:476 (gdb+0xb5a563) #32 captured_main gdb/main.c:1320 (gdb+0xb5c6e3) #33 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c792) #34 main gdb/gdb.c:32 (gdb+0x416776) Previous read of size 1 at 0x7b4400097d08 by thread T12: #0 bfd_check_format_matches bfd/format.c:323 (gdb+0x1492db4) #1 bfd_check_format bfd/format.c:94 (gdb+0x1492104) #2 build_id_bfd_get(bfd*) gdb/build-id.c:42 (gdb+0x6648f7) #3 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:110 (gdb+0x82d205) #4 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf1) #5 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40) #6 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f28f7) #7 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952) #8 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0) #9 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91) #10 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59) #11 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660) #12 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c) #13 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623) #14 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf) #15 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f) #16 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d) #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2) #19 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2) #20 pthread_once <null> (libtsan.so.0+0x4457c) #21 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd) #22 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224) #23 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852) #24 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef) #25 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac5b0) #26 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabed2) #27 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dacf81) #28 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac3b2) #29 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf6e4) #30 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf66f) #31 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf624) #32 <null> <null> (libstdc++.so.6+0xdcac2) ... SUMMARY: ThreadSanitizer: data race bfd/cache.c:584 in bfd_open_file ... The race happens when issuing the "file $exec" command. The race is between: - a worker thread getting the build id while writing the index cache, and in the process reading bfd::format, and - the main thread calling find_main_name, and in the process setting bfd::cacheable. The two bitfields bfd::cacheable and bfd::format share the same bitfield container. Fix this by capturing the build id in the main thread, and using the captured value in the worker thread. Likewise for the dwz build id, which likely suffers from the same issue. While we're at it, also move the creation of the cache directory to the index_cache_store_context constructor, to: - make sure there's no race between subsequent file commands, and - issue any related warning or error messages during the file command. Tested on x86_64-linux. Approved-By: Tom Tromey <[email protected]> PR symtab/30392 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp I run into: ... (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache... ================== WARNING: ThreadSanitizer: data race (pid=24296) Write of size 1 at 0x7b200000420d by main thread: #0 queue_comp_unit gdb/dwarf2/read.c:5564 (gdb+0x8939ce) #1 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1754 (gdb+0x885b96) #2 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x885d86) #3 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88ac77) #4 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16915 (gdb+0x8c1c8a) #5 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf389a1) #6 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66403) #7 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf66a67) #8 operator() gdb/symtab.c:2562 (gdb+0xf66bbe) #9 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf76ffd) #10 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77054) #11 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3f5e3) #12 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xeca793) #13 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad) #14 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf66e47) #15 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf670cc) #16 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf666ba) #17 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf655ff) #18 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf646f7) #19 set_initial_language() gdb/symfile.c:1708 (gdb+0xf429c0) #20 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf40f54) #21 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf428fb) #22 file_command gdb/exec.c:554 (gdb+0x94f875) #23 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528) #24 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69) #25 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff3166) #26 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94af08) #27 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94b5c5) #28 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x10348c6) #29 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94a4ad) #30 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11bdf87) #31 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a2ac) #32 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94a36d) #33 stdin_event_handler gdb/ui.c:155 (gdb+0x1074b6a) #34 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d9502c) #35 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d95764) #36 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d93b50) #37 start_event_loop gdb/main.c:412 (gdb+0xb5a49e) #38 captured_command_loop gdb/main.c:476 (gdb+0xb5a68d) #39 captured_main gdb/main.c:1320 (gdb+0xb5c80d) #40 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5c8bc) #41 main gdb/gdb.c:32 (gdb+0x416776) Previous read of size 1 at 0x7b200000420d by thread T12: #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x8310c8) #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x83232f) #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context*) gdb/dwarf2/index-cache.c:177 (gdb+0x82d62b) #3 cooked_index::maybe_write_index(dwarf2_per_bfd*) gdb/dwarf2/cooked-index.c:640 (gdb+0x7f1bf7) #4 operator() gdb/dwarf2/cooked-index.c:470 (gdb+0x7f0f40) #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2909) #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952) #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0) #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91) #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59) #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660) #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c) #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623) #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf) #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f) #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5) #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2) #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2) #19 pthread_once <null> (libtsan.so.0+0x4457c) #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd) #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224) #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852) #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef) #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dac6da) #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dabffc) #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dad0ab) #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dac4dc) #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1daf80e) #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1daf799) #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1daf74e) #31 <null> <null> (libstdc++.so.6+0xdcac2) ... SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:5564 in queue_comp_unit ... The race happens when issuing the "file $exec" command. The race is between: - a worker thread writing the index cache, and in the process reading dwarf2_per_cu_data::is_debug_type, and - the main thread expanding the CU containing main, and in the process setting dwarf2_per_cu_data::queued. The two bitfields dwarf2_per_cu_data::queue and dwarf2_per_cu_data::is_debug_type share the same bitfield container. Fix this by making dwarf2_per_cu_data::queued a packed<bool, 1>. Tested on x86_64-linux. Approved-By: Tom Tromey <[email protected]> PR symtab/30392 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
…s_debug_type} With gdb build with -fsanitize=thread and test-case gdb.base/index-cache.exp and target board debug-types, I run into: ... (gdb) file build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache Reading symbols from build/gdb/testsuite/outputs/gdb.base/index-cache/index-cache... ================== WARNING: ThreadSanitizer: data race (pid=9654) Write of size 1 at 0x7b200000420d by main thread: #0 dwarf2_per_cu_data::get_header() const gdb/dwarf2/read.c:21513 (gdb+0x8d1eee) #1 dwarf2_per_cu_data::addr_size() const gdb/dwarf2/read.c:21524 (gdb+0x8d1f4e) #2 dwarf2_cu::addr_type() const gdb/dwarf2/cu.c:112 (gdb+0x806327) #3 set_die_type gdb/dwarf2/read.c:21932 (gdb+0x8d3870) #4 read_base_type gdb/dwarf2/read.c:15448 (gdb+0x8bcacb) #5 read_type_die_1 gdb/dwarf2/read.c:19832 (gdb+0x8cc0a5) #6 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d) #7 lookup_die_type gdb/dwarf2/read.c:19739 (gdb+0x8cbdc7) #8 die_type gdb/dwarf2/read.c:19593 (gdb+0x8cb68a) #9 read_subroutine_type gdb/dwarf2/read.c:14648 (gdb+0x8b998e) #10 read_type_die_1 gdb/dwarf2/read.c:19792 (gdb+0x8cbf2f) #11 read_type_die gdb/dwarf2/read.c:19767 (gdb+0x8cbe6d) #12 read_func_scope gdb/dwarf2/read.c:10154 (gdb+0x8a4f36) #13 process_die gdb/dwarf2/read.c:6667 (gdb+0x898daa) #14 read_file_scope gdb/dwarf2/read.c:7682 (gdb+0x89bad8) #15 process_die gdb/dwarf2/read.c:6654 (gdb+0x898ced) #16 process_full_comp_unit gdb/dwarf2/read.c:6418 (gdb+0x8981de) #17 process_queue gdb/dwarf2/read.c:5690 (gdb+0x894433) #18 dw2_do_instantiate_symtab gdb/dwarf2/read.c:1770 (gdb+0x88623a) #19 dw2_instantiate_symtab gdb/dwarf2/read.c:1792 (gdb+0x886300) #20 dw2_expand_symtabs_matching_one(dwarf2_per_cu_data*, dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>, gdb::function_view<bool (compunit_symtab*)>) gdb/dwarf2/read.c:3042 (gdb+0x88b1f1) #21 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16917 (gdb+0x8c228e) #22 objfile::lookup_symbol(block_enum, char const*, domain_enum) gdb/symfile-debug.c:288 (gdb+0xf39055) #23 lookup_symbol_via_quick_fns gdb/symtab.c:2385 (gdb+0xf66ab7) #24 lookup_symbol_in_objfile gdb/symtab.c:2516 (gdb+0xf6711b) #25 operator() gdb/symtab.c:2562 (gdb+0xf67272) #26 operator() gdb/../gdbsupport/function-view.h:305 (gdb+0xf776b1) #27 _FUN gdb/../gdbsupport/function-view.h:299 (gdb+0xf77708) #28 gdb::function_view<bool (objfile*)>::operator()(objfile*) const gdb/../gdbsupport/function-view.h:289 (gdb+0xc3fc97) #29 svr4_iterate_over_objfiles_in_search_order gdb/solib-svr4.c:3455 (gdb+0xecae47) #30 gdbarch_iterate_over_objfiles_in_search_order(gdbarch*, gdb::function_view<bool (objfile*)>, objfile*) gdb/gdbarch.c:5041 (gdb+0x537cad) #31 lookup_global_or_static_symbol gdb/symtab.c:2559 (gdb+0xf674fb) #32 lookup_global_symbol(char const*, block const*, domain_enum) gdb/symtab.c:2615 (gdb+0xf67780) #33 language_defn::lookup_symbol_nonlocal(char const*, block const*, domain_enum) const gdb/symtab.c:2447 (gdb+0xf66d6e) #34 lookup_symbol_aux gdb/symtab.c:2123 (gdb+0xf65cb3) #35 lookup_symbol_in_language(char const*, block const*, domain_enum, language, field_of_this_result*) gdb/symtab.c:1931 (gdb+0xf64dab) #36 set_initial_language() gdb/symfile.c:1708 (gdb+0xf43074) #37 symbol_file_add_main_1 gdb/symfile.c:1212 (gdb+0xf41608) #38 symbol_file_command(char const*, int) gdb/symfile.c:1681 (gdb+0xf42faf) #39 file_command gdb/exec.c:554 (gdb+0x94ff29) #40 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x6d9528) #41 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x6e0f69) #42 execute_command(char const*, int) gdb/top.c:575 (gdb+0xff379c) #43 command_handler(char const*) gdb/event-top.c:552 (gdb+0x94b5bc) #44 command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) gdb/event-top.c:788 (gdb+0x94bc79) #45 tui_command_line_handler gdb/tui/tui-interp.c:104 (gdb+0x1034efc) #46 gdb_rl_callback_handler gdb/event-top.c:259 (gdb+0x94ab61) #47 rl_callback_read_char readline/readline/callback.c:290 (gdb+0x11be4ef) #48 gdb_rl_callback_read_char_wrapper_noexcept gdb/event-top.c:195 (gdb+0x94a960) #49 gdb_rl_callback_read_char_wrapper gdb/event-top.c:234 (gdb+0x94aa21) #50 stdin_event_handler gdb/ui.c:155 (gdb+0x10751a0) #51 handle_file_event gdbsupport/event-loop.cc:573 (gdb+0x1d95bac) #52 gdb_wait_for_event gdbsupport/event-loop.cc:694 (gdb+0x1d962e4) #53 gdb_do_one_event(int) gdbsupport/event-loop.cc:264 (gdb+0x1d946d0) #54 start_event_loop gdb/main.c:412 (gdb+0xb5ab52) #55 captured_command_loop gdb/main.c:476 (gdb+0xb5ad41) #56 captured_main gdb/main.c:1320 (gdb+0xb5cec1) #57 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xb5cf70) #58 main gdb/gdb.c:32 (gdb+0x416776) Previous read of size 1 at 0x7b200000420d by thread T11: #0 write_gdbindex gdb/dwarf2/index-write.c:1229 (gdb+0x831630) #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1484 (gdb+0x832897) #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x82db8d) #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:645 (gdb+0x7f1d49) #4 operator() gdb/dwarf2/cooked-index.c:474 (gdb+0x7f0f31) #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x7f2a13) #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x700952) #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x7381a0) #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x737e91) #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x737b59) #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x738660) #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x73825c) #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x733623) #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x732bdf) #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x734c4f) #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x733bc5) #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x73300d) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x7330b2) #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x7330f2) #19 pthread_once <null> (libtsan.so.0+0x4457c) #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72f5dd) #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x733224) #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x732852) #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x737bef) #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x1dad25a) #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x1dacb7c) #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1dadc2b) #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1dad05c) #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1db038e) #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1db0319) #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1db02ce) #31 <null> <null> (libstdc++.so.6+0xdcac2) ... SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:21513 in dwarf2_per_cu_data::get_header() const ... The race happens when issuing the "file $exec" command. The race is between: - a worker thread writing the index cache, and in the process reading dwarf2_per_cu_data::is_debug_type, and - the main thread writing to dwarf2_per_cu_data::m_header_read_in. The two bitfields dwarf2_per_cu_data::m_header_read_in and dwarf2_per_cu_data::is_debug_type share the same bitfield container. Fix this by making dwarf2_per_cu_data::m_header_read_in a packed<bool, 1>. Tested on x86_64-linux. Approved-By: Tom Tromey <[email protected]> PR symtab/30392 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30392
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
With gdb build with -fsanitize=thread, and the exec from test-case gdb.base/index-cache.exp, I run into: ... $ rm -f ~/.cache/gdb/*; \ gdb -q -batch -iex "set index-cache enabled on" index-cache \ -ex "print foobar" ... WARNING: ThreadSanitizer: data race (pid=23970) Write of size 1 at 0x7b200000410d by main thread: #0 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3077 (gdb+0x7ac54e) #1 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d039f) #2 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5aee) #3 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc439d) #4 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc44a2) #5 classify_name gdb/c-exp.y:3083 (gdb+0x61afec) #6 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13) #7 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e) #8 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864) #9 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x9771c5) #10 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10a9b) #11 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb110ae) #12 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf0c) #13 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4ca2a) #14 print_command gdb/printcmd.c:1468 (gdb+0xb4cd5a) #15 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078) #16 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53) #17 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a76a) #18 catch_command_errors gdb/main.c:518 (gdb+0xa1837d) #19 execute_cmdargs gdb/main.c:617 (gdb+0xa1853f) #20 captured_main_1 gdb/main.c:1289 (gdb+0xa1aa58) #21 captured_main gdb/main.c:1310 (gdb+0xa1b95a) #22 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b95a) #23 main gdb/gdb.c:39 (gdb+0x42506a) Previous read of size 1 at 0x7b200000410d by thread T1: #0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30) #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803) #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36) #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d) #4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d) #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d) #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c) #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db) #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db) #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db) #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db) #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db) #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954) #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954) #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a) #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a) #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a) #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a) #19 pthread_once <null> (libtsan.so.0+0x4457c) #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b) #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b) #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174568d) #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174568d) #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174568d) #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174568d) #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x1748040) #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x1748040) #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1748040) #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1748040) #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1748040) #31 <null> <null> (libstdc++.so.6+0xdcac2) ... SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:3077 in dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) ... The race happens when issuing the "file $exec" command. The race is between: - a worker thread writing the index cache, and in the process reading dwarf2_per_cu_data::is_debug_type, and - the main thread writing to dwarf2_per_cu_data::mark. The two bitfields dwarf2_per_cu_data::mark and dwarf2_per_cu_data::is_debug_type share the same bitfield container. Fix this by making dwarf2_per_cu_data::mark a packed<unsigned int, 1>. Tested on x86_64-linux. PR symtab/30718 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
…g_types} With gdb build with -fsanitize=thread, and the exec from test-case gdb.base/index-cache.exp, I run into: ... $ rm -f ~/.cache/gdb/*; \ gdb -q -batch -iex "set index-cache enabled on" index-cache \ -ex "print foobar" ... WARNING: ThreadSanitizer: data race (pid=25018) Write of size 1 at 0x7b200000410d by main thread: #0 dw2_get_file_names_reader gdb/dwarf2/read.c:2033 (gdb+0x7ab023) #1 dw2_get_file_names gdb/dwarf2/read.c:2130 (gdb+0x7ab023) #2 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3105 (gdb+0x7ac6e9) #3 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d040f) #4 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5b6e) #5 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc441d) #6 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc4522) #7 classify_name gdb/c-exp.y:3083 (gdb+0x61afec) #8 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13) #9 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e) #10 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864) #11 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x977245) #12 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10b1b) #13 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb1112e) #14 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf8c) #15 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4caaa) #16 print_command gdb/printcmd.c:1468 (gdb+0xb4cdda) #17 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078) #18 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53) #19 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a7ea) #20 catch_command_errors gdb/main.c:518 (gdb+0xa183fd) #21 execute_cmdargs gdb/main.c:617 (gdb+0xa185bf) #22 captured_main_1 gdb/main.c:1289 (gdb+0xa1aad8) #23 captured_main gdb/main.c:1310 (gdb+0xa1b9da) #24 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b9da) #25 main gdb/gdb.c:39 (gdb+0x42506a) Previous read of size 1 at 0x7b200000410d by thread T2: #0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30) #1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803) #2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36) #3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d) #4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d) #5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d) #6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c) #7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db) #8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db) #9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db) #10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db) #11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db) #12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954) #13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954) #14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a) #15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a) #16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a) #17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a) #18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a) #19 pthread_once <null> (libtsan.so.0+0x4457c) #20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b) #21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b) #22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174570d) #23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174570d) #24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174570d) #25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174570d) #26 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x17480c0) #27 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x17480c0) #28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x17480c0) #29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x17480c0) #30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x17480c0) #31 <null> <null> (libstdc++.so.6+0xdcac2) ... SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:2033 in dw2_get_file_names_reader ... The race happens when issuing the "file $exec" command. The race is between: - a worker thread writing the index cache, and in the process reading dwarf2_per_cu_data::is_debug_type, and - the main thread writing to dwarf2_per_cu_data::files_read. The two bitfields dwarf2_per_cu_data::files_read and dwarf2_per_cu_data::is_debug_type share the same bitfield container. Fix this by making dwarf2_per_cu_data::files_read a packed<bool, 1>. Tested on x86_64-linux. PR symtab/30718 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
palves
added a commit
that referenced
this issue
Feb 20, 2024
After running a number of programs under Windows gdb and detaching them, I typed run in gdb, and got a hang, here: (top-gdb) bt #0 sharing_input_terminal (pid=4672) at /home/pedro/gdb/src/gdb/mingw-hdep.c:388 #1 0x00007ff71a2d8678 in sharing_input_terminal (inf=0x23bf23dafb0) at /home/pedro/gdb/src/gdb/inflow.c:269 #2 0x00007ff71a2d887b in child_terminal_save_inferior (self=0x23bf23de060) at /home/pedro/gdb/src/gdb/inflow.c:423 #3 0x00007ff71a2c80c0 in inf_child_target::terminal_save_inferior (this=0x23bf23de060) at /home/pedro/gdb/src/gdb/inf-child.c:111 #4 0x00007ff71a429c0f in target_terminal_is_ours_kind (desired_state=target_terminal_state::is_ours_for_output) at /home/pedro/gdb/src/gdb/target.c:1037 #5 0x00007ff71a429e02 in target_terminal::ours_for_output () at /home/pedro/gdb/src/gdb/target.c:1094 #6 0x00007ff71a2ccc8e in post_create_inferior (from_tty=0) at /home/pedro/gdb/src/gdb/infcmd.c:245 #7 0x00007ff71a2cd431 in run_command_1 (args=0x0, from_tty=0, run_how=RUN_NORMAL) at /home/pedro/gdb/src/gdb/infcmd.c:502 #8 0x00007ff71a2cd58b in run_command (args=0x0, from_tty=0) at /home/pedro/gdb/src/gdb/infcmd.c:527 The problem is that the loop around GetConsoleProcessList looped forever, because there were exactly 10 processes to return. GetConsoleProcessList's documentation says: If the buffer is too small to hold all the valid process identifiers, the return value is the required number of array elements. The function will have stored no identifiers in the buffer. In this situation, use the return value to allocate a buffer that is large enough to store the entire list and call the function again. In this case, the buffer wasn't too small, it was exactly the right size, so we should have broken out of the loop. We didn't due to a "<" check that should have been "<=". That is fixed by this patch. Approved-By: Tom Tromey <[email protected]> Reviewed-By: Eli Zaretskii <[email protected]> Change-Id: I14e4909f2ac2fa83d0d9b6e64418b5831ac4e4e3
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
This commit fixes an issue that was discovered while writing the tests for the previous commit. I noticed that, when GDB restarts an inferior, the executable_changed event would trigger twice. The first notification would originate from: #0 exec_file_attach (filename=0x4046680 "/tmp/hello.x", from_tty=0) at ../../src/gdb/exec.c:513 #1 0x00000000006f3adb in reopen_exec_file () at ../../src/gdb/corefile.c:122 #2 0x0000000000e6a3f2 in generic_mourn_inferior () at ../../src/gdb/target.c:3682 #3 0x0000000000995121 in inf_child_target::mourn_inferior (this=0x2fe95c0 <the_amd64_linux_nat_target>) at ../../src/gdb/inf-child.c:192 #4 0x0000000000995cff in inf_ptrace_target::mourn_inferior (this=0x2fe95c0 <the_amd64_linux_nat_target>) at ../../src/gdb/inf-ptrace.c:125 #5 0x0000000000a32472 in linux_nat_target::mourn_inferior (this=0x2fe95c0 <the_amd64_linux_nat_target>) at ../../src/gdb/linux-nat.c:3609 #6 0x0000000000e68a40 in target_mourn_inferior (ptid=...) at ../../src/gdb/target.c:2761 #7 0x0000000000a323ec in linux_nat_target::kill (this=0x2fe95c0 <the_amd64_linux_nat_target>) at ../../src/gdb/linux-nat.c:3593 #8 0x0000000000e64d1c in target_kill () at ../../src/gdb/target.c:924 #9 0x00000000009a19bc in kill_if_already_running (from_tty=1) at ../../src/gdb/infcmd.c:328 #10 0x00000000009a1a6f in run_command_1 (args=0x0, from_tty=1, run_how=RUN_STOP_AT_MAIN) at ../../src/gdb/infcmd.c:381 #11 0x00000000009a20a5 in start_command (args=0x0, from_tty=1) at ../../src/gdb/infcmd.c:527 #12 0x000000000068dc5d in do_simple_func (args=0x0, from_tty=1, c=0x35c7200) at ../../src/gdb/cli/cli-decode.c:95 While the second originates from: #0 exec_file_attach (filename=0x3d7a1d0 "/tmp/hello.x", from_tty=0) at ../../src/gdb/exec.c:513 #1 0x0000000000dfe525 in reread_symbols (from_tty=1) at ../../src/gdb/symfile.c:2517 #2 0x00000000009a1a98 in run_command_1 (args=0x0, from_tty=1, run_how=RUN_STOP_AT_MAIN) at ../../src/gdb/infcmd.c:398 #3 0x00000000009a20a5 in start_command (args=0x0, from_tty=1) at ../../src/gdb/infcmd.c:527 #4 0x000000000068dc5d in do_simple_func (args=0x0, from_tty=1, c=0x35c7200) at ../../src/gdb/cli/cli-decode.c:95 In the first case the call to exec_file_attach first passes through reopen_exec_file. The reopen_exec_file performs a modification time check on the executable file, and only calls exec_file_attach if the executable has changed on disk since it was last loaded. However, in the second case things work a little differently. In this case GDB is really trying to reread the debug symbol. As such, we iterate over the objfiles list, and for each of those we check the modification time, if the file on disk has changed then we reload the debug symbols from that file. However, there is an additional check, if the objfile has the same name as the executable then we will call exec_file_attach, but we do so without checking the cached modification time that indicates when the executable was last reloaded, as a result, we reload the executable twice. In this commit I propose that reread_symbols be changed to unconditionally call reopen_exec_file before performing the objfile iteration. This will ensure that, if the executable has changed, then the executable will be reloaded, however, if the executable has already been recently reloaded, we will not reload it for a second time. After handling the executable, GDB can then iterate over the objfiles list and reload them in the normal way. With this done I now see the executable reloaded only once when GDB restarts an inferior, which means I can remove the kfail that I added to the gdb.python/py-exec-file.exp test in the previous commit. Approved-By: Tom Tromey <[email protected]>
palves
pushed a commit
that referenced
this issue
Feb 20, 2024
It was pointed out on the mailing list that a recently added test (gdb.python/py-progspace-events.exp) was failing when run with the native-extended-gdbserver board. This test was added with this commit: commit 59912fb Date: Tue Sep 19 11:45:36 2023 +0100 gdb: add Python events for program space addition and removal It turns out though that the test is failing due to a existing bug in GDB, the new test just exposes the problem. Additionally, the failure really doesn't even rely on the new functionality added in the above commit. I reduced the test to a simple set of steps that reproduced the failure and tested against GDB 13, and the test passes; so the bug was introduced since then. In fact, the bug was introduced with this commit: commit a282736 Date: Fri Sep 8 15:48:16 2023 +0100 gdb: remove final user of the executable_changed observer This commit changed how the per-inferior auxv data cache is managed, specifically, when the cache is cleared, and it is this that leads to the failure. This bug is interesting because it exposes a number of issues with GDB, I'll explain all of the problems I see, though ultimately, I only propose fixing one problem in this commit, which is enough to resolve the crash we are currently seeing. The crash that we are seeing manifests like this: ... [Inferior 2 (process 3970384) exited normally] +inferior 1 [Switching to inferior 1 [process 3970383] (/tmp/build/gdb/testsuite/outputs/gdb.python/py-progspace-events/py-progspace-events)] [Switching to thread 1.1 (Thread 3970383.3970383)] #0 breakpt () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.python/py-progspace-events.c:28 28 { /* Nothing. */ } (gdb) step +step terminate called after throwing an instance of 'gdb_exception_error' Fatal signal: Aborted ... etc ... What's happening is that GDB attempts to refill the auxv cache as a result of the gdbarch_has_shared_address_space call in program_space::~program_space, the backtrace looks like this: #0 0x00007fb4f419a9a5 in raise () from /lib64/libpthread.so.0 #1 0x00000000008b635d in handle_fatal_signal (sig=6) at ../../src/gdb/event-top.c:912 #2 <signal handler called> #3 0x00007fb4f38e3625 in raise () from /lib64/libc.so.6 #4 0x00007fb4f38cc8d9 in abort () from /lib64/libc.so.6 #5 0x00007fb4f3c70756 in __gnu_cxx::__verbose_terminate_handler() [clone .cold] () from /lib64/libstdc++.so.6 #6 0x00007fb4f3c7c6dc in __cxxabiv1::__terminate(void (*)()) () from /lib64/libstdc++.so.6 #7 0x00007fb4f3c7b6e9 in __cxa_call_terminate () from /lib64/libstdc++.so.6 #8 0x00007fb4f3c7c094 in __gxx_personality_v0 () from /lib64/libstdc++.so.6 #9 0x00007fb4f3a80c63 in _Unwind_RaiseException_Phase2 () from /lib64/libgcc_s.so.1 #10 0x00007fb4f3a8154e in _Unwind_Resume () from /lib64/libgcc_s.so.1 #11 0x0000000000e8832d in target_read_alloc_1<unsigned char> (ops=0x408a3a0, object=TARGET_OBJECT_AUXV, annex=0x0) at ../../src/gdb/target.c:2266 #12 0x0000000000e73dea in target_read_alloc (ops=0x408a3a0, object=TARGET_OBJECT_AUXV, annex=0x0) at ../../src/gdb/target.c:2315 #13 0x000000000058248c in target_read_auxv_raw (ops=0x408a3a0) at ../../src/gdb/auxv.c:379 #14 0x000000000058243d in target_read_auxv () at ../../src/gdb/auxv.c:368 #15 0x000000000058255c in target_auxv_search (match=0x0, valp=0x7ffdee17c598) at ../../src/gdb/auxv.c:415 #16 0x0000000000a464bb in linux_is_uclinux () at ../../src/gdb/linux-tdep.c:433 #17 0x0000000000a464f6 in linux_has_shared_address_space (gdbarch=0x409a2d0) at ../../src/gdb/linux-tdep.c:440 #18 0x0000000000510eae in gdbarch_has_shared_address_space (gdbarch=0x409a2d0) at ../../src/gdb/gdbarch.c:4889 #19 0x0000000000bc7558 in program_space::~program_space (this=0x4544aa0, __in_chrg=<optimized out>) at ../../src/gdb/progspace.c:124 #20 0x00000000009b245d in delete_inferior (inf=0x47b3de0) at ../../src/gdb/inferior.c:290 #21 0x00000000009b2c10 in prune_inferiors () at ../../src/gdb/inferior.c:480 #22 0x00000000009c5e3e in fetch_inferior_event () at ../../src/gdb/infrun.c:4558 #23 0x000000000099b4dc in inferior_event_handler (event_type=INF_REG_EVENT) at ../../src/gdb/inf-loop.c:42 #24 0x0000000000cbc64f in remote_async_serial_handler (scb=0x4090a30, context=0x408a6b0) at ../../src/gdb/remote.c:14859 #25 0x0000000000d83d3a in run_async_handler_and_reschedule (scb=0x4090a30) at ../../src/gdb/ser-base.c:138 #26 0x0000000000d83e1f in fd_event (error=0, context=0x4090a30) at ../../src/gdb/ser-base.c:189 So this is problem #1, if we throw an exception while deleting a program_space then this is not caught, and is going to crash GDB. Problem #2 becomes evident when we ask why GDB is throwing an error in this case; the error is thrown because the remote target, operating in non-async mode, can't read the auxv data while an inferior is running and GDB is waiting for a stop reply. The problem here then, is why does GDB get into a position where it tries to interact with the remote target in this way, at this time? The problem is caused by the prune_inferiors call which can be seen in the above backtrace. In prune_inferiors we check if the inferior is deletable, and if it is, we delete it. The problem is, I think, we should also check if the target is currently in a state that would allow us to delete the inferior. We don't currently have such a check available, we'd need to add one, but for the remote target, this would return false if the remote is in async mode and the remote is currently waiting for a stop reply. With this change in place GDB would defer deleting the inferior until the remote target has stopped, at which point GDB would be able to refill the auxv cache successfully. And then, problem #3 becomes evident when we ask why GDB is needing to refill the auxv cache now when it didn't need to for GDB 13. This is where the second commit mentioned above (a282736) comes in. Prior to this commit, the auxv cache was cleared by the executable_changed observer, while after that commit the auxv cache was cleared by the new_objfile observer -- but only when the new_objfile observer is used in the special mode that actually means that all objfiles have been unloaded (I know, the overloading of the new_objfile observer is horrible, and unnecessary, but it's not really important for this bug). The difference arises because the new_objfile observer is triggered from clear_symtab_users, which in turn is called from program_space::~program_space. The new_objfile observer for auxv does this: static void auxv_new_objfile_observer (struct objfile *objfile) { if (objfile == nullptr) invalidate_auxv_cache_inf (current_inferior ()); } That is, when all the objfiles are unloaded, we clear the auxv cache for the current inferior. The problem is, then when we look at the prune_inferiors -> delete_inferior -> ~program_space path, we see that the current inferior is not going to be an inferior that exists within the program_space being deleted; delete_inferior removes the deleted inferior from the global inferior list, and then only deletes the program_space if program_space::empty() returns true, which is only the case if the current inferior isn't within the program_space to delete, and no other inferior exists within that program_space either. What this means is that when the new_objfile observer is called we can't rely on the current inferior having any relationship with the program space in which the objfiles were removed. This was an error in the commit a282736, the only thing we can rely on is the current program space. As a result of this mistake, after commit a282736, GDB was sometimes clearing the auxv cache for a random inferior. In the native target case this was harmless as we can always refill the cache when needed, but in the remote target case, if we need to refill the cache when the remote target is executing, then we get the crash we observed. And additionally, if we think about this a little more, we see that commit a282736 made another mistake. When all the objfiles are removed, they are removed from a program_space, a program_space might contain multiple inferiors, so surely, we should clear the auxv cache for all of the matching inferiors? Given these two insights, that the current_inferior is not relevant, only the current_program_space, and that we should be clearing the cache for all inferiors in the current_program_space, we can update auxv_new_objfile_observer to: if (objfile == nullptr) { for (inferior *inf : all_inferiors ()) { if (inf->pspace == current_program_space) invalidate_auxv_cache_inf (inf); } } With this change we now correctly clear the auxv cache for the correct inferiors, and GDB no longer needs to refill the cache at an inconvenient time, this avoids the crash we were seeing. And finally, we reach problem #4. Inspired by the observation that using the current_inferior from within the ~program_space function was not correct, I added some debug to see if current_inferior() was called anywhere else (below ~program_space), and the answer is yes, it's called a often. Mostly the culprit is GDB doing: current_inferior ()->top_target ()-> .... But I think all of these calls are most likely doing the wrong thing, and only work because the top target in all these cases is shared between all inferiors, e.g. it's the native target, or the remote target for all inferiors. But if we had a truly multi-connection setup, then we might start to see odd behaviour. Problem #1 I'm just ignoring for now, I guess at some point we might run into this again, and then we'd need to solve this. But in this case I wasn't sure what a "good" solution would look like. We need the auxv data in order to implement the linux_is_uclinux() function. If we can't get the auxv data then what should we do, assume yes, or assume no? The right answer would probably be to propagate the error back up the stack, but then we reach ~program_space, and throwing exceptions from a destructor is problematic, so we'd need to catch and deal at this point. The linux_is_uclinux() call is made from within gdbarch_has_shared_address_space(), which is used like: if (!gdbarch_has_shared_address_space (target_gdbarch ())) delete this->aspace; So, we would have to choose; delete the address space or not. If we delete it on error, then we might delete an address space that is shared within another program space. If we don't delete the address space, then we might leak it. Neither choice is great. A better solution might be to have the address spaces be reference counted, then we could remove the gdbarch_has_shared_address_space call completely, and just rely on the reference count to auto-delete the address space when appropriate. The solution for problem #2 I already hinted at above, we should have a new target_can_delete_inferiors() call, which should be called from prune_inferiors, this would prevent GDB from trying to delete inferiors when a (remote) target is in a state where we know it can't delete the inferior. Deleting an inferior often (always?) requires sending packets to the remote, and if the remote is waiting for a stop reply then this will never work, so the pruning should be deferred in this case. The solution for problem #3 is included in this commit. And, for problem #4, I'm not sure what the right solution is. Maybe delete_inferior should ensure the inferior to be deleted is in place when ~program_space is called? But that seems a little weird, as the current inferior would, in theory, still be using the current program_space... Anyway, after this commit, the gdb.python/py-progspace-events.exp test now passes when run with the native-extended-remote board. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30935 Approved-By: Simon Marchi <[email protected]> Change-Id: I41f0e6e2d7ecc1e5e55ec170f37acd4052f46eaf
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
While itfocusing two threads, interrupt, continue and interrupt again.
The text was updated successfully, but these errors were encountered: