|
From: Christian C. <chr...@gm...> - 2016-07-26 18:04:33
|
Hi guys,
I'm writing my first Valgrind tool, and I'm unsure of the best way to
get something done. Any suggestions?
Suppose I have a simple target program like this:
int main( int argc, const char* argv[] ) {
int x = 42;
return 0;
}
I want my tool to have this functionality: When the program's
execution is paused at the "return 0;" statement, the user can enter
this command, which my tool receives via vgdbserver:
monitor foo x
When my tool's gdb-monitor handler is invoked with the "foo x"
argument, it should resolve the memory-address, size, and content of
the inferior's variable "x".
I saw some promising leads, but none of them looks like what I want:
* "v.translate" seems designed to translate from a numeric address
to a symbolic address, but not vice versa.
* "VG_(strtok_get_address_and_size)" only performs simple
string-to-number parsing.
* "VG_(get_data_description)" seems to be on the right track,
because it searches (nearby) stack frames as well as global variables.
But it seems designed for address-to-symbol translation (I need the
opposite), and it doesn't sound smart about C's rules regarding
identifier scoping, etc.
* "pub_tool_debuginfo.h" doesn't appear to have what I need, and
(even if it were okay for a tool to #include it) neither does
"pub_core_debuginfo.h".
* Ditto for "pub_tool_gdbserver.h" and "pub_core_gdbserver.h", respectively.
(Another reason I'm doubtful that Valgrind has support for what I want
is that an example regarding "v.set hostvisibility" shows a user
having to manually resolve a C-language lvalue expression into a
numeric address,length pair.)
I have two backup plans, but I don't love either of them:
* I can resolve the symbol myself, using debug info and the current
state of the call stack. (I've never done this, but I assume it's not
too hard.) Or,
* I can write a custom GDB command (i.e., in gdb's scripting
language, or using Python), which uses GDB's facilities for converting
the string "x" to a numeric address,length pair, and then provides
that numeric pair to my Valgrind tool's "monitor" handler. The main
downside I see to this is that my end users will (I think) need to
take the additional step of making this custom command available to
their GDB sessions.
Any suggestions would be greatly appreciated. Thanks!
- Christian
|
|
From: Philippe W. <phi...@sk...> - 2016-07-26 20:11:02
|
On Tue, 2016-07-26 at 14:04 -0400, Christian Convey wrote:
> Hi guys,
>
> I'm writing my first Valgrind tool, and I'm unsure of the best way to
> get something done. Any suggestions?
>
> Suppose I have a simple target program like this:
>
> int main( int argc, const char* argv[] ) {
> int x = 42;
> return 0;
> }
>
>
> I want my tool to have this functionality: When the program's
> execution is paused at the "return 0;" statement, the user can enter
> this command, which my tool receives via vgdbserver:
> monitor foo x
>
> When my tool's gdb-monitor handler is invoked with the "foo x"
> argument, it should resolve the memory-address, size, and content of
> the inferior's variable "x".
I am not sure to understand why you need a Valgrind tool to do that.
If you are busy debugging an executable,
then gdb can give you the address and content of global variables,
function arguments and local variables.
So, e.g. for the above, you could in gdb do:
p &x
or
info address x
(this last one will rather explain how the address is computed e.g. by
giving the DWARF expression).
The size can be found using p sizeof(x)
And of course, the content using p x
(of course, the above gdb functionalities are working for a native
debugging, but also for a debugging session with the Valgrind gdbserver:
all these commands are implemented at gdb side, not at gdbserver side).
Some valgrind tools (typically memcheck) allows to give a more detailed
description of malloc-ed memory (i.e. where it was allocated), while
gdb has no such feature by itself.
So, unclear why you need a tool, but I am still giving some feedback
below.
>
> I saw some promising leads, but none of them looks like what I want:
>
> * "v.translate" seems designed to translate from a numeric address
> to a symbolic address, but not vice versa.
v.translate is not related to variables or so, but rather to the JIT
compiler part of Valgrind: it shows the translation and instrumentation
of the code instructions at the given address.
>
> * "VG_(strtok_get_address_and_size)" only performs simple
> string-to-number parsing.
Yes, simple parsing.
>
> * "VG_(get_data_description)" seems to be on the right track,
> because it searches (nearby) stack frames as well as global variables.
Yes, this is basically what it does (address to 'symbol').
> But it seems designed for address-to-symbol translation (I need the
> opposite), and it doesn't sound smart about C's rules regarding
> identifier scoping, etc.
Not too sure what you mean about identifier scoping. It searches
global and stack variables, taking the C rules into account
(as these are implied by the stack structure that it scans).
>
> * "pub_tool_debuginfo.h" doesn't appear to have what I need, and
> (even if it were okay for a tool to #include it) neither does
> "pub_core_debuginfo.h".
Yes, pub_tool_*.h can be included by tools, and pub_core_*.h are not
supposed to be included.
>
> * Ditto for "pub_tool_gdbserver.h" and "pub_core_gdbserver.h", respectively.
>
> (Another reason I'm doubtful that Valgrind has support for what I want
> is that an example regarding "v.set hostvisibility" shows a user
> having to manually resolve a C-language lvalue expression into a
> numeric address,length pair.)
v.set hostvisibility is to allow to look at (some) aspects of
the valgrind host state while using gdb also for debugging the guest
(this hostvisibility is however limited to global variables, as host
stack is not made visible to gdb).
Unclear what you mean with this resolve C-language lvalue as
part of v.set hostvisibility
>
> I have two backup plans, but I don't love either of them:
>
> * I can resolve the symbol myself, using debug info and the current
> state of the call stack. (I've never done this, but I assume it's not
> too hard.) Or,
IMO this is hard :).
A.o. you need to read the debug info, dwarf etc,
and then you need to use this to compute where is x,
using whatever info needed e.g. by the dwarf expression
(e.g. registers).
Basically, a non trivial part of gdb (or in some part of
Valgrind debug info and dwarf reader).
>
> * I can write a custom GDB command (i.e., in gdb's scripting
> language, or using Python), which uses GDB's facilities for converting
> the string "x" to a numeric address,length pair, and then provides
> that numeric pair to my Valgrind tool's "monitor" handler. The main
> downside I see to this is that my end users will (I think) need to
> take the additional step of making this custom command available to
> their GDB sessions.
>
> Any suggestions would be greatly appreciated. Thanks!
As said above, basically, unclear why the gdb standard features are
not good enough for what you want to do.
Maybe I misunderstood your objective ?
Or maybe the 'monitor foo x' description above is incomplete
and foo supposed to do more than just give address/content/size of x ?
Philippe
|
|
From: Christian C. <chr...@gm...> - 2016-07-26 20:59:12
|
Hi Philippe,
Thanks very much for your response! You provided lots of helpful
information. A few replies below.
On Tue, Jul 26, 2016 at 4:15 PM, Philippe Waroquiers <
phi...@sk...> wrote:
> I am not sure to understand why you need a Valgrind tool to do that.
> If you are busy debugging an executable,
> then gdb can give you the address and content of global variables,
> function arguments and local variables.
> So, e.g. for the above, you could in gdb do:
> p &x
> or
> info address x
> (this last one will rather explain how the address is computed e.g. by
> giving the DWARF expression).
> The size can be found using p sizeof(x)
> And of course, the content using p x
Here's the bigger picture regarding what I'm trying to do...
As part of a personal project, I'm trying to implement a Valgrind tool
which monitors operations on a user-specified region of memory. Basically,
a watchpoint on steroids.
I want my analysis of a memory region to be active when, and only when, the
function in which one of my memory-watches is defined is present on the
callstack. Consider this example:
///////////// BEGIN EXAMPLE /////////////
1: // C is a mystery function.
2: // It might even recursively call B().
3: extern void C( int* );
4:
5: void B() {
6: int X = 42;
7: int Y = 100;
8: C( &X );
9: }
10:
11: void A() {
12: for (int i = 0; i < 1000; ++i) {
13: B();
14: }
15: }
I'd like to be able to define a quasi-watchpoint such as "the variable X in
function B".
For each activation of function "B", I want my Valgrind tool to be notified
with the numeric address range occupied by that frame's instance of "B".
I also want my Valgrind tool to be notified each time function "B" returns,
so it can deactivate the memory-watching that was established when that
stack frame was created.
The loop in function A() to point out that it's not always practical for a
human to perform the conversion from the symbolic
naming of the memory to be evaluated ("X in function B()") to a specific
numeric address.
///////////// END EXAMPLE /////////////
I do not think I can perform the kinds of analyses I want entirely within
GDB, even using its Python API. GDB hardware watchpoints can't handle the
sizes of memory regions I want to analyze, and gdb software breakpoints are
too slow for my needs.
I also believe that none of the currently available Valgrind tools performs
the kind of memory-operation analyses I want to do. I think Valgrind is
the right framework for what I want to do, but AFAICT I'll want to write a
new tool.
So my challenge is to somehow get GDB's help in converting an lvalue
expression like the one mentioned above, into a form that a Valgrind tool
can make sense of.
At the moment I'm looking to do this with a combination of:
* Running GDB commands at GDB breakpoints, and
* Having those commands send the relevant information, including
numeric (not symbolic) address ranges to my tool via `gdb monitor`).
I think this approach is workable, but I'd like to avoid adding
code/scripts to BOTH Valgrind and GDB.
>> * "VG_(get_data_description)" seems to be on the right track,
>> because it searches (nearby) stack frames as well as global variables.
> Yes, this is basically what it does (address to 'symbol').
>> But it seems designed for address-to-symbol translation (I need the
>> opposite), and it doesn't sound smart about C's rules regarding
>> identifier scoping, etc.
> Not too sure what you mean about identifier scoping. It searches
> global and stack variables, taking the C rules into account
> (as these are implied by the stack structure that it scans).
AFAIK, resolving a C identifier should never need to involve looking at the
variables/parameters of any stack frame other than the current one. Since
the docs for "VG_(get_data_description)" mentioned looking at additional
stack frames, I assumed that routine implements something other than the
C-language's resolution rules.
>>
>> I have two backup plans, but I don't love either of them:
>>
>> * I can resolve the symbol myself, using debug info and the current
>> state of the call stack. (I've never done this, but I assume it's not
>> too hard.) Or,
> IMO this is hard :).
Thanks very much for the warning! I will henceforth be less cavalier about
that option :)
- Christian
|
|
From: Philippe W. <phi...@sk...> - 2016-07-26 21:56:12
|
On Tue, 2016-07-26 at 16:59 -0400, Christian Convey wrote: > Hi Philippe, > > Thanks very much for your response! You provided lots of helpful > information. A few replies below. Which are clarifying the objective :). Some more feedback below ... > > > Here's the bigger picture regarding what I'm trying to do... > > > As part of a personal project, I'm trying to implement a Valgrind tool > which monitors operations on a user-specified region of memory. > Basically, a watchpoint on steroids. > > I want my analysis of a memory region to be active when, and only > when, the function in which one of my memory-watches is defined is > present on the callstack. Valgrind memcheck + gdb provides a reasonably fast (reasonably fast = much faster than the gdb software watchpoints) watchpoints. There is also no limitations in size or numbers of these 'extended watchpoints'. See http://www.valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver-limitations Hardware watchpoint support by the Valgrind gdbserver. GDB was modified so as to properly work with the (unlimited) 'simulated hardware watchpoints' as provided by Valgrind gdbserver. The gdb manual tells: " GDB automatically deletes watchpoints that watch local (automatic) variables, or expressions that involve such variables, when they go out of scope, ...." So, I think you should be able to implement what you need relatively simply with : * put a breakpoint on function B * add a command list to this breakpoint, doing: watch x continue and that should work (?). In other words, when entering B, gdb will encounter the breakpoint, and will translate and create a hw watchpoint (that valgrind gdbserver will implement reasonably efficiently). And as I understand, gdb is supposed to detect that B returns, and delete the watchpoint. That might however not be ultra-fast, if you have such watchpoints in often called functions, as this implies some not trivial work by GDB (breakpoint, create watchpoint, detect return of function and delete the watchpoint). > Consider this example: > > ///////////// BEGIN EXAMPLE ///////////// > > > 1: // C is a mystery function. > 2: // It might even recursively call B(). > 3: extern void C( int* ); > 4: > 5: void B() { > 6: int X = 42; > 7: int Y = 100; > 8: C( &X ); > 9: } > > 10: > 11: void A() { > 12: for (int i = 0; i < 1000; ++i) { > 13: B(); > 14: } > 15: } > > I'd like to be able to define a quasi-watchpoint such as "the variable > X in function B". > > > For each activation of function "B", I want my Valgrind tool to be > notified with the numeric address range occupied by that frame's > instance of "B". > > > I also want my Valgrind tool to be notified each time function "B" > returns, so it can deactivate the memory-watching that was established > when that stack frame was created. > > > The loop in function A() to point out that it's not always practical > for a human to perform the conversion from the symbolic > naming of the memory to be evaluated ("X in function B()") to a > specific numeric address. > > > ///////////// END EXAMPLE ///////////// > > > I do not think I can perform the kinds of analyses I want entirely > within GDB, even using its Python API. GDB hardware watchpoints can't > handle the sizes of memory regions I want to analyze, and gdb software > breakpoints are too slow for my needs. As discussed above, valgrind memcheck+gdbserver is providing (reasonably fast) simulated hardware watchpoint, and no limit on nr or size of such watchpoints. > > > I also believe that none of the currently available Valgrind tools > performs the kind of memory-operation analyses I want to do. I think > Valgrind is the right framework for what I want to do, but AFAICT I'll > want to write a new tool. > > > So my challenge is to somehow get GDB's help in converting an lvalue > expression like the one mentioned above, into a form that a Valgrind > tool can make sense of. > > At the moment I'm looking to do this with a combination of: > > > * Running GDB commands at GDB breakpoints, and > > > * Having those commands send the relevant information, including > numeric (not symbolic) address ranges to my tool via `gdb > monitor`). > > > I think this approach is workable, but I'd like to avoid adding > code/scripts to BOTH Valgrind and GDB. > > > >> * "VG_(get_data_description)" seems to be on the right track, > >> because it searches (nearby) stack frames as well as global > variables. > > Yes, this is basically what it does (address to 'symbol'). > >> But it seems designed for address-to-symbol translation (I need the > >> opposite), and it doesn't sound smart about C's rules regarding > >> identifier scoping, etc. > > Not too sure what you mean about identifier scoping. It searches > > global and stack variables, taking the C rules into account > > (as these are implied by the stack structure that it scans). > > > AFAIK, resolving a C identifier should never need to involve looking > at the variables/parameters of any stack frame other than the current > one. Since the docs for "VG_(get_data_description)" mentioned looking > at additional stack frames, I assumed that routine implements > something other than the C-language's resolution rules. VG_(get_data_description) is translating an address to a symbol, and such things are taking into account 'C scope' as implemented by the stack. Even for doing symbol to address, you must indicate in which frame you want to do the resolution, otherwise the symbol (var name) is ambiguous. Of course, this 'explicit frame' might be limited to the 'current frame'. > > > > > > IMO this is hard :). > Thanks very much for the warning! I will henceforth be less cavalier > about that option :) At this point, probably worth first experimenting with GDB + valgrind gdbserver + memcheck, and the watchpoint support by Valgrind gdbserver. Philippe > |
|
From: Christian C. <chr...@gm...> - 2016-07-27 17:40:17
|
HI Philippe,
On Tue, Jul 26, 2016 at 6:00 PM, Philippe Waroquiers
<phi...@sk...> wrote:
>
> On Tue, 2016-07-26 at 16:59 -0400, Christian Convey wrote:
> > Hi Philippe,
> > > IMO this is hard :).
> > Thanks very much for the warning! I will henceforth be less cavalier
> > about that option :)
> At this point, probably worth first experimenting with
> GDB + valgrind gdbserver + memcheck,
> and the watchpoint support by Valgrind gdbserver.
I took your advice and experimented with: (GDB watches) + (valgrind
gdbserver) + (memcheck). I didn't benchmark timings; I just focused
on what kinds of events the watchpoints detected.
I created a test program that, in main(), performs the following steps:
0. Allocate `char buffer[10]` as a local variable, initialized to all 0x00
characters because of my compiler flags.
1. buffer[0] = 'X'; // first write op. Changes the initial value.
2. buffer[0] = 'X'; // second write op. Does not change the value.
3. buffer[0] = 'Y'; // third write op. Changes the value.
4. read( fd, buffer, 10 ); // a syscall that writes a different
// value to buffer[0].
5. After calling `lseek(fd, 0, SEEK_SET);`, repeat the `read` call from
step 4. This is a syscall that writes to buffer[0], but doesn't actually
change its value.
I then tried various kinds of watchpoint implementations to see which
of the steps above triggered the watchpoint. Here's what I found.
(Apologies for the ASCII art, but I find it helpful.)
Watchpoint implementation | 1 | 2 | 3 | 4 | 5 |
==========================+===+===+===+===+===+
local gdb session | Y | N | Y | Y | Y |
(sw) watch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
local gdb session | Y | N | Y | Y | N |
(hw) watch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
local gdb session | Y | Y | Y | N | N |
(hw) awatch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
--------------------------+---+---+---+---+---+
remote vgdb=full memcheck | Y | N | Y | Y | N |
(sw) watch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
remote vgdb=full memcheck | Y | N | Y | Y | N |
(hw) watch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
remote vgdb=full memcheck | Y | Y | Y | Y | N |
(hw) awatch -l buffer[0] | | | | | |
--------------------------+---+---+---+---+---+
I included the "local gdb" runs only to satisfy my own curiosity. As
I mentioned earlier, gdb's hardware watchpoints are too restricted for
my needs, and the software watchpoints are too slow.
Unfortunately it looks like none of the variations I tried is
*exactly* what I want. Perhaps I'm mistaken, but it seems I'm forced
to always make at least one of the following concessions:
* With memcheck's "(sw/hw) watch -l buffer[0]" approaches, I only
discover that a syscall wrote to the watched memory if it resulted in
a change in that memory's content. (I.e., column "5" is "N")
* With memcheck's "(hw) awatch -l buffer[0]" approach, I cannot tell
whether the userspace memory-write operation (i.e., column 2) is (a
read) vs. (a content-changing write) vs. (a content-preserving write).
Do you happen to know if memcheck can be used in a manner which avoids
those problems?
One possibility does come to mind: I can create multiple memcheck
watchpoints, all covering the same region of memory. I can then
consider which subset of those watchpoints fired for each program
step. Based on that, I can probably get most/all of the information I
want. If you have no better ideas, I may go with this approach rather
than writing my own tool. But this approach is a bit cumbersome in
terms of GDB scripting, so I'm hoping for a more elegant solution.
Thanks again,
Christian
|
|
From: Philippe W. <phi...@sk...> - 2016-07-27 22:05:37
|
On Wed, 2016-07-27 at 13:40 -0400, Christian Convey wrote: > HI Philippe, > > On Tue, Jul 26, 2016 at 6:00 PM, Philippe Waroquiers > <phi...@sk...> wrote: > > > > On Tue, 2016-07-26 at 16:59 -0400, Christian Convey wrote: > > > Hi Philippe, > > > > IMO this is hard :). > > > Thanks very much for the warning! I will henceforth be less cavalier > > > about that option :) > > At this point, probably worth first experimenting with > > GDB + valgrind gdbserver + memcheck, > > and the watchpoint support by Valgrind gdbserver. > > I took your advice and experimented with: (GDB watches) + (valgrind > gdbserver) + (memcheck). I didn't benchmark timings; I just focused > on what kinds of events the watchpoints detected. > > I created a test program that, in main(), performs the following steps: > 0. Allocate `char buffer[10]` as a local variable, initialized to all 0x00 > characters because of my compiler flags. > > 1. buffer[0] = 'X'; // first write op. Changes the initial value. > > 2. buffer[0] = 'X'; // second write op. Does not change the value. > > 3. buffer[0] = 'Y'; // third write op. Changes the value. > > 4. read( fd, buffer, 10 ); // a syscall that writes a different > // value to buffer[0]. > > 5. After calling `lseek(fd, 0, SEEK_SET);`, repeat the `read` call from > step 4. This is a syscall that writes to buffer[0], but doesn't actually > change its value. > > I then tried various kinds of watchpoint implementations to see which > of the steps above triggered the watchpoint. Here's what I found. > (Apologies for the ASCII art, but I find it helpful.) > > Watchpoint implementation | 1 | 2 | 3 | 4 | 5 | > ==========================+===+===+===+===+===+ > local gdb session | Y | N | Y | Y | Y | > (sw) watch -l buffer[0] | | | | | | The case 5 above is strange. This does not correspond to the GDB documentation: the doc explicitely tells that the expression must change for the watchpoint to trigger. GDB has explicit code to check the value has really changed. So, the case 5 should not have triggered. > --------------------------+---+---+---+---+---+ > local gdb session | Y | N | Y | Y | N | > (hw) watch -l buffer[0] | | | | | | > --------------------------+---+---+---+---+---+ > local gdb session | Y | Y | Y | N | N | > (hw) awatch -l buffer[0] | | | | | | > --------------------------+---+---+---+---+---+ case 2 above is strange, for the same reason as above: there is no read for case 2, and the write did not change the value. Now, maybe GDB cannot differentiate a read from a write that does not change the value for an awatch. But then, case 5 should also have been a Y. And of course, case 4 is equally strange, as 4 changes the value. If the above table is correct, it seems you found several bugs in GDB. > > --------------------------+---+---+---+---+---+ > remote vgdb=full memcheck | Y | N | Y | Y | N | > (sw) watch -l buffer[0] | | | | | | > --------------------------+---+---+---+---+---+ > remote vgdb=full memcheck | Y | N | Y | Y | N | > (hw) watch -l buffer[0] | | | | | | > --------------------------+---+---+---+---+---+ > remote vgdb=full memcheck | Y | Y | Y | Y | N | > (hw) awatch -l buffer[0] | | | | | | > --------------------------+---+---+---+---+---+ > > I included the "local gdb" runs only to satisfy my own curiosity. As > I mentioned earlier, gdb's hardware watchpoints are too restricted for > my needs, and the software watchpoints are too slow. > > Unfortunately it looks like none of the variations I tried is > *exactly* what I want. Perhaps I'm mistaken, but it seems I'm forced > to always make at least one of the following concessions: > > * With memcheck's "(sw/hw) watch -l buffer[0]" approaches, I only > discover that a syscall wrote to the watched memory if it resulted in > a change in that memory's content. (I.e., column "5" is "N") I am quite sure this verification is done by GDB. See in GDB sources breakpoint.c function watchpoint_check. > > * With memcheck's "(hw) awatch -l buffer[0]" approach, I cannot tell > whether the userspace memory-write operation (i.e., column 2) is (a > read) vs. (a content-changing write) vs. (a content-preserving write). > > Do you happen to know if memcheck can be used in a manner which avoids > those problems? The watchpoints in memcheck are implemented using the addressibility bits : a watched location is (artificially) marked as not addressable. So, memcheck detects an error for any read or write, but because the location is watched, memcheck rather reports a hardware watchpoint hit to GDB, rather than producing an error. memcheck clearly knows that the operation is a read or a write. I am wondering if Valgrind gdbserver should not report the precise stop reason: it seems to always report "watch:" stop reason, instead of reporting e.g. rwatch for a read and watch for a write. (see Valgrind code remote-utils.c prepare_resume_reply. In other words, it reports 'watch' and expects that GDB will differentiate the read from the write by checking if the value changed. And then of course, a write that does not change the value is seen as a read. If that is the problem, I think Valgrind gdbserver can be changed so as to report rwatch or watch for respectively a read or a write. > > One possibility does come to mind: I can create multiple memcheck > watchpoints, all covering the same region of memory. I can then > consider which subset of those watchpoints fired for each program > step. Based on that, I can probably get most/all of the information I > want. If you have no better ideas, I may go with this approach rather > than writing my own tool. But this approach is a bit cumbersome in > terms of GDB scripting, so I'm hoping for a more elegant solution. GDB watchpoint concept is based on an expression that changes of value. This works both with sw and hw watchpoints. With GDB, read watchpoints are only working based on hw watchpoints. Not too sure that a write that does not change a value can be differentiated from a read. This is effectively a limitation, not clear how severe this limitation is. > > Thanks again, > Christian |
|
From: Christian C. <chr...@gm...> - 2016-07-27 18:10:05
|
> * With memcheck's "(hw) awatch -l buffer[0]" approach, I cannot tell > whether the userspace memory-write operation (i.e., column 2) is (a > read) vs. (a content-changing write) vs. (a content-preserving write). Clarification: Since I'm able to use gdb's Python API, I *can* distinguish (a content-changing write) vs. (a content-preserving write), if I do my own bookkeeping every time the watchpoint fires. - Christian |
|
From: Philippe W. <phi...@sk...> - 2016-07-27 22:10:24
|
On Wed, 2016-07-27 at 14:09 -0400, Christian Convey wrote: > > * With memcheck's "(hw) awatch -l buffer[0]" approach, I cannot tell > > whether the userspace memory-write operation (i.e., column 2) is (a > > read) vs. (a content-changing write) vs. (a content-preserving write). > > Clarification: Since I'm able to use gdb's Python API, I *can* > distinguish (a content-changing write) vs. (a content-preserving > write), if I do my own bookkeeping every time the watchpoint fires. As discussed in the other mail, GDB will not fire a watchpoint if the value did not change. In other words, GDB hides a hw triggered watchpoint when the value did not change. Philippe |