2

By control transfer, I mean, after the tracee executing a function and return, which signal is generated so that GDB can wait*() on it and seize control again? It is not SIGTRAP though many people claim that ...

walkerlala
  • 1,599
  • 1
  • 19
  • 32

1 Answers1

2

after the tracee executing a function and return, which signal is generated so that GDB can wait*() on it and seize control again?

The tracee is stopped, and control is transferred back to GDB, only when one of "interesting" events happens.

The interesting events are:

  1. A breakpoint fires,
  2. The tracee encounters a signal (e.g. SIGSEGV or SIGFPE as a result of performing invalid memory access or invalid floating-point operation),
  3. The tracee disappears altogether (such as getting SIGKILLed by an outside program),

[There might be other "interesting" events, but I can't think of anything else right now.]

Now, a technically correct answer to "what signal does GDB use ..." is: none at all. The control isn't transferred, unless one of above events happen.

Perhaps your question is: how does control get back to GDB after executing something like finish command (which steps out of the current function)?

The answer to that is: GDB sets a temporary breakpoint on the instruction immediately after the CALL instruction that got us into the current function.

Finally, what causes the kernel to stop tracee and make waitpid in GDB to return upon execution of the breakpoint instruction?

On x86, GDB uses the INT3 (opcode 0xCC) instruction to set breakpoints (there is an alternate mechanism using debug registers, but it is limited to 4 simultaneous breakpoints, and usually reserved for hardware watchpoints instead). When the tracee executes INT3 instruction, SIGTRAP is indeed the signal that the kernel generates (i.e. other answers you've found are correct).

Without knowing what led you to believe it isn't SIGTRAP, it's hard to guess how you convinced yourself that it isn't.

Update:

I try to manually send a SIGTRAP signal to the tracee, trying to causing a spuriously wake-up of GDB, but fail.

Fail in what way?

What I expect you observe is that GDB stops with Program received signal SIGTRAP .... That's because GDB knows where it has placed breakpoints.

When GDB receives SIGTRAP and the tracee instruction pointer matches one of its breakpoints, then GDB "knows" that is's the breakpoint that has fired, and acts accordingly.

But when GDB receives SIGTRAP and the tracee IP doesn't match any of the breakpoints, then GDB treats it as any other signal: prints a message and waits for you to tell it what to do next.

"GDB sets a temporary breakpoint ... that means GDB has to modify tracee's code area, which may be read-only. So, how does GDB cope with that?

You are correct: GDB needs to modify (typically non-writable) .text section to insert any breakpoint using INT3 method. Fortunately, that is one of the "superpowers" granted to it by the kernel via ptrace(POKE_TEXT, ...).

P.S. It's a fun exercise to white a program that checksums code bytes of one of its own functions. You can then perform the checksum before and after placing a breakpoint on the "to be checksummed" function, and observe that the checksum differs when a breakpoint is present.

P.P.S. If you are curious about what GDB is doing, setting maintenance debug inferior will provide a lot of clues.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • > Perhaps your question is: how does control get back to GDB after executing something like finish command (which steps out of the current function)? [Yes this is what I mean]. – walkerlala Nov 27 '17 at 02:29
  • The reason I think SIGTRAP is not the right signal is: I try to manually send a SIGTRAP signal to the tracee, trying to causing a spuriously wake-up of GDB, but fail. I think that is because that signal is not sent by the kernel? Is there any difference for a signal generated by another process and kernel? – walkerlala Nov 27 '17 at 02:32
  • And, "GDB sets a temporary breakpoint on the instruction immediately after the CALL instruction that got us into the current function". For me, that means GDB has to modify tracee's code area, which may be read-only. So, how does GDB cope with that? ;-) – walkerlala Nov 27 '17 at 02:46
  • Lots of info ;-) many thanks. And, "It's a fun exercise to white a program that checksums code bytes of one of its own functions. You can then perform the checksum before and after placing a breakpoint on the "to be checksummed" function, and observe that the checksum differs when a breakpoint is present.", this is challenging, but sound very interesting ;-) – walkerlala Nov 27 '17 at 03:33
  • You seems like a expert. Will this issue interest you: https://stackoverflow.com/questions/47503630/detect-whether-tracee-is-in-a-signal-handler-when-using-ptrace I have discussed this with multiple people and nobody seems to be able to come up with a plausible answer – walkerlala Nov 27 '17 at 03:41