diff options
author | Pedro Alves <palves@redhat.com> | 2019-04-22 14:20:59 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2019-04-22 14:20:59 +0100 |
commit | 7905fc359d6921c411999633e382330e6fd04fb6 (patch) | |
tree | 0f3a244806093ebf3563379e57fceaf444a10a15 /gdb/solib-svr4.c | |
parent | 73f8a5908695e96d8ecd5e0fbe9f1ebb16179547 (diff) | |
download | gdb-7905fc359d6921c411999633e382330e6fd04fb6.zip gdb-7905fc359d6921c411999633e382330e6fd04fb6.tar.gz gdb-7905fc359d6921c411999633e382330e6fd04fb6.tar.bz2 |
Fix "nosharedlibrary + continue + shared lib event" crash
On systems that use the probes-based solib interface, GDB misbehaves
if you run the "nosharelibrary" command, continue execution, and then
the program hits the shared library event breakpoint. On my system it
aborts like this:
(gdb) nosharedlibrary
(gdb) c
Continuing.
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
Though it's really undefined behavior territory, caused by deferencing
a dangling solib event probe pointer.
I've observed this by running "nosharedlibrary" when stopped at the
entry point, but it should happen at any other point, if the program
does a dlopen/dlclose after.
The fix is to discard an objfile's probes from the svr4 probes table
when an objfile is about to be released.
New test included, works with both native and gdbserver testing.
Valgrind log:
(gdb) starti
(gdb) nosharedlibrary
(gdb) c
Continuing.
==24895== Invalid read of size 8
==24895== at 0x89E5FB: solib_event_probe_action(probe_and_action*) (solib-svr4.c:1735)
==24895== by 0x89E95A: svr4_handle_solib_event() (solib-svr4.c:1872)
==24895== by 0x8A7198: handle_solib_event() (solib.c:1274)
==24895== by 0x4E3407: bpstat_stop_status(address_space const*, unsigned long, thread_info*, target_waitstatus const*, bpstats*) (breakpoint.c:5407)
==24895== by 0x721F41: handle_signal_stop(execution_control_state*) (infrun.c:5685)
==24895== by 0x720B11: handle_inferior_event(execution_control_state*) (infrun.c:5129)
==24895== by 0x71DD93: fetch_inferior_event(void*) (infrun.c:3748)
==24895== by 0x7059C3: inferior_event_handler(inferior_event_type, void*) (inf-loop.c:43)
==24895== by 0x874DF0: remote_async_serial_handler(serial*, void*) (remote.c:14039)
==24895== by 0x894101: run_async_handler_and_reschedule(serial*) (ser-base.c:137)
==24895== by 0x8941E6: fd_event(int, void*) (ser-base.c:188)
==24895== by 0x67AFEF: handle_file_event(file_handler*, int) (event-loop.c:732)
==24895== Address 0x18b63860 is 0 bytes inside a block of size 136 free'd
==24895== at 0x4C2E616: operator delete(void*, unsigned long) (vg_replace_malloc.c:585)
==24895== by 0x8C6A12: stap_probe::~stap_probe() (stap-probe.c:124)
==24895== by 0x66F7DB: probe_key_free(bfd*, void*) (elfread.c:1382)
==24895== by 0x69B705: bfdregistry_callback_adaptor(void (*)(registry_container*, void*), registry_container*, void*) (gdb_bfd.c:131)
==24895== by 0x855A57: registry_clear_data(registry_data_registry*, void (*)(void (*)(registry_container*, void*), registry_container*, void*), registry_container*, registry_fields*) (registry.c:79)
==24895== by 0x855B01: registry_container_free_data(registry_data_registry*, void (*)(void (*)(registry_container*, void*), registry_container*, void*), registry_container*, registry_fields*) (registry.c:92)
==24895== by 0x69B783: bfd_free_data(bfd*) (gdb_bfd.c:131)
==24895== by 0x69C4BA: gdb_bfd_unref(bfd*) (gdb_bfd.c:609)
==24895== by 0x7CC33F: objfile::~objfile() (objfiles.c:651)
==24895== by 0x7CD559: objfile_purge_solibs() (objfiles.c:1021)
==24895== by 0x8A7132: no_shared_libraries(char const*, int) (solib.c:1252)
==24895== by 0x548E3D: do_const_cfunc(cmd_list_element*, char const*, int) (cli-decode.c:106)
==24895== Block was alloc'd at
==24895== at 0x4C2D42A: operator new(unsigned long) (vg_replace_malloc.c:334)
==24895== by 0x8C527C: handle_stap_probe(objfile*, sdt_note*, std::vector<probe*, std::allocator<probe*> >*, unsigned long) (stap-probe.c:1561)
==24895== by 0x8C5535: stap_static_probe_ops::get_probes(std::vector<probe*, std::allocator<probe*> >*, objfile*) const (stap-probe.c:1656)
==24895== by 0x66F71B: elf_get_probes(objfile*) (elfread.c:1365)
==24895== by 0x7EDD85: find_probes_in_objfile(objfile*, char const*, char const*) (probe.c:227)
==24895== by 0x4DF382: create_longjmp_master_breakpoint() (breakpoint.c:3275)
==24895== by 0x4F6562: breakpoint_re_set() (breakpoint.c:13828)
==24895== by 0x8A66AA: solib_add(char const*, int, int) (solib.c:1010)
==24895== by 0x89F7C6: enable_break(svr4_info*, int) (solib-svr4.c:2360)
==24895== by 0x8A104C: svr4_solib_create_inferior_hook(int) (solib-svr4.c:2992)
==24895== by 0x8A70B9: solib_create_inferior_hook(int) (solib.c:1215)
==24895== by 0x70C073: post_create_inferior(target_ops*, int) (infcmd.c:467)
==24895==
pure virtual method called
terminate called without an active exception
==24895==
==24895== Process terminating with default action of signal 6 (SIGABRT): dumping core
==24895== at 0x7CF3750: raise (raise.c:51)
==24895== by 0x7CF4D30: abort (abort.c:79)
==24895== by 0xB008F4: __gnu_cxx::__verbose_terminate_handler() (in build/gdb/gdb)
==24895== by 0xAFF845: __cxxabiv1::__terminate(void (*)()) (in build/gdb/gdb)
==24895== by 0xAFF890: std::terminate() (in build/gdb/gdb)
==24895== by 0xAFF95E: __cxa_pure_virtual (in build/gdb/gdb)
==24895== by 0x89E610: solib_event_probe_action(probe_and_action*) (solib-svr4.c:1735)
==24895== by 0x89E95A: svr4_handle_solib_event() (solib-svr4.c:1872)
==24895== by 0x8A7198: handle_solib_event() (solib.c:1274)
==24895== by 0x4E3407: bpstat_stop_status(address_space const*, unsigned long, thread_info*, target_waitstatus const*, bpstats*) (breakpoint.c:5407)
==24895== by 0x721F41: handle_signal_stop(execution_control_state*) (infrun.c:5685)
==24895== by 0x720B11: handle_inferior_event(execution_control_state*) (infrun.c:5129)
==24895==
Note, this little bit in the patch is just a cleanup that I noticed:
- lookup.prob = prob;
lookup.address = address;
That line isn't necessary because hashing/comparison only looks at the
address.
gdb/ChangeLog:
2019-04-22 Pedro Alves <palves@redhat.com>
* solib-svr4.c (svr4_free_objfile_observer): New.
(probe_and_action::objfile): New field.
(probes_table_htab_remove_objfile_probes)
(probes_table_remove_objfile_probes): New functions.
(register_solib_event_probe): Add 'objfile' parameter. Store it
in the new probe_and_action. Don't store the probe in 'lookup'.
(svr4_create_probe_breakpoints): Pass objfile to
register_solib_event_probe.
(_initialize_svr4_solib): Register a free_objfile observer.
gdb/testsuite/ChangeLog:
2019-04-22 Pedro Alves <palves@redhat.com>
* gdb.base/solib-probes-nosharedlibrary.c,
gdb.base/solib-probes-nosharedlibrary.exp: New files.
Diffstat (limited to 'gdb/solib-svr4.c')
-rw-r--r-- | gdb/solib-svr4.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index cf83196..2c79dfe 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -50,6 +50,7 @@ static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); static void svr4_relocate_main_executable (void); static void svr4_free_library_list (void *p_list); +static void probes_table_remove_objfile_probes (struct objfile *objfile); /* On SVR4 systems, a list of symbols in the dynamic linker where GDB can try to place a breakpoint to monitor shared library @@ -1025,6 +1026,14 @@ struct svr4_library_list CORE_ADDR main_lm; }; +/* This module's 'free_objfile' observer. */ + +static void +svr4_free_objfile_observer (struct objfile *objfile) +{ + probes_table_remove_objfile_probes (objfile); +} + /* Implementation for target_so_ops.free_so. */ static void @@ -1636,6 +1645,9 @@ struct probe_and_action /* The action. */ enum probe_action action; + + /* The objfile where this probe was found. */ + struct objfile *objfile; }; /* Returns a hash code for the probe_and_action referenced by p. */ @@ -1660,11 +1672,37 @@ equal_probe_and_action (const void *p1, const void *p2) return pa1->address == pa2->address; } +/* Traversal function for probes_table_remove_objfile_probes. */ + +static int +probes_table_htab_remove_objfile_probes (void **slot, void *info) +{ + probe_and_action *pa = (probe_and_action *) *slot; + struct objfile *objfile = (struct objfile *) info; + + if (pa->objfile == objfile) + htab_clear_slot (get_svr4_info ()->probes_table, slot); + + return 1; +} + +/* Remove all probes that belong to OBJFILE from the probes table. */ + +static void +probes_table_remove_objfile_probes (struct objfile *objfile) +{ + svr4_info *info = get_svr4_info (); + if (info->probes_table != nullptr) + htab_traverse_noresize (info->probes_table, + probes_table_htab_remove_objfile_probes, objfile); +} + /* Register a solib event probe and its associated action in the probes table. */ static void -register_solib_event_probe (probe *prob, CORE_ADDR address, +register_solib_event_probe (struct objfile *objfile, + probe *prob, CORE_ADDR address, enum probe_action action) { struct svr4_info *info = get_svr4_info (); @@ -1677,7 +1715,6 @@ register_solib_event_probe (probe *prob, CORE_ADDR address, equal_probe_and_action, xfree, xcalloc, xfree); - lookup.prob = prob; lookup.address = address; slot = htab_find_slot (info->probes_table, &lookup, INSERT); gdb_assert (*slot == HTAB_EMPTY_ENTRY); @@ -1686,6 +1723,7 @@ register_solib_event_probe (probe *prob, CORE_ADDR address, pa->prob = prob; pa->address = address; pa->action = action; + pa->objfile = objfile; *slot = pa; } @@ -2030,7 +2068,7 @@ svr4_create_probe_breakpoints (struct gdbarch *gdbarch, CORE_ADDR address = p->get_relocated_address (objfile); create_solib_event_breakpoint (gdbarch, address); - register_solib_event_probe (p, address, action); + register_solib_event_probe (objfile, p, address, action); } } @@ -3224,4 +3262,6 @@ _initialize_svr4_solib (void) svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core; svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints; svr4_so_ops.handle_event = svr4_handle_solib_event; + + gdb::observers::free_objfile.attach (svr4_free_objfile_observer); } |