public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* Issues With Thread Events In User Mode GDBServer
@ 2022-09-09 20:04 Bill Messmer
  2022-09-11 18:55 ` Simon Marchi
  0 siblings, 1 reply; 6+ messages in thread
From: Bill Messmer @ 2022-09-09 20:04 UTC (permalink / raw)
  To: gdb

[-- Attachment #1: Type: text/plain, Size: 1776 bytes --]

Folks,

Apologies if this is the wrong mailing list to ask a question regarding GDBServer / RSP and a potential bug.

I have been working on new extensibility API surfaces for the Windows platform debuggers that allow folks to write plug-ins that can connect those debugging tools to a variety of new targets including ones that are not Windows based.  We've had the ability to do this for post-mortem targets for some time and are, of late, working to expand that API surface to various forms of live targets.

As proof of concept for the API surface, I've been experimenting with writing such a plug-in to connect to the standard user mode GDBServer for Linux.  A few things I'll note:


  1.  When thread events are enabled on the server via a QThreadEvents:1, GDBServer immediately crashes on any thread exit in "resume" on a NULL deref of current_thread.



  1.  I tried a quick patch here (adding "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED") to the set of conditions that won't set "current_thread->last_status" and the wXXX thread exit packets get sent; however, regardless of whether the target is in non-stop mode or not, the process is STILL RUNNING at the time the server sends the "wXXX" packet.


Am I missing something with GDBServer and thread events or is this just not well supported...?  The process seems to be stopped at the point that a thread creation event gets sent...  but not for a thread exit...  I assume that's a bug somewhere in GDBServer...?  Or am I misreading the docs at https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html...?  Is there some alternate means by which thread create/exit notifications come...?

Sincerely,

Bill Messmer
wmessmer@microsoft.com<mailto:wmessmer@microsoft.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Issues With Thread Events In User Mode GDBServer
  2022-09-09 20:04 Issues With Thread Events In User Mode GDBServer Bill Messmer
@ 2022-09-11 18:55 ` Simon Marchi
  2022-09-12 18:42   ` [EXTERNAL] " Bill Messmer
  0 siblings, 1 reply; 6+ messages in thread
From: Simon Marchi @ 2022-09-11 18:55 UTC (permalink / raw)
  To: Bill Messmer, gdb



On 2022-09-09 16:04, Bill Messmer via Gdb wrote:
> Folks,
> 
> Apologies if this is the wrong mailing list to ask a question regarding GDBServer / RSP and a potential bug.
> 
> I have been working on new extensibility API surfaces for the Windows platform debuggers that allow folks to write plug-ins that can connect those debugging tools to a variety of new targets including ones that are not Windows based.  We've had the ability to do this for post-mortem targets for some time and are, of late, working to expand that API surface to various forms of live targets.
> 
> As proof of concept for the API surface, I've been experimenting with writing such a plug-in to connect to the standard user mode GDBServer for Linux.  A few things I'll note:
> 
> 
>   1.  When thread events are enabled on the server via a QThreadEvents:1, GDBServer immediately crashes on any thread exit in "resume" on a NULL deref of current_thread.
> 
> 
> 
>   1.  I tried a quick patch here (adding "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED") to the set of conditions that won't set "current_thread->last_status" and the wXXX thread exit packets get sent; however, regardless of whether the target is in non-stop mode or not, the process is STILL RUNNING at the time the server sends the "wXXX" packet.
> 
> 
> Am I missing something with GDBServer and thread events or is this just not well supported...?  The process seems to be stopped at the point that a thread creation event gets sent...  but not for a thread exit...  I assume that's a bug somewhere in GDBServer...?  Or am I misreading the docs at https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html...?  Is there some alternate means by which thread create/exit notifications come...?
> 
> Sincerely,
> 
> Bill Messmer
> wmessmer@microsoft.com<mailto:wmessmer@microsoft.com>

Hi Bill,

I don't quite understand the situation you are describing.  Can you
maybe send a log of the communication between your tool and GDBserver?

Simon

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer
  2022-09-11 18:55 ` Simon Marchi
@ 2022-09-12 18:42   ` Bill Messmer
  2022-09-13 23:39     ` Simon Marchi
  0 siblings, 1 reply; 6+ messages in thread
From: Bill Messmer @ 2022-09-12 18:42 UTC (permalink / raw)
  To: Simon Marchi, gdb

Simon,

