1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- An example Valgrind tool.                          lk_main.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Lackey, an example Valgrind tool that does
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   some simple program measurement and tracing.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2002-2011 Nicholas Nethercote
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      njn@valgrind.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This tool shows how to do some basic instrumentation.
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// There are four kinds of instrumentation it can do.  They can be turned
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// on/off independently with command line options:
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// * --basic-counts   : do basic counts, eg. number of instructions
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                      executed, jumps executed, etc.
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// * --detailed-counts: do more detailed counts:  number of loads, stores
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                      and ALU operations of different sizes.
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// * --trace-mem=yes:   trace all (data) memory accesses.
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// * --trace-superblocks=yes:
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                      trace all superblock entries.  Mostly of interest
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                      to the Valgrind developers.
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The code for each kind of instrumentation is guarded by a clo_* variable:
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// clo_basic_counts, clo_detailed_counts, clo_trace_mem and clo_trace_sbs.
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If you want to modify any of the instrumentation code, look for the code
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// that is guarded by the relevant clo_* variable (eg. clo_trace_mem)
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If you're not interested in the other kinds of instrumentation you can
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// remove them.  If you want to do more complex modifications, please read
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// VEX/pub/libvex_ir.h to understand the intermediate representation.
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Specific Details about --trace-mem=yes
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// --------------------------------------
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Lackey's --trace-mem code is a good starting point for building Valgrind
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// tools that act on memory loads and stores.  It also could be used as is,
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// with its output used as input to a post-mortem processing step.  However,
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// because memory traces can be very large, online analysis is generally
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// better.
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// It prints memory data access traces that look like this:
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  0023C790,2  # instruction read at 0x0023C790 of size 2
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  0023C792,5
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    S BE80199C,4  # data store at 0xBE80199C of size 4
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  0025242B,3
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    L BE801950,4  # data load at 0xBE801950 of size 4
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  0023D476,7
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    M 0025747C,1  # data modify at 0x0025747C of size 1
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  0023DC20,2
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    L 00254962,1
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    L BE801FB3,1
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   I  00252305,1
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    L 00254AEB,1
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    S 00257998,1
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Every instruction executed has an "instr" event representing it.
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Instructions that do memory accesses are followed by one or more "load",
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// "store" or "modify" events.  Some instructions do more than one load or
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// store, as in the last two examples in the above trace.
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Here are some examples of x86 instructions that do different combinations
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// of loads, stores, and modifies.
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    Instruction          Memory accesses                  Event sequence
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    -----------          ---------------                  --------------
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    add %eax, %ebx       No loads or stores               instr
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    movl (%eax), %ebx    loads (%eax)                     instr, load
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    movl %eax, (%ebx)    stores (%ebx)                    instr, store
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    incl (%ecx)          modifies (%ecx)                  instr, modify
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    cmpsb                loads (%esi), loads(%edi)        instr, load, load
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    call*l (%edx)        loads (%edx), stores -4(%esp)    instr, load, store
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    pushl (%edx)         loads (%edx), stores -4(%esp)    instr, load, store
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//    movsw                loads (%esi), stores (%edi)      instr, load, store
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Instructions using x86 "rep" prefixes are traced as if they are repeated
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// N times.
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Lackey with --trace-mem gives good traces, but they are not perfect, for
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the following reasons:
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - It does not trace into the OS kernel, so system calls and other kernel
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   operations (eg. some scheduling and signal handling code) are ignored.
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - It could model loads and stores done at the system call boundary using
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   the pre_mem_read/post_mem_write events.  For example, if you call
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   fstat() you know that the passed in buffer has been written.  But it
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   currently does not do this.
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Valgrind replaces some code (not much) with its own, notably parts of
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   code for scheduling operations and signal handling.  This code is not
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   traced.
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - There is no consideration of virtual-to-physical address mapping.
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   This may not matter for many purposes.
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Valgrind modifies the instruction stream in some very minor ways.  For
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   example, on x86 the bts, btc, btr instructions are incorrectly
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   considered to always touch memory (this is a consequence of these
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   instructions being very difficult to simulate).
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Valgrind tools layout memory differently to normal programs, so the
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   addresses you get will not be typical.  Thus Lackey (and all Valgrind
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   tools) is suitable for getting relative memory traces -- eg. if you
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   want to analyse locality of memory accesses -- but is not good if
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   absolute addresses are important.
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Despite all these warnings, Lackey's results should be good enough for a
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// wide range of purposes.  For example, Cachegrind shares all the above
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// shortcomings and it is still useful.
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// For further inspiration, you should look at cachegrind/cg_main.c which
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// uses the same basic technique for tracing memory accesses, but also groups
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// events together for processing into twos and threes so that fewer C calls
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// are made and things run faster.
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Specific Details about --trace-superblocks=yes
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// ----------------------------------------------
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Valgrind splits code up into single entry, multiple exit blocks
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// known as superblocks.  By itself, --trace-superblocks=yes just
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// prints a message as each superblock is run:
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  SB 04013170
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  SB 04013177
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  SB 04013173
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  SB 04013177
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// The hex number is the address of the first instruction in the
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// superblock.  You can see the relationship more obviously if you use
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// --trace-superblocks=yes and --trace-mem=yes together.  Then a "SB"
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// message at address X is immediately followed by an "instr:" message
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// for that address, as the first instruction in the block is
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// executed, for example:
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  SB 04014073
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  04014073,3
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   L 7FEFFF7F8,8
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  04014076,4
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  0401407A,3
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  0401407D,3
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  04014080,3
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//  I  04014083,6
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h"
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_tooliface.h"
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_debuginfo.h"
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h"
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h"
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_machine.h"     // VG_(fnptr_to_fnentry)
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Command line options                                 ---*/
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Command line options controlling instrumentation kinds, as described at
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the top of this file. */
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool clo_basic_counts    = True;
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool clo_detailed_counts = False;
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool clo_trace_mem       = False;
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool clo_trace_sbs       = False;
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The name of the function of which the number of calls (under
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * --basic-counts=yes) is to be counted, with default. Override with command
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * line option --fnname. */
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Char* clo_fnname = "main";
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool lk_process_cmd_line_option(Char* arg)
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if VG_STR_CLO(arg, "--fnname", clo_fnname) {}
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--basic-counts",      clo_basic_counts) {}
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--detailed-counts",   clo_detailed_counts) {}
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--trace-mem",         clo_trace_mem) {}
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO(arg, "--trace-superblocks", clo_trace_sbs) {}
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_fnname);
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_fnname[0]);
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lk_print_usage(void)
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --basic-counts=no|yes     count instructions, jumps, etc. [yes]\n"
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --detailed-counts=no|yes  count loads, stores and alu ops [no]\n"
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --trace-mem=no|yes        trace all loads and stores [no]\n"
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --trace-superblocks=no|yes  trace all superblock entries [no]\n"
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    --fnname=<name>           count calls to <name> (only used if\n"
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"                              --basic-count=yes)  [main]\n"
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lk_print_debug_usage(void)
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"    (none)\n"
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stuff for --basic-counts                             ---*/
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Nb: use ULongs because the numbers can get very big */
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_func_calls    = 0;
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_SBs_entered   = 0;
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_SBs_completed = 0;
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_IRStmts       = 0;
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_guest_instrs  = 0;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_Jccs          = 0;
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_Jccs_untaken  = 0;
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_IJccs         = 0;
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong n_IJccs_untaken = 0;
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_func_call(void)
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_func_calls++;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_SB_entered(void)
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_SBs_entered++;
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_SB_completed(void)
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_SBs_completed++;
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_IRStmt(void)
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_IRStmts++;
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_guest_instr(void)
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_guest_instrs++;
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_Jcc(void)
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_Jccs++;
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_Jcc_untaken(void)
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_Jccs_untaken++;
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_inverted_Jcc(void)
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_IJccs++;
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_one_inverted_Jcc_untaken(void)
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_IJccs_untaken++;
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stuff for --detailed-counts                          ---*/
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Operations --- */
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_OPS 3
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Types --- */
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#define N_TYPES 10
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int type2index ( IRType ty )
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I1:      return 0;
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:      return 1;
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16:     return 2;
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32:     return 3;
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64:     return 4;
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I128:    return 5;
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_F32:     return 6;
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_F64:     return 7;
317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case Ity_F128:    return 8;
318b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case Ity_V128:    return 9;
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: tl_assert(0);
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameOfTypeIndex ( Int i )
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (i) {
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return "I1";   break;
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "I8";   break;
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "I16";  break;
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return "I32";  break;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return "I64";  break;
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: return "I128"; break;
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: return "F32";  break;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: return "F64";  break;
334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 8: return "F128";  break;
335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 9: return "V128"; break;
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: tl_assert(0);
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Counts --- */
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong detailCounts[N_OPS][N_TYPES];
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The helper that is called from the instrumented code. */
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(1)
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid increment_detail(ULong* detail)
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (*detail)++;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* A helper that adds the instrumentation for a detail. */
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void instrument_detail(IRSB* sb, Op op, IRType type)
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty* di;
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** argv;
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UInt typeIx = type2index(type);
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(op < N_OPS);
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(typeIx < N_TYPES);
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   di = unsafeIRDirty_0_N( 1, "increment_detail",
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(fnptr_to_fnentry)( &increment_detail ),
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              argv);
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( sb, IRStmt_Dirty(di) );
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Summarize and print the details. */
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void print_details ( void )
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int typeIx;
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(umsg)("   Type        Loads       Stores       AluOps\n");
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(umsg)("   -------------------------------------------\n");
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("   %4s %'12llu %'12llu %'12llu\n",
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameOfTypeIndex( typeIx ),
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                detailCounts[OpLoad ][typeIx],
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                detailCounts[OpStore][typeIx],
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                detailCounts[OpAlu  ][typeIx]
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stuff for --trace-mem                                ---*/
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAX_DSIZE    512
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRAtom;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EventKind;
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      EventKind  ekind;
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRAtom*    addr;
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int        size;
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Up to this many unnotified events are allowed.  Must be at least two,
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   so that reads and writes to the same address can be merged into a modify.
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Beyond that, larger numbers just potentially induce more spilling due to
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   extending live ranges of address temporaries. */
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_EVENTS 4
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Maintain an ordered list of memory events which are outstanding, in
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the sense that no IR has yet been generated to do the relevant
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   helper calls.  The SB is scanned top to bottom and memory events
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   are added to the end of the list, merging with the most recent
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   notified event where possible (Dw immediately following Dr and
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   having the same size and EA can be merged).
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This merging is done so that for architectures which have
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   load-op-store instructions (x86, amd64), the instr is treated as if
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it makes just one memory reference (a modify), rather than two (a
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   read followed by a write at the same address).
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   At various points the list will need to be flushed, that is, IR
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   generated from it.  That must happen before any possible exit from
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the block (the end, or an IRStmt_Exit).  Flushing also takes place
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   when there is no space to add a new event.
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If we require the simulation statistics to be up to date with
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   respect to possible memory exceptions, then the list would have to
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be flushed before each memory reference.  That's a pain so we don't
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bother.
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Flushing the list consists of walking it start to end and emitting
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instrumentation IR for each event, in the order in which they
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appear. */
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Event events[N_EVENTS];
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int   events_used = 0;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2) void trace_instr(Addr addr, SizeT size)
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("I  %08lx,%lu\n", addr, size);
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(" L %08lx,%lu\n", addr, size);
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(" S %08lx,%lu\n", addr, size);
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic VG_REGPARM(2) void trace_modify(Addr addr, SizeT size)
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(" M %08lx,%lu\n", addr, size);
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void flushEvents(IRSB* sb)
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int        i;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char*      helperName;
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*      helperAddr;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr**   argv;
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty*   di;
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event*     ev;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < events_used; i++) {
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ev = &events[i];
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Decide on helper fn to call and args to pass it.
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (ev->ekind) {
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Event_Ir: helperName = "trace_instr";
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        helperAddr =  trace_instr;  break;
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Event_Dr: helperName = "trace_load";
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        helperAddr =  trace_load;   break;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Event_Dw: helperName = "trace_store";
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        helperAddr =  trace_store;  break;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Event_Dm: helperName = "trace_modify";
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        helperAddr =  trace_modify; break;
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(0);
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Add the helper.
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argv = mkIRExprVec_2( ev->addr, mkIRExpr_HWord( ev->size ) );
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di   = unsafeIRDirty_0_N( /*regparms*/2,
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                helperName, VG_(fnptr_to_fnentry)( helperAddr ),
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                argv );
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sb, IRStmt_Dirty(di) );
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   events_used = 0;
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// WARNING:  If you aren't interested in instruction reads, you can omit the
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// code that adds calls to trace_instr() in flushEvents().  However, you
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// must still call this function, addEvent_Ir() -- it is necessary to add
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// the Ir events to the events list so that merging of paired load/store
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// events into modify events works correctly.
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void addEvent_Ir ( IRSB* sb, IRAtom* iaddr, UInt isize )
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event* evt;
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_trace_mem);
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            || VG_CLREQ_SZB == isize );
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (events_used == N_EVENTS)
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      flushEvents(sb);
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(events_used >= 0 && events_used < N_EVENTS);
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt = &events[events_used];
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->ekind = Event_Ir;
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->addr  = iaddr;
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->size  = isize;
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   events_used++;
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid addEvent_Dr ( IRSB* sb, IRAtom* daddr, Int dsize )
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event* evt;
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_trace_mem);
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isIRAtom(daddr));
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (events_used == N_EVENTS)
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      flushEvents(sb);
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(events_used >= 0 && events_used < N_EVENTS);
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt = &events[events_used];
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->ekind = Event_Dr;
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->addr  = daddr;
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->size  = dsize;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   events_used++;
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid addEvent_Dw ( IRSB* sb, IRAtom* daddr, Int dsize )
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event* lastEvt;
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Event* evt;
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_trace_mem);
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isIRAtom(daddr));
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Is it possible to merge this write with the preceding read?
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lastEvt = &events[events_used-1];
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (events_used > 0
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    && lastEvt->ekind == Event_Dr
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    && lastEvt->size  == dsize
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    && eqIRAtom(lastEvt->addr, daddr))
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lastEvt->ekind = Event_Dm;
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // No.  Add as normal.
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (events_used == N_EVENTS)
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      flushEvents(sb);
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(events_used >= 0 && events_used < N_EVENTS);
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt = &events[events_used];
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->ekind = Event_Dw;
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->size  = dsize;
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   evt->addr  = daddr;
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   events_used++;
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stuff for --trace-superblocks                        ---*/
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void trace_superblock(Addr addr)
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("SB %08lx\n", addr);
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Basic tool functions                                 ---*/
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lk_post_clo_init(void)
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int op, tyIx;
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_detailed_counts) {
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (op = 0; op < N_OPS; op++)
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (tyIx = 0; tyIx < N_TYPES; tyIx++)
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            detailCounts[op][tyIx] = 0;
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRSB* lk_instrument ( VgCallbackClosure* closure,
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRSB* sbIn,
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestLayout* layout,
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      VexGuestExtents* vge,
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      IRType gWordTy, IRType hWordTy )
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty*   di;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int        i;
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB*      sbOut;
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Char       fnname[100];
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType     type;
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTypeEnv* tyenv = sbIn->tyenv;
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr       iaddr = 0, dst;
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt       ilen = 0;
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool       condition_inverted = False;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gWordTy != hWordTy) {
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We don't currently support this case. */
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("host/guest word size mismatch");
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up SB */
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sbOut = deepCopyIRSBExceptStmts(sbIn);
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Copy verbatim any IR preamble preceding the first IMark
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   i = 0;
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, sbIn->stmts[i] );
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      i++;
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_basic_counts) {
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Count this superblock. */
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di = unsafeIRDirty_0_N( 0, "add_one_SB_entered",
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 VG_(fnptr_to_fnentry)( &add_one_SB_entered ),
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkIRExprVec_0() );
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_trace_sbs) {
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Print this superblock's address. */
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di = unsafeIRDirty_0_N(
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              0, "trace_superblock",
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              VG_(fnptr_to_fnentry)( &trace_superblock ),
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprVec_1( mkIRExpr_HWord( vge->base[0] ) )
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           );
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_trace_mem) {
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      events_used = 0;
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (/*use current i*/; i < sbIn->stmts_used; i++) {
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt* st = sbIn->stmts[i];
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!st || st->tag == Ist_NoOp) continue;
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (clo_basic_counts) {
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Count one VEX statement. */
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkIRExprVec_0() );
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (st->tag) {
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_NoOp:
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_AbiHint:
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Put:
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_PutI:
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_MBE:
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_IMark:
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_basic_counts) {
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Needed to be able to check for inverted condition in Ist_Exit */
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               iaddr = st->Ist.IMark.addr;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ilen  = st->Ist.IMark.len;
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Count guest instruction. */
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkIRExprVec_0() );
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* An unconditional branch to a known destination in the
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * guest's instructions can be represented, in the IRSB to
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * instrument, by the VEX statements that are the
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * translation of that known destination. This feature is
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * called 'SB chasing' and can be influenced by command
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * line option --vex-guest-chase-thresh.
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                *
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * To get an accurate count of the calls to a specific
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * function, taking SB chasing into account, we need to
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * check for each guest instruction (Ist_IMark) if it is
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                * the entry point of a function.
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                */
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(clo_fnname);
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(clo_fnname[0]);
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                            fnname, sizeof(fnname))
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && 0 == VG_(strcmp)(fnname, clo_fnname)) {
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  di = unsafeIRDirty_0_N(
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0, "add_one_func_call",
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             VG_(fnptr_to_fnentry)( &add_one_func_call ),
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkIRExprVec_0() );
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // WARNING: do not remove this function call, even if you
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // aren't interested in instruction reads.  See the comment
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // above the function itself for more detail.
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            st->Ist.IMark.len );
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_WrTmp:
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // Add a call to trace_load() if --trace-mem=yes.
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* data = st->Ist.WrTmp.data;
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (data->tag == Iex_Load) {
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addEvent_Dr( sbOut, data->Iex.Load.addr,
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               sizeofIRType(data->Iex.Load.ty) );
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_detailed_counts) {
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* expr = st->Ist.WrTmp.data;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               type = typeOfIRExpr(sbOut->tyenv, expr);
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(type != Ity_INVALID);
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               switch (expr->tag) {
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Load:
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     instrument_detail( sbOut, OpLoad, type );
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Unop:
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Binop:
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Triop:
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Qop:
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  case Iex_Mux0X:
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     instrument_detail( sbOut, OpAlu, type );
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  default:
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     break;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Store:
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* data  = st->Ist.Store.data;
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addEvent_Dw( sbOut, st->Ist.Store.addr,
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            sizeofIRType(typeOfIRExpr(tyenv, data)) );
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_detailed_counts) {
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               type = typeOfIRExpr(sbOut->tyenv, st->Ist.Store.data);
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(type != Ity_INVALID);
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instrument_detail( sbOut, OpStore, type );
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Dirty: {
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Int      dsize;
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = st->Ist.Dirty.details;
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (d->mFx != Ifx_None) {
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  // This dirty helper accesses memory.  Collect the details.
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tl_assert(d->mAddr != NULL);
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tl_assert(d->mSize != 0);
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dsize = d->mSize;
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addEvent_Dr( sbOut, d->mAddr, dsize );
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     addEvent_Dw( sbOut, d->mAddr, dsize );
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               } else {
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tl_assert(d->mAddr == NULL);
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  tl_assert(d->mSize == 0);
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               }
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_CAS: {
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We treat it as a read and a write of the location.  I
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               think that is the same behaviour as it was before IRCAS
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               was introduced, since prior to that point, the Vex
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               front ends would translate a lock-prefixed instruction
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               into a (normal) read followed by a (normal) write. */
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Int    dataSize;
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRType dataTy;
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRCAS* cas = st->Ist.CAS.details;
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(cas->addr != NULL);
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(cas->dataLo != NULL);
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dataTy   = typeOfIRExpr(tyenv, cas->dataLo);
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dataSize = sizeofIRType(dataTy);
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (cas->dataHi != NULL)
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dataSize *= 2; /* since it's a doubleword-CAS */
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addEvent_Dr( sbOut, cas->addr, dataSize );
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addEvent_Dw( sbOut, cas->addr, dataSize );
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_detailed_counts) {
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instrument_detail( sbOut, OpLoad, dataTy );
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (cas->dataHi != NULL) /* dcas */
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_detail( sbOut, OpLoad, dataTy );
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instrument_detail( sbOut, OpStore, dataTy );
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (cas->dataHi != NULL) /* dcas */
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_detail( sbOut, OpStore, dataTy );
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_LLSC: {
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRType dataTy;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (st->Ist.LLSC.storedata == NULL) {
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* LL */
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (clo_trace_mem)
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addEvent_Dr( sbOut, st->Ist.LLSC.addr,
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      sizeofIRType(dataTy) );
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (clo_detailed_counts)
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_detail( sbOut, OpLoad, dataTy );
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* SC */
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (clo_trace_mem)
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addEvent_Dw( sbOut, st->Ist.LLSC.addr,
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      sizeofIRType(dataTy) );
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (clo_detailed_counts)
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  instrument_detail( sbOut, OpStore, dataTy );
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case Ist_Exit:
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_basic_counts) {
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // The condition of a branch was inverted by VEX if a taken
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // branch is in fact a fall trough according to client address
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               tl_assert(iaddr != 0);
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dst = (sizeof(Addr) == 4) ? st->Ist.Exit.dst->Ico.U32 :
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           st->Ist.Exit.dst->Ico.U64;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               condition_inverted = (dst == iaddr + ilen);
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Count Jcc */
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!condition_inverted)
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(fnptr_to_fnentry)( &add_one_Jcc ),
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkIRExprVec_0() );
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc",
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(fnptr_to_fnentry)(
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             &add_one_inverted_Jcc ),
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkIRExprVec_0() );
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_trace_mem) {
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               flushEvents(sbOut);
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( sbOut, st );      // Original statement
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (clo_basic_counts) {
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Count non-taken Jcc */
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!condition_inverted)
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(fnptr_to_fnentry)(
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             &add_one_Jcc_untaken ),
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkIRExprVec_0() );
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               else
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc_untaken",
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(fnptr_to_fnentry)(
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             &add_one_inverted_Jcc_untaken ),
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          mkIRExprVec_0() );
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(0);
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_basic_counts) {
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Count this basic block. */
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      di = unsafeIRDirty_0_N( 0, "add_one_SB_completed",
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 VG_(fnptr_to_fnentry)( &add_one_SB_completed ),
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkIRExprVec_0() );
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_trace_mem) {
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At the end of the sbIn.  Flush outstandings. */
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      flushEvents(sbOut);
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sbOut;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lk_fini(Int exitcode)
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
911b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   char percentify_buf[5]; /* Two digits, '%' and 0. */
912b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const int percentify_size = sizeof(percentify_buf) - 1;
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const int percentify_decs = 0;
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_fnname);
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(clo_fnname[0]);
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_basic_counts) {
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong total_Jccs = n_Jccs + n_IJccs;
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong taken_Jccs = (n_Jccs - n_Jccs_untaken) + n_IJccs_untaken;
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("Counted %'llu call%s to %s()\n",
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                n_func_calls, ( n_func_calls==1 ? "" : "s" ), clo_fnname);
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("\n");
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("Jccs:\n");
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  total:         %'llu\n", total_Jccs);
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(percentify)(taken_Jccs, (total_Jccs ? total_Jccs : 1),
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         percentify_decs, percentify_size, percentify_buf);
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  taken:         %'llu (%s)\n",
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         taken_Jccs, percentify_buf);
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("\n");
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("Executed:\n");
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  SBs entered:   %'llu\n", n_SBs_entered);
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  SBs completed: %'llu\n", n_SBs_completed);
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  guest instrs:  %'llu\n", n_guest_instrs);
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  IRStmts:       %'llu\n", n_IRStmts);
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("\n");
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("Ratios:\n");
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(n_SBs_entered); // Paranoia time.
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("  guest instrs : SB entered  = %'llu : 10\n",
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         10 * n_guest_instrs / n_SBs_entered);
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("       IRStmts : SB entered  = %'llu : 10\n",
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         10 * n_IRStmts / n_SBs_entered);
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(n_guest_instrs); // Paranoia time.
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("       IRStmts : guest instr = %'llu : 10\n",
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         10 * n_IRStmts / n_guest_instrs);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_detailed_counts) {
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("\n");
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("IR-level counts by type:\n");
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      print_details();
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (clo_basic_counts) {
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("\n");
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(umsg)("Exit code:       %d\n", exitcode);
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void lk_pre_clo_init(void)
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_name)            ("Lackey");
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_version)         (NULL);
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_description)     ("an example Valgrind tool");
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_copyright_author)(
970b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      "Copyright (C) 2002-2011, and GNU GPL'd, by Nicholas Nethercote.");
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_bug_reports_to)  (VG_BUGS_TO);
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_avg_translation_sizeB) ( 200 );
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(basic_tool_funcs)          (lk_post_clo_init,
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   lk_instrument,
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   lk_fini);
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_command_line_options)(lk_process_cmd_line_option,
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   lk_print_usage,
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   lk_print_debug_usage);
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                lk_main.c ---*/
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
987