Re: [patch] Fix remote.c crash on gdbserver close (+fix py-finish-breakpoint.exp for gdbserver) [rediff]

Pedro Alves
2012-01-02T19:49:12Z

On 12/27/2011 11:23 PM, Jan Kratochvil wrote:
> [rediff on top of HEAD]
>
> On Sun, 25 Dec 2011 12:37:45 +0100, Jan Kratochvil wrote:
> Hi,
>
> with gdbserver as from
> http://sourceware.org/gdb/wiki/TestingGDB#Testing_gdbserver_in_a_native_configuration
>
> it will crash:
>
> (gdb) PASS: gdb.python/py-finish-breakpoint.exp: set FinishBP after the exit()
> continue
> Continuing.
> Child exited with status 0
> GDBserver exiting
> [Inferior 1 (Remote target) exited normally]
> SimpleFinishBreakpoint out of scope
> ERROR: Process no longer exists
> Program terminated with signal 11, Segmentation fault.
> #0 0x00000000007d48b9 in serial_debug_p (scb=0x0) at serial.c:584
> 584 return scb->debug_p || global_serial_debug_p;
> (gdb) p scb
> $1 = (struct serial *) 0x0
> (gdb) bt
> #0 in serial_debug_p (scb=0x0) at serial.c:584
> #1 in serial_write (scb=0x0, str=0x7fff727e3300 "$z0,4008a3,1#93", len=15) at serial.c:427
> #2 in putpkt_binary (buf=0x2a279b0 "z0,4008a3,1", cnt=11) at remote.c:6891
> #3 in putpkt (buf=0x2a279b0 "z0,4008a3,1") at remote.c:6823
> #4 in remote_remove_breakpoint (gdbarch=0x28e10f0, bp_tgt=0x2fb3d38) at remote.c:7749
> #5 in target_remove_breakpoint (gdbarch=0x28e10f0, bp_tgt=0x2fb3d38) at target.c:2422
> #6 in bkpt_remove_location (bl=0x2fb3cd0) at breakpoint.c:10967
> #7 in remove_breakpoint_1 (bl=0x2fb3cd0, is=mark_uninserted) at breakpoint.c:2654
> #8 in remove_breakpoint (bl=0x2fb3cd0, is=mark_uninserted) at breakpoint.c:2760
> #9 in update_global_location_list (should_insert=0) at breakpoint.c:10539
> #10 in delete_breakpoint (bpt=0x2f59290) at breakpoint.c:11392
> #11 in bpfinishpy_out_of_scope (bpfinish_obj=0x7fdf3c9f8130) at ./python/py-finishbreakpoint.c:327
> #12 in bpfinishpy_detect_out_scope_cb (b=0x2f59290, args=0x0) at ./python/py-finishbreakpoint.c:356
> #13 in iterate_over_breakpoints (callback=0x65150d<bpfinishpy_detect_out_scope_cb>, data=0x0) at breakpoint.c:13385
> #14 in bpfinishpy_handle_exit (inf=0x281d330) at ./python/py-finishbreakpoint.c:393
> #15 in observer_inferior_exit_notification_stub (data=0x6516b1, args_data=0x7fff727e3740) at observer.inc:887
> #16 in generic_observer_notify (subject=0x284f300, args=0x7fff727e3740) at observer.c:168
> #17 in observer_notify_inferior_exit (inf=0x281d330) at observer.inc:912
> #18 in exit_inferior_1 (inftoex=0x281d330, silent=1) at inferior.c:276
> #19 in exit_inferior_silent (pid=42000) at inferior.c:305
> #20 in discard_all_inferiors () at inferior.c:343
> #21 in remote_close (quitting=0) at remote.c:2950
> #22 in target_close (targ=0x1d19f80, quitting=0) at target.c:3387
> #23 in unpush_target (t=0x1d19f80) at target.c:1024
> #24 in remote_mourn_1 (target=0x1d19f80) at remote.c:7456
> #25 in remote_mourn (ops=0x1d19f80) at remote.c:7449
> #26 in target_mourn_inferior () at target.c:2747
> #27 in handle_inferior_event (ecs=0x7fff727e3c30) at infrun.c:3408
> #28 in wait_for_inferior () at infrun.c:2711
> #29 in proceed (addr=18446744073709551615, siggnal=TARGET_SIGNAL_DEFAULT, step=0) at infrun.c:2276
> #30 in continue_1 (all_threads=0) at infcmd.c:713
> #31 in continue_command (args=0x0, from_tty=1) at infcmd.c:805
>
>
> Reproducible with:
> ../gdbserver/gdbserver :1234 gdb.python/py-finish-breakpoint
> gdb -nx -x ~/.gdbinit -ex r --args ../gdb -nx -ex 'file gdb.python/py-finish-breakpoint' -ex 'target remote localhost:1234' -ex 'b test_exec_exit' -ex c -ex 'source gdb.python/py-finish-breakpoint.py' -ex 'python SimpleFinishBreakpoint(gdb.newest_frame())' -ex c
>
> I have seen this serial_debug_p crash in various GDB debugging cases but they
> were not well reproducible. I understand this bug is unrelated to
> gdb.python/py-finish-breakpoint.exp .
>
> I also tried to reorder remote_close a bit but this patch seems as the right
> one to me.

The issue is that the target is already gone, and we're going through
teardown. What I think would be a bit better is to add a new function
to breakpoint.c, similar to mark_breakpoints_out, like:

void
mark_all_breakpoints_out (void)
{
struct bp_location *bl, **blp_tmp;

ALL_BP_LOCATIONS (bl, blp_tmp)
bl->inserted = 0;
}

and call that from within remote_close, before discard_all_inferiors.

remote_desc == NULL checks throughout remote.c are plain hacks.

Even better would be to do discard_all_inferiors after target_close,
though that's tricky. Perhaps it'd work to do it only if the target
just closed is of process_stratum.