|
From: Ian L. <ig...@ea...> - 2008-04-05 12:39:15
|
Hi all, I would like valgrind to give me a stack trace when a given value (0x40D4F000) is written to or read from anywhere in memory. Am I right in thinking that valgrind can't do this out of the box? If so, I should be able to do it by writing a new tool, right? I had a look at doing so, but got stuck. Does anyone have any pointers on the best way to approach this please? Thanks Ian |
|
From: Julian S. <js...@ac...> - 2008-04-05 12:54:58
|
On Saturday 05 April 2008 14:37, Ian Lynagh wrote: > Hi all, > > I would like valgrind to give me a stack trace when a given value > (0x40D4F000) is written to or read from anywhere in memory. valgrind-3.3.0 --tool=helgrind --trace-addr=0x40D4F000 --trace-level=2 ... But really, if you just want to know when 0x40D4F000 is getting trashed (or read), you'd be better off using GDB's hardware watchpoint facility. Then the program can run at full speed and stop in GDB whenever the address is read/written. J |
|
From: Ian L. <ig...@ea...> - 2008-04-05 13:07:45
|
Hi Julian, On Sat, Apr 05, 2008 at 02:50:13PM +0200, Julian Seward wrote: > On Saturday 05 April 2008 14:37, Ian Lynagh wrote: > > Hi all, > > > > I would like valgrind to give me a stack trace when a given value > > (0x40D4F000) is written to or read from anywhere in memory. > > valgrind-3.3.0 --tool=helgrind --trace-addr=0x40D4F000 --trace-level=2 ... Thanks for the reply. However, that sounds like it is going to tell me when any value is written to/read from the address 0x40D4F000. I want to know when the value 0x40D4F000 is written to/read from any address. Thanks Ian |
|
From: Ian L. <ig...@ea...> - 2008-04-05 13:28:09
|
On Sat, Apr 05, 2008 at 01:37:08PM +0100, Ian Lynagh wrote: > > I would like valgrind to give me a stack trace when a given value > (0x40D4F000) is written to or read from anywhere in memory. Actually, now I think about it, this bug is more likely to be caused by writing a pointer to an address that is 1 mod 8 (on amd64). Can valgrind tell me when I am doing that? Thanks Ian |
|
From: Julian S. <js...@ac...> - 2008-04-05 15:09:17
|
> Thanks for the reply. However, that sounds like it is going to tell me > when any value is written to/read from the address 0x40D4F000. > > I want to know when the value 0x40D4F000 is written to/read from any > address. Oh, my mistake. So, don't try to write a tool from scratch (far too much effort). Instead, first play around with --tool=lackey, and then hack around lk_main.c to make it do what you want. At some point, when you're in the relevant helper function, and you want to "show" where the program is, do this ThreadId tid = VG_(get_running_tid)(); VG_(get_and_pp_StackTrace) ( tid, 12 ); J |
|
From: Ian L. <ig...@ea...> - 2008-04-05 15:43:49
|
On Sat, Apr 05, 2008 at 05:04:49PM +0200, Julian Seward wrote: > > > Thanks for the reply. However, that sounds like it is going to tell me > > when any value is written to/read from the address 0x40D4F000. > > > > I want to know when the value 0x40D4F000 is written to/read from any > > address. > > Oh, my mistake. So, don't try to write a tool from scratch (far too > much effort). Instead, first play around with --tool=lackey, and then > hack around lk_main.c to make it do what you want. > > At some point, when you're in the relevant helper function, and you > want to "show" where the program is, do this > > ThreadId tid = VG_(get_running_tid)(); > VG_(get_and_pp_StackTrace) ( tid, 12 ); Thanks! Ian |
|
From: David M. <dm...@gm...> - 2008-04-05 18:30:50
|
On Sat, Apr 5, 2008 at 5:37 AM, Ian Lynagh <ig...@ea...> wrote:
>
>
> If so, I should be able to do it by writing a new tool, right?
> I had a look at doing so, but got stuck. Does anyone have any pointers
> on the best way to approach this please?
>
I second the suggestion to look at Lackey - it really is a wonderful example
tool.
That being said, here is one possible design for your tool which may make
some sense after you've looked at Lackey. It probably isn't the best way of
doing things, so maybe others will have thoughts.
1) Create a helper function
void checkValueAndPrintST(HWord value)
This function will take as an argument the value stored to or loaded from
memory. It checks the value is equal to 1 mod 8, then if so calls
VG_(get_and_pp_StackTrace) as Julian said. Our goal will be to add this
helper function into an IRBB after each stor statement and after each
expression which includes a load expression. We want to pass the helper
function an expression which evaluates to the value stored or loaded.
For example, if the original IRBB has the statement
t5 = LDle:I32(0xDEADBEEF);
the new IRBB after the tool is done will add a statement something like this
following
DIRTY 1:I1 ::: checkValueAndPrintST{0x3800a27c}(t5)
2) In the main IRBB instrumentation callback (this is lk_instrument in
lk_main.c), do the following:
for each statement s in the IRBB
if s is an Ist_Store
then
insert helper function with argument s->Ist.Store.data
endif
if s is an Ist_Tmp
then
if tag of IRExpr in s->Ist.Tmp.Data is Iex_Load
insert helper function with argument s->Ist.Tmp.tmp
endif
end
Note this assumes the Ist.Store.data is always a single temporary variable,
and that there are no compound expressions involving Iex_Load on the right
hand side of an Ist_Tmp. The Ist.Store.data I haven't seen an exception, but
there are a few I think for the second. You can look for such behaviour by
running your program with --trace-flags=0100000 and --trace-notbelow=0,
which shows the IR as it is passed to your tool.
Some things to note with this approach:
* Issue: The VEX core only handles arguments of type Ity_I32 passed to
helper functions. If you try to pass an Ity_I1, Ity_I16, etc. you will hit a
sanity check error during the compilation of your instrumented basic block.
(At least, as of release 3.2, maybe it is different now).
Solution 0: hack the VEX core to properly pass different arguments on your
specific architecture(s). I have done this. It has the usual problems of
requiring new work for different architectures, plus your tool now will not
work with future Valgrind releases. It is quick to implement for Ity_I1,
Ity_I16, etc. however.
Solution 1: at instrumentation time, use the tyenv array in the basic block
to check
the type of the temporary variable tX . If tX is not Ity_I32, insert a new
IRStmt which allocates a new temporary tZ and inserts a conversion from the
type of tX to Ity_I32, then inserts a call to checkValueAndPrintST(tZ). I
have not actually done this, but it "should work."
* Issue: When adding many statements to a basic block which is already
large, it is possible to overrun the VEX translation buffer during the
compilation of the instrumented IRBB. (I've seen this with libjpg.)
Solution: Increase the size of the VEX translation buffer. You need to
modify
#define N_TMPBUF 20000
in /coregrind/m_translate.c
and also an assertion
vg_assert(code_len > 0 && code_len < 20000);
in coregrind/m_transtab.c .
hope this is useful, good luck with your tool,
-David Molnar
|
|
From: Julian S. <js...@ac...> - 2008-04-05 20:32:56
|
> for each statement s in the IRBB
> if s is an Ist_Store
> then
> insert helper function with argument s->Ist.Store.data
> endif
>
> if s is an Ist_Tmp
> then
> if tag of IRExpr in s->Ist.Tmp.Data is Iex_Load
> insert helper function with argument s->Ist.Tmp.tmp
> endif
> end
To get 100% coverage, you also need to handle Ist_Dirty, which is tricky.
> * Issue: The VEX core only handles arguments of type Ity_I32 passed to
> helper functions. [...]
> Solution 1: at instrumentation time, use the tyenv array in the basic block
> to check
> the type of the temporary variable tX . If tX is not Ity_I32, insert a new
> IRStmt which allocates a new temporary tZ and inserts a conversion from the
> type of tX to Ity_I32, then inserts a call to checkValueAndPrintST(tZ). I
> have not actually done this, but it "should work."
Yes - it's by far the simplest solution, and is used in various
tools. Basically widen the arg using Iop_{1,8,16}Uto32 before
handing it to the helper call.
J
|