Re: [patch] [i386] Put hlt at the ON_STACK breakpoint [Re: GDB 7.4.91 available for testing]

Philippe Waroquiers
2012-07-25T20:24:40Z

On Wed, 2012-07-25 at 15:58 +0100, Pedro Alves wrote:
> On 07/23/2012 09:36 PM, Philippe Waroquiers wrote:
>
> >> So the GDB patch is no longer needed when you have fixed valgrind to put 0xcc
> >> during Z0? Why valgrind cannot write 0xcc into stack memory when it already
> >> has to write there to create the stack frame / parameters passed by stack?
> > Effectively, I have a patch which fixes the problem.
> > But the patch is a kludge which heuristically guesses that GDB is
> > pushing an infcall.
>
> Why do you have to guess that, rather than just detecting a breakpoint is
> being set on a stack (or non text) address? If something sets a breakpoint
> in a data address, it is basically telling valgrind "this is actually code".

This is explained by the way Valgrind gdbsrv (must) implement
breakpoints.
(this is a little bit tricky, as it is linked to Valgrind internals).

Valgrind translates guest code instructions in small blocks.
As part of the translation, if there is a breakpoint at addr XXXX
then the translation of address XXXX will start with a call to a
helper function which reports to GDB that a breakpoint has been
encountered. This function then reads/executes protocol packets till a
continue packet is received.
The translated block is then continued <<< This is the critical info !!!

There is no way to re-translate the block currently being executed :
Valgrind has no way to "drop" the translated block it is currently
executing.
So, a breakpoint cannot be translated using a 0xCC because when GDB
tells to continue after the breakpoint, there is no way to retranslate
the original instructions (without the 0xCC) as long as the block
is being executed.
So, for normal breakpoints, Valgrind gdbsrv cannot insert 0xCC, as this
would just not work.

"Normal" breakpoints on the stack (trampoline code or whatever) or
JITted code or ... must be handled the same way: V gdbsrv cannot
touch the code to handle breakpoints.

The only special case in which Valgrind gdbsrv can insert a 0xCC is
when it is sure that this code will *not* be executed.
This is the case for the 0xcc for the push_dummy_code.
This code will not be executed because GDB will change the pc register.
When the continue packet is received, the execution of the block is
then not continued, instead the continue will cause a jump to the
"original pc" (the one before the infcall).

So, in summary:
* for all normal breakpoints, Valgrind gdbsrv cannot insert a 0xcc
* for "dummy inferior call return breakpoint", Valgrind gdbsrv can
insert a 0xcc, as GDB will ensure this piece of code is not
executed, and so there is no need to re-translate it without the
0xcc

So, the kludge patch I have done tries to guess if the breakpoint
on the stack is a normal breakpoint (so, V gdbsrv cannot touch it)
or is a "infcall" breakpoint (then the kludge patch inserts a 0xcc).

It would be much cleaner to have GDB inserting the 0xCC, as GDB *knows*
it is doing a infcall, and so knows it can safely insert a 0xCC.
(Valgrind gdbsrv needs in any case the Z0 packet, as this is what
will ensure the 0xCC is not executed).

Not too sure if the above explanations are clear, it is somewhat tricky.

So, if it is easy to change GDB to insert 0xcc (for x86 and amd84)
and the equivalent breakpoint instr for mips32, then that avoids
the kludgy patch in Valgrind, which is for sure fragile.

Philippe