Fix "nosharedlibrary + continue + shared lib event" crash

Message ID 20190409131410.10205-1-palves@redhat.com
State New
Headers show
Series
  • Fix "nosharedlibrary + continue + shared lib event" crash
Related show

Commit Message

Pedro Alves April 9, 2019, 1:14 p.m.
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:
yyyy-mm-dd  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:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.base/solib-probes-nosharedlibrary.c,
	gdb.base/solib-probes-nosharedlibrary.exp: New files.
---
 gdb/solib-svr4.c                                   | 46 +++++++++++++++++--
 .../gdb.base/solib-probes-nosharedlibrary.c        | 22 ++++++++++
 .../gdb.base/solib-probes-nosharedlibrary.exp      | 51 ++++++++++++++++++++++
 3 files changed, 116 insertions(+), 3 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.c
 create mode 100644 gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.exp

-- 
2.14.5

Comments

Simon Marchi April 11, 2019, 2:49 a.m. | #1
On 2019-04-09 9:14 a.m., Pedro Alves wrote:
> 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.


I am not able to reproduce the problem, and the test doesn't fail here, without
the rest of the patch applied.  I think it's because on my system gdb doesn't use
the probe based interface.

Anyhow, the fix makes sense.  Since the probe is deleted on objfile destruction, the
corresponding probe_and_action structures should too.

Simon
Pedro Alves April 22, 2019, 1:40 p.m. | #2
On 4/11/19 3:49 AM, Simon Marchi wrote:
> On 2019-04-09 9:14 a.m., Pedro Alves wrote:

>> 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.

> 

> I am not able to reproduce the problem, and the test doesn't fail here, without

> the rest of the patch applied.  I think it's because on my system gdb doesn't use

> the probe based interface.

> 

> Anyhow, the fix makes sense.  Since the probe is deleted on objfile destruction, the

> corresponding probe_and_action structures should too.


Thanks for the review.  I've pushed it in now, with an additional 

 "On systems that use the probes-based solib interface, "

at the beginning of the commit log.

Thanks,
Pedro Alves

Patch

diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index cf83196721f..2c79dfec2bb 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);
 }
diff --git a/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.c b/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.c
new file mode 100644
index 00000000000..d94b8074ec0
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.c
@@ -0,0 +1,22 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+main ()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.exp b/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.exp
new file mode 100644
index 00000000000..0d5dc870ad5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/solib-probes-nosharedlibrary.exp
@@ -0,0 +1,51 @@ 
+# Copyright 2005-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Regression test for a bug where GDB would misbehave (most likely
+# crash) if you ran the "nosharelibrary" command, continued execution,
+# and then the program hit the shared library event breakpoint.  GDB
+# would deference a dangling solib event probe pointer.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
+    return -1
+}
+
+if {$use_gdb_stub && [target_info exists gdb,do_reload_on_run]} {
+    # This is the path taken by gdbserver "target remote" boards.
+    if { [gdb_reload] != 0 } {
+	untested "could not run to initial instruction"
+	return
+    }
+    pass "stopped at entry"
+} else {
+    if { [gdb_starti_cmd] < 0 } {
+	untested "could not run to initial instruction"
+	return
+    }
+    gdb_test "" "Program stopped.*" "stopped at entry"
+}
+
+# The program should stop at the first instruction, before the shared
+# library event breakpoint is first hit.  On systems where probes are
+# present in the dynamic linker, such as GNU/Linux, discarding all
+# shared libraries discards such probes too.  The probes-based
+# interface can no longer be used.
+gdb_test_no_output "nosharedlibrary"
+
+# Continue to main(), past the solib event.
+gdb_breakpoint main
+gdb_continue_to_breakpoint "main"