0

Say I'm writing a hypothetical debugger. A debugger wants to set breakpoints and watchpoints (both software and hardware) and what not. When a tracee hits a breakpoint a SIGTRAP is generated.

But using ptrace, it too, can "generate" SIGTRAP signals, which leads me to this question - is there a way to immediately differentiate between a SIGTRAP caused by some ptrace request? It would allow for not having to "scan" all the breakpoints the debugger might have potentially set, to see if the SIGTRAP was caused by a breakpoint it set or by some ptrace request.

Sure, one way would be to store some meta data/state, representing if the tracer has issued a ptrace request - but this is fragile (very, very fragile) as anything might have happened between issuing the request and seeing the signal (from the tracer's perspective). Many of the (if not all) of the PTRACE_O_... (so called PTRACE_EVENT stops) settings can be inspected via some bit shifting, but these are events reported "automatically"; they don't come after some issued ptrace request.

Simon Farre
  • 71
  • 1
  • 6
  • You don't have to scan breakpoints; you would fetch the program counter value using `PTRACE_GETREGS` and look it up in something like a `map`. – Nate Eldredge Jul 29 '23 at 23:33

1 Answers1

2

Yes, as is written in the documentation, for example:

PTRACE_O_TRACEFORK (since Linux 2.5.46)
      Stop the tracee at the next fork(2) and automatically start tracing the newly forked process, which will start with a SIGSTOP, or PTRACE_EVENT_STOP if PTRACE_SEIZE was used.  A waitpid(2) by the tracer will return a status value such that

         status>>8 == (SIGTRAP | (PTRACE_EVENT_FORK<<8))

You'll get the the distinction in the status returned by waitpid.

If you talk about response to a PTRACE_INTERRUPT request, then IMHO you should rethink whether it really matters that it stopped for this reason or due to a breakpoint hit earlier. And of course "scaning" all the breakpoints the debugger might have potentially set is basically the bread and butter of the debugger's operation.

jpalecek
  • 47,058
  • 7
  • 102
  • 144
  • Right, I added the `PTRACE_EVENT` stops to the question, as I figured I'd probably get a response like this, talking about those. Indeed, PTRACE_INTERRUPT, PTRACE_SINGLESTEP and PTRACE_SYSCALL generate SIGTRAP's. So what you're saying is, they have no equivalence for the PTRACE_EVENT stops, then? Yes, it is indeed the bread and butter, which is why I wondered if a smarter solution existed - especially since they realized it with the PTRACE_EVENT stops! – Simon Farre Jul 29 '23 at 22:33
  • They do, `PTRACE_INTERRUPT` causes `PTRACE_EVENT_STOP`, PTRACE_SYSCALL causes `SIGTRAP|0x80` if you have `PTRACE_O_TRACESYSGOOD` on. – jpalecek Jul 29 '23 at 22:50
  • `PTRACE_SINGLESTEP` is IMHO best handled by the "internal bookkeeping approach", after all, you invoke it typically when the target is stopped. – jpalecek Jul 29 '23 at 22:52
  • That's great, so that just leaves `PTRACE_SINGLESTEP` then. The docs say something about using GETSIGINFO and inspecting `si_code` - it says if si_code <= 0, it means `SIGTRAP was delivered as a result of a user-space action` - does hitting a breakpoint count as such as an action? Does a ptrace request, count as such an action? – Simon Farre Jul 29 '23 at 22:56
  • ok, seems like it. Thank you for your time. – Simon Farre Jul 29 '23 at 22:56
  • I don't know about that. IIRC in the code of `ltrace`, singlestep is handled just as a normal breakpoint (and not distinguished from them). – jpalecek Jul 29 '23 at 23:37