Thanks for the response.  I have a silly test app which spins up and then waits on 5 pthreads each of which sleep for a varying amount, compute a Fibonacci number, and then exit.  I spin up the standard gdbserver fetched from Ubuntu VM (gdbserver localhost:1234 ./thread_test) and connect to it.  With that gdbserver, I get the following communication log between my plug-in and the gdbserver (somewhat condensed -- I removed most of the memory related back and forth):

    GDBServerComposition: Command: ?
    GDBServerComposition: CommandOuptut: T0506:0000000000000000;07:10dfffffff7f0000;10:b032fef7ff7f0000;thread:262b;core:e;
    GDBServerComposition: Command: qSupported
    GDBServerComposition: CommandOuptut: PacketSize=47ff;QPassSignals+;QProgramSignals+;QStartupWithShell+;QEnvironmentHexEncoded+;QEnvironmentReset+;QEnvironmentUnset+;QSetWorkingDir+;QCatchSyscalls+;qXfer:libraries-svr4:read+;augmented-libraries-svr4-read+;qXfer:auxv:read+;qXfer:siginfo:read+;qXfer:siginfo:write+;qXfer:features:read+;QStartNoAckMode+;qXfer:osdata:read+;multiprocess+;fork-events+;vfork-events+;exec-events+;QNonStop+;QDisableRandomization+;qXfer:threads:read+;ConditionalTracepoints+;TraceStateVariables+;TracepointSource+;DisconnectedTracing+;StaticTracepoints+;InstallInTrace+;qXfer:statictrace:read+;qXfer:traceframe-info:read+;EnableDisableTracepoints+;QTBuffer:size+;tracenz+;ConditionalBreakpoints+;BreakpointCommands+;QAgent+;Qbtrace:bts+;Qbtrace-conf:bts:size+;Qbtrace:pt+;Qbtrace-conf:pt:size+;Qbtrace:off+;qXfer:btrace:read+;qXfer:btrace-conf:read+;swbreak+;hwbreak+;qXfer:exec-file:read+;vContSupported+;QThreadEvents+;no-resumed+
    GDBServerComposition: Command: qSupported:QThreadEvents+
    GDBServerComposition: CommandOuptut: PacketSize=47ff;QPassSignals+;QProgramSignals+;QStartupWithShell+;QEnvironmentHexEncoded+;QEnvironmentReset+;QEnvironmentUnset+;QSetWorkingDir+;QCatchSyscalls+;qXfer:libraries-svr4:read+;augmented-libraries-svr4-read+;qXfer:auxv:read+;qXfer:siginfo:read+;qXfer:siginfo:write+;qXfer:features:read+;QStartNoAckMode+;qXfer:osdata:read+;multiprocess+;fork-events+;vfork-events+;exec-events+;QNonStop+;QDisableRandomization+;qXfer:threads:read+;ConditionalTracepoints+;TraceStateVariables+;TracepointSource+;DisconnectedTracing+;StaticTracepoints+;InstallInTrace+;qXfer:statictrace:read+;qXfer:traceframe-info:read+;EnableDisableTracepoints+;QTBuffer:size+;tracenz+;ConditionalBreakpoints+;BreakpointCommands+;QAgent+;Qbtrace:bts+;Qbtrace-conf:bts:size+;Qbtrace:pt+;Qbtrace-conf:pt:size+;Qbtrace:off+;qXfer:btrace:read+;qXfer:btrace-conf:read+;swbreak+;hwbreak+;qXfer:exec-file:read+;vContSupported+;QThreadEvents+;no-resumed+
    GDBServerComposition: Command: QThreadEvents:1
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: QNonStop:0
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: qXfer:features:read:target.xml:0,3e8
    GDBServerComposition: CommandOuptut: l<target><architecture>i386:x86-64</architecture><osabi>GNU/Linux</osabi></target>
    GDBServerComposition: Command: qXfer:threads:read::0,3e8
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: qXfer:exec-file:read:262b:0,3e8
    GDBServerComposition: CommandOuptut: l/home/wmessmer/thread_test/thread_test
    GDBServerComposition: Command: qXfer:auxv:read::0,3e8
    GDBServerComposition: CommandOuptut: l!

    <<<< SIGNIFICANT MEMORY RELATED COMMUNICATION REMOVED HERE >>>>

    GDBServerComposition: Command: Z0,555555555100,1
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: qXfer:libraries-svr4:read::0,1000
    GDBServerComposition: CommandOuptut: l<library-list-svr4 version="1.0"/>
    GDBServerComposition: Command: m555555554000,400
    GDBServerComposition: CommandOuptut: 7f454c46...
    GDBServerComposition: Command: m555555554400,400
    GDBServerComposition: CommandOuptut: 00000000...
    GDBServerComposition: Command: m555555554800,400
    GDBServerComposition: CommandOuptut: 00000000...
    GDBServerComposition: Command: m555555554c00,400
    GDBServerComposition: CommandOuptut: 00000000...
    GDBServerComposition: Command: m555555554000,40
    GDBServerComposition: CommandOuptut: 7f454c4602010100000000000000000003003e000100000000110000000000004000000000000000004000000000000000000000400038000d00400025002400
    GDBServerComposition: Command: m555555554000,4
    GDBServerComposition: CommandOuptut: 7f454c46
    GDBServerComposition: Command: m555555554000,4c
    GDBServerComposition: CommandOuptut: 7f454c4602010100000000000000000003003e000100000000110000000000004000000000000000004000000000000000000000400038000d00400025002400060000000400000040000000
    ModLoad: 00005555`55554000 00005555`55558018   /home/wmessmer/thread_test/thread_test
    GDBServerComposition: Command: m555555554000,40
    GDBServerComposition: CommandOuptut: 7f454c4602010100000000000000000003003e000100000000110000000000004000000000000000004000000000000000000000400038000d00400025002400
    GDBServerComposition: Command: m555555554000,4
    GDBServerComposition: CommandOuptut: 7f454c46
    GDBServerComposition: Command: m555555554000,4c
    GDBServerComposition: CommandOuptut: 7f454c4602010100000000000000000003003e000100000000110000000000004000000000000000004000000000000000000000400038000d00400025002400060000000400000040000000
    .
    GDBServerComposition: Command: m3d8,348
    GDBServerComposition: CommandOuptut: E01
    ReadVirtual() failed in GetXStateConfiguration() first read attempt (error == 0.)
    GDBServerComposition: Command: Hg262b
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: g
    GDBServerComposition: CommandOuptut: 00000000...

    <<<< SIGNIFICANT MEMORY RELATED COMMUNICATION REMOVED HERE >>>>
    <<<< INITIAL POINT AT WHICH THE GDBSERVER IS BROKEN IN >>>>

    00007fff`f7fe32b0 4889e7          mov     rdi,rsp
    0:000> g
    GDBServerComposition: Command: m7ffff7fe32b0,1
    GDBServerComposition: CommandOuptut: 48
    GDBServerComposition: Command: Hg262b
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: g
    GDBServerComposition: CommandOuptut: 00000000...
    GDBServerComposition: Command: Hg262b
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: P12=33000000
    GDBServerComposition: CommandOuptut: 
    GDBServerComposition: Command: g
    GDBServerComposition: CommandOuptut: 00000000...
    GDBServerComposition: Command: G00000000...
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T0206:0000000000000000;07:10dfffffff7f0000;10:b032fef7ff7f0000;thread:262b;core:e;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: qXfer:siginfo:read::0,3e8
    GDBServerComposition: CommandOuptut: l 
    
    (262b.262b): Signal SIGINT code SI_USER (Sent by kill, sigsend, raise) at 0x7ffff7fe32b0 originating from PID 262b
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.

    GDBServerComposition: Command: Hg262b
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: g
    GDBServerComposition: CommandOuptut: 00000000...

    <<<< SIGNIFICANT MEMORY RELATED COMMUNICATION REMOVED HERE >>>>

    00007fff`f7fe32b0 4889e7          mov     rdi,rsp
    0:000> g

    GDBServerComposition: Command: m7ffff7fe32b0,1
    GDBServerComposition: CommandOuptut: 48
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T0506:0000000000000000;07:10dfffffff7f0000;10:0151555555550000;thread:262b;core:e;
    GDBServerComposition: Command: z0,555555555100,1
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: g
    GDBServerComposition: CommandOuptut: 1c000000...
    GDBServerComposition: Command: G1c000000...
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: m555555557e68,8
    GDBServerComposition: CommandOuptut: 18e1fff7ff7f0000
    GDBServerComposition: Command: m7ffff7ffe128,8
    GDBServerComposition: CommandOuptut: 0063fcf7ff7f0000
    GDBServerComposition: Command: Z0,7ffff7fc6300,1
    GDBServerComposition: CommandOuptut: OK
    GDBServerComposition: Command: qXfer:libraries-svr4:read::0,1000
    GDBServerComposition: CommandOuptut: l<library-list-svr4 version="1.0" main-lm="0x7ffff7ffe2e0"><library name="linux-vdso.so.1" lm="0x7ffff7ffe890" l_addr="0x7ffff7fc2000" l_ld="0x7ffff7fc23a0"/><library name="/lib/x86_64-linux-gnu/libc.so.6" lm="0x7ffff7fbc160" l_addr="0x7ffff7d8e000" l_ld="0x7ffff7fa6bc0"/><library name="/lib64/ld-linux-x86-64.so.2" lm="0x7ffff7ffdaf0" l_addr="0x7ffff7fc3000" l_ld="0x7ffff7ffce80"/></library-list-svr4>

    <<<< SIGNIFICANT MEMORY RELATED COMMUNICATION TRUNCATED HERE >>>>

    ModLoad: 00007fff`f7fc2000 00007fff`f7fc2000   linux-vdso.so.1
    GDBServerComposition: Command: m7ffff7d8e000,40
    GDBServerComposition: CommandOuptut: 7f454c4602010103000000000000000003003e0001000000509f0200000000004000000000000000f0c021000000000000000000400038000e00400042004100
    GDBServerComposition: Command: m7ffff7d8e000,4
    GDBServerComposition: CommandOuptut: 7f454c46
    GDBServerComposition: Command: m7ffff7d8e000,4c
    GDBServerComposition: CommandOuptut: 7f454c4602010103000000000000000003003e0001000000509f0200000000004000000000000000f0c021000000000000000000400038000e00400042004100060000000400000040000000
    ModLoad: 00007fff`f7d8e000 00007fff`f7fb5e50   /lib/x86_64-linux-gnu/libc.so.6
    GDBServerComposition: Command: m7ffff7fc3000,40
    GDBServerComposition: CommandOuptut: 7f454c4602010103000000000000000003003e0001000000b002020000000000400000000000000068a603000000000000000000400038000b0040001b001a00
    GDBServerComposition: Command: m7ffff7fc3000,4
    GDBServerComposition: CommandOuptut: 7f454c46
    GDBServerComposition: Command: m7ffff7fc3000,4c
    GDBServerComposition: CommandOuptut: 7f454c4602010103000000000000000003003e0001000000b002020000000000400000000000000068a603000000000000000000400038000b0040001b001a00010000000400000000000000
    ModLoad: 00007fff`f7fc3000 00007fff`f7ffe2d8   /lib64/ld-linux-x86-64.so.2
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T05create:;06:80ffffffffffffff;07:009fd8f7ff7f0000;10:ed49ebf7ff7f0000;thread:262c;core:10;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    <thread id="262c" core="16" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T05create:;06:80ffffffffffffff;07:008f58f7ff7f0000;10:ed49ebf7ff7f0000;thread:262d;core:12;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    <thread id="262c" core="16" name="thread_test"/>
    <thread id="262d" core="18" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T05create:;06:80ffffffffffffff;07:007fd8f6ff7f0000;10:ed49ebf7ff7f0000;thread:262e;core:0;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    <thread id="262c" core="16" name="thread_test"/>
    <thread id="262d" core="18" name="thread_test"/>
    <thread id="262e" core="0" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T05create:;06:80ffffffffffffff;07:006f58f6ff7f0000;10:ed49ebf7ff7f0000;thread:262f;core:5;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    <thread id="262c" core="16" name="thread_test"/>
    <thread id="262d" core="18" name="thread_test"/>
    <thread id="262e" core="0" name="thread_test"/>
    <thread id="262f" core="5" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: vCont;c
    GDBServerComposition: CommandOuptut: T05create:;06:80ffffffffffffff;07:005fd8f5ff7f0000;10:ed49ebf7ff7f0000;thread:2630;core:a;
    GDBServerComposition: Command: qXfer:threads:read::0,1000
    GDBServerComposition: CommandOuptut: l<threads>
    <thread id="262b" core="14" name="thread_test"/>
    <thread id="262c" core="16" name="thread_test"/>
    <thread id="262d" core="18" name="thread_test"/>
    <thread id="262e" core="0" name="thread_test"/>
    <thread id="262f" core="5" name="thread_test"/>
    <thread id="2630" core="10" name="thread_test"/>
    </threads>
    GDBServerComposition: Command: vCont;c

    <<<< GDBServer Crashes Here >>>>

The GDBServer then segfaults when the first thread exits.  GDB itself shows that the gdbserver faulted at:

    Program received signal SIGSEGV, Segmentation fault.
    resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
    2966    /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc: No such file or directory.
    (gdb) bt
    #0  resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
    #1  0x000055e854c61020 in handle_v_cont (own_buf=0x55e85604aed0 "vCont;c")
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2910
    #2  handle_v_requests (own_buf=0x55e85604aed0 "vCont;c", packet_len=<optimized out>,
        new_packet_len=<optimized out>) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3177
    #3  0x000055e854c6299e in process_serial_event ()
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4523
    #4  handle_serial_event (err=<optimized out>, client_data=<optimized out>)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4555
    #5  0x000055e854c994b6 in gdb_wait_for_event (block=block@entry=1)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:700
    #6  0x000055e854c9994b in gdb_wait_for_event (block=1)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:596
    #7  gdb_do_one_event () at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:237
    #8  0x000055e854c50872 in start_event_loop ()
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3553
    #9  captured_main (argv=<optimized out>, argc=<optimized out>)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4033
    #10 main (argc=<optimized out>, argv=<optimized out>)
        at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4119

So I went into *resume* and added the "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED) to the below code in that function as the "current_thread->last_status" reference is the source of the segfault:

      if (cs.last_status.kind () != TARGET_WAITKIND_EXITED
          && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED
          && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED
          && cs.last_status.kind () != TARGET_WAITKIND_THREAD_EXITED)
        current_thread->last_status = cs.last_status;

After making this change, the server no longer crashes at the first thread exit, but instead, I get a packet that is

    w0;2635

Here's the problem though.  When I receive the various "T05create;..." packets, the debuggee process is frozen.  There's a bunch of printf's in my test app...  and nothing happens until I issue the vCont back to the server.  On receipt of the w0;2635 packet, however, the process just keeps going...

I suspect that's a bug in the gdbserver (I'm no expert here in either gdbserver or its code).  That's the first question...  and the second is whether there's some other way that thread creations and exits get detected other than QThreadEvents:1 (as this doesn't seem to be well supported).

Sincerely,

Bill Messmer
wmessmer@microsoft.com

-----Original Message-----
From: Simon Marchi <simark@simark.ca> 
Sent: Sunday, September 11, 2022 11:56 AM
To: Bill Messmer <wmessmer@microsoft.com>; gdb@sourceware.org
Subject: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer

[You don't often get email from simark@simark.ca. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]

On 2022-09-09 16:04, Bill Messmer via Gdb wrote:
> Folks,
>
> Apologies if this is the wrong mailing list to ask a question regarding GDBServer / RSP and a potential bug.
>
> I have been working on new extensibility API surfaces for the Windows platform debuggers that allow folks to write plug-ins that can connect those debugging tools to a variety of new targets including ones that are not Windows based.  We've had the ability to do this for post-mortem targets for some time and are, of late, working to expand that API surface to various forms of live targets.
>
> As proof of concept for the API surface, I've been experimenting with writing such a plug-in to connect to the standard user mode GDBServer for Linux.  A few things I'll note:
>
>
>   1.  When thread events are enabled on the server via a QThreadEvents:1, GDBServer immediately crashes on any thread exit in "resume" on a NULL deref of current_thread.
>
>
>
>   1.  I tried a quick patch here (adding "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED") to the set of conditions that won't set "current_thread->last_status" and the wXXX thread exit packets get sent; however, regardless of whether the target is in non-stop mode or not, the process is STILL RUNNING at the time the server sends the "wXXX" packet.
>
>
> Am I missing something with GDBServer and thread events or is this just not well supported...?  The process seems to be stopped at the point that a thread creation event gets sent...  but not for a thread exit...  I assume that's a bug somewhere in GDBServer...?  Or am I misreading the docs at https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsourceware.org%2Fgdb%2Fonlinedocs%2Fgdb%2FGeneral-Query-Packets.html&amp;data=05%7C01%7Cwmessmer%40microsoft.com%7C0880b41dbd38466bdd5a08da942739ce%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637985193606221095%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=at6X74%2FAK1fkpb4aEGEZonPzTqzZ%2FYTgKeV7MEJcsUY%3D&amp;reserved=0...?  Is there some alternate means by which thread create/exit notifications come...?
>
> Sincerely,
>
> Bill Messmer
> wmessmer@microsoft.com<mailto:wmessmer@microsoft.com>

Hi Bill,

I don't quite understand the situation you are describing.  Can you maybe send a log of the communication between your tool and GDBserver?

Simon

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer
  2022-09-12 18:42   ` [EXTERNAL] " Bill Messmer
@ 2022-09-13 23:39     ` Simon Marchi
  2022-09-30 21:08       ` Bill Messmer
  0 siblings, 1 reply; 6+ messages in thread
From: Simon Marchi @ 2022-09-13 23:39 UTC (permalink / raw)
  To: Bill Messmer, gdb

> The GDBServer then segfaults when the first thread exits.  GDB itself shows that the gdbserver faulted at:
>
>     Program received signal SIGSEGV, Segmentation fault.
>     resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
>     2966    /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc: No such file or directory.
>     (gdb) bt
>     #0  resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
>     #1  0x000055e854c61020 in handle_v_cont (own_buf=0x55e85604aed0 "vCont;c")
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2910
>     #2  handle_v_requests (own_buf=0x55e85604aed0 "vCont;c", packet_len=<optimized out>,
>         new_packet_len=<optimized out>) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3177
>     #3  0x000055e854c6299e in process_serial_event ()
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4523
>     #4  handle_serial_event (err=<optimized out>, client_data=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4555
>     #5  0x000055e854c994b6 in gdb_wait_for_event (block=block@entry=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:700
>     #6  0x000055e854c9994b in gdb_wait_for_event (block=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:596
>     #7  gdb_do_one_event () at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:237
>     #8  0x000055e854c50872 in start_event_loop ()
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3553
>     #9  captured_main (argv=<optimized out>, argc=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4033
>     #10 main (argc=<optimized out>, argv=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4119

Thanks for the detailed report.

A bit of background: the only time GDB ever requests thread events from
GDBserver is in non-stop mode, when it wants to stop all threads.  It is
the case described in the QThreadEvent documentation:

   For example, this is used in non-stop mode when GDB stops a set of
   threads and synchronously waits for the their corresponding stop
   replies. Without exit events, if one of the threads exits, GDB would
   hang forever not knowing that it should no longer expect a stop for
   that same thread.

By using QThreadEvents in all-stop mode, you likely trigger some
different code path (not a reason for GDBserver to crash, of course).

I think I was able to reproduce the crash using GDB, with this simple
patch that enables thread events all the time, just like you do:

diff --git a/gdb/remote.c b/gdb/remote.c
index 70f918a7362c..700e2c2b929f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4776,6 +4776,8 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     set_permissions ();

+  this->thread_events (1);
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an

Using a test program similar to yours:

  $ ./gdb -nx -q --data-directory=data-directory a.out -ex "tar rem :1234" -ex c

... leads to gdbserver crashing, the backtrace looks just like yours:

==33707==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000030 (pc 0x55d6edb7df07 bp 0x7fff852bc360 sp 0x7fff852bc350 T0)
==33707==The signal is caused by a READ memory access.
==33707==Hint: address points to the zero page.
    #0 0x55d6edb7df07 in target_waitstatus::reset() /home/smarchi/src/binutils-gdb/gdbserver/../gdb/target/waitstatus.h:400
    #1 0x55d6edbc6519 in target_waitstatus::operator=(target_waitstatus const&) /home/smarchi/src/binutils-gdb/gdbserver/../gdb/target/waitstatus.h:187
    #2 0x55d6edbb6bab in resume /home/smarchi/src/binutils-gdb/gdbserver/server.cc:2931
    #3 0x55d6edbb6523 in handle_v_cont /home/smarchi/src/binutils-gdb/gdbserver/server.cc:2875
    #4 0x55d6edbb8129 in handle_v_requests(char*, int, int*) /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3138
    #5 0x55d6edbc1844 in process_serial_event /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4484
    #6 0x55d6edbc1a9b in handle_serial_event(int, void*) /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4516
    #7 0x55d6edcdcef1 in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:574
    #8 0x55d6edcdd82d in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:695
    #9 0x55d6edcdb4f8 in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:265
    #10 0x55d6edbba12b in start_event_loop /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3514
    #11 0x55d6edbbde10 in captured_main /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3994
    #12 0x55d6edbbe4b8 in main /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4080
    #13 0x7ff01623c28f  (/usr/lib/libc.so.6+0x2328f)
    #14 0x7ff01623c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
    #15 0x55d6edb59ec4 in _start ../sysdeps/x86_64/start.S:115


> So I went into *resume* and added the "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED) to the below code in that function as the "current_thread->last_status" reference is the source of the segfault:
>
>       if (cs.last_status.kind () != TARGET_WAITKIND_EXITED
>           && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED
>           && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED
>           && cs.last_status.kind () != TARGET_WAITKIND_THREAD_EXITED)
>         current_thread->last_status = cs.last_status;

I think that makes sense, as if linux-low.cc has reported
TARGET_WAITKIND_THREAD_EXITED, it has deleted that thread_info, so
current_thread will be made nullptr.

> After making this change, the server no longer crashes at the first thread exit, but instead, I get a packet that is
>
>     w0;2635
>
> Here's the problem though.  When I receive the various "T05create;..." packets, the debuggee process is frozen.  There's a bunch of printf's in my test app...  and nothing happens until I issue the vCont back to the server.  On receipt of the w0;2635 packet, however, the process just keeps going...

That is a bug, from what I understand.  In all-stop, the target should
all threads whenever it returns any stop reply.  This should be done by
the "low" target, linux-low.cc.  Off-hand I don't understand why this
call to stop_all_lwps in linux_process_target::wait_1 doesn't stop the
threads in that situation:

  https://gitlab.com/gnutools/binutils-gdb/-/blob/e9a241e87b42f902d0408704df6bbcd8bf465a46/gdbserver/linux-low.cc#L3463

> I suspect that's a bug in the gdbserver (I'm no expert here in either gdbserver or its code).  That's the first question...  and the second is whether there's some other way that thread creations and exits get detected other than QThreadEvents:1 (as this doesn't seem to be well supported).

Yes, I think it's a bug.  QThreadEvents should be the way to get
notified about thread creation / exit events as it happens.  As
mentioned earlier, it's only used when stopping all threads, at the
moment.  It's not enabled by default because it would be inefficient
when debugging applications with lots of short-lived threads.  I think
it's just that it has never been used in all-stop mode yet, so you are
the lucky one to stumble on those bugs.

Simon

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer
  2022-09-13 23:39     ` Simon Marchi
@ 2022-09-30 21:08       ` Bill Messmer
  2022-10-19 16:19         ` Simon Marchi
  0 siblings, 1 reply; 6+ messages in thread
From: Bill Messmer @ 2022-09-30 21:08 UTC (permalink / raw)
  To: Simon Marchi, gdb

Simon,

Apologies for the delay in response.  I finally had a bit of time to debug through gdbserver while trying to get all of this working on my side...

linux_process_target::wait_1 does *NOT* call stop_all_lwps at all (even in full stop mode) if the event is a termination event.  The relevant block is the large

      if (WIFEXITED (w) || WIFSIGNALED (w))
        {

        ...

          if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
            return filter_exit_event (event_child, ourstatus);

          return ptid_of (current_thread);
        }

I went and tweaked this to:

      if (WIFEXITED (w) || WIFSIGNALED (w))
        {

        ...

          if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
           result = filter_exit_event (event_child, ourstatus);

          result = ptid_of (current_thread);

          if (!non_stop)
            {
              stop_all_lwps(0, NULL);
            }

          return result;
        }

With the tests I have, things appear to largely work as a I'd expect after making these changes.  Again -- I have little familiarity with GDBServer, so I don't know if I'm missing something here.

If this seems reasonably correct to you -- I'm happy to submit a patch.

Sincerely,

Bill Messmer
wmessmer@microsoft.com

-----Original Message-----
From: Simon Marchi <simark@simark.ca> 
Sent: Tuesday, September 13, 2022 4:39 PM
To: Bill Messmer <wmessmer@microsoft.com>; gdb@sourceware.org
Subject: Re: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer

[You don't often get email from simark@simark.ca. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]

> The GDBServer then segfaults when the first thread exits.  GDB itself shows that the gdbserver faulted at:
>
>     Program received signal SIGSEGV, Segmentation fault.
>     resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
>     2966    /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc: No such file or directory.
>     (gdb) bt
>     #0  resume (actions=actions@entry=0x55e85605f590, num_actions=num_actions@entry=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2966
>     #1  0x000055e854c61020 in handle_v_cont (own_buf=0x55e85604aed0 "vCont;c")
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:2910
>     #2  handle_v_requests (own_buf=0x55e85604aed0 "vCont;c", packet_len=<optimized out>,
>         new_packet_len=<optimized out>) at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3177
>     #3  0x000055e854c6299e in process_serial_event ()
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4523
>     #4  handle_serial_event (err=<optimized out>, client_data=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4555
>     #5  0x000055e854c994b6 in gdb_wait_for_event (block=block@entry=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:700
>     #6  0x000055e854c9994b in gdb_wait_for_event (block=1)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:596
>     #7  gdb_do_one_event () at /build/gdb-wIRHdd/gdb-12.0.90/gdbsupport/event-loop.cc:237
>     #8  0x000055e854c50872 in start_event_loop ()
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:3553
>     #9  captured_main (argv=<optimized out>, argc=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4033
>     #10 main (argc=<optimized out>, argv=<optimized out>)
>         at /build/gdb-wIRHdd/gdb-12.0.90/gdbserver/server.cc:4119

Thanks for the detailed report.

A bit of background: the only time GDB ever requests thread events from GDBserver is in non-stop mode, when it wants to stop all threads.  It is the case described in the QThreadEvent documentation:

   For example, this is used in non-stop mode when GDB stops a set of
   threads and synchronously waits for the their corresponding stop
   replies. Without exit events, if one of the threads exits, GDB would
   hang forever not knowing that it should no longer expect a stop for
   that same thread.

By using QThreadEvents in all-stop mode, you likely trigger some different code path (not a reason for GDBserver to crash, of course).

I think I was able to reproduce the crash using GDB, with this simple patch that enables thread events all the time, just like you do:

diff --git a/gdb/remote.c b/gdb/remote.c index 70f918a7362c..700e2c2b929f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4776,6 +4776,8 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     set_permissions ();

+  this->thread_events (1);
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an

Using a test program similar to yours:

  $ ./gdb -nx -q --data-directory=data-directory a.out -ex "tar rem :1234" -ex c

... leads to gdbserver crashing, the backtrace looks just like yours:

==33707==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000030 (pc 0x55d6edb7df07 bp 0x7fff852bc360 sp 0x7fff852bc350 T0) ==33707==The signal is caused by a READ memory access.
==33707==Hint: address points to the zero page.
    #0 0x55d6edb7df07 in target_waitstatus::reset() /home/smarchi/src/binutils-gdb/gdbserver/../gdb/target/waitstatus.h:400
    #1 0x55d6edbc6519 in target_waitstatus::operator=(target_waitstatus const&) /home/smarchi/src/binutils-gdb/gdbserver/../gdb/target/waitstatus.h:187
    #2 0x55d6edbb6bab in resume /home/smarchi/src/binutils-gdb/gdbserver/server.cc:2931
    #3 0x55d6edbb6523 in handle_v_cont /home/smarchi/src/binutils-gdb/gdbserver/server.cc:2875
    #4 0x55d6edbb8129 in handle_v_requests(char*, int, int*) /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3138
    #5 0x55d6edbc1844 in process_serial_event /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4484
    #6 0x55d6edbc1a9b in handle_serial_event(int, void*) /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4516
    #7 0x55d6edcdcef1 in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:574
    #8 0x55d6edcdd82d in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:695
    #9 0x55d6edcdb4f8 in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:265
    #10 0x55d6edbba12b in start_event_loop /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3514
    #11 0x55d6edbbde10 in captured_main /home/smarchi/src/binutils-gdb/gdbserver/server.cc:3994
    #12 0x55d6edbbe4b8 in main /home/smarchi/src/binutils-gdb/gdbserver/server.cc:4080
    #13 0x7ff01623c28f  (/usr/lib/libc.so.6+0x2328f)
    #14 0x7ff01623c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
    #15 0x55d6edb59ec4 in _start ../sysdeps/x86_64/start.S:115


> So I went into *resume* and added the "cs.last_status.kind() != TARGET_WAITKIND_THREAD_EXITED) to the below code in that function as the "current_thread->last_status" reference is the source of the segfault:
>
>       if (cs.last_status.kind () != TARGET_WAITKIND_EXITED
>           && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED
>           && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED
>           && cs.last_status.kind () != TARGET_WAITKIND_THREAD_EXITED)
>         current_thread->last_status = cs.last_status;

I think that makes sense, as if linux-low.cc has reported TARGET_WAITKIND_THREAD_EXITED, it has deleted that thread_info, so current_thread will be made nullptr.

> After making this change, the server no longer crashes at the first 
> thread exit, but instead, I get a packet that is
>
>     w0;2635
>
> Here's the problem though.  When I receive the various "T05create;..." packets, the debuggee process is frozen.  There's a bunch of printf's in my test app...  and nothing happens until I issue the vCont back to the server.  On receipt of the w0;2635 packet, however, the process just keeps going...

That is a bug, from what I understand.  In all-stop, the target should all threads whenever it returns any stop reply.  This should be done by the "low" target, linux-low.cc.  Off-hand I don't understand why this call to stop_all_lwps in linux_process_target::wait_1 doesn't stop the threads in that situation:

  https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitlab.com%2Fgnutools%2Fbinutils-gdb%2F-%2Fblob%2Fe9a241e87b42f902d0408704df6bbcd8bf465a46%2Fgdbserver%2Flinux-low.cc%23L3463&amp;data=05%7C01%7Cwmessmer%40microsoft.com%7C57a0cc725b7f47e2ae1108da95e12859%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637987091529234592%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=dAvf11H6aKpNyU7pWGu4LvF4Sh02mZpRLg1R2RIal0M%3D&amp;reserved=0

> I suspect that's a bug in the gdbserver (I'm no expert here in either gdbserver or its code).  That's the first question...  and the second is whether there's some other way that thread creations and exits get detected other than QThreadEvents:1 (as this doesn't seem to be well supported).

Yes, I think it's a bug.  QThreadEvents should be the way to get notified about thread creation / exit events as it happens.  As mentioned earlier, it's only used when stopping all threads, at the moment.  It's not enabled by default because it would be inefficient when debugging applications with lots of short-lived threads.  I think it's just that it has never been used in all-stop mode yet, so you are the lucky one to stumble on those bugs.

Simon

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [EXTERNAL] Re: Issues With Thread Events In User Mode GDBServer
  2022-09-30 21:08       ` Bill Messmer
@ 2022-10-19 16:19         ` Simon Marchi
  0 siblings, 0 replies; 6+ messages in thread
From: Simon Marchi @ 2022-10-19 16:19 UTC (permalink / raw)
  To: Bill Messmer, gdb

On 9/30/22 17:08, Bill Messmer wrote:
> Simon,
> 
> Apologies for the delay in response.  I finally had a bit of time to debug through gdbserver while trying to get all of this working on my side...
> 
> linux_process_target::wait_1 does *NOT* call stop_all_lwps at all (even in full stop mode) if the event is a termination event.  The relevant block is the large
> 
>       if (WIFEXITED (w) || WIFSIGNALED (w))
>         {
> 
>         ...
> 
>           if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
>             return filter_exit_event (event_child, ourstatus);
> 
>           return ptid_of (current_thread);
>         }
> 
> I went and tweaked this to:
> 
>       if (WIFEXITED (w) || WIFSIGNALED (w))
>         {
> 
>         ...
> 
>           if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
>            result = filter_exit_event (event_child, ourstatus);
> 
>           result = ptid_of (current_thread);

Not sure about that last line.  If filter_exit_event has deleted the
current thread, I guess current_thread will be nullptr?

> 
>           if (!non_stop)
>             {
>               stop_all_lwps(0, NULL);

Hmm, if filter_exit_event transforms the event into an ignore, I guess
you don't want to stop_all_lwps, because we won't stop nor report
anything to GDB.

I don't think we need to call stop_all_threads if we are in the
WSIGNALLED case, I guess that one can only be reported for the leader
once all the other threads have already reported exit (though I didn't
verify).

That's what I have so far, including my hack in remote.c:


From c6ea8b47328a6236d74f80f3a5cb6eac78276af5 Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@efficios.com>
Date: Wed, 19 Oct 2022 11:57:20 -0400
Subject: [PATCH] fix

Change-Id: Iaac45d828116b65ea2812469da2d395f70f015d9
---
 gdb/remote.c           | 2 ++
 gdbserver/linux-low.cc | 9 ++++++++-
 gdbserver/server.cc    | 3 ++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/gdb/remote.c b/gdb/remote.c
index 17c2d17c8fe8..24816cb2704c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4776,6 +4776,8 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
   if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
     set_permissions ();

+  this->thread_events (1);
+
   /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
      unknown 'v' packet with string "OK".  "OK" gets interpreted by GDB
      as a reply to known packet.  For packet "vFile:setfs:" it is an
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 4754366d4436..898e948d911d 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -3020,7 +3020,14 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	}

       if (ourstatus->kind () == TARGET_WAITKIND_EXITED)
-	return filter_exit_event (event_child, ourstatus);
+	{
+	  ptid_t ptid_ = filter_exit_event (event_child, ourstatus);
+
+	  if (!non_stop && ourstatus->kind () == TARGET_WAITKIND_THREAD_EXITED)
+	    stop_all_lwps (0, nullptr);
+
+	  return ptid_;
+	}

       return ptid_of (current_thread);
     }
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 366a843ea894..d0cf80915ee1 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -2927,7 +2927,8 @@ resume (struct thread_resume *actions, size_t num_actions)

       if (cs.last_status.kind () != TARGET_WAITKIND_EXITED
 	  && cs.last_status.kind () != TARGET_WAITKIND_SIGNALLED
-	  && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED)
+	  && cs.last_status.kind () != TARGET_WAITKIND_NO_RESUMED
+	  && cs.last_status.kind () != TARGET_WAITKIND_THREAD_EXITED)
 	current_thread->last_status = cs.last_status;

       /* From the client's perspective, all-stop mode always stops all
-- 
2.38.0


>             }
> 
>           return result;
>         }
> 
> With the tests I have, things appear to largely work as a I'd expect after making these changes.  Again -- I have little familiarity with GDBServer, so I don't know if I'm missing something here.
> 
> If this seems reasonably correct to you -- I'm happy to submit a patch.

It's really hard to say.  This is the kind of problem that gets you
scratching your head for week, trying to think of all the possible
cases.

If we want to support thread events in all-stop mode (by that I mean the
all-stop version of the remote protocol and therefore mode of operation
of GDBserver), I think the route forward would be:

 - Add a mode to GDB (maybe a maintenance setting) to tell targets to
   always report thread events
 - Write some tests that use it

Making it work will need some modifications on the GDB side, as GDB
currently doesn't handle thread exist stop notifications (small case
`w`) when using the all-stop remote protocol.  With my patch above
applied, when a thread exits, I get:

    warning: Invalid remote reply: w0;pb8251.b826b

We would need to teach remote_target::wait_as about it.

We may also need modifications to the local Linux debugging target
(linux-nat.c), I don't know if it will work out of the box when asked to
report thread events in all-stop.

Simon

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-10-19 16:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-09 20:04 Issues With Thread Events In User Mode GDBServer Bill Messmer
2022-09-11 18:55 ` Simon Marchi
2022-09-12 18:42   ` [EXTERNAL] " Bill Messmer
2022-09-13 23:39     ` Simon Marchi
2022-09-30 21:08       ` Bill Messmer
2022-10-19 16:19         ` Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).