This repository has been archived by the owner on Aug 17, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 234
/riscv-binutils-gdb/sim/riscv/sim-main.c:93:21: error: 'CLOCK_BOOTTIME' undeclared (first use in this function) if (clock_gettime (CLOCK_BOOTTIME, &ts) == 0) #21
Comments
palmer-dabbelt merged commit 1a49dc3 into riscv:riscv-binutils-2.27 |
palmer-dabbelt
pushed a commit
that referenced
this issue
Mar 13, 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.
palmer-dabbelt
pushed 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.
timsifive
pushed a commit
that referenced
this issue
Jul 3, 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.
ilg-ul
pushed a commit
to xpack-dev-tools/riscv-binutils-gdb
that referenced
this issue
Apr 17, 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 riscvarchive#1 0x55b6edf6c2f7 in std::char_traits<char>::length(char const*) /usr/include/c++/8.2.1/bits/char_traits.h:320 riscvarchive#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 riscvarchive#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 riscvarchive#4 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 riscvarchive#5 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#6 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#7 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#8 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#9 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#10 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#12 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#13 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#14 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#15 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#16 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#17 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#18 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#19 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#20 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#21 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#22 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#23 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#24 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#25 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 riscvarchive#26 0x7fed88ad8222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) riscvarchive#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 riscvarchive#1 0x55b6edfe12df in xfree<char> /home/simark/src/binutils-gdb/gdb/common/common-utils.h:60 riscvarchive#2 0x55b6edfea675 in gdb::xfree_deleter<char>::operator()(char*) const /home/simark/src/binutils-gdb/gdb/common/gdb_unique_ptr.h:34 riscvarchive#3 0x55b6edfe532c in std::unique_ptr<char, gdb::xfree_deleter<char> >::reset(char*) /usr/include/c++/8.2.1/bits/unique_ptr.h:382 riscvarchive#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 riscvarchive#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 riscvarchive#6 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 riscvarchive#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 riscvarchive#8 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 riscvarchive#9 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#10 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#11 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#12 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#13 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#14 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#16 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#17 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#18 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#19 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#20 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#21 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#22 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#23 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#24 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#25 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#26 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#27 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#28 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#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 riscvarchive#1 0x7fed88af983f in realpath@@GLIBC_2.3 (/usr/lib/libc.so.6+0x4583f) riscvarchive#2 0x7fed899dbbbc in __interceptor_canonicalize_file_name /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:3297 riscvarchive#3 0x55b6ee376a03 in gdb_realpath(char const*) /home/simark/src/binutils-gdb/gdb/common/pathstuff.c:72 riscvarchive#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 riscvarchive#5 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 riscvarchive#6 0x55b6ef0a0f12 in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1270 riscvarchive#7 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#8 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#9 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#10 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#11 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#12 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#14 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#15 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#16 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#17 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#18 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#19 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#20 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#21 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#22 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#23 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#24 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#25 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#26 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#27 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 riscvarchive#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.
jim-wilson
pushed a commit
that referenced
this issue
May 16, 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.
kito-cheng
pushed a commit
to kito-cheng/riscv-binutils-gdb
that referenced
this issue
Jul 1, 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) riscvarchive#1 0x5e7a0d in typename_concat gdb/dwarf2read.c:22661 riscvarchive#2 0x5c6437 in partial_die_full_name gdb/dwarf2read.c:8876 riscvarchive#3 0x5c6555 in add_partial_symbol gdb/dwarf2read.c:8893 riscvarchive#4 0x5c6ecf in add_partial_subprogram gdb/dwarf2read.c:9156 riscvarchive#5 0x5c5e90 in scan_partial_symbols gdb/dwarf2read.c:8668 riscvarchive#6 0x5c6c0a in add_partial_namespace gdb/dwarf2read.c:9081 riscvarchive#7 0x5c5f99 in scan_partial_symbols gdb/dwarf2read.c:8702 riscvarchive#8 0x5c48b6 in process_psymtab_comp_unit_reader gdb/dwarf2read.c:8056 riscvarchive#9 0x5c3c1f in init_cutu_and_read_dies gdb/dwarf2read.c:7689 riscvarchive#10 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 riscvarchive#11 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 riscvarchive#12 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 riscvarchive#13 0x612359 in read_psyms gdb/elfread.c:1311 riscvarchive#14 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 riscvarchive#15 0x867d7b in read_symbols gdb/symfile.c:821 riscvarchive#16 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 riscvarchive#17 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 riscvarchive#18 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 riscvarchive#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 riscvarchive#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 riscvarchive#21 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 riscvarchive#22 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 riscvarchive#23 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 riscvarchive#24 0x71f10e in catch_command_errors gdb/main.c:372 riscvarchive#25 0x71ff5f in captured_main_1 gdb/main.c:1043 riscvarchive#26 0x72045d in captured_main gdb/main.c:1163 riscvarchive#27 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 riscvarchive#28 0x40fd7d in main gdb/gdb.c:32 riscvarchive#29 0x7f137e300f49 in __libc_start_main (/lib64/libc.so.6+0x20f49) riscvarchive#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) riscvarchive#1 0x435e44 in xfree<void> gdb/common/common-utils.h:60 riscvarchive#2 0xa82c25 in call_freefun libiberty/obstack.c:103 riscvarchive#3 0xa83098 in _obstack_free libiberty/obstack.c:280 riscvarchive#4 0x4367da in auto_obstack::~auto_obstack() gdb/gdb_obstack.h:101 riscvarchive#5 0x5ed72c in dwarf2_cu::~dwarf2_cu() gdb/dwarf2read.c:25341 riscvarchive#6 0x5fb5bb in std::default_delete<dwarf2_cu>::operator()(dwarf2_cu*) const \ /usr/include/c++/7/bits/unique_ptr.h:78 riscvarchive#7 0x5f7334 in std::unique_ptr<dwarf2_cu, \ std::default_delete<dwarf2_cu> >::~unique_ptr() \ /usr/include/c++/7/bits/unique_ptr.h:268 riscvarchive#8 0x5c3ce5 in init_cutu_and_read_dies gdb/dwarf2read.c:7624 riscvarchive#9 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 riscvarchive#10 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 riscvarchive#11 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 riscvarchive#12 0x612359 in read_psyms gdb/elfread.c:1311 riscvarchive#13 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 riscvarchive#14 0x867d7b in read_symbols gdb/symfile.c:821 riscvarchive#15 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 riscvarchive#16 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 riscvarchive#17 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 riscvarchive#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 riscvarchive#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 riscvarchive#20 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 riscvarchive#21 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 riscvarchive#22 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 riscvarchive#23 0x71f10e in catch_command_errors gdb/main.c:372 riscvarchive#24 0x71ff5f in captured_main_1 gdb/main.c:1043 riscvarchive#25 0x72045d in captured_main gdb/main.c:1163 riscvarchive#26 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 riscvarchive#27 0x40fd7d in main gdb/gdb.c:32 riscvarchive#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) riscvarchive#1 0x5114b5 in xmalloc gdb/common/common-utils.c:44 riscvarchive#2 0xa82bd5 in call_chunkfun libiberty/obstack.c:94 riscvarchive#3 0xa82eda in _obstack_newchunk libiberty/obstack.c:206 riscvarchive#4 0x477310 in allocate_on_obstack::operator new(unsigned long, obstack*) \ gdb/gdb_obstack.h:117 riscvarchive#5 0x5dea8c in load_partial_dies gdb/dwarf2read.c:18571 riscvarchive#6 0x5c487f in process_psymtab_comp_unit_reader gdb/dwarf2read.c:8054 riscvarchive#7 0x5c3c1f in init_cutu_and_read_dies gdb/dwarf2read.c:7689 riscvarchive#8 0x5c4c03 in process_psymtab_comp_unit gdb/dwarf2read.c:8140 riscvarchive#9 0x5c58a2 in dwarf2_build_psymtabs_hard gdb/dwarf2read.c:8500 riscvarchive#10 0x5c0d03 in dwarf2_build_psymtabs(objfile*) gdb/dwarf2read.c:6337 riscvarchive#11 0x612359 in read_psyms gdb/elfread.c:1311 riscvarchive#12 0x798a64 in require_partial_symbols(objfile*, int) gdb/psymtab.c:115 riscvarchive#13 0x867d7b in read_symbols gdb/symfile.c:821 riscvarchive#14 0x8683d9 in syms_from_objfile_1 gdb/symfile.c:1000 riscvarchive#15 0x8684a1 in syms_from_objfile gdb/symfile.c:1017 riscvarchive#16 0x868873 in symbol_file_add_with_addrs gdb/symfile.c:1124 riscvarchive#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 riscvarchive#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 riscvarchive#19 0x868c39 in symbol_file_add_main_1 gdb/symfile.c:1240 riscvarchive#20 0x868bd0 in symbol_file_add_main(char const*, \ enum_flags<symfile_add_flag>) gdb/symfile.c:1231 riscvarchive#21 0x71f1b2 in symbol_file_add_main_adapter gdb/main.c:395 riscvarchive#22 0x71f10e in catch_command_errors gdb/main.c:372 riscvarchive#23 0x71ff5f in captured_main_1 gdb/main.c:1043 riscvarchive#24 0x72045d in captured_main gdb/main.c:1163 riscvarchive#25 0x7204c8 in gdb_main(captured_main_args*) gdb/main.c:1188 riscvarchive#26 0x40fd7d in main gdb/gdb.c:32 riscvarchive#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.
kito-cheng
pushed a commit
to kito-cheng/riscv-binutils-gdb
that referenced
this issue
Jul 1, 2019
When compiling gdb with '-lasan -fsanitizer=address' and running tests with 'export ASAN_OPTIONS="detect_leaks=0:alloc_dealloc_mismatch=0"', I run into: ... ERROR: GDB process no longer exists UNRESOLVED: gdb.linespec/cpls-abi-tag.exp: \ test_abi_tag: completion: at tag: tab complete "b test_abi_tag_function[abi:" ... In more detail: ... ==3637==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address \ 0x7fff5952bbdd at pc 0x000000fe5c57 bp 0x7fff5952af30 sp 0x7fff5952af28 READ of size 1 at 0x7fff5952bbdd thread T0 #0 0xfe5c56 in linespec_lexer_lex_string src/gdb/linespec.c:727 riscvarchive#1 0xfe7473 in linespec_lexer_lex_one src/gdb/linespec.c:946 riscvarchive#2 0xfe799d in linespec_lexer_consume_token src/gdb/linespec.c:982 riscvarchive#3 0xff446d in parse_linespec src/gdb/linespec.c:2564 riscvarchive#4 0xff78be in linespec_complete(completion_tracker&, char const*, \ symbol_name_match_type) src/gdb/linespec.c:2961 riscvarchive#5 0xb9299c in complete_address_and_linespec_locations \ src/gdb/completer.c:573 riscvarchive#6 0xb93e90 in location_completer(cmd_list_element*, completion_tracker&, \ char const*, char const*) src/gdb/completer.c:919 riscvarchive#7 0xb940c5 in location_completer_handle_brkchars src/gdb/completer.c:956 riscvarchive#8 0xb957ec in complete_line_internal_normal_command \ src/gdb/completer.c:1208 riscvarchive#9 0xb96507 in complete_line_internal_1 src/gdb/completer.c:1430 riscvarchive#10 0xb965c2 in complete_line_internal src/gdb/completer.c:1449 riscvarchive#11 0xb98630 in gdb_completion_word_break_characters_throw \ src/gdb/completer.c:1862 riscvarchive#12 0xb98838 in gdb_completion_word_break_characters() \ src/gdb/completer.c:1897 riscvarchive#13 0x16c6362 in _rl_find_completion_word src/readline/complete.c:943 riscvarchive#14 0x16ca8d0 in rl_complete_internal src/readline/complete.c:1843 riscvarchive#15 0x16c460c in rl_complete src/readline/complete.c:408 riscvarchive#16 0x16b3368 in _rl_dispatch_subseq src/readline/readline.c:774 riscvarchive#17 0x16b3092 in _rl_dispatch src/readline/readline.c:724 riscvarchive#18 0x16b2939 in readline_internal_char src/readline/readline.c:552 riscvarchive#19 0x16f1fb0 in rl_callback_read_char src/readline/callback.c:201 riscvarchive#20 0xddc5a1 in gdb_rl_callback_read_char_wrapper_noexcept \ src/gdb/event-top.c:175 riscvarchive#21 0xddc773 in gdb_rl_callback_read_char_wrapper src/gdb/event-top.c:192 riscvarchive#22 0xddd9f5 in stdin_event_handler(int, void*) src/gdb/event-top.c:514 riscvarchive#23 0xdd7d8f in handle_file_event src/gdb/event-loop.c:731 riscvarchive#24 0xdd8607 in gdb_wait_for_event src/gdb/event-loop.c:857 riscvarchive#25 0xdd629c in gdb_do_one_event() src/gdb/event-loop.c:321 riscvarchive#26 0xdd6344 in start_event_loop() src/gdb/event-loop.c:370 riscvarchive#27 0x10a7715 in captured_command_loop src/gdb/main.c:331 riscvarchive#28 0x10aa548 in captured_main src/gdb/main.c:1173 riscvarchive#29 0x10aa5d8 in gdb_main(captured_main_args*) src/gdb/main.c:1188 riscvarchive#30 0x87bd35 in main src/gdb/gdb.c:32 riscvarchive#31 0x7fb0364c6f89 in __libc_start_main (/lib64/libc.so.6+0x20f89) riscvarchive#32 0x87bb49 in _start (build/gdb/gdb+0x87bb49) Address 0x7fff5952bbdd is located in stack of thread T0 at offset 557 in frame #0 0xb93702 in location_completer(cmd_list_element*, completion_tracker&, \ char const*, char const*) src/gdb/completer.c:831 This frame has 4 object(s): [32, 40) 'copy' [96, 104) 'location' [160, 168) 'text' [224, 256) 'completion_info' <== Memory access at offset 557 overflows \ this variable HINT: this may be a false positive if your program uses some custom stack \ unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: dynamic-stack-buffer-overflow \ src/gdb/linespec.c:727 in linespec_lexer_lex_string Shadow bytes around the buggy address: 0x10006b29d720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10006b29d730: 00 00 00 00 00 00 f1 f1 f1 f1 00 f2 f2 f2 f2 f2 0x10006b29d740: f2 f2 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f2 f2 0x10006b29d750: f2 f2 00 00 00 00 f3 f3 f3 f3 00 00 00 00 00 00 0x10006b29d760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x10006b29d770: 00 00 00 00 ca ca ca ca 00 00 00[05]cb cb cb cb 0x10006b29d780: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 0x10006b29d790: 00 f2 f2 f2 f2 f2 f2 f2 00 f2 f2 f2 f3 f3 f3 f3 0x10006b29d7a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10006b29d7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10006b29d7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==3637==ABORTING ... The problem happens in linespec_lexer_lex_string when lexing "b test_abi_tag_function[abi:\0" (using a notation where we make the implicit terminating \0 explicit). We arrrive here with (PARSER_STREAM (parser)) == ":\0": ... /* Do not tokenize ABI tags such as "[abi:cxx11]". */ else if (PARSER_STREAM (parser) - start > 4 && startswith (PARSER_STREAM (parser) - 4, "[abi")) ++(PARSER_STREAM (parser)); ... and consume ':', after which we end up here and consume '\0': ... /* Advance the stream. */ ++(PARSER_STREAM (parser)); ... after which (PARSER_STREAM (parser)) points past the end of the string. Fix this by removing the first "++(PARSER_STREAM (parser))", and add an assert to the second one to detect moving past the end-of-string. Build and tested on x86_64-linux. gdb/ChangeLog: 2019-06-10 Tom de Vries <[email protected]> PR gdb/24611 * linespec.c (linespec_lexer_lex_string): Remove incorrect "++(PARSER_STREAM (parser))" for "[abi"-prefixed colon. Add assert.
kito-cheng
pushed a commit
to kito-cheng/riscv-binutils-gdb
that referenced
this issue
Jul 1, 2019
When compiling gdb with '-lasan -fsanitizer=address' and running tests with: - export ASAN_OPTIONS="detect_leaks=0:alloc_dealloc_mismatch=0", - target board cc-with-gdb-index, - the "[gdb/testsuite] Fix gdb.base/break-probes.exp with native-gdbserver" commit reverted to avoid running into PR24617, we get with gdb.arch/amd64-init-x87-values.exp: ... ==31229==ERROR: AddressSanitizer: heap-buffer-overflow on address \ 0x62500098c93c at pc 0x000000bcc748 bp 0x7ffe39487660 sp 0x7ffe39487658 READ of size 1 at 0x62500098c93c thread T0 #0 0xbcc747 in cp_find_first_component_aux src/gdb/cp-support.c:999 riscvarchive#1 0xbcc6e9 in cp_find_first_component(char const*) \ src/gdb/cp-support.c:977 riscvarchive#2 0xcc2cf3 in mapped_index_base::build_name_components() \ src/gdb/dwarf2read.c:4499 riscvarchive#3 0xcc3322 in dw2_expand_symtabs_matching_symbol src/gdb/dwarf2read.c:4552 riscvarchive#4 0xcc817f in dw2_expand_symtabs_matching src/gdb/dwarf2read.c:5228 riscvarchive#5 0xfe8f48 in iterate_over_all_matching_symtabs src/gdb/linespec.c:1147 riscvarchive#6 0x1003506 in add_matching_symbols_to_info src/gdb/linespec.c:4413 riscvarchive#7 0xffe21b in find_function_symbols src/gdb/linespec.c:3886 riscvarchive#8 0xffe4a2 in find_linespec_symbols src/gdb/linespec.c:3914 riscvarchive#9 0xfee3ad in linespec_parse_basic src/gdb/linespec.c:1865 riscvarchive#10 0xff5128 in parse_linespec src/gdb/linespec.c:2655 riscvarchive#11 0xff8872 in event_location_to_sals src/gdb/linespec.c:3150 riscvarchive#12 0xff90a8 in decode_line_full(event_location const*, int, \ program_space*, symtab*, int, linespec_result*, \ char const*, char const*) src/gdb/linespec.c:3230 riscvarchive#13 0x9ce449 in parse_breakpoint_sals src/gdb/breakpoint.c:9057 riscvarchive#14 0x9ea022 in create_sals_from_location_default src/gdb/breakpoint.c:13708 riscvarchive#15 0x9e2c1f in bkpt_create_sals_from_location src/gdb/breakpoint.c:12514 riscvarchive#16 0x9cff06 in create_breakpoint(gdbarch*, event_location const*, \ char const*, int, char const*, int, int, bptype, int, \ auto_boolean, breakpoint_ops const*, int, int, int, \ unsigned int) src/gdb/breakpoint.c:9238 riscvarchive#17 0x9d114a in break_command_1 src/gdb/breakpoint.c:9402 riscvarchive#18 0x9d1b60 in break_command(char const*, int) src/gdb/breakpoint.c:9473 riscvarchive#19 0xac96aa in do_const_cfunc src/gdb/cli/cli-decode.c:106 riscvarchive#20 0xad0e5a in cmd_func(cmd_list_element*, char const*, int) \ src/gdb/cli/cli-decode.c:1892 riscvarchive#21 0x15226f6 in execute_command(char const*, int) src/gdb/top.c:630 riscvarchive#22 0xddde37 in command_handler(char const*) src/gdb/event-top.c:586 riscvarchive#23 0xdde7c1 in command_line_handler(std::unique_ptr<char, \ gdb::xfree_deleter<char> >&&) src/gdb/event-top.c:773 riscvarchive#24 0xddc9e8 in gdb_rl_callback_handler src/gdb/event-top.c:217 riscvarchive#25 0x16f2198 in rl_callback_read_char src/readline/callback.c:220 riscvarchive#26 0xddc5a1 in gdb_rl_callback_read_char_wrapper_noexcept \ src/gdb/event-top.c:175 riscvarchive#27 0xddc773 in gdb_rl_callback_read_char_wrapper src/gdb/event-top.c:192 riscvarchive#28 0xddd9f5 in stdin_event_handler(int, void*) src/gdb/event-top.c:514 riscvarchive#29 0xdd7d8f in handle_file_event src/gdb/event-loop.c:731 riscvarchive#30 0xdd8607 in gdb_wait_for_event src/gdb/event-loop.c:857 riscvarchive#31 0xdd629c in gdb_do_one_event() src/gdb/event-loop.c:321 riscvarchive#32 0xdd6344 in start_event_loop() src/gdb/event-loop.c:370 riscvarchive#33 0x10a7715 in captured_command_loop src/gdb/main.c:331 riscvarchive#34 0x10aa548 in captured_main src/gdb/main.c:1173 riscvarchive#35 0x10aa5d8 in gdb_main(captured_main_args*) src/gdb/main.c:1188 riscvarchive#36 0x87bd35 in main src/gdb/gdb.c:32 riscvarchive#37 0x7f16e1434f89 in __libc_start_main (/lib64/libc.so.6+0x20f89) riscvarchive#38 0x87bb49 in _start (build/gdb/gdb+0x87bb49) 0x62500098c93c is located 0 bytes to the right of 8252-byte region \ [0x62500098a900,0x62500098c93c) allocated by thread T0 here: #0 0x7f16e359a600 in malloc (/usr/lib64/libasan.so.5+0xeb600) riscvarchive#1 0x1742ddf in bfd_malloc src/bfd/libbfd.c:275 riscvarchive#2 0x1738824 in bfd_get_full_section_contents src/bfd/compress.c:253 riscvarchive#3 0xe30044 in gdb_bfd_map_section(bfd_section*, unsigned long*) \ src/gdb/gdb_bfd.c:704 riscvarchive#4 0xcb56bf in dwarf2_read_section(objfile*, dwarf2_section_info*) \ src/gdb/dwarf2read.c:2539 riscvarchive#5 0xd5bcd0 in get_gdb_index_contents_from_section<dwarf2_per_objfile> \ src/gdb/dwarf2read.c:6217 riscvarchive#6 0xd7fc7d in gdb::function_view<gdb::array_view<unsigned char const> \ (...) const src/gdb/common/function-view.h:284 riscvarchive#7 0xd7fddd in gdb::function_view<gdb::array_view<unsigned char const> \ (...) src/gdb/common/function-view.h:278 riscvarchive#8 0xd730cf in gdb::function_view<gdb::array_view<unsigned char const> \ (...) const src/gdb/common/function-view.h:247 riscvarchive#9 0xcbc7ee in dwarf2_read_gdb_index src/gdb/dwarf2read.c:3582 riscvarchive#10 0xcce731 in dwarf2_initialize_objfile(objfile*, dw_index_kind*) \ src/gdb/dwarf2read.c:6297 riscvarchive#11 0xdb88c4 in elf_symfile_read src/gdb/elfread.c:1256 riscvarchive#12 0x141262a in read_symbols src/gdb/symfile.c:798 riscvarchive#13 0x14140a7 in syms_from_objfile_1 src/gdb/symfile.c:1000 riscvarchive#14 0x1414393 in syms_from_objfile src/gdb/symfile.c:1017 riscvarchive#15 0x1414fb7 in symbol_file_add_with_addrs src/gdb/symfile.c:1124 riscvarchive#16 0x14159b7 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*) src/gdb/symfile.c:1203 riscvarchive#17 0x1415b6c in symbol_file_add(char const*, enum_flags<symfile_add_flag>, std::vector<other_sections, \ std::allocator<other_sections> >*, \ enum_flags<objfile_flag>) src/gdb/symfile.c:1216 riscvarchive#18 0x1415f2f in symbol_file_add_main_1 src/gdb/symfile.c:1240 riscvarchive#19 0x1418599 in symbol_file_command(char const*, int) \ src/gdb/symfile.c:1675 riscvarchive#20 0xde2fa6 in file_command src/gdb/exec.c:433 riscvarchive#21 0xac96aa in do_const_cfunc src/gdb/cli/cli-decode.c:106 riscvarchive#22 0xad0e5a in cmd_func(cmd_list_element*, char const*, int) \ src/gdb/cli/cli-decode.c:1892 riscvarchive#23 0x15226f6 in execute_command(char const*, int) src/gdb/top.c:630 riscvarchive#24 0xddde37 in command_handler(char const*) src/gdb/event-top.c:586 riscvarchive#25 0xdde7c1 in command_line_handler(std::unique_ptr<char, \ gdb::xfree_deleter<char> >&&) src/gdb/event-top.c:773 riscvarchive#26 0xddc9e8 in gdb_rl_callback_handler src/gdb/event-top.c:217 riscvarchive#27 0x16f2198 in rl_callback_read_char src/readline/callback.c:220 riscvarchive#28 0xddc5a1 in gdb_rl_callback_read_char_wrapper_noexcept \ src/gdb/event-top.c:175 riscvarchive#29 0xddc773 in gdb_rl_callback_read_char_wrapper src/gdb/event-top.c:192 SUMMARY: AddressSanitizer: heap-buffer-overflow src/gdb/cp-support.c:999 in \ cp_find_first_component_aux Shadow bytes around the buggy address: 0x0c4a801298d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a801298e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a801298f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a80129900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c4a80129910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c4a80129920: 00 00 00 00 00 00 00[04]fa fa fa fa fa fa fa fa 0x0c4a80129930: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a80129940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a80129950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a80129960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c4a80129970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==31229==ABORTING ... The problem happens as follows. The executable amd64-init-x87-values gets an index (due to target board cc-with-gdb-index), which looks as follows: ... Hex dump of section '.gdb_index': 0x00000000 08000000 18000000 28000000 28000000 ........(...(... 0x00000010 3c000000 3c200000 00000000 00000000 <...< .......... 0x00000020 2e000000 00000000 d4004000 00000000 ..........@..... 0x00000030 db004000 00000000 00000000 00000000 ..@............. 0x00000040 00000000 00000000 00000000 00000000 ................ 0x00000050 00000000 00000000 00000000 00000000 ................ ... more zeroes ... 0x00002010 00000000 00000000 00000000 00000000 ................ 0x00002020 00000000 00000000 00000000 00000000 ................ 0x00002030 00000000 00000000 00000000 ............ ... The structure of this index is: ... header : [0x0, 0x18) : size 0x18 culist : [0x18 ,0x28) : size 0x10 typesculist : [0x28, 0x28) : size 0x0 adress area : [0x28, 0x3c) : size 0x14 symbol table : [0x3c, 0x203c) : size 0x2000 constant pool: [0x203c, 0x203c): size 0x0 EOF : 0x203c ... Note that the symbol table consists entirely of empty slots (where an empty slot is a pair of 32-bit zeroes), and that the constant pool is empty. The problem happens here in mapped_index_base::build_name_components: ... auto count = this->symbol_name_count (); for (offset_type idx = 0; idx < count; idx++) { if (this->symbol_name_slot_invalid (idx)) continue; const char *name = this->symbol_name_at (idx); ... when accessing the slot at idx == 0 in the symbol table, symbol_name_slot_invalid returns false so we calculate name, which is calculated using 'constant_pool + symbol_table[idx].name', which means we get name == constant_pool. And given that the constant pool is empty, name now points past the memory allocated for the index, and when we access name[0] for the first time in cp_find_first_component_aux, we run into the heap-buffer-overflow. Fix this by fixing the definition of symbol_name_slot_invalid: ... - return bucket.name == 0 && bucket.vec; + return bucket.name == 0 && bucket.vec == 0; ... Tested on x86_64-linux. gdb/ChangeLog: 2019-06-10 Tom de Vries <[email protected]> PR gdb/24618 * dwarf2read.c (struct mapped_index::symbol_name_slot_invalid): Make sure an empty slot (defined by a 32-bit zero pair) is recognized as invalid.
kito-cheng
pushed a commit
to kito-cheng/riscv-binutils-gdb
that referenced
this issue
Jul 1, 2019
When compiling gdb with '-lasan -fsanitizer=address' and running tests with: - export ASAN_OPTIONS="detect_leaks=0:alloc_dealloc_mismatch=0", and - a target board using local-board.exp, which sets sysroot to "" we run into a heap-buffer-overflow in child_path for f.i. gdb.arch/amd64-byte: ... ==3997==ERROR: AddressSanitizer: heap-buffer-overflow on address \ 0x60200002abcf at pc 0x5602acdf6872 bp 0x7ffe5237a090 sp 0x7ffe5237a080 READ of size 1 at 0x60200002abcf thread T0 #0 0x5602acdf6871 in child_path(char const*, char const*) \ gdb/common/pathstuff.c:161 riscvarchive#1 0x5602adb06587 in find_separate_debug_file gdb/symfile.c:1483 riscvarchive#2 0x5602adb06f2f in find_separate_debug_file_by_debuglink[abi:cxx11](...) \ gdb/symfile.c:1563 riscvarchive#3 0x5602ad13b743 in elf_symfile_read gdb/elfread.c:1293 riscvarchive#4 0x5602adb01cfa in read_symbols gdb/symfile.c:798 riscvarchive#5 0x5602adb03769 in syms_from_objfile_1 gdb/symfile.c:1000 riscvarchive#6 0x5602adb039d0 in syms_from_objfile gdb/symfile.c:1017 riscvarchive#7 0x5602adb04551 in symbol_file_add_with_addrs gdb/symfile.c:1124 riscvarchive#8 0x5602adb04ebf in symbol_file_add_from_bfd(...) gdb/symfile.c:1204 riscvarchive#9 0x5602ada5a78d in solib_read_symbols(...) gdb/solib.c:695 riscvarchive#10 0x5602ada5bdae in solib_add(char const*, int, int) gdb/solib.c:1004 riscvarchive#11 0x5602ada49bcd in enable_break gdb/solib-svr4.c:2394 riscvarchive#12 0x5602ada4dae9 in svr4_solib_create_inferior_hook gdb/solib-svr4.c:3028 riscvarchive#13 0x5602ada5d4f1 in solib_create_inferior_hook(int) gdb/solib.c:1215 riscvarchive#14 0x5602ad347f66 in post_create_inferior(target_ops*, int) \ gdb/infcmd.c:467 riscvarchive#15 0x5602ad348b3c in run_command_1 gdb/infcmd.c:663 riscvarchive#16 0x5602ad348e55 in run_command gdb/infcmd.c:686 riscvarchive#17 0x5602acd7d32b in do_const_cfunc gdb/cli/cli-decode.c:106 riscvarchive#18 0x5602acd84bfe in cmd_func(cmd_list_element*, char const*, int) \ gdb/cli/cli-decode.c:1892 riscvarchive#19 0x5602adc62a90 in execute_command(char const*, int) gdb/top.c:630 riscvarchive#20 0x5602ad5053e6 in catch_command_errors gdb/main.c:372 riscvarchive#21 0x5602ad507eb1 in captured_main_1 gdb/main.c:1138 riscvarchive#22 0x5602ad5081ec in captured_main gdb/main.c:1163 riscvarchive#23 0x5602ad508281 in gdb_main(captured_main_args*) gdb/main.c:1188 riscvarchive#24 0x5602ac9ddc3a in main gdb/gdb.c:32 riscvarchive#25 0x7f582b56eb96 in __libc_start_main \ (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) riscvarchive#26 0x5602ac9dda09 in _start \ (/home/smarchi/build/binutils-gdb/gdb/gdb+0x19a2a09) 0x60200002abcf is located 1 bytes to the left of 1-byte region \ [0x60200002abd0,0x60200002abd1) allocated by thread T0 here: #0 0x7f582e0e4b50 in __interceptor_malloc \ (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50) riscvarchive#1 0x5602acdd3656 in xmalloc gdb/common/common-utils.c:44 riscvarchive#2 0x5602aefe17d1 in xstrdup libiberty/xstrdup.c:34 riscvarchive#3 0x5602acdf61f6 in gdb_realpath(char const*) gdb/common/pathstuff.c:80 riscvarchive#4 0x5602adb06278 in find_separate_debug_file gdb/symfile.c:1444 riscvarchive#5 0x5602adb06f2f in find_separate_debug_file_by_debuglink[abi:cxx11](...) \ gdb/symfile.c:1563 riscvarchive#6 0x5602ad13b743 in elf_symfile_read gdb/elfread.c:1293 riscvarchive#7 0x5602adb01cfa in read_symbols gdb/symfile.c:798 riscvarchive#8 0x5602adb03769 in syms_from_objfile_1 gdb/symfile.c:1000 riscvarchive#9 0x5602adb039d0 in syms_from_objfile gdb/symfile.c:1017 riscvarchive#10 0x5602adb04551 in symbol_file_add_with_addrs gdb/symfile.c:1124 riscvarchive#11 0x5602adb04ebf in symbol_file_add_from_bfd(...) gdb/solib.c:695 riscvarchive#13 0x5602ada5bdae in solib_add(char const*, int, int) gdb/solib.c:1004 riscvarchive#14 0x5602ada49bcd in enable_break gdb/solib-svr4.c:2394 riscvarchive#15 0x5602ada4dae9 in svr4_solib_create_inferior_hook gdb/solib-svr4.c:3028 riscvarchive#16 0x5602ada5d4f1 in solib_create_inferior_hook(int) gdb/solib.c:1215 riscvarchive#17 0x5602ad347f66 in post_create_inferior(target_ops*, int) \ gdb/infcmd.c:467 riscvarchive#18 0x5602ad348b3c in run_command_1 gdb/infcmd.c:663 riscvarchive#19 0x5602ad348e55 in run_command gdb/infcmd.c:686 riscvarchive#20 0x5602acd7d32b in do_const_cfunc gdb/cli/cli-decode.c:106 riscvarchive#21 0x5602acd84bfe in cmd_func(cmd_list_element*, char const*, int) \ gdb/cli/cli-decode.c:1892 riscvarchive#22 0x5602adc62a90 in execute_command(char const*, int) gdb/top.c:630 riscvarchive#23 0x5602ad5053e6 in catch_command_errors gdb/main.c:372 riscvarchive#24 0x5602ad507eb1 in captured_main_1 gdb/main.c:1138 riscvarchive#25 0x5602ad5081ec in captured_main gdb/main.c:1163 riscvarchive#26 0x5602ad508281 in gdb_main(captured_main_args*) gdb/main.c:1188 riscvarchive#27 0x5602ac9ddc3a in main gdb/gdb.c:32 riscvarchive#28 0x7f582b56eb96 in __libc_start_main \ (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) SUMMARY: AddressSanitizer: heap-buffer-overflow gdb/common/pathstuff.c:161 \ in child_path(char const*, char const*) Shadow bytes around the buggy address: 0x0c047fffd520: fa fa fd fd fa fa fd fd fa fa fd fa fa fa fd fa 0x0c047fffd530: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fffd540: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa 0x0c047fffd550: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa 0x0c047fffd560: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 00 00 =>0x0c047fffd570: fa fa 07 fa fa fa 00 fa fa[fa]01 fa fa fa fa fa 0x0c047fffd580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffd590: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffd5a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffd5b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fffd5c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==3997==ABORTING ... The direct cause is that child_path gets called with parent == "", so this test: ... if (IS_DIR_SEPARATOR (parent[parent_len - 1])) ... accesses parent[-1]. [ There is an open discussion (1) about whether an empty sysroot should indeed be represented internally as "". But this patch focuses on fixing the heap-buffer-overflow without any redesign. ] Fix this by guarding the test with 'parent_len > 0'. Note that the fix makes child_path behave the same for: - parent == "/" && child == "/foo" (returns "foo") - parent == "" and child == "/foo" (returns "foo"). Build and reg-tested on x86_64-linux. (1) https://sourceware.org/ml/gdb-patches/2019-05/msg00193.html gdb/ChangeLog: 2019-06-17 Tom de Vries <[email protected]> PR gdb/24617 * common/pathstuff.c (child_path): Make sure parent_len > 0 before accessing parent[parent_len - 1].
mablinov
pushed a commit
to mablinov/riscv-binutils-gdb
that referenced
this issue
Aug 8, 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 riscvarchive#1 0x55b6edf6c2f7 in std::char_traits<char>::length(char const*) /usr/include/c++/8.2.1/bits/char_traits.h:320 riscvarchive#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 riscvarchive#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 riscvarchive#4 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 riscvarchive#5 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#6 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#7 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#8 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#9 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#10 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#12 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#13 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#14 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#15 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#16 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#17 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#18 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#19 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#20 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#21 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#22 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#23 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#24 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#25 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 riscvarchive#26 0x7fed88ad8222 in __libc_start_main (/usr/lib/libc.so.6+0x24222) riscvarchive#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 riscvarchive#1 0x55b6edfe12df in xfree<char> /home/simark/src/binutils-gdb/gdb/common/common-utils.h:60 riscvarchive#2 0x55b6edfea675 in gdb::xfree_deleter<char>::operator()(char*) const /home/simark/src/binutils-gdb/gdb/common/gdb_unique_ptr.h:34 riscvarchive#3 0x55b6edfe532c in std::unique_ptr<char, gdb::xfree_deleter<char> >::reset(char*) /usr/include/c++/8.2.1/bits/unique_ptr.h:382 riscvarchive#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 riscvarchive#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 riscvarchive#6 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 riscvarchive#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 riscvarchive#8 0x55b6ef0a15cb in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1340 riscvarchive#9 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#10 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#11 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#12 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#13 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#14 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#16 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#17 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#18 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#19 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#20 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#21 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#22 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#23 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#24 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#25 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#26 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#27 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#28 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#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 riscvarchive#1 0x7fed88af983f in realpath@@GLIBC_2.3 (/usr/lib/libc.so.6+0x4583f) riscvarchive#2 0x7fed899dbbbc in __interceptor_canonicalize_file_name /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:3297 riscvarchive#3 0x55b6ee376a03 in gdb_realpath(char const*) /home/simark/src/binutils-gdb/gdb/common/pathstuff.c:72 riscvarchive#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 riscvarchive#5 0x55b6ef09f56a in open_source_file(symtab*) /home/simark/src/binutils-gdb/gdb/source.c:1069 riscvarchive#6 0x55b6ef0a0f12 in print_source_lines_base /home/simark/src/binutils-gdb/gdb/source.c:1270 riscvarchive#7 0x55b6ef0a2045 in print_source_lines(symtab*, int, int, enum_flags<print_source_lines_flag>) /home/simark/src/binutils-gdb/gdb/source.c:1415 riscvarchive#8 0x55b6ef112c87 in print_frame_info(frame_info*, int, print_what, int, int) /home/simark/src/binutils-gdb/gdb/stack.c:914 riscvarchive#9 0x55b6ef10e90d in print_stack_frame(frame_info*, int, print_what, int) /home/simark/src/binutils-gdb/gdb/stack.c:180 riscvarchive#10 0x55b6ee9592f8 in print_stop_location /home/simark/src/binutils-gdb/gdb/infrun.c:7853 riscvarchive#11 0x55b6ee95948f in print_stop_event(ui_out*) /home/simark/src/binutils-gdb/gdb/infrun.c:7870 riscvarchive#12 0x55b6ef34b962 in tui_on_normal_stop /home/simark/src/binutils-gdb/gdb/tui/tui-interp.c:98 riscvarchive#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 riscvarchive#14 0x55b6ee965415 in std::function<void (bpstats*, int)>::operator()(bpstats*, int) const /usr/include/c++/8.2.1/bits/std_function.h:687 riscvarchive#15 0x55b6ee962f1b in gdb::observers::observable<bpstats*, int>::notify(bpstats*, int) const /home/simark/src/binutils-gdb/gdb/common/observable.h:106 riscvarchive#16 0x55b6ee95a6e7 in normal_stop() /home/simark/src/binutils-gdb/gdb/infrun.c:8142 riscvarchive#17 0x55b6ee93f236 in fetch_inferior_event(void*) /home/simark/src/binutils-gdb/gdb/infrun.c:3782 riscvarchive#18 0x55b6ee8f2641 in inferior_event_handler(inferior_event_type, void*) /home/simark/src/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#19 0x55b6eea2a1f0 in handle_target_event /home/simark/src/binutils-gdb/gdb/linux-nat.c:4358 riscvarchive#20 0x55b6ee7045f1 in handle_file_event /home/simark/src/binutils-gdb/gdb/event-loop.c:733 riscvarchive#21 0x55b6ee704e89 in gdb_wait_for_event /home/simark/src/binutils-gdb/gdb/event-loop.c:859 riscvarchive#22 0x55b6ee7027b5 in gdb_do_one_event() /home/simark/src/binutils-gdb/gdb/event-loop.c:322 riscvarchive#23 0x55b6ee702907 in start_event_loop() /home/simark/src/binutils-gdb/gdb/event-loop.c:371 riscvarchive#24 0x55b6eeadfc16 in captured_command_loop /home/simark/src/binutils-gdb/gdb/main.c:331 riscvarchive#25 0x55b6eeae2ef9 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1174 riscvarchive#26 0x55b6eeae30c2 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1190 riscvarchive#27 0x55b6edf4fa89 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 riscvarchive#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.
mablinov
pushed a commit
to mablinov/riscv-binutils-gdb
that referenced
this issue
Aug 8, 2019
When: - building trunk gdb with '-fsanitize=address -lasan', - running gdb tests with "export ASAN_OPTIONS=detect_leaks=0", I run into a heap-buffer-overflow failure for gdb.base/utf8-identifiers.exp. In more detail, the libasan error report looks like this: ... ================================================================= ==22340==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000054a80 at pc 0x7fcd0306b4c9 bp 0x7fffb1a8d880 sp 0x7fffb1a8d030 READ of size 32766 at 0x619000054a80 thread T0 #0 0x7fcd0306b4c8 (/usr/lib64/libasan.so.4+0xae4c8) riscvarchive#1 0x15f12a1 in update_line /data/gdb_versions/devel/src/readline/display.c:1377 riscvarchive#2 0x15f03cb in rl_redisplay /data/gdb_versions/devel/src/readline/display.c:1204 riscvarchive#3 0x15bf932 in readline_internal_setup /data/gdb_versions/devel/src/readline/readline.c:394 riscvarchive#4 0x15fe723 in _rl_callback_newline /data/gdb_versions/devel/src/readline/callback.c:89 riscvarchive#5 0x15fe7ef in rl_callback_handler_install /data/gdb_versions/devel/src/readline/callback.c:102 riscvarchive#6 0xd7bce6 in gdb_rl_callback_handler_install(char const*) /data/gdb_versions/devel/src/gdb/event-top.c:319 riscvarchive#7 0xd7c0c6 in display_gdb_prompt(char const*) /data/gdb_versions/devel/src/gdb/event-top.c:409 riscvarchive#8 0xd7d6c1 in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /data/gdb_versions/devel/src/gdb/event-top.c:776 riscvarchive#9 0xd7b92a in gdb_rl_callback_handler /data/gdb_versions/devel/src/gdb/event-top.c:217 riscvarchive#10 0x15ff479 in rl_callback_read_char /data/gdb_versions/devel/src/readline/callback.c:220 riscvarchive#11 0xd7b4d5 in gdb_rl_callback_read_char_wrapper_noexcept /data/gdb_versions/devel/src/gdb/event-top.c:175 riscvarchive#12 0xd7b6b5 in gdb_rl_callback_read_char_wrapper /data/gdb_versions/devel/src/gdb/event-top.c:192 riscvarchive#13 0xd7c8aa in stdin_event_handler(int, void*) /data/gdb_versions/devel/src/gdb/event-top.c:514 riscvarchive#14 0xd76ca7 in handle_file_event /data/gdb_versions/devel/src/gdb/event-loop.c:731 riscvarchive#15 0xd7751f in gdb_wait_for_event /data/gdb_versions/devel/src/gdb/event-loop.c:857 riscvarchive#16 0xd7547e in gdb_do_one_event() /data/gdb_versions/devel/src/gdb/event-loop.c:321 riscvarchive#17 0xd75526 in start_event_loop() /data/gdb_versions/devel/src/gdb/event-loop.c:370 riscvarchive#18 0x101b04c in captured_command_loop /data/gdb_versions/devel/src/gdb/main.c:331 riscvarchive#19 0x101de73 in captured_main /data/gdb_versions/devel/src/gdb/main.c:1173 riscvarchive#20 0x101df03 in gdb_main(captured_main_args*) /data/gdb_versions/devel/src/gdb/main.c:1188 riscvarchive#21 0x872dba in main /data/gdb_versions/devel/src/gdb/gdb.c:32 riscvarchive#22 0x7fcd00f2ff49 in __libc_start_main (/lib64/libc.so.6+0x20f49) riscvarchive#23 0x872bc9 in _start (/data/gdb_versions/devel/build/gdb/gdb+0x872bc9) 0x619000054a80 is located 0 bytes to the right of 1024-byte region [0x619000054680,0x619000054a80) allocated by thread T0 here: #0 0x7fcd03099510 in malloc (/usr/lib64/libasan.so.4+0xdc510) riscvarchive#1 0xae0078 in xmalloc /data/gdb_versions/devel/src/gdb/common/common-utils.c:44 riscvarchive#2 0x15eaccb in init_line_structures /data/gdb_versions/devel/src/readline/display.c:458 riscvarchive#3 0x15eb4d8 in rl_redisplay /data/gdb_versions/devel/src/readline/display.c:526 riscvarchive#4 0x15bf932 in readline_internal_setup /data/gdb_versions/devel/src/readline/readline.c:394 riscvarchive#5 0x15fe723 in _rl_callback_newline /data/gdb_versions/devel/src/readline/callback.c:89 riscvarchive#6 0x15fe7ef in rl_callback_handler_install /data/gdb_versions/devel/src/readline/callback.c:102 riscvarchive#7 0xd7bce6 in gdb_rl_callback_handler_install(char const*) /data/gdb_versions/devel/src/gdb/event-top.c:319 riscvarchive#8 0xd7c0c6 in display_gdb_prompt(char const*) /data/gdb_versions/devel/src/gdb/event-top.c:409 riscvarchive#9 0xaa041b in cli_interp_base::pre_command_loop() /data/gdb_versions/devel/src/gdb/cli/cli-interp.c:286 riscvarchive#10 0xf5342a in interp_pre_command_loop(interp*) /data/gdb_versions/devel/src/gdb/interps.c:320 riscvarchive#11 0x101b047 in captured_command_loop /data/gdb_versions/devel/src/gdb/main.c:328 riscvarchive#12 0x101de73 in captured_main /data/gdb_versions/devel/src/gdb/main.c:1173 riscvarchive#13 0x101df03 in gdb_main(captured_main_args*) /data/gdb_versions/devel/src/gdb/main.c:1188 riscvarchive#14 0x872dba in main /data/gdb_versions/devel/src/gdb/gdb.c:32 riscvarchive#15 0x7fcd00f2ff49 in __libc_start_main (/lib64/libc.so.6+0x20f49) SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib64/libasan.so.4+0xae4c8) Shadow bytes around the buggy address: 0x0c3280002900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c3280002950:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280002960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c3280002970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c3280002990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c32800029a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==22340==ABORTING ... I've written an assert in rl_redisplay that formulates the error condition: ... @@ -1387,6 +1389,10 @@ rl_redisplay (void) cpos_adjusted = 0; + assert (last_lmargin + (_rl_screenwidth + visible_wrap_offset) + <= line_size); + assert (lmargin + (_rl_screenwidth + (lmargin ? 0 : wrap_offset)) + <= line_size); update_line (&visible_line[last_lmargin], &invisible_line[lmargin], 0, _rl_screenwidth + visible_wrap_offset, _rl_screenwidth + (lmargin ? 0 : wrap_offset), 0); ... which triggers without needing the address sanitizer (or even an executable), like this: ... $ TERM=dumb gdb -q -ex "set width 0" gdb: src/display.c:1393: rl_redisplay: Assertion `last_lmargin + (_rl_screenwidth + visible_wrap_offset) <= line_size' failed. Aborted (core dumped) ... The basic problem is this: visible_line and invisible_line have length line_size, but the update_line call assumes that line_size is at least _rl_screenwidth + 1. Executing "set width 0" sets _rl_screenwidth to 32766 but doesn't affect line_size, which is initialized to 1024. Fix this by ensuring in init_line_structures and rl_redisplay that line_size is at least _rl_screenwidth + 1. Tested on x86_64-linux. Reviewed by readline maintainer ( https://sourceware.org/ml/gdb-patches/2019-05/msg00566.html ). readline/ChangeLog.gdb: 2019-07-12 Tom de Vries <[email protected]> Chet Ramey <[email protected]> PR cli/24514 * readline/display.c (init_line_structures, rl_redisplay): Ensure line_size is at least _rl_screenwidth + 1.
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
May 14, 2020
There has been some breakage for aarch64-linux, arm-linux and s390-linux in terms of inline frame unwinding. There may be other targets, but these are the ones i'm aware of. The following testcases started to show numerous failures and trigger internal errors in GDB after commit 1009d92, "Find tailcall frames before inline frames". gdb.opt/inline-break.exp gdb.opt/inline-cmds.exp gdb.python/py-frame-inline.exp gdb.reverse/insn-reverse.exp The internal errors were of this kind: binutils-gdb/gdb/frame.c:579: internal-error: frame_id get_frame_id(frame_info*): Assertion `fi->level == 0' failed. After a lengthy investigation to try and find the cause of these assertions, it seems we're dealing with some fragile/poorly documented code to handle inline frames and we are attempting to unwind from this fragile section of code. Before commit 1009d92, the tailcall sniffer was invoked from dwarf2_frame_prev_register. By the time we invoke the dwarf2_frame_prev_register function, we've probably already calculated the frame id (via compute_frame_id). After said commit, the call to dwarf2_tailcall_sniffer_first was moved to dwarf2_frame_cache. This is very early in a frame creation process, and we're still calculating the frame ID (so compute_frame_id is in the call stack). This would be fine for regular frames, but the above testcases all deal with some inline frames. The particularity of inline frames is that their frame ID's depend on the previous frame's ID, and the previous frame's ID relies in the inline frame's registers. So it is a bit of a messy situation. We have comments in various parts of the code warning about some of these particularities. In the case of dwarf2_tailcall_sniffer_first, we attempt to unwind the PC, which goes through various functions until we eventually invoke frame_unwind_got_register. This function will eventually attempt to create a lazy value for a particular register, and this lazy value will require a valid frame ID. Since the inline frame doesn't have a valid frame ID yet (remember we're still calculating the previous frame's ID so we can tell what the inline frame ID is) we will call compute_frame_id for the inline frame (level 0). We'll eventually hit the assertion above, inside get_frame_id: -- /* If we haven't computed the frame id yet, then it must be that this is the current frame. Compute it now, and stash the result. The IDs of other frames are computed as soon as they're created, in order to detect cycles. See get_prev_frame_if_no_cycle. */ gdb_assert (fi->level == 0); -- It seems to me we shouldn't have reached this assertion without having the inline frame ID already calculated. In fact, it seems we even start recursing a bit when we invoke get_prev_frame_always within inline_frame_this_id. But a check makes us quit the recursion and proceed to compute the id. Here's the call stack for context: #0 get_prev_frame_always_1 (this_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:2109 RECURSION - riscvarchive#1 0x0000aaaaaae1d098 in get_prev_frame_always (this_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:2124 riscvarchive#2 0x0000aaaaaae95768 in inline_frame_this_id (this_frame=0xaaaaab85a670, this_cache=0xaaaaab85a688, this_id=0xaaaaab85a6d0) at ../../../repos/binutils-gdb/gdb/inline-frame.c:165 riscvarchive#3 0x0000aaaaaae1916c in compute_frame_id (fi=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:550 riscvarchive#4 0x0000aaaaaae19318 in get_frame_id (fi=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:582 riscvarchive#5 0x0000aaaaaae13480 in value_of_register_lazy (frame=0xaaaaab85a730, regnum=30) at ../../../repos/binutils-gdb/gdb/findvar.c:296 riscvarchive#6 0x0000aaaaaae16c00 in frame_unwind_got_register (frame=0xaaaaab85a730, regnum=30, new_regnum=30) at ../../../repos/binutils-gdb/gdb/frame-unwind.c:268 riscvarchive#7 0x0000aaaaaad52604 in dwarf2_frame_prev_register (this_frame=0xaaaaab85a730, this_cache=0xaaaaab85a748, regnum=30) at ../../../repos/binutils-gdb/gdb/dwarf2/frame.c:1296 riscvarchive#8 0x0000aaaaaae1ae68 in frame_unwind_register_value (next_frame=0xaaaaab85a730, regnum=30) at ../../../repos/binutils-gdb/gdb/frame.c:1229 riscvarchive#9 0x0000aaaaaae1b304 in frame_unwind_register_unsigned (next_frame=0xaaaaab85a730, regnum=30) at ../../../repos/binutils-gdb/gdb/frame.c:1320 riscvarchive#10 0x0000aaaaaab76574 in aarch64_dwarf2_prev_register (this_frame=0xaaaaab85a730, this_cache=0xaaaaab85a748, regnum=32) at ../../../repos/binutils-gdb/gdb/aarch64-tdep.c:1114 riscvarchive#11 0x0000aaaaaad52724 in dwarf2_frame_prev_register (this_frame=0xaaaaab85a730, this_cache=0xaaaaab85a748, regnum=32) at ../../../repos/binutils-gdb/gdb/dwarf2/frame.c:1316 riscvarchive#12 0x0000aaaaaae1ae68 in frame_unwind_register_value (next_frame=0xaaaaab85a730, regnum=32) at ../../../repos/binutils-gdb/gdb/frame.c:1229 riscvarchive#13 0x0000aaaaaae1b304 in frame_unwind_register_unsigned (next_frame=0xaaaaab85a730, regnum=32) at ../../../repos/binutils-gdb/gdb/frame.c:1320 riscvarchive#14 0x0000aaaaaae16a84 in default_unwind_pc (gdbarch=0xaaaaab81edc0, next_frame=0xaaaaab85a730) at ../../../repos/binutils-gdb/gdb/frame-unwind.c:223 riscvarchive#15 0x0000aaaaaae32124 in gdbarch_unwind_pc (gdbarch=0xaaaaab81edc0, next_frame=0xaaaaab85a730) at ../../../repos/binutils-gdb/gdb/gdbarch.c:3074 riscvarchive#16 0x0000aaaaaad4f15c in dwarf2_tailcall_sniffer_first (this_frame=0xaaaaab85a730, tailcall_cachep=0xaaaaab85a830, entry_cfa_sp_offsetp=0x0) at ../../../repos/binutils-gdb/gdb/dwarf2/frame-tailcall.c:388 riscvarchive#17 0x0000aaaaaad520c0 in dwarf2_frame_cache (this_frame=0xaaaaab85a730, this_cache=0xaaaaab85a748) at ../../../repos/binutils-gdb/gdb/dwarf2/frame.c:1190 riscvarchive#18 0x0000aaaaaad52204 in dwarf2_frame_this_id (this_frame=0xaaaaab85a730, this_cache=0xaaaaab85a748, this_id=0xaaaaab85a790) at ../../../repos/binutils-gdb/gdb/dwarf2/frame.c:1218 riscvarchive#19 0x0000aaaaaae1916c in compute_frame_id (fi=0xaaaaab85a730) at ../../../repos/binutils-gdb/gdb/frame.c:550 riscvarchive#20 0x0000aaaaaae1c958 in get_prev_frame_if_no_cycle (this_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:1927 riscvarchive#21 0x0000aaaaaae1cc44 in get_prev_frame_always_1 (this_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:2006 FIRST CALL - riscvarchive#22 0x0000aaaaaae1d098 in get_prev_frame_always (this_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:2124 riscvarchive#23 0x0000aaaaaae18f68 in skip_artificial_frames (frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:495 riscvarchive#24 0x0000aaaaaae193e8 in get_stack_frame_id (next_frame=0xaaaaab85a670) at ../../../repos/binutils-gdb/gdb/frame.c:596 riscvarchive#25 0x0000aaaaaae87a54 in process_event_stop_test (ecs=0xffffffffefc8) at ../../../repos/binutils-gdb/gdb/infrun.c:6857 riscvarchive#26 0x0000aaaaaae86bdc in handle_signal_stop (ecs=0xffffffffefc8) at ../../../repos/binutils-gdb/gdb/infrun.c:6381 riscvarchive#27 0x0000aaaaaae84fd0 in handle_inferior_event (ecs=0xffffffffefc8) at ../../../repos/binutils-gdb/gdb/infrun.c:5578 riscvarchive#28 0x0000aaaaaae81588 in fetch_inferior_event (client_data=0x0) at ../../../repos/binutils-gdb/gdb/infrun.c:4020 riscvarchive#29 0x0000aaaaaae5f7fc in inferior_event_handler (event_type=INF_REG_EVENT, client_data=0x0) at ../../../repos/binutils-gdb/gdb/inf-loop.c:43 riscvarchive#30 0x0000aaaaaae8d768 in infrun_async_inferior_event_handler (data=0x0) at ../../../repos/binutils-gdb/gdb/infrun.c:9377 riscvarchive#31 0x0000aaaaaabff970 in check_async_event_handlers () at ../../../repos/binutils-gdb/gdb/async-event.c:291 riscvarchive#32 0x0000aaaaab27cbec in gdb_do_one_event () at ../../../repos/binutils-gdb/gdbsupport/event-loop.cc:194 riscvarchive#33 0x0000aaaaaaef1894 in start_event_loop () at ../../../repos/binutils-gdb/gdb/main.c:356 riscvarchive#34 0x0000aaaaaaef1a04 in captured_command_loop () at ../../../repos/binutils-gdb/gdb/main.c:416 riscvarchive#35 0x0000aaaaaaef3338 in captured_main (data=0xfffffffff1f0) at ../../../repos/binutils-gdb/gdb/main.c:1254 riscvarchive#36 0x0000aaaaaaef33a0 in gdb_main (args=0xfffffffff1f0) at ../../../repos/binutils-gdb/gdb/main.c:1269 riscvarchive#37 0x0000aaaaaab6e0dc in main (argc=6, argv=0xfffffffff348) at ../../../repos/binutils-gdb/gdb/gdb.c:32 The following patch addresses this by using a function that unwinds the PC from the next (inline) frame directly as opposed to creating a lazy value that is bound to the next frame's ID (still not computed). gdb/ChangeLog: 2020-04-23 Luis Machado <[email protected]> * dwarf2/frame-tailcall.c (dwarf2_tailcall_sniffer_first): Use get_frame_register instead of gdbarch_unwind_pc.
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Oct 6, 2020
…, part 1 Running the testsuite against an Asan-enabled build of GDB makes gdb.base/multi-target.exp expose this bug. scoped_restore_current_thread's ctor calls get_frame_id to record the selected frame's ID to restore later. If the frame ID hasn't been computed yet, it will be computed on the spot, and that will usually require accessing the target's memory and registers, which requires remote accesses. If the remote connection closes while we're computing the frame ID, the remote target exits its inferiors, unpushes itself, and throws a TARGET_CLOSE_ERROR error. If that happens, GDB can currently crash, here: > ==18555==ERROR: AddressSanitizer: heap-use-after-free on address 0x621004670aa8 at pc 0x0000007ab125 bp 0x7ffdecaecd20 sp 0x7ffdecaecd10 > READ of size 4 at 0x621004670aa8 thread T0 > #0 0x7ab124 in dwarf2_frame_this_id src/binutils-gdb/gdb/dwarf2/frame.c:1228 > riscvarchive#1 0x983ec5 in compute_frame_id src/binutils-gdb/gdb/frame.c:550 > riscvarchive#2 0x9841ee in get_frame_id(frame_info*) src/binutils-gdb/gdb/frame.c:582 > riscvarchive#3 0x1093faa in scoped_restore_current_thread::scoped_restore_current_thread() src/binutils-gdb/gdb/thread.c:1462 > riscvarchive#4 0xaee5ba in fetch_inferior_event(void*) src/binutils-gdb/gdb/infrun.c:3968 > riscvarchive#5 0xaa990b in inferior_event_handler(inferior_event_type, void*) src/binutils-gdb/gdb/inf-loop.c:43 > riscvarchive#6 0xea61b6 in remote_async_serial_handler src/binutils-gdb/gdb/remote.c:14161 > riscvarchive#7 0xefca8a in run_async_handler_and_reschedule src/binutils-gdb/gdb/ser-base.c:137 > riscvarchive#8 0xefcd23 in fd_event src/binutils-gdb/gdb/ser-base.c:188 > riscvarchive#9 0x15a7416 in handle_file_event src/binutils-gdb/gdbsupport/event-loop.cc:548 > riscvarchive#10 0x15a7c36 in gdb_wait_for_event src/binutils-gdb/gdbsupport/event-loop.cc:673 > riscvarchive#11 0x15a5dbb in gdb_do_one_event() src/binutils-gdb/gdbsupport/event-loop.cc:215 > riscvarchive#12 0xbfe62d in start_event_loop src/binutils-gdb/gdb/main.c:356 > riscvarchive#13 0xbfe935 in captured_command_loop src/binutils-gdb/gdb/main.c:416 > riscvarchive#14 0xc01d39 in captured_main src/binutils-gdb/gdb/main.c:1253 > riscvarchive#15 0xc01dc9 in gdb_main(captured_main_args*) src/binutils-gdb/gdb/main.c:1268 > riscvarchive#16 0x414ddd in main src/binutils-gdb/gdb/gdb.c:32 > riscvarchive#17 0x7f590110b82f in __libc_start_main ../csu/libc-start.c:291 > riscvarchive#18 0x414bd8 in _start (build/binutils-gdb/gdb/gdb+0x414bd8) What happens is that above, we're in dwarf2_frame_this_id, just after the dwarf2_frame_cache call. The "cache" variable that the dwarf2_frame_cache function returned is already stale. It's been released here, from within the dwarf2_frame_cache: (top-gdb) bt #0 reinit_frame_cache () at src/gdb/frame.c:1855 riscvarchive#1 0x00000000014ff7b0 in switch_to_no_thread () at src/gdb/thread.c:1301 riscvarchive#2 0x0000000000f66d3e in switch_to_inferior_no_thread (inf=0x615000338180) at src/gdb/inferior.c:626 riscvarchive#3 0x00000000012f3826 in remote_unpush_target (target=0x6170000c5900) at src/gdb/remote.c:5521 riscvarchive#4 0x00000000013097e0 in remote_target::readchar (this=0x6170000c5900, timeout=2) at src/gdb/remote.c:9137 riscvarchive#5 0x000000000130be4d in remote_target::getpkt_or_notif_sane_1 (this=0x6170000c5900, buf=0x6170000c5918, forever=0, expecting_notif=0, is_notif=0x0) at src/gdb/remote.c:9683 riscvarchive#6 0x000000000130c8ab in remote_target::getpkt_sane (this=0x6170000c5900, buf=0x6170000c5918, forever=0) at src/gdb/remote.c:9790 riscvarchive#7 0x000000000130bc0d in remote_target::getpkt (this=0x6170000c5900, buf=0x6170000c5918, forever=0) at src/gdb/remote.c:9623 riscvarchive#8 0x000000000130838e in remote_target::remote_read_bytes_1 (this=0x6170000c5900, memaddr=0x7fffffffcdc0, myaddr=0x6080000ad3bc "", len_units=64, unit_size=1, xfered_len_units=0x7fff6a29b9a0) at src/gdb/remote.c:8860 riscvarchive#9 0x0000000001308bd2 in remote_target::remote_read_bytes (this=0x6170000c5900, memaddr=0x7fffffffcdc0, myaddr=0x6080000ad3bc "", len=64, unit_size=1, xfered_len=0x7fff6a29b9a0) at src/gdb/remote.c:8987 riscvarchive#10 0x0000000001311ed1 in remote_target::xfer_partial (this=0x6170000c5900, object=TARGET_OBJECT_MEMORY, annex=0x0, readbuf=0x6080000ad3bc "", writebuf=0x0, offset=140737488342464, len=64, xfered_len=0x7fff6a29b9a0) at src/gdb/remote.c:10988 riscvarchive#11 0x00000000014ba969 in raw_memory_xfer_partial (ops=0x6170000c5900, readbuf=0x6080000ad3bc "", writebuf=0x0, memaddr=140737488342464, len=64, xfered_len=0x7fff6a29b9a0) at src/gdb/target.c:918 riscvarchive#12 0x00000000014bb720 in target_xfer_partial (ops=0x6170000c5900, object=TARGET_OBJECT_RAW_MEMORY, annex=0x0, readbuf=0x6080000ad3bc "", writebuf=0x0, offset=140737488342464, len=64, xfered_len=0x7fff6a29b9a0) at src/gdb/target.c:1148 riscvarchive#13 0x00000000014bc3b5 in target_read_partial (ops=0x6170000c5900, object=TARGET_OBJECT_RAW_MEMORY, annex=0x0, buf=0x6080000ad3bc "", offset=140737488342464, len=64, xfered_len=0x7fff6a29b9a0) at src/gdb/target.c:1380 riscvarchive#14 0x00000000014bc593 in target_read (ops=0x6170000c5900, object=TARGET_OBJECT_RAW_MEMORY, annex=0x0, buf=0x6080000ad3bc "", offset=140737488342464, len=64) at src/gdb/target.c:1419 riscvarchive#15 0x00000000014bbd4d in target_read_raw_memory (memaddr=0x7fffffffcdc0, myaddr=0x6080000ad3bc "", len=64) at src/gdb/target.c:1252 riscvarchive#16 0x0000000000bf27df in dcache_read_line (dcache=0x6060001eddc0, db=0x6080000ad3a0) at src/gdb/dcache.c:336 riscvarchive#17 0x0000000000bf2b72 in dcache_peek_byte (dcache=0x6060001eddc0, addr=0x7fffffffcdd8, ptr=0x6020001231b0 "") at src/gdb/dcache.c:403 riscvarchive#18 0x0000000000bf3103 in dcache_read_memory_partial (ops=0x6170000c5900, dcache=0x6060001eddc0, memaddr=0x7fffffffcdd8, myaddr=0x6020001231b0 "", len=8, xfered_len=0x7fff6a29bf20) at src/gdb/dcache.c:484 riscvarchive#19 0x00000000014bafe9 in memory_xfer_partial_1 (ops=0x6170000c5900, object=TARGET_OBJECT_STACK_MEMORY, readbuf=0x6020001231b0 "", writebuf=0x0, memaddr=140737488342488, len=8, xfered_len=0x7fff6a29bf20) at src/gdb/target.c:1034 riscvarchive#20 0x00000000014bb212 in memory_xfer_partial (ops=0x6170000c5900, object=TARGET_OBJECT_STACK_MEMORY, readbuf=0x6020001231b0 "", writebuf=0x0, memaddr=140737488342488, len=8, xfered_len=0x7fff6a29bf20) at src/gdb/target.c:1076 riscvarchive#21 0x00000000014bb6b3 in target_xfer_partial (ops=0x6170000c5900, object=TARGET_OBJECT_STACK_MEMORY, annex=0x0, readbuf=0x6020001231b0 "", writebuf=0x0, offset=140737488342488, len=8, xfered_len=0x7fff6a29bf20) at src/gdb/target.c:1133 riscvarchive#22 0x000000000164564d in read_value_memory (val=0x60f000029440, bit_offset=0, stack=1, memaddr=0x7fffffffcdd8, buffer=0x6020001231b0 "", length=8) at src/gdb/valops.c:956 riscvarchive#23 0x0000000001680fff in value_fetch_lazy_memory (val=0x60f000029440) at src/gdb/value.c:3764 riscvarchive#24 0x0000000001681efd in value_fetch_lazy (val=0x60f000029440) at src/gdb/value.c:3910 riscvarchive#25 0x0000000001676143 in value_optimized_out (value=0x60f000029440) at src/gdb/value.c:1411 riscvarchive#26 0x0000000000e0fcb8 in frame_register_unwind (next_frame=0x6210066bfde0, regnum=16, optimizedp=0x7fff6a29c200, unavailablep=0x7fff6a29c240, lvalp=0x7fff6a29c2c0, addrp=0x7fff6a29c300, realnump=0x7fff6a29c280, bufferp=0x7fff6a29c3a0 "@\304)j\377\177") at src/gdb/frame.c:1144 riscvarchive#27 0x0000000000e10418 in frame_unwind_register (next_frame=0x6210066bfde0, regnum=16, buf=0x7fff6a29c3a0 "@\304)j\377\177") at src/gdb/frame.c:1196 riscvarchive#28 0x0000000000f00431 in i386_unwind_pc (gdbarch=0x6210043d0110, next_frame=0x6210066bfde0) at src/gdb/i386-tdep.c:1969 riscvarchive#29 0x0000000000e39724 in gdbarch_unwind_pc (gdbarch=0x6210043d0110, next_frame=0x6210066bfde0) at src/gdb/gdbarch.c:3056 riscvarchive#30 0x0000000000c2ea90 in dwarf2_tailcall_sniffer_first (this_frame=0x6210066bfde0, tailcall_cachep=0x6210066bfee0, entry_cfa_sp_offsetp=0x0) at src/gdb/dwarf2/frame-tailcall.c:423 riscvarchive#31 0x0000000000c36bdb in dwarf2_frame_cache (this_frame=0x6210066bfde0, this_cache=0x6210066bfdf8) at src/gdb/dwarf2/frame.c:1198 riscvarchive#32 0x0000000000c36eb3 in dwarf2_frame_this_id (this_frame=0x6210066bfde0, this_cache=0x6210066bfdf8, this_id=0x6210066bfe40) at src/gdb/dwarf2/frame.c:1226 Note that remote_target::readchar in frame riscvarchive#4 throws TARGET_CLOSE_ERROR after the remote_unpush_target in frame riscvarchive#3 returns. The problem is that the TARGET_CLOSE_ERROR is swallowed by value_optimized_out in frame riscvarchive#25. If we fix that one, then we run into dwarf2_tailcall_sniffer_first swallowing the exception in frame riscvarchive#30 too. The attached patch fixes it by making those spots swallow fewer kinds of errors. gdb/ChangeLog: * frame-tailcall.c (dwarf2_tailcall_sniffer_first): Only swallow NO_ENTRY_VALUE_ERROR / MEMORY_ERROR / OPTIMIZED_OUT_ERROR / NOT_AVAILABLE_ERROR. * value.c (value_optimized_out): Only swallow MEMORY_ERROR / OPTIMIZED_OUT_ERROR / NOT_AVAILABLE_ERROR.
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Oct 6, 2020
gdb.base/corefile.exp is showing an unexpected failure and an unresolved testcase when testing against unix/-m32: (gdb) PASS: gdb.base/corefile.exp: attach: sanity check we see the core file attach 15741 gdb/dwarf2-frame.c:1009: internal-error: dwarf2_frame_cache* dwarf2_frame_cache(frame_info*, void**): Assertion `fde != NULL' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. Quit this debugging session? (y or n) FAIL: gdb.base/corefile.exp: attach: with core (GDB internal error) Resyncing due to internal error. This regressed with: From 5b6d1e4 Mon Sep 17 00:00:00 2001 From: Pedro Alves <[email protected]> Date: Fri, 10 Jan 2020 20:06:08 +0000 Subject: [PATCH] Multi-target support The assertion is here: #0 internal_error (file=0xbffffccb0 <error: Cannot access memory at address 0xbffffccb0>, line=0, fmt=0x555556327320 "en_US.UTF-8") at sr c/gdbsupport/errors.cc:51 riscvarchive#1 0x00005555557d4e45 in dwarf2_frame_cache (this_frame=0x55555672f950, this_cache=0x55555672f968) at src/gdb/dwarf2/frame.c:1013 riscvarchive#2 0x00005555557d5886 in dwarf2_frame_this_id (this_frame=0x55555672f950, this_cache=0x55555672f968, this_id=0x55555672f9b0) at src/gdb/d warf2/frame.c:1226 riscvarchive#3 0x00005555558b184e in compute_frame_id (fi=0x55555672f950) at src/gdb/frame.c:558 riscvarchive#4 0x00005555558b19b2 in get_frame_id (fi=0x55555672f950) at src/gdb/frame.c:588 riscvarchive#5 0x0000555555bda338 in scoped_restore_current_thread::scoped_restore_current_thread (this=0x7fffffffd0d8) at src/gdb/thread.c:1458 riscvarchive#6 0x00005555556ce41f in scoped_restore_current_pspace_and_thread::scoped_restore_current_pspace_and_thread (During symbol reading: .debug_line address at offset 0x1db2d3 is 0 [in module /home/pedro/gdb/cascais-builds/binutils-gdb/gdb/gdb] this=0x7fffffffd0d0) at src/gdb/progspace-and-thread.h:29 riscvarchive#7 0x0000555555898ea6 in remove_target_sections (owner=0x555556935550) at src/gdb/exec.c:798 riscvarchive#8 0x0000555555b700b6 in symfile_free_objfile (objfile=0x555556935550) at src/gdb/symfile.c:3742 riscvarchive#9 0x000055555565050e in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7fffffffd190 : 0x555556935550) at /usr/include/c++/9/bits/std_function.h:300 riscvarchive#10 0x0000555555a3053d in std::function<void (objfile*)>::operator()(objfile*) const (this=0x555556752a20, __args#0=0x555556935550) at /usr/include/c++/9/bits/std_function. h:688 riscvarchive#11 0x0000555555a2ff01 in gdb::observers::observable<objfile*>::notify (this=0x5555562eaa80 <gdb::observers::free_objfile>, args#0=0x555556935550) at /net/cascais.nfs/gdb/b inutils-gdb/src/gdb/../gdbsupport/observable.h:106 riscvarchive#12 0x0000555555a2c56a in objfile::~objfile (this=0x555556935550, __in_chrg=<optimized out>) at src/gdb/objfiles.c:521 riscvarchive#13 0x0000555555a31d46 in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x555556c1f6f0) at /usr/include/c++/9/bits/shared_ptr_base.h:377 riscvarchive#14 0x00005555556d3444 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x555556c1f6f0) at /usr/include/c++/9/bits/shared_ptr_base.h:155 riscvarchive#15 0x00005555556cec77 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x555556b99ee8, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:730 riscvarchive#16 0x0000555555a2f8da in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x555556b99ee0, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr_base.h:1169 riscvarchive#17 0x0000555555a2f8fa in std::shared_ptr<objfile>::~shared_ptr (this=0x555556b99ee0, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/shared_ptr.h:103 riscvarchive#18 0x0000555555a63fba in __gnu_cxx::new_allocator<std::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> > (this=0x55555679f0c0, __p=0x555556b99ee0) at /usr/include/c++/9/ext/new_allocator.h:153 riscvarchive#19 0x0000555555a638fb in std::allocator_traits<std::allocator<std::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> > (__a=..., __p=0x555556b99ee0) at /usr/include/c++/9/bits/alloc_traits.h:497 riscvarchive#20 0x0000555555a6351c in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase (this=0x55555679f0c0, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556935550}) at /usr/include/c++/9/bits/stl_list.h:1921 riscvarchive#21 0x0000555555a62dab in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase (this=0x55555679f0c0, __position=std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x555556935550}) at /usr/include/c++/9/bits/list.tcc:158 riscvarchive#22 0x0000555555a614dd in program_space::remove_objfile (this=0x55555679f080, objfile=0x555556935550) at src/gdb/progspace.c:207 riscvarchive#23 0x0000555555a2c4dc in objfile::unlink (this=0x555556935550) at src/gdb/objfiles.c:497 riscvarchive#24 0x0000555555a2da65 in objfile_purge_solibs () at src/gdb/objfiles.c:904 riscvarchive#25 0x0000555555b3af74 in no_shared_libraries (ignored=0x0, from_tty=1) at src/gdb/solib.c:1236 riscvarchive#26 0x0000555555bbafc7 in target_pre_inferior (from_tty=1) at src/gdb/target.c:1900 riscvarchive#27 0x0000555555940afb in attach_command (args=0x5555563277c7 "15741", from_tty=1) at src/gdb/infcmd.c:2582 ... The problem is that the multi-target commit added a scoped_restore_current_thread to remove_target_sections (frame riscvarchive#7 above). scoped_restore_current_thread's ctor fetches the selected frame's frame id. If the frame had not had its frame id computed yet, it is computed then (frame riscvarchive#4 above). Because it has been determined earlier that the frame's unwinder is the DWARF unwinder, we end up here: static struct dwarf2_frame_cache * dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) { ... /* Find the correct FDE. */ fde = dwarf2_frame_find_fde (&pc1, &cache->per_objfile); gdb_assert (fde != NULL); And, that assertion fails. The assertion is reasonable, because the DWARF unwinder only claims the frame if it managed to find the FDE earlier (in dwarf2_frame_sniffer). (unix/-m32 is thus really a red herring here -- it's just that on x86_64 -m64, the frame is not claimed by the DWARF unwinder.) The reason the assertion is failing, is because the objfile that contains the FDE has been removed from the objfiles list already when we get here (frame riscvarchive#22 above). This suggests that the fix should be to invalidate DWARF frames when their objfile is removed. Or to keep it simple and safe, invalidate the frame cache when an objfile is removed. That is what this commit does. OOC, I checked why is it that when you unload a file with plain "(gdb) file", we don't hit the assertion. It must be because we're already flushing the frame cache somewhere else in that case. And indeed, we flush the frame cache here: (gdb) bt #0 reinit_frame_cache () at src/gdb/frame.c:1857 riscvarchive#1 0x0000555555ad1ad6 in registers_changed_ptid (target=0x0, ptid=...) at src/gdb/regcache.c:470 riscvarchive#2 0x0000555555ad1b58 in registers_changed () at src/gdb/regcache.c:485 riscvarchive#3 0x00005555558d095e in set_target_gdbarch (new_gdbarch=0x555556d5f5b0) at src/gdb/gdbarch.c:5528 riscvarchive#4 0x0000555555677175 in set_gdbarch_from_file (abfd=0x0) at src/gdb/arch-utils.c:601 riscvarchive#5 0x0000555555897c6b in exec_file_attach (filename=0x0, from_tty=1) at src/gdb/exec.c:409 riscvarchive#6 0x000055555589852d in exec_file_command (args=0x0, from_tty=1) at src/gdb/exec.c:571 riscvarchive#7 0x00005555558985a1 in file_command (arg=0x0, from_tty=1) at src/gdb/exec.c:583 riscvarchive#8 0x000055555572b55f in do_const_cfunc (c=0x55555672e200, args=0x0, from_tty=1) at src/gdb/cli/cli-decode.c:95 riscvarchive#9 0x000055555572f3d3 in cmd_func (cmd=0x55555672e200, args=0x0, from_tty=1) at src/gdb/cli/cli-decode.c:2181 riscvarchive#10 0x0000555555be1ecc in execute_command (p=0x555556327804 "", from_tty=1) at src/gdb/top.c:668 riscvarchive#11 0x0000555555895427 in command_handler (command=0x555556327800 "file") at src/gdb/event-top.c:588 riscvarchive#12 0x00005555558958af in command_line_handler (rl=...) at src/gdb/event-top.c:773 riscvarchive#13 0x0000555555894b3e in gdb_rl_callback_handler (rl=0x55555a09e240 "file") at src/gdb/event-top.c:219 riscvarchive#14 0x0000555555ccfeec in rl_callback_read_char () at src/readline/readline/callback.c:281 riscvarchive#15 0x000055555589495a in gdb_rl_callback_read_char_wrapper_noexcept () at src/gdb/event-top.c:177 riscvarchive#16 0x0000555555894a08 in gdb_rl_callback_read_char_wrapper (client_data=0x555556327520) at src/gdb/event-top.c:194 riscvarchive#17 0x00005555558952a5 in stdin_event_handler (error=0, client_data=0x555556327520) at src/gdb/event-top.c:516 riscvarchive#18 0x0000555555e027d6 in handle_file_event (file_ptr=0x555558d20840, ready_mask=1) at src/gdbsupport/event-loop.cc:548 riscvarchive#19 0x0000555555e02d88 in gdb_wait_for_event (block=1) at src/gdbsupport/event-loop.cc:673 riscvarchive#20 0x0000555555e01c42 in gdb_do_one_event () at src/gdbsupport/event-loop.cc:215 riscvarchive#21 0x00005555559c47c2 in start_event_loop () at src/gdb/main.c:356 riscvarchive#22 0x00005555559c490d in captured_command_loop () at src/gdb/main.c:416 riscvarchive#23 0x00005555559c6217 in captured_main (data=0x7fffffffdc00) at src/gdb/main.c:1253 riscvarchive#24 0x00005555559c6289 in gdb_main (args=0x7fffffffdc00) at src/gdb/main.c:1268 riscvarchive#25 0x0000555555621756 in main (argc=3, argv=0x7fffffffdd18) at src/gdb/gdb.c:32 gdb/ChangeLog: PR gdb/26336 * progspace.c (program_space::remove_objfile): Invalidate the frame cache.
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Oct 6, 2020
I'm dealing these days with a class of bugs that involve trying to get a certain frame's id while we are in the process of computing it. In other words, compute_frame_id being called for a frame, eventually calling get_frame_id for that same frame. I don't think this is ever supposed to happen, as that creates a cyclic dependency. Usually, these problems cause some failure down the line. I'm proposing with this patch to catch them as early as possible, as soon as the situation described above happens. I think that helps because the failed assertion will be closer to the root of the problem. To do so, the patch changes the frame_info::this_id::p flag from a boolean (is the frame id computed or not) to a tri-state: - the frame id is not computed - the frame id is being computed - the frame id is computed Then, we can properly assert that get_frame_id doesn't get called for a frame whose id is being computed. To illustrate how that can help, let's imagine we apply the following change to frame_unwind_got_optimized: --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -260,8 +260,7 @@ frame_unwind_got_optimized (struct frame_info *frame, int regnum) mark_value_bytes_optimized_out (val, 0, TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_register; VALUE_REGNUM (val) = regnum; - VALUE_NEXT_FRAME_ID (val) - = get_frame_id (get_next_frame_sentinel_okay (frame)); + VALUE_NEXT_FRAME_ID (val) = get_frame_id (frame); return val; } ... and run the following command, which leads to a failed assertion (you need to run the corresponding test to generate the binary first): $ ./gdb -q -nx testsuite/outputs/gdb.dwarf2/dw2-undefined-ret-addr/dw2-undefined-ret-addr -ex "b stop_frame" -ex r Without this patch applied, we catch the issue indirectly, when the top-level get_frame_id tries to stash the frame: /home/smarchi/src/binutils-gdb/gdb/frame.c:593: internal-error: frame_id get_frame_id(frame_info*): Assertion `stashed' failed. ... riscvarchive#9 0x0000000001af1c3a in internal_error (file=0x1cea060 "/home/smarchi/src/binutils-gdb/gdb/frame.c", line=593, fmt=0x1ce9f80 "%s: Assertion `%s' failed.") at /home/smarchi/src/binutils-gdb/gdbsupport/errors.cc:55 riscvarchive#10 0x0000000000e9b413 in get_frame_id (fi=0x6210005105e0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:593 riscvarchive#11 0x0000000000e99e35 in scoped_restore_selected_frame::scoped_restore_selected_frame (this=0x7fff1d8b9760) at /home/smarchi/src/binutils-gdb/gdb/frame.c:308 riscvarchive#12 0x000000000149a261 in print_frame_args (fp_opts=..., func=0x6210000dd7d0, frame=0x6210005105e0, num=-1, stream=0x60300008a580) at /home/smarchi/src/binutils-gdb/gdb/stack.c:750 riscvarchive#13 0x000000000149d938 in print_frame (fp_opts=..., frame=0x6210005105e0, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at /home/smarchi/src/binutils-gdb/gdb/stack.c:1394 riscvarchive#14 0x000000000149c0c8 in print_frame_info (fp_opts=..., frame=0x6210005105e0, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /home/smarchi/src/binutils-gdb/gdb/stack.c:1119 riscvarchive#15 0x0000000001498100 in print_stack_frame (frame=0x6210005105e0, print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at /home/smarchi/src/binutils-gdb/gdb/stack.c:366 riscvarchive#16 0x00000000010234b7 in print_stop_location (ws=0x7fff1d8ba1f0) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:8366 riscvarchive#17 0x000000000102362d in print_stop_event (uiout=0x607000018660, displays=true) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:8382 ... It freaks out because the frame is already in the stash: it was added by an inner call to get_frame_id, called indirectly by compute_frame_id. Debugging this failure is difficult because we have to backtrack to where this happened. With the patch applied, we catch the issue earlier, here: /home/smarchi/src/binutils-gdb/gdb/frame.c:601: internal-error: frame_id get_frame_id(frame_info*): Assertion `fi->this_id.p != frame_id_status::COMPUTING' failed ... riscvarchive#9 0x0000000001af22bc in internal_error (file=0x1cea6e0 "/home/smarchi/src/binutils-gdb/gdb/frame.c", line=601, fmt=0x1cea600 "%s: Assertion `%s' failed.") at /home/smarchi/src/binutils-gdb/gdbsupport/errors.cc:55 riscvarchive#10 0x0000000000e9b7e3 in get_frame_id (fi=0x62100050dde0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:601 riscvarchive#11 0x0000000000e989b3 in frame_unwind_got_optimized (frame=0x62100050dde0, regnum=16) at /home/smarchi/src/binutils-gdb/gdb/frame-unwind.c:264 riscvarchive#12 0x0000000000cbe386 in dwarf2_frame_prev_register (this_frame=0x62100050dde0, this_cache=0x62100050ddf8, regnum=16) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:1267 riscvarchive#13 0x0000000000e9f569 in frame_unwind_register_value (next_frame=0x62100050dde0, regnum=16) at /home/smarchi/src/binutils-gdb/gdb/frame.c:1266 riscvarchive#14 0x0000000000e9eaab in frame_register_unwind (next_frame=0x62100050dde0, regnum=16, optimizedp=0x7ffca814ade0, unavailablep=0x7ffca814adf0, lvalp=0x7ffca814ae10, addrp=0x7ffca814ae20, realnump=0x7ffca814ae00, bufferp=0x7ffca814aec0 "") at /home/smarchi/src/binutils-gdb/gdb/frame.c:1169 riscvarchive#15 0x0000000000e9f233 in frame_unwind_register (next_frame=0x62100050dde0, regnum=16, buf=0x7ffca814aec0 "") at /home/smarchi/src/binutils-gdb/gdb/frame.c:1225 riscvarchive#16 0x0000000000f84262 in i386_unwind_pc (gdbarch=0x6210000eed10, next_frame=0x62100050dde0) at /home/smarchi/src/binutils-gdb/gdb/i386-tdep.c:1969 riscvarchive#17 0x0000000000ec95dd in gdbarch_unwind_pc (gdbarch=0x6210000eed10, next_frame=0x62100050dde0) at /home/smarchi/src/binutils-gdb/gdb/gdbarch.c:3062 riscvarchive#18 0x0000000000cb5e9d in dwarf2_tailcall_sniffer_first (this_frame=0x62100050dde0, tailcall_cachep=0x62100050dee0, entry_cfa_sp_offsetp=0x7ffca814b160) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame-tailcall.c:387 riscvarchive#19 0x0000000000cbdd38 in dwarf2_frame_cache (this_frame=0x62100050dde0, this_cache=0x62100050ddf8) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:1198 riscvarchive#20 0x0000000000cbe026 in dwarf2_frame_this_id (this_frame=0x62100050dde0, this_cache=0x62100050ddf8, this_id=0x62100050de40) at /home/smarchi/src/binutils-gdb/gdb/dwarf2/frame.c:1226 riscvarchive#21 0x0000000000e9b447 in compute_frame_id (fi=0x62100050dde0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:580 riscvarchive#22 0x0000000000e9b89e in get_frame_id (fi=0x62100050dde0) at /home/smarchi/src/binutils-gdb/gdb/frame.c:613 riscvarchive#23 0x0000000000e99e35 in scoped_restore_selected_frame::scoped_restore_selected_frame (this=0x7ffca814b610) at /home/smarchi/src/binutils-gdb/gdb/frame.c:315 riscvarchive#24 0x000000000149a8e3 in print_frame_args (fp_opts=..., func=0x6210000dd7d0, frame=0x62100050dde0, num=-1, stream=0x60300008a520) at /home/smarchi/src/binutils-gdb/gdb/stack.c:750 riscvarchive#25 0x000000000149dfba in print_frame (fp_opts=..., frame=0x62100050dde0, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at /home/smarchi/src/binutils-gdb/gdb/stack.c:1394 riscvarchive#26 0x000000000149c74a in print_frame_info (fp_opts=..., frame=0x62100050dde0, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /home/smarchi/src/binutils-gdb/gdb/stack.c:1119 riscvarchive#27 0x0000000001498782 in print_stack_frame (frame=0x62100050dde0, print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at /home/smarchi/src/binutils-gdb/gdb/stack.c:366 riscvarchive#28 0x0000000001023b39 in print_stop_location (ws=0x7ffca814c0a0) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:8366 riscvarchive#29 0x0000000001023caf in print_stop_event (uiout=0x607000018660, displays=true) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:8382 ... Now, we can clearly see that get_frame_id for frame `fi=0x62100050dde0` gets called while compute_frame_id is active for that frame. The backtrace is more helpful to identify the root of the problem. gdb/ChangeLog: * frame.c (enum class frame_id_status): New. (struct frame_info) <this_id::p>: Change type to frame_id_status. (fprintf_frame): Update. (compute_frame_id): Set frame id status to "computing" on entry. Set it back to "not_computed" on failure and to "computed" on success. (get_frame_id): Assert the frame id is not being computed. (create_sentinel_frame): Use frame_id_status::COMPUTED. (create_new_frame): Likewise. (frame_cleanup_after_sniffer): Update assert. Change-Id: I5f1a25fafe045f756bd75f358892720b30ed20c9
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Oct 6, 2020
TLDR: frame_unwind_got_optimized uses wrong frame id value, trying to fix it makes GDB sad, return not_lval value and don't use frame id value instead. Longer version: The `prev_register` method of the `frame_unwind` interface corresponds to asking the question: "where did this frame - passed as a parameter - save the value this register had in its caller frame?". When "this frame" did not save that register value (DW_CFA_undefined in DWARF), the implementation can use the `frame_unwind_got_optimized` function to create a struct value that represents the optimized out / not saved register. `frame_unwind_got_optimized` marks the value as fully optimized out, sets the lval field to lval_register and assigns the required data for lval_register: the next frame id and the register number. The problem is that it uses the frame id from the wrong frame (see below for in depth explanation). In practice, this is not problematic because the frame id is never used: the value is already not lazy (and is marked as optimized out), so the value is never fetched from the target. When trying to change it to put the right next frame id in the value, we bump into problems: computing the frame id for some frame requires unwinding some register, if that register is not saved / optimized out, we try to get the frame id that we are currently computing. This patch addresses the problem by changing `frame_unwind_got_optimized` to return a not_lval value instead. Doing so, we don't need to put a frame id, so we don't hit that problem. It may seem like an unnecessary change today, because it looks like we're fixing something that is not broken (from the user point of view). However, the bug becomes user visible with the following patches, where inline frames are involved. I put this change in its own patch to keep it logically separate. Let's now illustrate how we are putting the wrong frame id in the value returned by `frame_unwind_got_optimized`. Let's assume this stack: frame #0 frame riscvarchive#1 frame riscvarchive#2 frame riscvarchive#3 Let's suppose that we are calling `frame_unwind_register_value` with frame riscvarchive#2 as the "next_frame" parameter and some register number X as the regnum parameter. That is like asking the question "where did frame riscvarchive#2 save frame riscvarchive#3's value for register X". `frame_unwind_register_value` calls the frame unwinder's `prev_register` method, which in our case is `dwarf2_frame_prev_register`. Note that in `dwarf2_frame_prev_register`, the parameter is now called `this_frame`, but its value is still frame riscvarchive#2, and we are still looking for where frame riscvarchive#2 saved frame riscvarchive#3's value of register X. Let's now suppose that frame riscvarchive#2's CFI explicitly indicates that the register X is was not saved (DW_CFA_undefined). We go into `frame_unwind_got_optimized`. In `frame_unwind_got_optimized`, the intent is to create a value that represents register X in frame riscvarchive#3. An lval_register value requires that we specify the id of the _next_ frame, that is the frame from which we would need to unwind in order to get the value. Therefore, we would want to put the id of frame riscvarchive#2 in there. However, `frame_unwind_got_optimized` does: VALUE_NEXT_FRAME_ID (val) = get_frame_id (get_next_frame_sentinel_okay (frame)); where `frame` is frame riscvarchive#2. The get_next_frame_sentinel_okay call returns frame riscvarchive#1, so we end up putting frame riscvarchive#1's id in the value. Let's now pretend that we try to "fix" it by placing the right frame id, in other words doing this change: --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -260,8 +260,7 @@ frame_unwind_got_optimized (struct frame_info *frame, int regnum) mark_value_bytes_optimized_out (val, 0, TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_register; VALUE_REGNUM (val) = regnum; - VALUE_NEXT_FRAME_ID (val) - = get_frame_id (get_next_frame_sentinel_okay (frame)); + VALUE_NEXT_FRAME_ID (val) = get_frame_id (frame); return val; } This makes some tests fails, such as gdb.dwarf2/dw2-undefined-ret-addr.exp, like so: ... riscvarchive#9 0x0000557a8ab15a5d in internal_error (file=0x557a8b31ef80 "/home/simark/src/binutils-gdb/gdb/frame.c", line=623, fmt=0x557a8b31efe0 "%s: Assertion `%s' failed.") at /home/simark/src/binutils-gdb/gdbsupport/errors.cc:55 riscvarchive#10 0x0000557a87f816d6 in get_frame_id (fi=0x62100034bde0) at /home/simark/src/binutils-gdb/gdb/frame.c:623 riscvarchive#11 0x0000557a87f7cac7 in frame_unwind_got_optimized (frame=0x62100034bde0, regnum=16) at /home/simark/src/binutils-gdb/gdb/frame-unwind.c:264 riscvarchive#12 0x0000557a87a71a76 in dwarf2_frame_prev_register (this_frame=0x62100034bde0, this_cache=0x62100034bdf8, regnum=16) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1267 riscvarchive#13 0x0000557a87f86621 in frame_unwind_register_value (next_frame=0x62100034bde0, regnum=16) at /home/simark/src/binutils-gdb/gdb/frame.c:1288 riscvarchive#14 0x0000557a87f855d5 in frame_register_unwind (next_frame=0x62100034bde0, regnum=16, optimizedp=0x7fff5f459070, unavailablep=0x7fff5f459080, lvalp=0x7fff5f4590a0, addrp=0x7fff5f4590b0, realnump=0x7fff5f459090, bufferp=0x7fff5f459150 "") at /home/simark/src/binutils-gdb/gdb/frame.c:1191 riscvarchive#15 0x0000557a87f860ef in frame_unwind_register (next_frame=0x62100034bde0, regnum=16, buf=0x7fff5f459150 "") at /home/simark/src/binutils-gdb/gdb/frame.c:1247 riscvarchive#16 0x0000557a881875f9 in i386_unwind_pc (gdbarch=0x621000190110, next_frame=0x62100034bde0) at /home/simark/src/binutils-gdb/gdb/i386-tdep.c:1971 riscvarchive#17 0x0000557a87fe58a5 in gdbarch_unwind_pc (gdbarch=0x621000190110, next_frame=0x62100034bde0) at /home/simark/src/binutils-gdb/gdb/gdbarch.c:3062 riscvarchive#18 0x0000557a87a6267b in dwarf2_tailcall_sniffer_first (this_frame=0x62100034bde0, tailcall_cachep=0x62100034bee0, entry_cfa_sp_offsetp=0x7fff5f4593f0) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame-tailcall.c:387 riscvarchive#19 0x0000557a87a70cdf in dwarf2_frame_cache (this_frame=0x62100034bde0, this_cache=0x62100034bdf8) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1198 riscvarchive#20 0x0000557a87a711c2 in dwarf2_frame_this_id (this_frame=0x62100034bde0, this_cache=0x62100034bdf8, this_id=0x62100034be40) at /home/simark/src/binutils-gdb/gdb/dwarf2/frame.c:1226 riscvarchive#21 0x0000557a87f81167 in compute_frame_id (fi=0x62100034bde0) at /home/simark/src/binutils-gdb/gdb/frame.c:587 riscvarchive#22 0x0000557a87f81803 in get_frame_id (fi=0x62100034bde0) at /home/simark/src/binutils-gdb/gdb/frame.c:635 riscvarchive#23 0x0000557a87f7efef in scoped_restore_selected_frame::scoped_restore_selected_frame (this=0x7fff5f459920) at /home/simark/src/binutils-gdb/gdb/frame.c:320 riscvarchive#24 0x0000557a891488ae in print_frame_args (fp_opts=..., func=0x621000183b90, frame=0x62100034bde0, num=-1, stream=0x6030000caa20) at /home/simark/src/binutils-gdb/gdb/stack.c:750 riscvarchive#25 0x0000557a8914e87a in print_frame (fp_opts=..., frame=0x62100034bde0, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at /home/simark/src/binutils-gdb/gdb/stack.c:1394 riscvarchive#26 0x0000557a8914c2ae in print_frame_info (fp_opts=..., frame=0x62100034bde0, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at /home/simark/src/binutils-gdb/gdb/stack.c:1119 ... We end up calling get_frame_id (in the hunk above, frame riscvarchive#10) while we are computing it (frame riscvarchive#21), and that's not good. Now, the question is how do we fix this. I suggest making the unwinder return a not_lval value in this case. The reason why we return an lval_register here is to make sure that this is printed as "not saved" and not "optimized out" down the line. See these two commits: 1. 901461f ("Print registers not saved in the frame as "<not saved>" instead of "<optimized out>"."). 2. 6bd273a ("Make "set debug frame 1" output print <not saved> instead of <optimized out>.") The current design (introduced by the first commit) is to check the value's lval to choose which one to print (see val_print_optimized_out). Making the unwinder return not_lval instead of lval_register doesn't break "not saved" when doing "print $rax" or "info registers", because value_fetch_lazy_register only consumes the contents and optimized-out property from the value the unwinder returned. The value being un-lazified stays an lval_register. I believe that this is a correct technical solution (and not just papering over the problem), because what we expect of unwinders is to tell us where a given register's value is saved. If the value is saved in memory, -> lval_memory. If the value is saved in some other register of the next frame, -> lval_register. If the value is not saved, it doesn't really make sense to return an lval_register value. not_lval would be more appropriate. If the code then wants to represent an optimized out register value (like value_fetch_lazy_register does), then it's a separate concern which shouldn't involve the unwinder. This change breaks the output of "set debug frame 1" though (introduced by the second commit), since that logging statement consumes the return value of the unwinder directly. To keep the correct behavior, just make `frame_unwind_register_value` call `val_print_not_saved` directly, instead of `val_print_optimized_out`. This is fine because we know in this context that we are always talking about a register value, and that we want to show "not saved" for those. I augmented the gdb.dwarf2/dw2-reg-undefined.exp test case to test some cases I stumbled on while working on this, which I think are not tested anywhere: - the "set debug frame 1" debug output mentioned above. It's just debug output, but if we want to make sure it doesn't change, it should be tested - printing not-saved register values from the history (should print not saved) - copying a not-saved register value in a convenience variable. In this case, we expect that printing the convenience variable shows "optimized out", because we copied the value, not the property of where the value came from. gdb/ChangeLog: * frame-unwind.c (frame_unwind_got_optimized): Don't set regnum/frame in value. Call allocate_value_lazy. * frame.c (frame_unwind_register_value): Use val_print_not_saved. gdb/testsuite/ChangeLog: * gdb.dwarf2/dw2-reg-undefined.exp: Test "set debug frame 1" output, printing a "not saved" value from history and printing a convenience variable created from a "not saved" value. Change-Id: If451739a3ef7a5b453b1f50707e21ce16d74807e
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Nov 24, 2020
The recent commit to make scoped_restore_current_thread's cdtors exception free regressed gdb.base/eh_return.exp: Breakpoint 1, 0x00000000004012bb in eh2 (gdb/frame.c:641: 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.base/eh_return.exp: hit breakpoint (GDB internal error) That testcase uses __builtin_eh_return and, before the regression, the backtrace at eh2 looked like this: (gdb) bt #0 0x00000000004006eb in eh2 (p=0x4006ec <continuation>) at src/gdb/testsuite/gdb.base/eh_return.c:54 Backtrace stopped: previous frame identical to this frame (corrupt stack?) That "previous frame identical to this frame" is caught by the cycle detection based on frame id. The assertion failing is this one: 638 /* Since this is the first frame in the chain, this should 639 always succeed. */ 640 bool stashed = frame_stash_add (fi); 641 gdb_assert (stashed); originally added by commit f245535 Author: Pedro Alves <[email protected]> AuthorDate: Mon Sep 5 18:41:38 2016 +0100 Fix PR19927: Avoid unwinder recursion if sniffer uses calls parse_and_eval The assertion is failing because frame riscvarchive#1's frame id was stashed before the id of frame #0 is stashed. The frame id of frame riscvarchive#1 was stashed here: (top-gdb) bt #0 frame_stash_add (frame=0x1e24c90) at src/gdb/frame.c:276 riscvarchive#1 0x0000000000669c1b in get_prev_frame_if_no_cycle (this_frame=0x19f8370) at src/gdb/frame.c:2120 riscvarchive#2 0x000000000066a339 in get_prev_frame_always_1 (this_frame=0x19f8370) at src/gdb/frame.c:2303 riscvarchive#3 0x000000000066a360 in get_prev_frame_always (this_frame=0x19f8370) at src/gdb/frame.c:2319 riscvarchive#4 0x000000000066b56c in get_frame_unwind_stop_reason (frame=0x19f8370) at src/gdb/frame.c:3028 riscvarchive#5 0x000000000059f929 in dwarf2_frame_cfa (this_frame=0x19f8370) at src/gdb/dwarf2/frame.c:1462 riscvarchive#6 0x00000000005ce434 in dwarf_evaluate_loc_desc::get_frame_cfa (this=0x7fffffffc070) at src/gdb/dwarf2/loc.c:666 riscvarchive#7 0x00000000005989a9 in dwarf_expr_context::execute_stack_op (this=0x7fffffffc070, op_ptr=0x1b2a053 "\364\003", op_end=0x1b2a053 "\364\003") at src/gdb/dwarf2/expr.c:1161 riscvarchive#8 0x0000000000596af6 in dwarf_expr_context::eval (this=0x7fffffffc070, addr=0x1b2a052 "\234\364\003", len=1) at src/gdb/dwarf2/expr.c:303 riscvarchive#9 0x0000000000597b4e in dwarf_expr_context::execute_stack_op (this=0x7fffffffc070, op_ptr=0x1b2a063 "", op_end=0x1b2a063 "") at src/gdb/dwarf2/expr.c:865 riscvarchive#10 0x0000000000596af6 in dwarf_expr_context::eval (this=0x7fffffffc070, addr=0x1b2a061 "\221X", len=2) at src/gdb/dwarf2/expr.c:303 riscvarchive#11 0x00000000005c8b5a in dwarf2_evaluate_loc_desc_full (type=0x1b564d0, frame=0x19f8370, data=0x1b2a061 "\221X", size=2, per_cu=0x1b28760, per_objfile=0x1a84930, subobj_type=0x1b564d0, subobj_byte_offset=0) at src/gdb/dwarf2/loc.c:2260 riscvarchive#12 0x00000000005c9243 in dwarf2_evaluate_loc_desc (type=0x1b564d0, frame=0x19f8370, data=0x1b2a061 "\221X", size=2, per_cu=0x1b28760, per_objfile=0x1a84930) at src/gdb/dwarf2/loc.c:2444 riscvarchive#13 0x00000000005cb769 in locexpr_read_variable (symbol=0x1b59840, frame=0x19f8370) at src/gdb/dwarf2/loc.c:3687 riscvarchive#14 0x0000000000663137 in language_defn::read_var_value (this=0x122ea60 <c_language_defn>, var=0x1b59840, var_block=0x0, frame=0x19f8370) at src/gdb/findvar.c:618 riscvarchive#15 0x0000000000663c3b in read_var_value (var=0x1b59840, var_block=0x0, frame=0x19f8370) at src/gdb/findvar.c:822 riscvarchive#16 0x00000000008c7d9f in read_frame_arg (fp_opts=..., sym=0x1b59840, frame=0x19f8370, argp=0x7fffffffc470, entryargp=0x7fffffffc490) at src/gdb/stack.c:542 riscvarchive#17 0x00000000008c89cd in print_frame_args (fp_opts=..., func=0x1b597c0, frame=0x19f8370, num=-1, stream=0x1aba860) at src/gdb/stack.c:890 riscvarchive#18 0x00000000008c9bf8 in print_frame (fp_opts=..., frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at src/gdb/stack.c:1394 riscvarchive#19 0x00000000008c92b9 in print_frame_info (fp_opts=..., frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at src/gdb/stack.c:1119 riscvarchive#20 0x00000000008c75f0 in print_stack_frame (frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at src/gdb/stack.c:366 riscvarchive#21 0x000000000070250b in print_stop_location (ws=0x7fffffffc9e0) at src/gdb/infrun.c:8110 riscvarchive#22 0x0000000000702569 in print_stop_event (uiout=0x1a8b9e0, displays=true) at src/gdb/infrun.c:8126 riscvarchive#23 0x000000000096d04b in tui_on_normal_stop (bs=0x1bcd1c0, print_frame=1) at src/gdb/tui/tui-interp.c:98 ... Before the commit to make scoped_restore_current_thread's cdtors exception free, scoped_restore_current_thread's dtor would call get_frame_id on the selected frame, and we use scoped_restore_current_thread pervasively. That had the side effect of stashing the frame id of frame #0 before reaching the path shown in the backtrace. I.e., the frame id of frame #0 happened to be stashed before the frame id of frame riscvarchive#1. But that was by chance, not by design. This commit: commit 256ae5d Author: Kevin Buettner <[email protected]> AuthorDate: Mon Oct 31 12:47:42 2016 -0700 Stash frame id of current frame before stashing frame id for previous frame Fixed a similar problem, by making sure get_prev_frame computes the frame id of the current frame before unwinding the previous frame, so that the cycle detection works properly. That fix misses the scenario we're now running against, because if you notice, the backtrace above shows that frame riscvarchive#4 calls get_prev_frame_always, not get_prev_frame. I.e., nothing is calling get_frame_id on the current frame. The fix here is to move Kevin's fix down from get_prev_frame to get_prev_frame_always. Or actually, a bit further down to get_prev_frame_always_1 -- note that inline_frame_this_id calls get_prev_frame_always, so we need to be careful to avoid recursion in that scenario. gdb/ChangeLog: * frame.c (get_prev_frame): Move get_frame_id call from here ... (get_prev_frame_always_1): ... to here. * inline-frame.c (inline_frame_this_id): Mention get_prev_frame_always_1 in comment. Change-Id: Id960c98ab2d072c48a436c3eb160cc4b2a5cfd1d
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Mar 9, 2021
…PR gdb/27147) PR 27147 shows that on sparc64, GDB is unable to properly unwind: Expected result (from GDB 9.2): #0 0x0000000000108de4 in puts () riscvarchive#1 0x0000000000100950 in hello () at gdb-test.c:4 riscvarchive#2 0x0000000000100968 in main () at gdb-test.c:8 Actual result (from GDB latest git): #0 0x0000000000108de4 in puts () riscvarchive#1 0x0000000000100950 in hello () at gdb-test.c:4 Backtrace stopped: previous frame inner to this frame (corrupt stack?) The first failing commit is 5b6d1e4 ("Multi-target support"). The cause of the change in behavior is due to (thanks for Andrew Burgess for finding this): - inferior_ptid is no longer set on entry of target_ops::wait, whereas it was set to something valid previously - deep down in linux_nat_target::wait (see stack trace below), we fetch the registers of the event thread - on sparc64, fetching registers involves reading memory (in sparc_supply_rwindow, see stack trace below) - reading memory (target_ops::xfer_partial) relies on inferior_ptid being set to the thread from which we want to read memory This is where things go wrong: #0 linux_nat_target::xfer_partial (this=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, annex=0x0, readbuf=0x7feffe3b000 "", writebuf=0x0, offset=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3697 riscvarchive#1 0x00000100007f5b10 in raw_memory_xfer_partial (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, readbuf=0x7feffe3b000 "", writebuf=0x0, memaddr=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/target.c:912 riscvarchive#2 0x00000100007f60e8 in memory_xfer_partial_1 (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, readbuf=0x7feffe3b000 "", writebuf=0x0, memaddr=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/target.c:1043 riscvarchive#3 0x00000100007f61b4 in memory_xfer_partial (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, readbuf=0x7feffe3b000 "", writebuf=0x0, memaddr=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/target.c:1072 riscvarchive#4 0x00000100007f6538 in target_xfer_partial (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, annex=0x0, readbuf=0x7feffe3b000 "", writebuf=0x0, offset=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/target.c:1129 riscvarchive#5 0x00000100007f7094 in target_read_partial (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, annex=0x0, buf=0x7feffe3b000 "", offset=8791798050744, len=8, xfered_len=0x7feffe3ae88) at /home/simark/src/binutils-gdb/gdb/target.c:1375 riscvarchive#6 0x00000100007f721c in target_read (ops=0x10000fa2c40 <the_sparc64_linux_nat_target>, object=TARGET_OBJECT_MEMORY, annex=0x0, buf=0x7feffe3b000 "", offset=8791798050744, len=8) at /home/simark/src/binutils-gdb/gdb/target.c:1415 riscvarchive#7 0x00000100007f69d4 in target_read_memory (memaddr=8791798050744, myaddr=0x7feffe3b000 "", len=8) at /home/simark/src/binutils-gdb/gdb/target.c:1218 riscvarchive#8 0x0000010000758520 in sparc_supply_rwindow (regcache=0x10000fea4f0, sp=8791798050736, regnum=-1) at /home/simark/src/binutils-gdb/gdb/sparc-tdep.c:1960 riscvarchive#9 0x000001000076208c in sparc64_supply_gregset (gregmap=0x10000be3190 <sparc64_linux_ptrace_gregmap>, regcache=0x10000fea4f0, regnum=-1, gregs=0x7feffe3b230) at /home/simark/src/binutils-gdb/gdb/sparc64-tdep.c:1974 riscvarchive#10 0x0000010000751b64 in sparc_fetch_inferior_registers (regcache=0x10000fea4f0, regnum=80) at /home/simark/src/binutils-gdb/gdb/sparc-nat.c:170 riscvarchive#11 0x0000010000759d68 in sparc64_linux_nat_target::fetch_registers (this=0x10000fa2c40 <the_sparc64_linux_nat_target>, regcache=0x10000fea4f0, regnum=80) at /home/simark/src/binutils-gdb/gdb/sparc64-linux-nat.c:38 riscvarchive#12 0x00000100008146ec in target_fetch_registers (regcache=0x10000fea4f0, regno=80) at /home/simark/src/binutils-gdb/gdb/target.c:3287 riscvarchive#13 0x00000100006a8c5c in regcache::raw_update (this=0x10000fea4f0, regnum=80) at /home/simark/src/binutils-gdb/gdb/regcache.c:584 riscvarchive#14 0x00000100006a8d94 in readable_regcache::raw_read (this=0x10000fea4f0, regnum=80, buf=0x7feffe3b7c0 "") at /home/simark/src/binutils-gdb/gdb/regcache.c:598 riscvarchive#15 0x00000100006a93b8 in readable_regcache::cooked_read (this=0x10000fea4f0, regnum=80, buf=0x7feffe3b7c0 "") at /home/simark/src/binutils-gdb/gdb/regcache.c:690 riscvarchive#16 0x00000100006b288c in readable_regcache::cooked_read<unsigned long, void> (this=0x10000fea4f0, regnum=80, val=0x7feffe3b948) at /home/simark/src/binutils-gdb/gdb/regcache.c:777 riscvarchive#17 0x00000100006a9b44 in regcache_cooked_read_unsigned (regcache=0x10000fea4f0, regnum=80, val=0x7feffe3b948) at /home/simark/src/binutils-gdb/gdb/regcache.c:791 riscvarchive#18 0x00000100006abf3c in regcache_read_pc (regcache=0x10000fea4f0) at /home/simark/src/binutils-gdb/gdb/regcache.c:1295 riscvarchive#19 0x0000010000507920 in save_stop_reason (lp=0x10000fc5b10) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:2612 riscvarchive#20 0x00000100005095a4 in linux_nat_filter_event (lwpid=520983, status=1407) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3050 riscvarchive#21 0x0000010000509f9c in linux_nat_wait_1 (ptid=..., ourstatus=0x7feffe3c8f0, target_options=...) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3194 riscvarchive#22 0x000001000050b1d0 in linux_nat_target::wait (this=0x10000fa2c40 <the_sparc64_linux_nat_target>, ptid=..., ourstatus=0x7feffe3c8f0, target_options=...) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3432 riscvarchive#23 0x00000100007f8ac0 in target_wait (ptid=..., status=0x7feffe3c8f0, options=...) at /home/simark/src/binutils-gdb/gdb/target.c:2000 riscvarchive#24 0x00000100004ac17c in do_target_wait_1 (inf=0x1000116d280, ptid=..., status=0x7feffe3c8f0, options=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:3464 riscvarchive#25 0x00000100004ac3b8 in operator() (__closure=0x7feffe3c678, inf=0x1000116d280) at /home/simark/src/binutils-gdb/gdb/infrun.c:3527 riscvarchive#26 0x00000100004ac7cc in do_target_wait (wait_ptid=..., ecs=0x7feffe3c8c8, options=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:3540 riscvarchive#27 0x00000100004ad8c4 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:3880 riscvarchive#28 0x0000010000485568 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 riscvarchive#29 0x000001000050d394 in handle_target_event (error=0, client_data=0x0) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:4060 riscvarchive#30 0x0000010000ab5c8c in handle_file_event (file_ptr=0x10001207270, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:575 riscvarchive#31 0x0000010000ab6334 in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:701 riscvarchive#32 0x0000010000ab487c in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 riscvarchive#33 0x0000010000542668 in start_event_loop () at /home/simark/src/binutils-gdb/gdb/main.c:348 riscvarchive#34 0x000001000054287c in captured_command_loop () at /home/simark/src/binutils-gdb/gdb/main.c:408 riscvarchive#35 0x0000010000544e84 in captured_main (data=0x7feffe3d188) at /home/simark/src/binutils-gdb/gdb/main.c:1242 riscvarchive#36 0x0000010000544f2c in gdb_main (args=0x7feffe3d188) at /home/simark/src/binutils-gdb/gdb/main.c:1257 riscvarchive#37 0x00000100000c1f14 in main (argc=4, argv=0x7feffe3d548) at /home/simark/src/binutils-gdb/gdb/gdb.c:32 There is a target_read_memory call in sparc_supply_rwindow, whose return value is not checked. That call fails, because inferior_ptid does not contain a valid ptid, and uninitialized buffer contents is used. Ultimately it results in a corrupt stop_pc. target_ops::fetch_registers can be (and should remain, in my opinion) independent of inferior_ptid, because the ptid of the thread from which to fetch registers can be obtained from the regcache. In other words, implementations of target_ops::fetch_registers should not rely on inferior_ptid having a sensible value on entry. The sparc64_linux_nat_target::fetch_registers case is special, because it calls a target method that is dependent on the inferior_ptid value (target_read_inferior, and ultimately target_ops::xfer_partial). So I would say it's the responsibility of sparc64_linux_nat_target::fetch_registers to set up inferior_ptid correctly prior to calling target_read_inferior. This patch makes sparc64_linux_nat_target::fetch_registers (and store_registers, since it works the same) temporarily set inferior_ptid. If we ever make target_ops::xfer_partial independent of inferior_ptid, setting inferior_ptid won't be necessary, we'll simply pass down the ptid as a parameter in some way. I chose to set/restore inferior_ptid in sparc_fetch_inferior_registers, because I am not convinced that doing so in an inner location (in sparc_supply_rwindow for instance) would always be correct. We have access to the ptid in sparc_supply_rwindow (from the regcache), so we _could_ set inferior_ptid there. However, I don't want to just set inferior_ptid, as that would make it not desync'ed with `current_thread ()` and `current_inferior ()`. It's preferable to use switch_to_thread instead, as that switches all the global "current" stuff in a coherent way. But doing so requires a `thread_info *`, and getting a `thread_info *` from a ptid requires a `process_stratum_target *`. We could use `current_inferior()->process_target()` in sparc_supply_rwindow for this (using target_read_memory uses the current inferior's target stack anyway). However, sparc_supply_rwindow is also used in the context of BSD uthreads, where a thread stratum target defines threads. I presume the ptid in the regcache would be the ptid of the uthread, defined by the thread stratum target (bsd_uthread_target). Using `current_inferior()->process_target()` would look up a ptid defined by the thread stratum target using the process stratum target. I don't think it would give good results. So I prefer playing it safe and looking up the thread earlier, in sparc_fetch_inferior_registers. I added some assertions (in sparc_supply_rwindow and others) to verify that the regcache's ptid matches inferior_ptid. That verifies that the caller has properly set the correct global context. This would have caught (though a failed assertion) the current problem. gdb/ChangeLog: PR gdb/27147 * sparc-nat.h (sparc_fetch_inferior_registers): Add process_stratum_target parameter, sparc_store_inferior_registers): update callers. * sparc-nat.c (sparc_fetch_inferior_registers, sparc_store_inferior_registers): Add process_stratum_target parameter. Switch current thread before calling sparc_supply_gregset / sparc_collect_rwindow. (sparc_store_inferior_registers): Likewise. * sparc-obsd-tdep.c (sparc32obsd_supply_uthread): Add assertion. (sparc32obsd_collect_uthread): Likewise. * sparc-tdep.c (sparc_supply_rwindow, sparc_collect_rwindow): Add assertion. * sparc64-obsd-tdep.c (sparc64obsd_collect_uthread, sparc64obsd_supply_uthread): Add assertion. Change-Id: I16c658cd70896cea604516714f7e2428fbaf4301
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jun 11, 2021
The past commit d1e93af ("gdb: set current thread in sparc_{fetch,collect}_inferior_registers (PR gdb/27147)") changed sparc_fetch_inferior_registers and sparc_store_inferior_registers to look up the thread corresponding to the regcache's ptid and make it the current thread. The reason being that down the call chain, some functions (like sparc_supply_rwindow) can do some memory reads or write, through target_read_memory/target_write_memory, and those rely on the current global context. There is one small problem with this approach: when debugging a multi-threaded program, the regcache for a new thread is created just before the corresponding thread_info is created. In fact, the regcache is created somewhere during the call to thread_from_lwp, which is responsible for creating the thread_info: riscvarchive#8 0x0000010000ab9968 in internal_error (file=0x10000bfca20 "/home/simark/src/binutils-gdb/gdb/thread.c", line=1346, fmt=0x10000bfc918 "%s: Assertion `%s' failed.") at /home/simark/src/binutils-gdb/gdbsupport/errors.cc:55 riscvarchive#9 0x0000010000827f3c in switch_to_thread (thr=0x0) at /home/simark/src/binutils-gdb/gdb/thread.c:1346 riscvarchive#10 0x0000010000753444 in sparc_fetch_inferior_registers (proc_target=0x10000fa8cb0 <the_sparc64_linux_nat_target>, regcache=0x10000ff03c0, regnum=-1) at /home/simark/src/binutils-gdb/gdb/sparc-nat.c:175 riscvarchive#11 0x000001000075b908 in sparc64_linux_nat_target::fetch_registers (this=0x10000fa8cb0 <the_sparc64_linux_nat_target>, regcache=0x10000ff03c0, regnum=-1) at /home/simark/src/binutils-gdb/gdb/sparc64-linux-nat.c:38 riscvarchive#12 0x00000100007fe6f4 in target_ops::fetch_registers (this=0x10000f7feb0 <the_thread_db_target>, arg0=0x10000ff03c0, arg1=-1) at /home/simark/src/binutils-gdb/gdb/target-delegates.c:496 riscvarchive#13 0x00000100008162a0 in target_fetch_registers (regcache=0x10000ff03c0, regno=-1) at /home/simark/src/binutils-gdb/gdb/target.c:3287 riscvarchive#14 0x000001000060a4bc in ps_lgetregs (ph=0x10001264368, lwpid=458727, gregset=0x7feff97d388) at /home/simark/src/binutils-gdb/gdb/proc-service.c:158 riscvarchive#15 0xffff800103e32420 in __td_ta_lookup_th_unique (ta_arg=0x100012d7080, lwpid=<optimized out>, th=0x7feff97d7c8) at td_ta_map_lwp2thr.c:119 riscvarchive#16 0xffff800103e32604 in td_ta_map_lwp2thr (ta_arg=0x100012d7080, lwpid=<optimized out>, th=0x7feff97d7c8) at td_ta_map_lwp2thr.c:207 riscvarchive#17 0x000001000051fee8 in thread_from_lwp (stopped=0x100011a3650, ptid=...) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:415 riscvarchive#18 0x0000010000520150 in thread_db_notice_clone (parent=..., child=...) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:446 riscvarchive#19 0x00000100005068a8 in linux_handle_extended_wait (lp=0x10001230700, status=4479) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:1978 riscvarchive#20 0x000001000050a278 in linux_nat_filter_event (lwpid=458724, status=198015) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:2913 riscvarchive#21 0x000001000050b818 in linux_nat_wait_1 (ptid=..., ourstatus=0x7feff97e8d0, target_options=...) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3194 riscvarchive#22 0x000001000050ca4c in linux_nat_target::wait (this=0x10000fa8cb0 <the_sparc64_linux_nat_target>, ptid=..., ourstatus=0x7feff97e8d0, target_options=...) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:3432 riscvarchive#23 0x00000100005237ec in thread_db_target::wait (this=0x10000f7feb0 <the_thread_db_target>, ptid=..., ourstatus=0x7feff97e8d0, options=...) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1379 riscvarchive#24 0x00000100007fa668 in target_wait (ptid=..., status=0x7feff97e8d0, options=...) at /home/simark/src/binutils-gdb/gdb/target.c:2000 riscvarchive#25 0x00000100004adb0c in do_target_wait_1 (inf=0x10001173170, ptid=..., status=0x7feff97e8d0, options=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:3464 riscvarchive#26 0x00000100004add48 in operator() (__closure=0x7feff97e658, inf=0x10001173170) at /home/simark/src/binutils-gdb/gdb/infrun.c:3527 riscvarchive#27 0x00000100004ae15c in do_target_wait (wait_ptid=..., ecs=0x7feff97e8a8, options=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:3540 riscvarchive#28 0x00000100004af254 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:3880 riscvarchive#29 0x0000010000486ef8 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 The problem is that while sparc_fetch_inferior_registers runs and is asked to read the registers of a given ptid, there isn't a thread_info with that ptid yet. So, find_thread_ptid returns nullptr, and switch_to_thread gives an internal error. Fix this by only setting inferior_ptid, instead of the whole global context, as switch_to_thread does. This is sufficient for target_read_memory / target_write_memory to work down the line. Ideally, it would be nice to be able to pass the ptid down the whole call chain and to target_read_memory / target_write_memory, so that this setting of inferior_ptid would not be necessary. But this is not going to happen soon. This fixes running a multi-threaded program, which would hit the internal error show in the call stack above. gdb/ChangeLog: PR gdb/27899 * sparc-nat.c (sparc_fetch_inferior_registers): Set inferior_ptid instead of using switch_to_thread. (sparc_store_inferior_registers): Likewise. Change-Id: I0b6ddb3af9b11f67b10ee46a734fb82ecc6462d5
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jun 15, 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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#5 0x000055555d06b4bc in thread_from_lwp (stopped=0x617000035d80, ptid=...) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:418 riscvarchive#6 0x000055555d07040d in try_thread_db_load_1 (info=0x60c000011140) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:912 riscvarchive#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 riscvarchive#8 0x000055555d072168 in try_thread_db_load_from_sdir () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1091 riscvarchive#9 0x000055555d072d1c in thread_db_load_search () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1146 riscvarchive#10 0x000055555d07365c in thread_db_load () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1203 riscvarchive#11 0x000055555d07373e in check_for_thread_db () at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1246 riscvarchive#12 0x000055555d0738ab in thread_db_new_objfile (objfile=0x61300000c0c0) at /home/simark/src/binutils-gdb/gdb/linux-thread-db.c:1275 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#20 0x000055555d95f9fa in solib_read_symbols (so=0x6190000d8e80, flags=...) at /home/simark/src/binutils-gdb/gdb/solib.c:681 riscvarchive#21 0x000055555d96233d in solib_add (pattern=0x0, from_tty=0, readsyms=1) at /home/simark/src/binutils-gdb/gdb/solib.c:987 riscvarchive#22 0x000055555d93646e in enable_break (info=0x608000008f20, from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:2238 riscvarchive#23 0x000055555d93cfc0 in svr4_solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:3049 riscvarchive#24 0x000055555d96610d in solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib.c:1195 riscvarchive#25 0x000055555cdee318 in post_create_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:318 riscvarchive#26 0x000055555ce00e6e in setup_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:2439 riscvarchive#27 0x000055555ce59c34 in handle_one (event=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:4887 riscvarchive#28 0x000055555ce5cd00 in stop_all_threads () at /home/simark/src/binutils-gdb/gdb/infrun.c:5064 riscvarchive#29 0x000055555ce7f0da in stop_waiting (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:8006 riscvarchive#30 0x000055555ce67f5c in handle_signal_stop (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:6062 riscvarchive#31 0x000055555ce63653 in handle_inferior_event (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:5727 riscvarchive#32 0x000055555ce4f297 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:4105 riscvarchive#33 0x000055555cdbe3bf in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 riscvarchive#34 0x000055555d018047 in handle_target_event (error=0, client_data=0x0) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:4060 riscvarchive#35 0x000055555e5ea77e in handle_file_event (file_ptr=0x60600008b1c0, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:575 riscvarchive#36 0x000055555e5eb09c in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:701 riscvarchive#37 0x000055555e5e8d19 in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 riscvarchive#38 0x000055555dd6e0d4 in wait_sync_command_done () at /home/simark/src/binutils-gdb/gdb/top.c:528 riscvarchive#39 0x000055555dd6e372 in maybe_wait_sync_command_done (was_sync=0) at /home/simark/src/binutils-gdb/gdb/top.c:545 riscvarchive#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 riscvarchive#41 0x000055555d0f03ad in captured_main_1 (context=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1149 riscvarchive#42 0x000055555d0f1239 in captured_main (data=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1232 riscvarchive#43 0x000055555d0f1315 in gdb_main (args=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1257 riscvarchive#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 riscvarchive#1 0x000055555d95fded in solib_read_symbols (so=0x6190000d8e80, flags=...) at /home/simark/src/binutils-gdb/gdb/solib.c:689 riscvarchive#2 0x000055555d96233d in solib_add (pattern=0x0, from_tty=0, readsyms=1) at /home/simark/src/binutils-gdb/gdb/solib.c:987 riscvarchive#3 0x000055555d93646e in enable_break (info=0x608000008f20, from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:2238 riscvarchive#4 0x000055555d93cfc0 in svr4_solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib-svr4.c:3049 riscvarchive#5 0x000055555d96610d in solib_create_inferior_hook (from_tty=0) at /home/simark/src/binutils-gdb/gdb/solib.c:1195 riscvarchive#6 0x000055555cdee318 in post_create_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:318 riscvarchive#7 0x000055555ce00e6e in setup_inferior (from_tty=0) at /home/simark/src/binutils-gdb/gdb/infcmd.c:2439 riscvarchive#8 0x000055555ce59c34 in handle_one (event=...) at /home/simark/src/binutils-gdb/gdb/infrun.c:4887 riscvarchive#9 0x000055555ce5cd00 in stop_all_threads () at /home/simark/src/binutils-gdb/gdb/infrun.c:5064 riscvarchive#10 0x000055555ce7f0da in stop_waiting (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:8006 riscvarchive#11 0x000055555ce67f5c in handle_signal_stop (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:6062 riscvarchive#12 0x000055555ce63653 in handle_inferior_event (ecs=0x7fffffffd170) at /home/simark/src/binutils-gdb/gdb/infrun.c:5727 riscvarchive#13 0x000055555ce4f297 in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:4105 riscvarchive#14 0x000055555cdbe3bf in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:42 riscvarchive#15 0x000055555d018047 in handle_target_event (error=0, client_data=0x0) at /home/simark/src/binutils-gdb/gdb/linux-nat.c:4060 riscvarchive#16 0x000055555e5ea77e in handle_file_event (file_ptr=0x60600008b1c0, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:575 riscvarchive#17 0x000055555e5eb09c in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:701 riscvarchive#18 0x000055555e5e8d19 in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 riscvarchive#19 0x000055555dd6e0d4 in wait_sync_command_done () at /home/simark/src/binutils-gdb/gdb/top.c:528 riscvarchive#20 0x000055555dd6e372 in maybe_wait_sync_command_done (was_sync=0) at /home/simark/src/binutils-gdb/gdb/top.c:545 riscvarchive#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 riscvarchive#22 0x000055555d0f03ad in captured_main_1 (context=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1149 riscvarchive#23 0x000055555d0f1239 in captured_main (data=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1232 riscvarchive#24 0x000055555d0f1315 in gdb_main (args=0x7fffffffdd10) at /home/simark/src/binutils-gdb/gdb/main.c:1257 riscvarchive#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
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jul 8, 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 riscvarchive#1 0x00007ffff63ef862 in abort () from /usr/lib/libc.so.6 riscvarchive#2 0x00007ffff664e21e in __gnu_debug::_Error_formatter::_M_error() const [clone .cold] from /usr/lib/libstdc++.so.6 riscvarchive#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 riscvarchive#4 0x0000555556a58c17 in objfile::section_offset (this=0x61300000a4c0, section=0x55555bbe4ac0 <_bfd_std_section>) at /home/simark/src/binutils-gdb/gdb/objfiles.h:644 riscvarchive#5 0x0000555556a58cac in obj_section::offset (this=0x62100016d2a8) at /home/simark/src/binutils-gdb/gdb/objfiles.h:838 riscvarchive#6 0x0000555556a58cfa in obj_section::addr (this=0x62100016d2a8) at /home/simark/src/binutils-gdb/gdb/objfiles.h:850 riscvarchive#7 0x000055555779f5f7 in sort_cmp (sect1=0x62100016d2a8, sect2=0x62100016d170) at /home/simark/src/binutils-gdb/gdb/objfiles.c:902 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#13 0x00005555577a147e in update_section_map (pspace=0x61200001d2c0, pmap=0x6030000d40b0, pmap_size=0x6030000d40b8) at /home/simark/src/binutils-gdb/gdb/objfiles.c:1165 riscvarchive#14 0x00005555577a19a0 in find_pc_section (pc=0x100003fa0) at /home/simark/src/binutils-gdb/gdb/objfiles.c:1212 riscvarchive#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 riscvarchive#16 0x00005555576de552 in lookup_minimal_symbol_by_pc (pc=0x100003fa0) at /home/simark/src/binutils-gdb/gdb/minsyms.c:986 riscvarchive#17 0x0000555557d44b54 in find_pc_sect_line (pc=0x100003fa0, section=0x62100016d170, notcurrent=0) at /home/simark/src/binutils-gdb/gdb/symtab.c:3163 riscvarchive#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 riscvarchive#19 0x0000555557d49015 in find_function_start_sal (sym=0x621000191670, funfirstline=true) at /home/simark/src/binutils-gdb/gdb/symtab.c:3706 riscvarchive#20 0x0000555557485283 in symbol_to_sal (result=0x7fffffffbb30, funfirstline=1, sym=0x621000191670) at /home/simark/src/binutils-gdb/gdb/linespec.c:4460 riscvarchive#21 0x00005555574728c2 in convert_linespec_to_sals (state=0x7fffffffc390, ls=0x7fffffffc3e0) at /home/simark/src/binutils-gdb/gdb/linespec.c:2335 riscvarchive#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 riscvarchive#23 0x0000555557479027 in event_location_to_sals (parser=0x7fffffffc360, location=0x606000097be0) at /home/simark/src/binutils-gdb/gdb/linespec.c:3173 riscvarchive#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 riscvarchive#25 0x0000555556b4949f in parse_breakpoint_sals (location=0x606000097be0, canonical=0x7fffffffcca0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9134 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#29 0x0000555556b4d3b1 in break_command_1 (arg=0x7fffffffe291 "", flag=0, from_tty=0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9590 riscvarchive#30 0x0000555556b4dc1b in break_command (arg=0x7fffffffe28d "main", from_tty=0) at /home/simark/src/binutils-gdb/gdb/breakpoint.c:9660 riscvarchive#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 riscvarchive#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 riscvarchive#33 0x0000555557e84e93 in execute_command (p=0x7fffffffe290 "n", from_tty=0) at /home/simark/src/binutils-gdb/gdb/top.c:674 riscvarchive#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 riscvarchive#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 riscvarchive#36 0x00005555575ad48a in captured_main_1 (context=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1322 riscvarchive#37 0x00005555575ada9c in captured_main (data=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1343 riscvarchive#38 0x00005555575adb31 in gdb_main (args=0x7fffffffdd00) at /home/simark/src/binutils-gdb/gdb/main.c:1368 riscvarchive#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
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jul 22, 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 riscvarchive#1 0x0000555555bbaa46 in remote_target::readchar (this=0x555556a11040, timeout=10000) at src/gdb/remote.c:9440 riscvarchive#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 riscvarchive#3 0x0000555555bbbda9 in remote_target::getpkt_sane (this=0x555556a11040, buf=0x555556a11058, forever=0) at src/gdb/remote.c:10030 riscvarchive#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 riscvarchive#5 0x0000555555bc1b6c in remote_target::remote_hostio_close (this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12455 riscvarchive#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 riscvarchive#7 0x0000555555c9274c in target_fileio_close (fd=3, target_errno=0x7fffffffcfd0) at src/gdb/target.c:3365 riscvarchive#8 0x000055555595a19d in gdb_bfd_iovec_fileio_close (abfd=0x555556b9f8a0, stream=0x555556b11530) at src/gdb/gdb_bfd.c:439 riscvarchive#9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556b9f8a0) at src/bfd/opncls.c:599 riscvarchive#10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556b9f8a0) at src/bfd/opncls.c:847 riscvarchive#11 0x0000555555e0a27a in bfd_close (abfd=0x555556b9f8a0) at src/bfd/opncls.c:814 riscvarchive#12 0x000055555595a9d3 in gdb_bfd_close_or_warn (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:626 riscvarchive#13 0x000055555595ad29 in gdb_bfd_unref (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:715 riscvarchive#14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#24 0x0000555555b19576 in program_space::remove_objfile (this=0x5555564cdd20, objfile=0x555556515540) at src/gdb/progspace.c:210 riscvarchive#25 0x0000555555ae4502 in objfile::unlink (this=0x555556515540) at src/gdb/objfiles.c:487 riscvarchive#26 0x0000555555ae5a12 in objfile_purge_solibs () at src/gdb/objfiles.c:875 riscvarchive#27 0x0000555555c09686 in no_shared_libraries (ignored=0x0, from_tty=1) at src/gdb/solib.c:1236 riscvarchive#28 0x00005555559e3f5f in detach_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:2769 So frame riscvarchive#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 riscvarchive#14: riscvarchive#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 riscvarchive#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 riscvarchive#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
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jul 22, 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 riscvarchive#1 0x0000555555bbaa46 in remote_target::readchar (this=0x555556a11040, timeout=10000) at src/gdb/remote.c:9440 riscvarchive#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 riscvarchive#3 0x0000555555bbbda9 in remote_target::getpkt_sane (this=0x555556a11040, buf=0x555556a11058, forever=0) at src/gdb/remote.c:10030 riscvarchive#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 riscvarchive#5 0x0000555555bc1b6c in remote_target::remote_hostio_close (this=0x555556a11040, fd=8, remote_errno=0x7fffffffcfd0) at src/gdb/remote.c:12455 riscvarchive#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 riscvarchive#7 0x0000555555c9274c in target_fileio_close (fd=3, target_errno=0x7fffffffcfd0) at src/gdb/target.c:3365 riscvarchive#8 0x000055555595a19d in gdb_bfd_iovec_fileio_close (abfd=0x555556b9f8a0, stream=0x555556b11530) at src/gdb/gdb_bfd.c:439 riscvarchive#9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556b9f8a0) at src/bfd/opncls.c:599 riscvarchive#10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556b9f8a0) at src/bfd/opncls.c:847 riscvarchive#11 0x0000555555e0a27a in bfd_close (abfd=0x555556b9f8a0) at src/bfd/opncls.c:814 riscvarchive#12 0x000055555595a9d3 in gdb_bfd_close_or_warn (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:626 riscvarchive#13 0x000055555595ad29 in gdb_bfd_unref (abfd=0x555556b9f8a0) at src/gdb/gdb_bfd.c:715 riscvarchive#14 0x0000555555ae4730 in objfile::~objfile (this=0x555556515540, __in_chrg=<optimized out>) at src/gdb/objfiles.c:573 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#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 riscvarchive#24 0x0000555555b19576 in program_space::remove_objfile (this=0x5555564cdd20, objfile=0x555556515540) at src/gdb/progspace.c:210 riscvarchive#25 0x0000555555ae4502 in objfile::unlink (this=0x555556515540) at src/gdb/objfiles.c:487 riscvarchive#26 0x0000555555ae5a12 in objfile_purge_solibs () at src/gdb/objfiles.c:875 riscvarchive#27 0x0000555555c09686 in no_shared_libraries (ignored=0x0, from_tty=1) at src/gdb/solib.c:1236 riscvarchive#28 0x00005555559e3f5f in detach_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:2769 Note frame riscvarchive#14: riscvarchive#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 riscvarchive#9-riscvarchive#11 are BFD frames: riscvarchive#9 0x0000555555e09e3f in opncls_bclose (abfd=0x555556bc27e0) at src/bfd/opncls.c:599 riscvarchive#10 0x0000555555e0a2c7 in bfd_close_all_done (abfd=0x555556bc27e0) at src/bfd/opncls.c:847 riscvarchive#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 riscvarchive#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
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Jul 22, 2021
As documented in bug 28086, test gdb.btrace/enable-new-thread.exp started failing with commit 0618ae4 ("gdb: optimize all_matching_threads_iterator"): (gdb) record btrace^M (gdb) PASS: gdb.btrace/enable-new-thread.exp: record btrace break 24^M Breakpoint 2 at 0x555555555175: file /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.btrace/enable-new-thread.c, line 24.^M (gdb) continue^M Continuing.^M /home/smarchi/src/binutils-gdb/gdb/inferior.c:303: internal-error: inferior* find_inferior_pid(process_stratum_target*, int): Assertion `pid != 0' failed.^M A problem internal to GDB has been detected,^M further debugging may prove unreliable.^M Quit this debugging session? (y or n) FAIL: gdb.btrace/enable-new-thread.exp: continue to breakpoint: cont to bp.1 (GDB internal error) Note that I only see the failure if GDB is compiled without libipt support. This is because GDB then makes use BTS instead of PT, so exercises different code paths. I think that the commit above just exposed an existing problem. The stack trace of the internal error is: riscvarchive#8 0x0000561cb81e404e in internal_error (file=0x561cb83aa2f8 "/home/smarchi/src/binutils-gdb/gdb/inferior.c", line=303, fmt=0x561cb83aa099 "%s: Assertion `%s' failed.") at /home/smarchi/src/binutils-gdb/gdbsupport/errors.cc:55 riscvarchive#9 0x0000561cb7b5c031 in find_inferior_pid (targ=0x561cb8aafb60 <the_amd64_linux_nat_target>, pid=0) at /home/smarchi/src/binutils-gdb/gdb/inferior.c:303 riscvarchive#10 0x0000561cb7b5c102 in find_inferior_ptid (targ=0x561cb8aafb60 <the_amd64_linux_nat_target>, ptid=...) at /home/smarchi/src/binutils-gdb/gdb/inferior.c:317 riscvarchive#11 0x0000561cb7f1d1c3 in find_thread_ptid (targ=0x561cb8aafb60 <the_amd64_linux_nat_target>, ptid=...) at /home/smarchi/src/binutils-gdb/gdb/thread.c:487 riscvarchive#12 0x0000561cb7f1b921 in all_matching_threads_iterator::all_matching_threads_iterator (this=0x7ffc4ee34678, filter_target=0x561cb8aafb60 <the_amd64_linux_nat_target>, filter_ptid=...) at /home/smarchi/src/binutils-gdb/gdb/thread-iter.c:125 riscvarchive#13 0x0000561cb77bc462 in filtered_iterator<all_matching_threads_iterator, non_exited_thread_filter>::filtered_iterator<process_stratum_target* const&, ptid_t const&> (this=0x7ffc4ee34670) at /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/filtered-iterator.h:42 riscvarchive#14 0x0000561cb77b97cb in all_non_exited_threads_range::begin (this=0x7ffc4ee34650) at /home/smarchi/src/binutils-gdb/gdb/thread-iter.h:243 riscvarchive#15 0x0000561cb7d8ba30 in record_btrace_target::record_is_replaying (this=0x561cb8aa6250 <record_btrace_ops>, ptid=...) at /home/smarchi/src/binutils-gdb/gdb/record-btrace.c:1411 riscvarchive#16 0x0000561cb7d8bb83 in record_btrace_target::xfer_partial (this=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_MEMORY, annex=0x0, readbuf=0x7ffc4ee34c58 "\260g\343N\374\177", writebuf=0x0, offset=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/record-btrace.c:1437 riscvarchive#17 0x0000561cb7ef73a9 in raw_memory_xfer_partial (ops=0x561cb8aa6250 <record_btrace_ops>, readbuf=0x7ffc4ee34c58 "\260g\343N\374\177", writebuf=0x0, memaddr=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/target.c:1504 riscvarchive#18 0x0000561cb7ef77da in memory_xfer_partial_1 (ops=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_CODE_MEMORY, readbuf=0x7ffc4ee34c58 "\260g\343N\374\177", writebuf=0x0, memaddr=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/target.c:1635 riscvarchive#19 0x0000561cb7ef78b5 in memory_xfer_partial (ops=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_CODE_MEMORY, readbuf=0x7ffc4ee34c58 "\260g\343N\374\177", writebuf=0x0, memaddr=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/target.c:1664 riscvarchive#20 0x0000561cb7ef7ba4 in target_xfer_partial (ops=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_CODE_MEMORY, annex=0x0, readbuf=0x7ffc4ee34c58 "\260g\343N\374\177", writebuf=0x0, offset=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/target.c:1721 riscvarchive#21 0x0000561cb7ef8503 in target_read_partial (ops=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_CODE_MEMORY, annex=0x0, buf=0x7ffc4ee34c58 "\260g\343N\374\177", offset=140737352774277, len=1, xfered_len=0x7ffc4ee34ad8) at /home/smarchi/src/binutils-gdb/gdb/target.c:1974 riscvarchive#22 0x0000561cb7ef861f in target_read (ops=0x561cb8aa6250 <record_btrace_ops>, object=TARGET_OBJECT_CODE_MEMORY, annex=0x0, buf=0x7ffc4ee34c58 "\260g\343N\374\177", offset=140737352774277, len=1) at /home/smarchi/src/binutils-gdb/gdb/target.c:2014 riscvarchive#23 0x0000561cb7ef809f in target_read_code (memaddr=140737352774277, myaddr=0x7ffc4ee34c58 "\260g\343N\374\177", len=1) at /home/smarchi/src/binutils-gdb/gdb/target.c:1869 riscvarchive#24 0x0000561cb7937f4d in gdb_disassembler::dis_asm_read_memory (memaddr=140737352774277, myaddr=0x7ffc4ee34c58 "\260g\343N\374\177", len=1, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/gdb/disasm.c:139 riscvarchive#25 0x0000561cb80ab66d in fetch_data (info=0x7ffc4ee34e88, addr=0x7ffc4ee34c59 "g\343N\374\177") at /home/smarchi/src/binutils-gdb/opcodes/i386-dis.c:194 riscvarchive#26 0x0000561cb80ab7e2 in ckprefix () at /home/smarchi/src/binutils-gdb/opcodes/i386-dis.c:8628 riscvarchive#27 0x0000561cb80adbd8 in print_insn (pc=140737352774277, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/opcodes/i386-dis.c:9587 riscvarchive#28 0x0000561cb80abe4f in print_insn_i386 (pc=140737352774277, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/opcodes/i386-dis.c:8894 riscvarchive#29 0x0000561cb7744a19 in default_print_insn (memaddr=140737352774277, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/gdb/arch-utils.c:1029 riscvarchive#30 0x0000561cb7b33067 in i386_print_insn (pc=140737352774277, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/gdb/i386-tdep.c:4013 riscvarchive#31 0x0000561cb7acd8f4 in gdbarch_print_insn (gdbarch=0x561cbae2fb60, vma=140737352774277, info=0x7ffc4ee34e88) at /home/smarchi/src/binutils-gdb/gdb/gdbarch.c:3478 riscvarchive#32 0x0000561cb793a32d in gdb_disassembler::print_insn (this=0x7ffc4ee34e80, memaddr=140737352774277, branch_delay_insns=0x0) at /home/smarchi/src/binutils-gdb/gdb/disasm.c:795 riscvarchive#33 0x0000561cb793a5b0 in gdb_print_insn (gdbarch=0x561cbae2fb60, memaddr=140737352774277, stream=0x561cb8ac99f8 <null_stream>, branch_delay_insns=0x0) at /home/smarchi/src/binutils-gdb/gdb/disasm.c:850 riscvarchive#34 0x0000561cb793a631 in gdb_insn_length (gdbarch=0x561cbae2fb60, addr=140737352774277) at /home/smarchi/src/binutils-gdb/gdb/disasm.c:859 riscvarchive#35 0x0000561cb77f53f4 in btrace_compute_ftrace_bts (tp=0x561cbba11210, btrace=0x7ffc4ee35188, gaps=...) at /home/smarchi/src/binutils-gdb/gdb/btrace.c:1107 riscvarchive#36 0x0000561cb77f55f5 in btrace_compute_ftrace_1 (tp=0x561cbba11210, btrace=0x7ffc4ee35180, cpu=0x0, gaps=...) at /home/smarchi/src/binutils-gdb/gdb/btrace.c:1527 riscvarchive#37 0x0000561cb77f5705 in btrace_compute_ftrace (tp=0x561cbba11210, btrace=0x7ffc4ee35180, cpu=0x0) at /home/smarchi/src/binutils-gdb/gdb/btrace.c:1560 riscvarchive#38 0x0000561cb77f583b in btrace_add_pc (tp=0x561cbba11210) at /home/smarchi/src/binutils-gdb/gdb/btrace.c:1589 riscvarchive#39 0x0000561cb77f5a86 in btrace_enable (tp=0x561cbba11210, conf=0x561cb8ac6878 <record_btrace_conf>) at /home/smarchi/src/binutils-gdb/gdb/btrace.c:1629 riscvarchive#40 0x0000561cb7d88d26 in record_btrace_enable_warn (tp=0x561cbba11210) at /home/smarchi/src/binutils-gdb/gdb/record-btrace.c:294 riscvarchive#41 0x0000561cb7c603dc in std::__invoke_impl<void, void (*&)(thread_info*), thread_info*> (__f=@0x561cbb6c4878: 0x561cb7d88cdc <record_btrace_enable_warn(thread_info*)>) at /usr/include/c++/10/bits/invoke.h:60 riscvarchive#42 0x0000561cb7c5e5a6 in std::__invoke_r<void, void (*&)(thread_info*), thread_info*> (__fn=@0x561cbb6c4878: 0x561cb7d88cdc <record_btrace_enable_warn(thread_info*)>) at /usr/include/c++/10/bits/invoke.h:153 riscvarchive#43 0x0000561cb7c5dc92 in std::_Function_handler<void (thread_info*), void (*)(thread_info*)>::_M_invoke(std::_Any_data const&, thread_info*&&) (__functor=..., __args#0=@0x7ffc4ee35310: 0x561cbba11210) at /usr/include/c++/10/bits/std_function.h:291 riscvarchive#44 0x0000561cb7f2600f in std::function<void (thread_info*)>::operator()(thread_info*) const (this=0x561cbb6c4878, __args#0=0x561cbba11210) at /usr/include/c++/10/bits/std_function.h:622 riscvarchive#45 0x0000561cb7f23dc8 in gdb::observers::observable<thread_info*>::notify (this=0x561cb8ac5aa0 <gdb::observers::new_thread>, args#0=0x561cbba11210) at /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/observable.h:150 riscvarchive#46 0x0000561cb7f1c436 in add_thread_silent (targ=0x561cb8aafb60 <the_amd64_linux_nat_target>, ptid=...) at /home/smarchi/src/binutils-gdb/gdb/thread.c:263 riscvarchive#47 0x0000561cb7f1c479 in add_thread_with_info (targ=0x561cb8aafb60 <the_amd64_linux_nat_target>, ptid=..., priv=0x561cbb3f7ab0) at /home/smarchi/src/binutils-gdb/gdb/thread.c:272 riscvarchive#48 0x0000561cb7bfa1d0 in record_thread (info=0x561cbb0413a0, tp=0x0, ptid=..., th_p=0x7ffc4ee35610, ti_p=0x7ffc4ee35620) at /home/smarchi/src/binutils-gdb/gdb/linux-thread-db.c:1380 riscvarchive#49 0x0000561cb7bf7a2a in thread_from_lwp (stopped=0x561cba81db20, ptid=...) at /home/smarchi/src/binutils-gdb/gdb/linux-thread-db.c:429 riscvarchive#50 0x0000561cb7bf7ac5 in thread_db_notice_clone (parent=..., child=...) at /home/smarchi/src/binutils-gdb/gdb/linux-thread-db.c:447 riscvarchive#51 0x0000561cb7bdc9a2 in linux_handle_extended_wait (lp=0x561cbae25720, status=4991) at /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:1981 riscvarchive#52 0x0000561cb7bdf0f3 in linux_nat_filter_event (lwpid=435403, status=198015) at /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:2920 riscvarchive#53 0x0000561cb7bdfed6 in linux_nat_wait_1 (ptid=..., ourstatus=0x7ffc4ee36398, target_options=...) at /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:3202 riscvarchive#54 0x0000561cb7be0b68 in linux_nat_target::wait (this=0x561cb8aafb60 <the_amd64_linux_nat_target>, ptid=..., ourstatus=0x7ffc4ee36398, target_options=...) at /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:3440 riscvarchive#55 0x0000561cb7bfa2fc in thread_db_target::wait (this=0x561cb8a9acd0 <the_thread_db_target>, ptid=..., ourstatus=0x7ffc4ee36398, options=...) at /home/smarchi/src/binutils-gdb/gdb/linux-thread-db.c:1412 riscvarchive#56 0x0000561cb7d8e356 in record_btrace_target::wait (this=0x561cb8aa6250 <record_btrace_ops>, ptid=..., status=0x7ffc4ee36398, options=...) at /home/smarchi/src/binutils-gdb/gdb/record-btrace.c:2547 riscvarchive#57 0x0000561cb7ef996d in target_wait (ptid=..., status=0x7ffc4ee36398, options=...) at /home/smarchi/src/binutils-gdb/gdb/target.c:2608 riscvarchive#58 0x0000561cb7b6d297 in do_target_wait_1 (inf=0x561cba6d8780, ptid=..., status=0x7ffc4ee36398, options=...) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:3640 riscvarchive#59 0x0000561cb7b6d43e in operator() (__closure=0x7ffc4ee36190, inf=0x561cba6d8780) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:3701 riscvarchive#60 0x0000561cb7b6d7b2 in do_target_wait (ecs=0x7ffc4ee36370, options=...) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:3720 riscvarchive#61 0x0000561cb7b6e67d in fetch_inferior_event () at /home/smarchi/src/binutils-gdb/gdb/infrun.c:4069 riscvarchive#62 0x0000561cb7b4659b in inferior_event_handler (event_type=INF_REG_EVENT) at /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:41 riscvarchive#63 0x0000561cb7be25f7 in handle_target_event (error=0, client_data=0x0) at /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4227 riscvarchive#64 0x0000561cb81e4ee2 in handle_file_event (file_ptr=0x561cbae24e10, ready_mask=1) at /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:575 riscvarchive#65 0x0000561cb81e5490 in gdb_wait_for_event (block=0) at /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:701 riscvarchive#66 0x0000561cb81e41be in gdb_do_one_event () at /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:212 riscvarchive#67 0x0000561cb7c18096 in start_event_loop () at /home/smarchi/src/binutils-gdb/gdb/main.c:421 riscvarchive#68 0x0000561cb7c181e0 in captured_command_loop () at /home/smarchi/src/binutils-gdb/gdb/main.c:481 riscvarchive#69 0x0000561cb7c19d7e in captured_main (data=0x7ffc4ee366a0) at /home/smarchi/src/binutils-gdb/gdb/main.c:1353 riscvarchive#70 0x0000561cb7c19df0 in gdb_main (args=0x7ffc4ee366a0) at /home/smarchi/src/binutils-gdb/gdb/main.c:1368 riscvarchive#71 0x0000561cb7693186 in main (argc=11, argv=0x7ffc4ee367b8) at /home/smarchi/src/binutils-gdb/gdb/gdb.c:32 At frame 45, the new_thread observable is fired. At this moment, the new thread isn't the current thread, inferior_ptid is null_ptid. I think this is ok: the new_thread observable doesn't give any guarantee on the global context when observers are invoked. Frame 35, btrace_compute_ftrace_bts, calls gdb_insn_length. gdb_insn_length doesn't have a thread_info or other parameter what could indicate where to read memory from, it implicitly uses the global context (inferior_ptid). So we reach the all_non_exited_threads_range in record_btrace_target::record_is_replaying with a null inferior_ptid. The previous implemention of all_non_exited_threads_range didn't care, but the new one does. The problem of calling gdb_insn_length and ultimately trying to read memory with a null inferior_ptid already existed, but the commit mentioned above made it visible. Something between frames 40 (record_btrace_enable_warn) and 35 (btrace_compute_ftrace_bts) needs to be switching the global context to make TP the current thread. Since btrace_compute_ftrace_bts takes the thread_info to work with as a parameter, that typically means that it doesn't require its caller to also set the global current context (current thread) when calling. If it needs to call other functions that do require the global current thread to be set, then it needs to temporarily change the current thread while calling these other functions. Therefore, switch and restore the current thread in btrace_compute_ftrace_bts. By inspection, it looks like btrace_compute_ftrace_pt may also call functions sensitive to the global context: it installs the btrace_pt_readmem_callback callback in the PT instruction decoder. When this function gets called, inferior_ptid must be set appropriately. Add a switch and restore in there too. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28086 Change-Id: I407fbfe41aab990068bd102491aa3709b0a034b3
Nelson1225
pushed a commit
to Nelson1225/riscv-binutils-gdb
that referenced
this issue
Sep 27, 2021
The original reproducer for PR28030 required use of a specific compiler version - gcc-c++-11.1.1-3.fc34 is mentioned in the PR, though it seems probable that other gcc versions might also be able to reproduce the bug as well. This commit introduces a test case which, using the DWARF assembler, provides a reproducer which is independent of the compiler version. (Well, it'll work with whatever compilers the DWARF assembler works with.) To the best of my knowledge, it's also the first test case which uses the DWARF assembler to provide debug info for a shared object. That being the case, I provided more than the usual commentary which should allow this case to be used as a template when a combo shared library / DWARF assembler test case is required in the future. I provide some details regarding the bug in a comment near the beginning of locexpr-dml.exp. This problem was difficult to reproduce; I found myself constantly referring to the backtrace while trying to figure out what (else) I might be missing while trying to create a reproducer. Below is a partial backtrace which I include for posterity. #0 internal_error ( file=0xc50110 "/ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c", line=5575, fmt=0xc520c0 "Unexpected type field location kind: %d") at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdbsupport/errors.cc:51 riscvarchive#1 0x00000000006ef0c5 in copy_type_recursive (objfile=0x1635930, type=0x274c260, copied_types=0x30bb290) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c:5575 riscvarchive#2 0x00000000006ef382 in copy_type_recursive (objfile=0x1635930, type=0x274ca10, copied_types=0x30bb290) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c:5602 riscvarchive#3 0x0000000000a7409a in preserve_one_value (value=0x24269f0, objfile=0x1635930, copied_types=0x30bb290) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/value.c:2529 riscvarchive#4 0x000000000072012a in gdbscm_preserve_values ( extlang=0xc55720 <extension_language_guile>, objfile=0x1635930, copied_types=0x30bb290) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/guile/scm-value.c:94 riscvarchive#5 0x00000000006a3f82 in preserve_ext_lang_values (objfile=0x1635930, copied_types=0x30bb290) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/extension.c:568 riscvarchive#6 0x0000000000a7428d in preserve_values (objfile=0x1635930) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/value.c:2579 riscvarchive#7 0x000000000082d514 in objfile::~objfile (this=0x1635930, __in_chrg=<optimized out>) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:549 riscvarchive#8 0x0000000000831cc8 in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x1654580) at /usr/include/c++/11/bits/shared_ptr_base.h:348 riscvarchive#9 0x00000000004e6617 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x1654580) at /usr/include/c++/11/bits/shared_ptr_base.h:168 riscvarchive#10 0x00000000004e1d2f in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x190bb88, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/shared_ptr_base.h:705 riscvarchive#11 0x000000000082feee in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x190bb80, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/shared_ptr_base.h:1154 riscvarchive#12 0x000000000082ff0a in std::shared_ptr<objfile>::~shared_ptr ( this=0x190bb80, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/shared_ptr.h:122 riscvarchive#13 0x000000000085ed7e in __gnu_cxx::new_allocator<std::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> > (this=0x114bc00, __p=0x190bb80) at /usr/include/c++/11/ext/new_allocator.h:168 riscvarchive#14 0x000000000085e88d in std::allocator_traits<std::allocator<std::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> > (__a=..., __p=0x190bb80) at /usr/include/c++/11/bits/alloc_traits.h:531 riscvarchive#15 0x000000000085e50c in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase (this=0x114bc00, __position= std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x1635930}) at /usr/include/c++/11/bits/stl_list.h:1925 riscvarchive#16 0x000000000085df0e in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase (this=0x114bc00, __position= std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x1635930}) at /usr/include/c++/11/bits/list.tcc:158 riscvarchive#17 0x000000000085c748 in program_space::remove_objfile (this=0x114bbc0, objfile=0x1635930) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/progspace.c:210 riscvarchive#18 0x000000000082d3ae in objfile::unlink (this=0x1635930) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:487 riscvarchive#19 0x000000000082e68c in objfile_purge_solibs () at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:875 riscvarchive#20 0x000000000092dd37 in no_shared_libraries (ignored=0x0, from_tty=1) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/solib.c:1236 riscvarchive#21 0x00000000009a37fe in target_pre_inferior (from_tty=1) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/target.c:2496 riscvarchive#22 0x00000000007454d6 in run_command_1 (args=0x0, from_tty=1, run_how=RUN_NORMAL) at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/infcmd.c:437 I'll note a few points regarding this backtrace: Frame riscvarchive#1 is where the internal error occurs. It's caused by an unhandled case for FIELD_LOC_KIND_DWARF_BLOCK. The fix for this bug adds support for this case. Frame riscvarchive#22 - it's a partial backtrace - shows that GDB is attempting to (re)run the program. You can see the exact command sequence that was used for reproducing this problem in the PR (at https://sourceware.org/bugzilla/show_bug.cgi?id=28030), but in a nutshell, after starting the program and advancing to the appropriate source line, GDB was asked to step into libstdc++; a "finish" command was issued, returning a value. The fact that a value was returned is very important. GDB was then used to step back into libstdc++. A breakpoint was set on a source line in the library after which a "run" command was issued. Frame riscvarchive#19 shows a call to objfile_purge_solibs. It's aptly named. Frame riscvarchive#7 is a call to the destructor for one of the objfile solibs; it turned out to be the one for libstdc++. Frames riscvarchive#6 thru riscvarchive#3 show various value preservation frames. If you look at preserve_values() in gdb/value.c, the value history is preserved first, followed by internal variables, followed by values for the extension languages (python and guile).
pz9115
pushed a commit
to pz9115/riscv-binutils-gdb
that referenced
this issue
Nov 11, 2021
This commit fixes Bug 28308, titled "Strange interactions with dprintf and break/commands": Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28308 Since creating that bug report, I've found a somewhat simpler way of reproducing the problem. I've encapsulated it into the GDB test case which I've created along with this bug fix. The name of the new test is gdb.base/dprintf-execution-x-script.exp, I'll demonstrate the problem using this test case, though for brevity, I've placed all relevant files in the same directory and have renamed the files to all start with 'dp-bug' instead of 'dprintf-execution-x-script'. The script file, named dp-bug.gdb, consists of the following commands: dprintf increment, "dprintf in increment(), vi=%d\n", vi break inc_vi commands continue end run Note that the final command in this script is 'run'. When 'run' is instead issued interactively, the bug does not occur. So, let's look at the interactive case first in order to see the correct/expected output: $ gdb -q -x dp-bug.gdb dp-bug ... eliding buggy output which I'll discuss later ... (gdb) run Starting program: /mesquite2/sourceware-git/f34-master/bld/gdb/tmp/dp-bug vi=0 dprintf in increment(), vi=0 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 in dprintf-execution-x-script.c vi=1 dprintf in increment(), vi=1 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 in dprintf-execution-x-script.c vi=2 dprintf in increment(), vi=2 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 in dprintf-execution-x-script.c vi=3 [Inferior 1 (process 1539210) exited normally] In this run, in which 'run' was issued from the gdb prompt (instead of at the end of the script), there are three dprintf messages along with three 'Breakpoint 2' messages. This is the correct output. Now let's look at the output that I snipped above; this is the output when 'run' is issued from the script loaded via GDB's -x switch: $ gdb -q -x dp-bug.gdb dp-bug Reading symbols from dp-bug... Dprintf 1 at 0x40116e: file dprintf-execution-x-script.c, line 38. Breakpoint 2 at 0x40113a: file dprintf-execution-x-script.c, line 26. vi=0 dprintf in increment(), vi=0 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 dprintf-execution-x-script.c: No such file or directory. vi=1 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 in dprintf-execution-x-script.c vi=2 Breakpoint 2, inc_vi () at dprintf-execution-x-script.c:26 26 in dprintf-execution-x-script.c vi=3 [Inferior 1 (process 1539175) exited normally] In the output shown above, only the first dprintf message is printed. The 2nd and 3rd dprintf messages are missing! However, all three 'Breakpoint 2...' messages are still printed. Why does this happen? bpstat_do_actions_1() in gdb/breakpoint.c contains the following comment and code near the start of the function: /* Avoid endless recursion if a `source' command is contained in bs->commands. */ if (executing_breakpoint_commands) return 0; scoped_restore save_executing = make_scoped_restore (&executing_breakpoint_commands, 1); Also, as described by this comment prior to the 'async' field in 'struct ui' in top.h, the main UI starts off in sync mode when processing command line arguments: /* True if the UI is in async mode, false if in sync mode. If in sync mode, a synchronous execution command (e.g, "next") does not return until the command is finished. If in async mode, then running a synchronous command returns right after resuming the target. Waiting for the command's completion is later done on the top event loop. For the main UI, this starts out disabled, until all the explicit command line arguments (e.g., `gdb -ex "start" -ex "next"') are processed. */ This combination of things, the state of the static global 'executing_breakpoint_commands' plus the state of the async field in the main UI causes this behavior. This is a backtrace after hitting the dprintf breakpoint for the second time when doing 'run' from the script file, i.e. non-interactively: Thread 1 "gdb" hit Breakpoint 3, bpstat_do_actions_1 (bsp=0x7fffffffc2b8) at /ironwood1/sourceware-git/f34-master/bld/../../worktree-master/gdb/breakpoint.c:4431 4431 if (executing_breakpoint_commands) #0 bpstat_do_actions_1 (bsp=0x7fffffffc2b8) at gdb/breakpoint.c:4431 #1 0x00000000004d8bc6 in dprintf_after_condition_true (bs=0x1538090) at gdb/breakpoint.c:13048 #2 0x00000000004c5caa in bpstat_stop_status (aspace=0x116dbc0, bp_addr=0x40116e, thread=0x137f450, ws=0x7fffffffc718, stop_chain=0x1538090) at gdb/breakpoint.c:5498 #3 0x0000000000768d98 in handle_signal_stop (ecs=0x7fffffffc6f0) at gdb/infrun.c:6172 riscvarchive#4 0x00000000007678d3 in handle_inferior_event (ecs=0x7fffffffc6f0) at gdb/infrun.c:5662 riscvarchive#5 0x0000000000763cd5 in fetch_inferior_event () at gdb/infrun.c:4060 riscvarchive#6 0x0000000000746d7d in inferior_event_handler (event_type=INF_REG_EVENT) at gdb/inf-loop.c:41 riscvarchive#7 0x00000000007a702f in handle_target_event (error=0, client_data=0x0) at gdb/linux-nat.c:4207 riscvarchive#8 0x0000000000b8cd6e in gdb_wait_for_event (block=block@entry=0) at gdbsupport/event-loop.cc:701 riscvarchive#9 0x0000000000b8d032 in gdb_wait_for_event (block=0) at gdbsupport/event-loop.cc:597 riscvarchive#10 gdb_do_one_event () at gdbsupport/event-loop.cc:212 riscvarchive#11 0x00000000009d19b6 in wait_sync_command_done () at gdb/top.c:528 riscvarchive#12 0x00000000009d1a3f in maybe_wait_sync_command_done (was_sync=0) at gdb/top.c:545 riscvarchive#13 0x00000000009d2033 in execute_command (p=0x7fffffffcb18 "", from_tty=0) at gdb/top.c:676 riscvarchive#14 0x0000000000560d5b in execute_control_command_1 (cmd=0x13b9bb0, from_tty=0) at gdb/cli/cli-script.c:547 riscvarchive#15 0x000000000056134a in execute_control_command (cmd=0x13b9bb0, from_tty=0) at gdb/cli/cli-script.c:717 riscvarchive#16 0x00000000004c3bbe in bpstat_do_actions_1 (bsp=0x137f530) at gdb/breakpoint.c:4469 riscvarchive#17 0x00000000004c3d40 in bpstat_do_actions () at gdb/breakpoint.c:4533 riscvarchive#18 0x00000000006a473a in command_handler (command=0x1399ad0 "run") at gdb/event-top.c:624 riscvarchive#19 0x00000000009d182e in read_command_file (stream=0x113e540) at gdb/top.c:443 riscvarchive#20 0x0000000000563697 in script_from_file (stream=0x113e540, file=0x13bb0b0 "dp-bug.gdb") at gdb/cli/cli-script.c:1642 riscvarchive#21 0x00000000006abd63 in source_gdb_script (extlang=0xc44e80 <extension_language_gdb>, stream=0x113e540, file=0x13bb0b0 "dp-bug.gdb") at gdb/extension.c:188 riscvarchive#22 0x0000000000544400 in source_script_from_stream (stream=0x113e540, file=0x7fffffffd91a "dp-bug.gdb", file_to_open=0x13bb0b0 "dp-bug.gdb") at gdb/cli/cli-cmds.c:692 riscvarchive#23 0x0000000000544557 in source_script_with_search (file=0x7fffffffd91a "dp-bug.gdb", from_tty=1, search_path=0) at gdb/cli/cli-cmds.c:750 riscvarchive#24 0x00000000005445cf in source_script (file=0x7fffffffd91a "dp-bug.gdb", from_tty=1) at gdb/cli/cli-cmds.c:759 riscvarchive#25 0x00000000007cf6d9 in catch_command_errors (command=0x5445aa <source_script(char const*, int)>, arg=0x7fffffffd91a "dp-bug.gdb", from_tty=1, do_bp_actions=false) at gdb/main.c:523 riscvarchive#26 0x00000000007cf85d in execute_cmdargs (cmdarg_vec=0x7fffffffd1b0, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffd18c) at gdb/main.c:615 riscvarchive#27 0x00000000007d0c8e in captured_main_1 (context=0x7fffffffd3f0) at gdb/main.c:1322 riscvarchive#28 0x00000000007d0eba in captured_main (data=0x7fffffffd3f0) at gdb/main.c:1343 riscvarchive#29 0x00000000007d0f25 in gdb_main (args=0x7fffffffd3f0) at gdb/main.c:1368 riscvarchive#30 0x00000000004186dd in main (argc=5, argv=0x7fffffffd508) at gdb/gdb.c:32 There are two frames for bpstat_do_actions_1(), one at frame riscvarchive#16 and the other at frame #0. The one at frame riscvarchive#16 is processing the actions for Breakpoint 2, which is a 'continue'. The one at frame #0 is attempting to process the dprintf breakpoint action. However, at this point, the value of 'executing_breakpoint_commands' is 1, forcing an early return, i.e. prior to executing the command(s) associated with the dprintf breakpoint. For the sake of comparison, this is what the stack looks like when hitting the dprintf breakpoint for the second time when issuing the 'run' command from the GDB prompt. Thread 1 "gdb" hit Breakpoint 3, bpstat_do_actions_1 (bsp=0x7fffffffccd8) at /ironwood1/sourceware-git/f34-master/bld/../../worktree-master/gdb/breakpoint.c:4431 4431 if (executing_breakpoint_commands) #0 bpstat_do_actions_1 (bsp=0x7fffffffccd8) at gdb/breakpoint.c:4431 #1 0x00000000004d8bc6 in dprintf_after_condition_true (bs=0x16b0290) at gdb/breakpoint.c:13048 #2 0x00000000004c5caa in bpstat_stop_status (aspace=0x116dbc0, bp_addr=0x40116e, thread=0x13f0e60, ws=0x7fffffffd138, stop_chain=0x16b0290) at gdb/breakpoint.c:5498 #3 0x0000000000768d98 in handle_signal_stop (ecs=0x7fffffffd110) at gdb/infrun.c:6172 riscvarchive#4 0x00000000007678d3 in handle_inferior_event (ecs=0x7fffffffd110) at gdb/infrun.c:5662 riscvarchive#5 0x0000000000763cd5 in fetch_inferior_event () at gdb/infrun.c:4060 riscvarchive#6 0x0000000000746d7d in inferior_event_handler (event_type=INF_REG_EVENT) at gdb/inf-loop.c:41 riscvarchive#7 0x00000000007a702f in handle_target_event (error=0, client_data=0x0) at gdb/linux-nat.c:4207 riscvarchive#8 0x0000000000b8cd6e in gdb_wait_for_event (block=block@entry=0) at gdbsupport/event-loop.cc:701 riscvarchive#9 0x0000000000b8d032 in gdb_wait_for_event (block=0) at gdbsupport/event-loop.cc:597 riscvarchive#10 gdb_do_one_event () at gdbsupport/event-loop.cc:212 riscvarchive#11 0x00000000007cf512 in start_event_loop () at gdb/main.c:421 riscvarchive#12 0x00000000007cf631 in captured_command_loop () at gdb/main.c:481 riscvarchive#13 0x00000000007d0ebf in captured_main (data=0x7fffffffd3f0) at gdb/main.c:1353 riscvarchive#14 0x00000000007d0f25 in gdb_main (args=0x7fffffffd3f0) at gdb/main.c:1368 riscvarchive#15 0x00000000004186dd in main (argc=5, argv=0x7fffffffd508) at gdb/gdb.c:32 This relatively short backtrace is due to the current UI's async field being set to 1. Yet another thing to be aware of regarding this problem is the difference in the way that commands associated to dprintf breakpoints versus regular breakpoints are handled. While they both use a command list associated with the breakpoint, regular breakpoints will place the commands to be run on the bpstat chain constructed in bp_stop_status(). These commands are run later on. For dprintf breakpoints, commands are run via the 'after_condition_true' function pointer directly from bpstat_stop_status(). (The 'commands' field in the bpstat is cleared in dprintf_after_condition_true(). This prevents the dprintf commands from being run again later on when other commands on the bpstat chain are processed.) Another thing that I noticed is that dprintf breakpoints are the only type of breakpoint which use 'after_condition_true'. This suggests that one possible way of fixing this problem, that of making dprintf breakpoints work more like regular breakpoints, probably won't work. (I must admit, however, that my understanding of this code isn't complete enough to say why. I'll trust that whoever implemented it had a good reason for doing it this way.) The comment referenced earlier regarding 'executing_breakpoint_commands' states that the reason for checking this variable is to avoid potential endless recursion when a 'source' command appears in bs->commands. We know that a dprintf command is constrained to either 1) execution of a GDB printf command, 2) an inferior function call of a printf-like function, or 3) execution of an agent-printf command. Therefore, infinite recursion due to a 'source' command cannot happen when executing commands upon hitting a dprintf breakpoint. I chose to fix this problem by having dprintf_after_condition_true() directly call execute_control_commands(). This means that it no longer attempts to go through bpstat_do_actions_1() avoiding the infinite recursion check for potential 'source' commands on the command chain. I think it simplifies this code a little bit too, a definite bonus. Summary: * breakpoint.c (dprintf_after_condition_true): Don't call bpstat_do_actions_1(). Call execute_control_commands() instead.
Nelson1225
pushed a commit
that referenced
this issue
Feb 10, 2022
g++ 11.1.0 has a bug where it will emit a negative DW_AT_data_member_location in some cases: $ cat test.cpp #include <memory> int main() { std::unique_ptr<int> ptr; } $ g++ -g test.cpp $ llvm-dwarfdump -F a.out ... 0x00000964: DW_TAG_member DW_AT_name [DW_FORM_strp] ("_M_head_impl") DW_AT_decl_file [DW_FORM_data1] ("/usr/include/c++/11.1.0/tuple") DW_AT_decl_line [DW_FORM_data1] (125) DW_AT_decl_column [DW_FORM_data1] (0x27) DW_AT_type [DW_FORM_ref4] (0x0000067a "default_delete<int>") DW_AT_data_member_location [DW_FORM_sdata] (-1) ... This leads to a GDB crash (when built with ASan, otherwise probably garbage results), since it tries to read just before (to the left, in ASan speak) of the value's buffer: ==888645==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000c52af at pc 0x7f711b239f4b bp 0x7fff356bd470 sp 0x7fff356bcc18 READ of size 1 at 0x6020000c52af thread T0 #0 0x7f711b239f4a in __interceptor_memcpy /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 #1 0x555c4977efa1 in value_contents_copy_raw /home/simark/src/binutils-gdb/gdb/value.c:1347 #2 0x555c497909cd in value_primitive_field(value*, long, int, type*) /home/simark/src/binutils-gdb/gdb/value.c:3126 #3 0x555c478f2eaa in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:333 #4 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #5 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #6 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #7 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #8 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #9 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #10 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #11 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #12 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #13 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 #14 0x555c49759b17 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1151 #15 0x555c478f2fcb in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:335 #16 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #17 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #18 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #19 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #20 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #21 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 #22 0x555c49759b17 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1151 #23 0x555c478f2fcb in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:335 #24 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #25 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #26 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #27 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 #28 0x555c49759b17 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1151 #29 0x555c4760f04c in c_value_print(value*, ui_file*, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:587 #30 0x555c483ff954 in language_defn::value_print(value*, ui_file*, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:614 #31 0x555c49759f61 in value_print(value*, ui_file*, value_print_options const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1189 #32 0x555c48950f70 in print_formatted /home/simark/src/binutils-gdb/gdb/printcmd.c:337 #33 0x555c48958eda in print_value(value*, value_print_options const&) /home/simark/src/binutils-gdb/gdb/printcmd.c:1258 #34 0x555c48959891 in print_command_1 /home/simark/src/binutils-gdb/gdb/printcmd.c:1367 #35 0x555c4895a3df in print_command /home/simark/src/binutils-gdb/gdb/printcmd.c:1458 #36 0x555c4767f974 in do_simple_func /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:97 #37 0x555c47692e25 in cmd_func(cmd_list_element*, char const*, int) /home/simark/src/binutils-gdb/gdb/cli/cli-decode.c:2475 #38 0x555c4936107e in execute_command(char const*, int) /home/simark/src/binutils-gdb/gdb/top.c:670 #39 0x555c485f1bff in catch_command_errors /home/simark/src/binutils-gdb/gdb/main.c:523 #40 0x555c485f249c in execute_cmdargs /home/simark/src/binutils-gdb/gdb/main.c:618 #41 0x555c485f6677 in captured_main_1 /home/simark/src/binutils-gdb/gdb/main.c:1317 #42 0x555c485f6c83 in captured_main /home/simark/src/binutils-gdb/gdb/main.c:1338 #43 0x555c485f6d65 in gdb_main(captured_main_args*) /home/simark/src/binutils-gdb/gdb/main.c:1363 #44 0x555c46e41ba8 in main /home/simark/src/binutils-gdb/gdb/gdb.c:32 #45 0x7f71198bcb24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24) #46 0x555c46e4197d in _start (/home/simark/build/binutils-gdb-one-target/gdb/gdb+0x77f197d) 0x6020000c52af is located 1 bytes to the left of 8-byte region [0x6020000c52b0,0x6020000c52b8) allocated by thread T0 here: #0 0x7f711b2b7459 in __interceptor_calloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:154 #1 0x555c470acdc9 in xcalloc /home/simark/src/binutils-gdb/gdb/alloc.c:100 #2 0x555c49b775cd in xzalloc(unsigned long) /home/simark/src/binutils-gdb/gdbsupport/common-utils.cc:29 #3 0x555c4977bdeb in allocate_value_contents /home/simark/src/binutils-gdb/gdb/value.c:1029 #4 0x555c4977be25 in allocate_value(type*) /home/simark/src/binutils-gdb/gdb/value.c:1040 #5 0x555c4979030d in value_primitive_field(value*, long, int, type*) /home/simark/src/binutils-gdb/gdb/value.c:3092 #6 0x555c478f6280 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:501 #7 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #8 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #9 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #10 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #11 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #12 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #13 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #14 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #15 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 #16 0x555c49759b17 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1151 #17 0x555c478f2fcb in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:335 #18 0x555c478f63b2 in cp_print_value /home/simark/src/binutils-gdb/gdb/cp-valprint.c:513 #19 0x555c478f02ca in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:161 #20 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #21 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #22 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #23 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 #24 0x555c49759b17 in common_val_print(value*, ui_file*, int, value_print_options const*, language_defn const*) /home/simark/src/binutils-gdb/gdb/valprint.c:1151 #25 0x555c478f2fcb in cp_print_value_fields(value*, ui_file*, int, value_print_options const*, type**, int) /home/simark/src/binutils-gdb/gdb/cp-valprint.c:335 #26 0x555c4760d45f in c_value_print_struct /home/simark/src/binutils-gdb/gdb/c-valprint.c:383 #27 0x555c4760df4c in c_value_print_inner(value*, ui_file*, int, value_print_options const*) /home/simark/src/binutils-gdb/gdb/c-valprint.c:438 #28 0x555c483ff9a7 in language_defn::value_print_inner(value*, ui_file*, int, value_print_options const*) const /home/simark/src/binutils-gdb/gdb/language.c:632 #29 0x555c49758b68 in do_val_print /home/simark/src/binutils-gdb/gdb/valprint.c:1048 Since there are some binaries with this in the wild, I think it would be useful for GDB to work around this. I did the obvious simple thing, if the DW_AT_data_member_location's value is -1, replace it with 0. I added a producer check to only apply this fixup for GCC 11. The idea is that if some other compiler ever uses a DW_AT_data_member_location value of -1 by mistake, we don't know (before analyzing the bug at least) if they did mean 0 or some other value. So I wouldn't want to apply the fixup in that case. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28063 Change-Id: Ieef3459b0b9bbce8bdad838ba83b4b64e7269d42
Nelson1225
pushed a commit
that referenced
this issue
Feb 10, 2022
Starting with commit commit 1da5d0e Date: Tue Jan 4 08:02:24 2022 -0700 Change how Python architecture and language are handled we see a failure in gdb.threads/killed-outside.exp: ... Executing on target: kill -9 16622 (timeout = 300) builtin_spawn -ignore SIGHUP kill -9 16622 continue Continuing. Couldn't get registers: No such process. (gdb) [Thread 0x7ffff77c2700 (LWP 16626) exited] Program terminated with signal SIGKILL, Killed. The program no longer exists. FAIL: gdb.threads/killed-outside.exp: prompt after first continue (timeout) This is not a regression but a failure due to a change in GDB's output. Prior to the aforementioned commit, GDB has been printing the "Couldn't get registers: No such process." message twice. The second one came from (top-gdb) bt #0 amd64_linux_nat_target::fetch_registers (this=0x555557f31440 <the_amd64_linux_nat_target>, regcache=0x555558805ce0, regnum=16) at /gdb-up/gdb/amd64-linux-nat.c:225 #1 0x000055555640ac5f in target_ops::fetch_registers (this=0x555557d636d0 <the_thread_db_target>, arg0=0x555558805ce0, arg1=16) at /gdb-up/gdb/target-delegates.c:502 #2 0x000055555641a647 in target_fetch_registers (regcache=0x555558805ce0, regno=16) at /gdb-up/gdb/target.c:3945 #3 0x0000555556278e68 in regcache::raw_update (this=0x555558805ce0, regnum=16) at /gdb-up/gdb/regcache.c:587 #4 0x0000555556278f14 in readable_regcache::raw_read (this=0x555558805ce0, regnum=16, buf=0x555558881950 "") at /gdb-up/gdb/regcache.c:601 #5 0x00005555562792aa in readable_regcache::cooked_read (this=0x555558805ce0, regnum=16, buf=0x555558881950 "") at /gdb-up/gdb/regcache.c:690 #6 0x000055555627965e in readable_regcache::cooked_read_value (this=0x555558805ce0, regnum=16) at /gdb-up/gdb/regcache.c:748 #7 0x0000555556352a37 in sentinel_frame_prev_register (this_frame=0x555558181090, this_prologue_cache=0x5555581810a8, regnum=16) at /gdb-up/gdb/sentinel-frame.c:53 #8 0x0000555555fa4773 in frame_unwind_register_value (next_frame=0x555558181090, regnum=16) at /gdb-up/gdb/frame.c:1235 #9 0x0000555555fa420d in frame_register_unwind (next_frame=0x555558181090, regnum=16, optimizedp=0x7fffffffd570, unavailablep=0x7fffffffd574, lvalp=0x7fffffffd57c, addrp=0x7fffffffd580, realnump=0x7fffffffd578, bufferp=0x7fffffffd5b0 "") at /gdb-up/gdb/frame.c:1143 #10 0x0000555555fa455f in frame_unwind_register (next_frame=0x555558181090, regnum=16, buf=0x7fffffffd5b0 "") at /gdb-up/gdb/frame.c:1199 #11 0x00005555560178e2 in i386_unwind_pc (gdbarch=0x5555587c4a70, next_frame=0x555558181090) at /gdb-up/gdb/i386-tdep.c:1972 #12 0x0000555555cd2b9d in gdbarch_unwind_pc (gdbarch=0x5555587c4a70, next_frame=0x555558181090) at /gdb-up/gdb/gdbarch.c:3007 #13 0x0000555555fa3a5b in frame_unwind_pc (this_frame=0x555558181090) at /gdb-up/gdb/frame.c:948 #14 0x0000555555fa7621 in get_frame_pc (frame=0x555558181160) at /gdb-up/gdb/frame.c:2572 #15 0x0000555555fa7706 in get_frame_address_in_block (this_frame=0x555558181160) at /gdb-up/gdb/frame.c:2602 #16 0x0000555555fa77d0 in get_frame_address_in_block_if_available (this_frame=0x555558181160, pc=0x7fffffffd708) at /gdb-up/gdb/frame.c:2665 #17 0x0000555555fa5f8d in select_frame (fi=0x555558181160) at /gdb-up/gdb/frame.c:1890 #18 0x0000555555fa5bab in lookup_selected_frame (a_frame_id=..., frame_level=-1) at /gdb-up/gdb/frame.c:1720 #19 0x0000555555fa5e47 in get_selected_frame (message=0x0) at /gdb-up/gdb/frame.c:1810 #20 0x0000555555cc9c6e in get_current_arch () at /gdb-up/gdb/arch-utils.c:848 #21 0x000055555625b239 in gdbpy_before_prompt_hook (extlang=0x555557451f20 <extension_language_python>, current_gdb_prompt=0x555557f4d890 <top_prompt+16> "(gdb) ") at /gdb-up/gdb/python/python.c:1063 #22 0x0000555555f7cfbb in ext_lang_before_prompt (current_gdb_prompt=0x555557f4d890 <top_prompt+16> "(gdb) ") at /gdb-up/gdb/extension.c:922 #23 0x0000555555f7d442 in std::_Function_handler<void (char const*), void (*)(char const*)>::_M_invoke(std::_Any_data const&, char const*&&) (__functor=..., __args#0=@0x7fffffffd900: 0x555557f4d890 <top_prompt+16> "(gdb) ") at /usr/include/c++/7/bits/std_function.h:316 #24 0x0000555555f752dd in std::function<void (char const*)>::operator()(char const*) const (this=0x55555817d838, __args#0=0x555557f4d890 <top_prompt+16> "(gdb) ") at /usr/include/c++/7/bits/std_function.h:706 #25 0x0000555555f75100 in gdb::observers::observable<char const*>::notify (this=0x555557f49060 <gdb::observers::before_prompt>, args#0=0x555557f4d890 <top_prompt+16> "(gdb) ") at /gdb-up/gdb/../gdbsupport/observable.h:150 #26 0x0000555555f736dc in top_level_prompt () at /gdb-up/gdb/event-top.c:444 #27 0x0000555555f735ba in display_gdb_prompt (new_prompt=0x0) at /gdb-up/gdb/event-top.c:411 #28 0x00005555564611a7 in tui_on_command_error () at /gdb-up/gdb/tui/tui-interp.c:205 #29 0x0000555555c2173f in std::_Function_handler<void (), void (*)()>::_M_invoke(std::_Any_data const&) (__functor=...) at /usr/include/c++/7/bits/std_function.h:316 #30 0x0000555555e10c20 in std::function<void ()>::operator()() const (this=0x5555580f9028) at /usr/include/c++/7/bits/std_function.h:706 #31 0x0000555555e10973 in gdb::observers::observable<>::notify() const (this=0x555557f48d20 <gdb::observers::command_error>) at /gdb-up/gdb/../gdbsupport/observable.h:150 #32 0x00005555560e9b3f in start_event_loop () at /gdb-up/gdb/main.c:438 #33 0x00005555560e9bcc in captured_command_loop () at /gdb-up/gdb/main.c:481 #34 0x00005555560eb616 in captured_main (data=0x7fffffffddd0) at /gdb-up/gdb/main.c:1348 #35 0x00005555560eb67c in gdb_main (args=0x7fffffffddd0) at /gdb-up/gdb/main.c:1363 #36 0x0000555555c1b6b3 in main (argc=12, argv=0x7fffffffded8) at /gdb-up/gdb/gdb.c:32 Commit 1da5d0e eliminated the call to 'get_current_arch' in 'gdbpy_before_prompt_hook'. Hence, the second instance of "Couldn't get registers: No such process." does not appear anymore. Fix the failure by updating the regular expression in the test.
Liaoshihua
pushed a commit
to Liaoshihua/riscv-binutils-gdb
that referenced
this issue
May 9, 2022
Commit 152a174 ("gdb: prune inferiors at end of fetch_inferior_event, fix intermittent failure of gdb.threads/fork-plus-threads.exp") broke some tests with the native-gdbserver board, such as: (gdb) PASS: gdb.base/step-over-syscall.exp: detach-on-fork=off: follow-fork=child: break cond on target : vfork: break marker continue^M Continuing.^M terminate called after throwing an instance of 'gdb_exception_error'^M I can manually reproduce the issue by running (just the commands that the test does as a one liner): $ ./gdb -q --data-directory=data-directory \ testsuite/outputs/gdb.base/step-over-syscall/step-over-vfork \ -ex "tar rem | ../gdbserver/gdbserver - testsuite/outputs/gdb.base/step-over-syscall/step-over-vfork" \ -ex "b main" \ -ex c \ -ex "d 1" \ -ex "set displaced-stepping off" \ -ex "b *0x7ffff7d7ac5a if main == 0" \ -ex "set detach-on-fork off" \ -ex "set follow-fork-mode child" \ -ex c \ -ex "inferior 1" \ -ex "b marker" \ -ex c ... where 0x7ffff7d7ac5a is the exact address of the vfork syscall (which can be found by looking at gdb.log). The important part of the above is that a vfork syscall creates inferior 2, then inferior 2 executes until exit, then we switch back to inferior 1 and try to resume it. The uncaught exception happens here: riscvarchive#4 0x00005596969d81a9 in error (fmt=0x559692da9e40 "Cannot execute this command while the target is running.\nUse the \"interrupt\" command to stop the target\nand then try again.") at /home/simark/src/binutils-gdb/gdbsupport/errors.cc:43 riscvarchive#5 0x0000559695af6f66 in remote_target::putpkt_binary (this=0x617000038080, buf=0x559692da4380 "qSymbol::", cnt=9) at /home/simark/src/binutils-gdb/gdb/remote.c:9560 riscvarchive#6 0x0000559695af6aaf in remote_target::putpkt (this=0x617000038080, buf=0x559692da4380 "qSymbol::") at /home/simark/src/binutils-gdb/gdb/remote.c:9518 riscvarchive#7 0x0000559695ab50dc in remote_target::remote_check_symbols (this=0x617000038080) at /home/simark/src/binutils-gdb/gdb/remote.c:5141 riscvarchive#8 0x0000559695b3cccf in remote_new_objfile (objfile=0x0) at /home/simark/src/binutils-gdb/gdb/remote.c:14600 riscvarchive#9 0x0000559693bc52a9 in std::__invoke_impl<void, void (*&)(objfile*), objfile*> (__f=@0x61b0000167f8: 0x559695b3cb1d <remote_new_objfile(objfile*)>) at /usr/include/c++/11.2.0/bits/invoke.h:61 riscvarchive#10 0x0000559693bb2848 in std::__invoke_r<void, void (*&)(objfile*), objfile*> (__fn=@0x61b0000167f8: 0x559695b3cb1d <remote_new_objfile(objfile*)>) at /usr/include/c++/11.2.0/bits/invoke.h:111 riscvarchive#11 0x0000559693b8dddf in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7ffe0bae0590: 0x0) at /usr/include/c++/11.2.0/bits/std_function.h:291 riscvarchive#12 0x00005596956374b2 in std::function<void (objfile*)>::operator()(objfile*) const (this=0x61b0000167f8, __args#0=0x0) at /usr/include/c++/11.2.0/bits/std_function.h:560 riscvarchive#13 0x0000559695633c64 in gdb::observers::observable<objfile*>::notify (this=0x55969ef5c480 <gdb::observers::new_objfile>, args#0=0x0) at /home/simark/src/binutils-gdb/gdb/../gdbsupport/observable.h:150 riscvarchive#14 0x0000559695df6cc2 in clear_symtab_users (add_flags=...) at /home/simark/src/binutils-gdb/gdb/symfile.c:2873 riscvarchive#15 0x000055969574c263 in program_space::~program_space (this=0x6120000c8a40, __in_chrg=<optimized out>) at /home/simark/src/binutils-gdb/gdb/progspace.c:154 riscvarchive#16 0x0000559694fc086b in delete_inferior (inf=0x61700003bf80) at /home/simark/src/binutils-gdb/gdb/inferior.c:205 riscvarchive#17 0x0000559694fc341f in prune_inferiors () at /home/simark/src/binutils-gdb/gdb/inferior.c:390 riscvarchive#18 0x0000559695017ada in fetch_inferior_event () at /home/simark/src/binutils-gdb/gdb/infrun.c:4293 riscvarchive#19 0x0000559694f629e6 in inferior_event_handler (event_type=INF_REG_EVENT) at /home/simark/src/binutils-gdb/gdb/inf-loop.c:41 riscvarchive#20 0x0000559695b3b0e3 in remote_async_serial_handler (scb=0x6250001ef100, context=0x6170000380a8) at /home/simark/src/binutils-gdb/gdb/remote.c:14466 riscvarchive#21 0x0000559695c59eb7 in run_async_handler_and_reschedule (scb=0x6250001ef100) at /home/simark/src/binutils-gdb/gdb/ser-base.c:138 riscvarchive#22 0x0000559695c5a42a in fd_event (error=0, context=0x6250001ef100) at /home/simark/src/binutils-gdb/gdb/ser-base.c:189 riscvarchive#23 0x00005596969d9ebf in handle_file_event (file_ptr=0x60700005af40, ready_mask=1) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:574 riscvarchive#24 0x00005596969da7fa in gdb_wait_for_event (block=0) at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:700 riscvarchive#25 0x00005596969d8539 in gdb_do_one_event () at /home/simark/src/binutils-gdb/gdbsupport/event-loop.cc:212 If I enable "set debug infrun" just before the last continue, we see: (gdb) continue Continuing. [infrun] clear_proceed_status_thread: 965604.965604.0 [infrun] proceed: enter [infrun] proceed: addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT [infrun] scoped_disable_commit_resumed: reason=proceeding [infrun] start_step_over: enter [infrun] start_step_over: stealing global queue of threads to step, length = 0 [infrun] operator(): step-over queue now empty [infrun] start_step_over: exit [infrun] resume_1: step=0, signal=GDB_SIGNAL_0, trap_expected=0, current thread [965604.965604.0] at 0x7ffff7d7ac5c [infrun] do_target_resume: resume_ptid=965604.0.0, step=0, sig=GDB_SIGNAL_0 [infrun] prepare_to_wait: prepare_to_wait [infrun] reset: reason=proceeding [infrun] maybe_set_commit_resumed_all_targets: enabling commit-resumed for target remote [infrun] maybe_call_commit_resumed_all_targets: calling commit_resumed for target remote [infrun] proceed: exit [infrun] fetch_inferior_event: enter [infrun] scoped_disable_commit_resumed: reason=handling event [infrun] do_target_wait: Found 2 inferiors, starting at pz9115#1 [infrun] random_pending_event_thread: None found. [infrun] print_target_wait_results: target_wait (-1.0.0 [process -1], status) = [infrun] print_target_wait_results: 965604.965604.0 [Thread 965604.965604], [infrun] print_target_wait_results: status->kind = VFORK_DONE [infrun] handle_inferior_event: status->kind = VFORK_DONE [infrun] context_switch: Switching context from 0.0.0 to 965604.965604.0 [infrun] handle_vfork_done: not waiting for a vfork-done event [infrun] start_step_over: enter [infrun] start_step_over: stealing global queue of threads to step, length = 0 [infrun] operator(): step-over queue now empty [infrun] start_step_over: exit [infrun] resume_1: step=0, signal=GDB_SIGNAL_0, trap_expected=0, current thread [965604.965604.0] at 0x7ffff7d7ac5c [infrun] do_target_resume: resume_ptid=965604.0.0, step=0, sig=GDB_SIGNAL_0 [infrun] prepare_to_wait: prepare_to_wait [infrun] reset: reason=handling event [infrun] maybe_set_commit_resumed_all_targets: enabling commit-resumed for target remote [infrun] maybe_call_commit_resumed_all_targets: calling commit_resumed for target remote terminate called after throwing an instance of 'gdb_exception_error' What happens is: - After doing the "continue" on inferior 1, the remote target gives us a VFORK_DONE event. The core ignores it and resumes inferior 1. - Since prune_inferiors is now called after each handled event, in fetch_inferior_event, it is called after we handled that VFORK_DONE event and resumed inferior 1. - Inferior 2 is pruned, which (see backtrace above) causes its program space to be deleted, which clears the symtabs for that program space, which calls the new_objfile observable and remote_new_objfile observer (with a nullptr objfile, to indicate that the previously loaded symbols have been discarded), which calls remote_check_symbols. remote_check_symbols is the function that sends the qSymbol packet, to let the remote side ask for symbol addresses. The problem is that the remote target is working in all-stop / sync mode and is currently resumed. It has sent a vCont packet to resume the target and is waiting for a stop reply. It can't send any packets in the mean time. That causes the exception to be thrown. This wasn't a problem before, when prune_inferiors was called in normal_stop, because it was always called at a time the target was not resumed. An important observation here is that the new_objfile observable is invoked for a change in inferior 2's program space (inferior 2's program space is the current program space). Inferior 2 isn't bound to any process on the remote side (it has exited, that's why it's being pruned). It doesn't make sense to try to send a qSymbol packet for a process that doesn't exist on the remote side. remote_check_symbols actually attempts to avoid that: /* The remote side has no concept of inferiors that aren't running yet, it only knows about running processes. If we're connected but our current inferior is not running, we should not invite the remote target to request symbol lookups related to its (unrelated) current process. */ if (!target_has_execution ()) return; The problem here is that while inferior 2's program space is the current program space, inferior 1 is the current inferior. So the check above passes, since inferior has execution. We therefore try to send a qSymbol packet for inferior 1 in reaction to a change in inferior 2's program space, that's wrong. This exposes a conceptual flaw in remote_new_objfile. The "new_objfile" event concerns a specific program space, which can concern multiple inferiors, as inferiors can share a program space. We shouldn't consider the current inferior at all, but instead all inferiors bound to the affected program space. Especially since the current inferior can be unrelated to the current program space at that point. To be clear, we are in this state because ~program_space sets itself as the current program space, but there is no more inferior having that program space to switch to, inferior 2 has already been unlinked. To fix this, make remote_new_objfile iterate on all inferiors bound to the affected program space. Remove the target_has_execution check from remote_check_symbols, replace it with an assert. All callers must ensure that the current inferior has execution before calling it. Change-Id: Ica643145bcc03115248290fd310cadab8ec8371c
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Proposed patch in #20
A more robust fix for additional OSes might be required.
The text was updated successfully, but these errors were encountered: