blob: 707ba972276d16c666c0cf34341ecfffad4c466d [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnd99644d2006-04-07 11:52:55 +00003/*--- An example Valgrind tool. lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00004/*--------------------------------------------------------------------*/
5
6/*
nethercote137bc552003-11-14 17:47:54 +00007 This file is part of Lackey, an example Valgrind tool that does
njnd99644d2006-04-07 11:52:55 +00008 some simple program measurement and tracing.
njn25e49d8e72002-09-23 09:36:25 +00009
Elliott Hughesed398002017-06-21 14:41:24 -070010 Copyright (C) 2002-2017 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000011 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000012
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnfd73ebb2005-12-30 22:39:58 +000031// This tool shows how to do some basic instrumentation.
32//
sewardj5d1c9012007-02-12 08:42:13 +000033// There are four kinds of instrumentation it can do. They can be turned
njnd99644d2006-04-07 11:52:55 +000034// on/off independently with command line options:
35//
36// * --basic-counts : do basic counts, eg. number of instructions
37// executed, jumps executed, etc.
38// * --detailed-counts: do more detailed counts: number of loads, stores
39// and ALU operations of different sizes.
40// * --trace-mem=yes: trace all (data) memory accesses.
sewardj5d1c9012007-02-12 08:42:13 +000041// * --trace-superblocks=yes:
42// trace all superblock entries. Mostly of interest
43// to the Valgrind developers.
njnd99644d2006-04-07 11:52:55 +000044//
45// The code for each kind of instrumentation is guarded by a clo_* variable:
sewardj5d1c9012007-02-12 08:42:13 +000046// clo_basic_counts, clo_detailed_counts, clo_trace_mem and clo_trace_sbs.
njnd99644d2006-04-07 11:52:55 +000047//
48// If you want to modify any of the instrumentation code, look for the code
49// that is guarded by the relevant clo_* variable (eg. clo_trace_mem)
50// If you're not interested in the other kinds of instrumentation you can
51// remove them. If you want to do more complex modifications, please read
52// VEX/pub/libvex_ir.h to understand the intermediate representation.
53//
54//
55// Specific Details about --trace-mem=yes
56// --------------------------------------
njneaf0ca92006-04-09 01:23:29 +000057// Lackey's --trace-mem code is a good starting point for building Valgrind
58// tools that act on memory loads and stores. It also could be used as is,
59// with its output used as input to a post-mortem processing step. However,
60// because memory traces can be very large, online analysis is generally
61// better.
njnfd73ebb2005-12-30 22:39:58 +000062//
njneaf0ca92006-04-09 01:23:29 +000063// It prints memory data access traces that look like this:
64//
sewardj5d1c9012007-02-12 08:42:13 +000065// I 0023C790,2 # instruction read at 0x0023C790 of size 2
66// I 0023C792,5
67// S BE80199C,4 # data store at 0xBE80199C of size 4
68// I 0025242B,3
69// L BE801950,4 # data load at 0xBE801950 of size 4
70// I 0023D476,7
71// M 0025747C,1 # data modify at 0x0025747C of size 1
72// I 0023DC20,2
73// L 00254962,1
74// L BE801FB3,1
75// I 00252305,1
76// L 00254AEB,1
77// S 00257998,1
njneaf0ca92006-04-09 01:23:29 +000078//
79// Every instruction executed has an "instr" event representing it.
80// Instructions that do memory accesses are followed by one or more "load",
81// "store" or "modify" events. Some instructions do more than one load or
82// store, as in the last two examples in the above trace.
83//
84// Here are some examples of x86 instructions that do different combinations
85// of loads, stores, and modifies.
86//
87// Instruction Memory accesses Event sequence
88// ----------- --------------- --------------
89// add %eax, %ebx No loads or stores instr
90//
91// movl (%eax), %ebx loads (%eax) instr, load
92//
93// movl %eax, (%ebx) stores (%ebx) instr, store
94//
95// incl (%ecx) modifies (%ecx) instr, modify
96//
97// cmpsb loads (%esi), loads(%edi) instr, load, load
98//
99// call*l (%edx) loads (%edx), stores -4(%esp) instr, load, store
100// pushl (%edx) loads (%edx), stores -4(%esp) instr, load, store
101// movsw loads (%esi), stores (%edi) instr, load, store
102//
103// Instructions using x86 "rep" prefixes are traced as if they are repeated
104// N times.
105//
106// Lackey with --trace-mem gives good traces, but they are not perfect, for
107// the following reasons:
108//
109// - It does not trace into the OS kernel, so system calls and other kernel
110// operations (eg. some scheduling and signal handling code) are ignored.
111//
njne8d217d2006-10-18 23:46:26 +0000112// - It could model loads and stores done at the system call boundary using
113// the pre_mem_read/post_mem_write events. For example, if you call
114// fstat() you know that the passed in buffer has been written. But it
115// currently does not do this.
116//
117// - Valgrind replaces some code (not much) with its own, notably parts of
118// code for scheduling operations and signal handling. This code is not
119// traced.
njneaf0ca92006-04-09 01:23:29 +0000120//
121// - There is no consideration of virtual-to-physical address mapping.
122// This may not matter for many purposes.
123//
124// - Valgrind modifies the instruction stream in some very minor ways. For
125// example, on x86 the bts, btc, btr instructions are incorrectly
126// considered to always touch memory (this is a consequence of these
127// instructions being very difficult to simulate).
128//
129// - Valgrind tools layout memory differently to normal programs, so the
130// addresses you get will not be typical. Thus Lackey (and all Valgrind
131// tools) is suitable for getting relative memory traces -- eg. if you
132// want to analyse locality of memory accesses -- but is not good if
133// absolute addresses are important.
134//
njn6fb923b2009-08-05 06:57:45 +0000135// Despite all these warnings, Lackey's results should be good enough for a
njneaf0ca92006-04-09 01:23:29 +0000136// wide range of purposes. For example, Cachegrind shares all the above
137// shortcomings and it is still useful.
njn9dd72772006-03-11 06:48:20 +0000138//
njnfd73ebb2005-12-30 22:39:58 +0000139// For further inspiration, you should look at cachegrind/cg_main.c which
njneaf0ca92006-04-09 01:23:29 +0000140// uses the same basic technique for tracing memory accesses, but also groups
141// events together for processing into twos and threes so that fewer C calls
142// are made and things run faster.
sewardj5d1c9012007-02-12 08:42:13 +0000143//
144// Specific Details about --trace-superblocks=yes
145// ----------------------------------------------
146// Valgrind splits code up into single entry, multiple exit blocks
147// known as superblocks. By itself, --trace-superblocks=yes just
148// prints a message as each superblock is run:
149//
150// SB 04013170
151// SB 04013177
152// SB 04013173
153// SB 04013177
154//
155// The hex number is the address of the first instruction in the
156// superblock. You can see the relationship more obviously if you use
157// --trace-superblocks=yes and --trace-mem=yes together. Then a "SB"
158// message at address X is immediately followed by an "instr:" message
159// for that address, as the first instruction in the block is
160// executed, for example:
161//
162// SB 04014073
163// I 04014073,3
164// L 7FEFFF7F8,8
165// I 04014076,4
166// I 0401407A,3
167// I 0401407D,3
168// I 04014080,3
169// I 04014083,6
170
njnfd73ebb2005-12-30 22:39:58 +0000171
njnc7561b92005-06-19 01:24:32 +0000172#include "pub_tool_basics.h"
njn43b9a8a2005-05-10 04:37:01 +0000173#include "pub_tool_tooliface.h"
njnf39e9a32005-06-12 02:43:17 +0000174#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +0000175#include "pub_tool_libcprint.h"
sewardj7a26f022005-11-01 17:52:34 +0000176#include "pub_tool_debuginfo.h"
177#include "pub_tool_libcbase.h"
178#include "pub_tool_options.h"
sewardj5fed8c02005-12-23 12:56:11 +0000179#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
sewardj7a26f022005-11-01 17:52:34 +0000180
njnd99644d2006-04-07 11:52:55 +0000181/*------------------------------------------------------------*/
182/*--- Command line options ---*/
183/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000184
njnd99644d2006-04-07 11:52:55 +0000185/* Command line options controlling instrumentation kinds, as described at
186 * the top of this file. */
187static Bool clo_basic_counts = True;
188static Bool clo_detailed_counts = False;
189static Bool clo_trace_mem = False;
sewardj5d1c9012007-02-12 08:42:13 +0000190static Bool clo_trace_sbs = False;
sewardj7a26f022005-11-01 17:52:34 +0000191
njnd99644d2006-04-07 11:52:55 +0000192/* The name of the function of which the number of calls (under
193 * --basic-counts=yes) is to be counted, with default. Override with command
194 * line option --fnname. */
florian19f91bb2012-11-10 22:29:54 +0000195static const HChar* clo_fnname = "main";
sewardj7a26f022005-11-01 17:52:34 +0000196
florian19f91bb2012-11-10 22:29:54 +0000197static Bool lk_process_cmd_line_option(const HChar* arg)
sewardj7a26f022005-11-01 17:52:34 +0000198{
njn83df0b62009-02-25 01:01:05 +0000199 if VG_STR_CLO(arg, "--fnname", clo_fnname) {}
200 else if VG_BOOL_CLO(arg, "--basic-counts", clo_basic_counts) {}
201 else if VG_BOOL_CLO(arg, "--detailed-counts", clo_detailed_counts) {}
202 else if VG_BOOL_CLO(arg, "--trace-mem", clo_trace_mem) {}
203 else if VG_BOOL_CLO(arg, "--trace-superblocks", clo_trace_sbs) {}
sewardj7a26f022005-11-01 17:52:34 +0000204 else
205 return False;
206
njnd99644d2006-04-07 11:52:55 +0000207 tl_assert(clo_fnname);
208 tl_assert(clo_fnname[0]);
sewardj7a26f022005-11-01 17:52:34 +0000209 return True;
210}
211
212static void lk_print_usage(void)
213{
214 VG_(printf)(
njn6fb923b2009-08-05 06:57:45 +0000215" --basic-counts=no|yes count instructions, jumps, etc. [yes]\n"
sewardj7a26f022005-11-01 17:52:34 +0000216" --detailed-counts=no|yes count loads, stores and alu ops [no]\n"
njnd99644d2006-04-07 11:52:55 +0000217" --trace-mem=no|yes trace all loads and stores [no]\n"
sewardj5d1c9012007-02-12 08:42:13 +0000218" --trace-superblocks=no|yes trace all superblock entries [no]\n"
njnd99644d2006-04-07 11:52:55 +0000219" --fnname=<name> count calls to <name> (only used if\n"
njn6fb923b2009-08-05 06:57:45 +0000220" --basic-count=yes) [main]\n"
sewardj7a26f022005-11-01 17:52:34 +0000221 );
222}
223
224static void lk_print_debug_usage(void)
225{
njneaf0ca92006-04-09 01:23:29 +0000226 VG_(printf)(
227" (none)\n"
228 );
sewardj7a26f022005-11-01 17:52:34 +0000229}
230
njnd99644d2006-04-07 11:52:55 +0000231/*------------------------------------------------------------*/
njneaf0ca92006-04-09 01:23:29 +0000232/*--- Stuff for --basic-counts ---*/
njnd99644d2006-04-07 11:52:55 +0000233/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000234
njn25e49d8e72002-09-23 09:36:25 +0000235/* Nb: use ULongs because the numbers can get very big */
sewardj7a26f022005-11-01 17:52:34 +0000236static ULong n_func_calls = 0;
sewardj5d1c9012007-02-12 08:42:13 +0000237static ULong n_SBs_entered = 0;
238static ULong n_SBs_completed = 0;
njneaf0ca92006-04-09 01:23:29 +0000239static ULong n_IRStmts = 0;
sewardj7a26f022005-11-01 17:52:34 +0000240static ULong n_guest_instrs = 0;
241static ULong n_Jccs = 0;
242static ULong n_Jccs_untaken = 0;
weidendoba5b3b22007-02-16 11:13:53 +0000243static ULong n_IJccs = 0;
244static ULong n_IJccs_untaken = 0;
njn25e49d8e72002-09-23 09:36:25 +0000245
sewardj7a26f022005-11-01 17:52:34 +0000246static void add_one_func_call(void)
njn25e49d8e72002-09-23 09:36:25 +0000247{
sewardj7a26f022005-11-01 17:52:34 +0000248 n_func_calls++;
njn25e49d8e72002-09-23 09:36:25 +0000249}
250
sewardj5d1c9012007-02-12 08:42:13 +0000251static void add_one_SB_entered(void)
njn25e49d8e72002-09-23 09:36:25 +0000252{
sewardj5d1c9012007-02-12 08:42:13 +0000253 n_SBs_entered++;
sewardj7a26f022005-11-01 17:52:34 +0000254}
255
sewardj5d1c9012007-02-12 08:42:13 +0000256static void add_one_SB_completed(void)
sewardj7a26f022005-11-01 17:52:34 +0000257{
sewardj5d1c9012007-02-12 08:42:13 +0000258 n_SBs_completed++;
njn25e49d8e72002-09-23 09:36:25 +0000259}
260
sewardj7a26f022005-11-01 17:52:34 +0000261static void add_one_IRStmt(void)
njn25e49d8e72002-09-23 09:36:25 +0000262{
sewardj7a26f022005-11-01 17:52:34 +0000263 n_IRStmts++;
njn25e49d8e72002-09-23 09:36:25 +0000264}
265
sewardj9f649aa2004-11-22 20:38:40 +0000266static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +0000267{
sewardj9f649aa2004-11-22 20:38:40 +0000268 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +0000269}
270
271static void add_one_Jcc(void)
272{
273 n_Jccs++;
274}
275
276static void add_one_Jcc_untaken(void)
277{
278 n_Jccs_untaken++;
279}
280
weidendoba5b3b22007-02-16 11:13:53 +0000281static void add_one_inverted_Jcc(void)
282{
283 n_IJccs++;
284}
285
286static void add_one_inverted_Jcc_untaken(void)
287{
288 n_IJccs_untaken++;
289}
290
njnd99644d2006-04-07 11:52:55 +0000291/*------------------------------------------------------------*/
njneaf0ca92006-04-09 01:23:29 +0000292/*--- Stuff for --detailed-counts ---*/
njnd99644d2006-04-07 11:52:55 +0000293/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000294
sewardjcafe5052013-01-17 14:24:35 +0000295typedef
296 IRExpr
297 IRAtom;
298
sewardj7a26f022005-11-01 17:52:34 +0000299/* --- Operations --- */
300
301typedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
302
303#define N_OPS 3
304
305
306/* --- Types --- */
307
floriancd70d492014-09-17 19:48:36 +0000308#define N_TYPES 14
sewardj7a26f022005-11-01 17:52:34 +0000309
310static Int type2index ( IRType ty )
njn25e49d8e72002-09-23 09:36:25 +0000311{
sewardj7a26f022005-11-01 17:52:34 +0000312 switch (ty) {
313 case Ity_I1: return 0;
314 case Ity_I8: return 1;
315 case Ity_I16: return 2;
316 case Ity_I32: return 3;
317 case Ity_I64: return 4;
318 case Ity_I128: return 5;
319 case Ity_F32: return 6;
320 case Ity_F64: return 7;
sewardjb5b87402011-03-07 16:05:35 +0000321 case Ity_F128: return 8;
322 case Ity_V128: return 9;
sewardj574d9a82012-05-21 13:44:54 +0000323 case Ity_V256: return 10;
floriancd70d492014-09-17 19:48:36 +0000324 case Ity_D32: return 11;
325 case Ity_D64: return 12;
326 case Ity_D128: return 13;
njnf36ae992007-11-22 23:33:20 +0000327 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000328 }
njn25e49d8e72002-09-23 09:36:25 +0000329}
330
florian19f91bb2012-11-10 22:29:54 +0000331static const HChar* nameOfTypeIndex ( Int i )
sewardj7a26f022005-11-01 17:52:34 +0000332{
njnab9c37e2007-08-27 22:18:58 +0000333 switch (i) {
sewardj7a26f022005-11-01 17:52:34 +0000334 case 0: return "I1"; break;
335 case 1: return "I8"; break;
336 case 2: return "I16"; break;
337 case 3: return "I32"; break;
338 case 4: return "I64"; break;
339 case 5: return "I128"; break;
340 case 6: return "F32"; break;
341 case 7: return "F64"; break;
sewardjb5b87402011-03-07 16:05:35 +0000342 case 8: return "F128"; break;
floriancd70d492014-09-17 19:48:36 +0000343 case 9: return "V128"; break;
sewardj574d9a82012-05-21 13:44:54 +0000344 case 10: return "V256"; break;
floriancd70d492014-09-17 19:48:36 +0000345 case 11: return "D32"; break;
346 case 12: return "D64"; break;
347 case 13: return "D128"; break;
njnf36ae992007-11-22 23:33:20 +0000348 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000349 }
350}
njn25e49d8e72002-09-23 09:36:25 +0000351
njn25e49d8e72002-09-23 09:36:25 +0000352
sewardj7a26f022005-11-01 17:52:34 +0000353/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000354
sewardj7a26f022005-11-01 17:52:34 +0000355static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000356
sewardj7a26f022005-11-01 17:52:34 +0000357/* The helper that is called from the instrumented code. */
358static VG_REGPARM(1)
359void increment_detail(ULong* detail)
360{
361 (*detail)++;
362}
njn25e49d8e72002-09-23 09:36:25 +0000363
sewardjcafe5052013-01-17 14:24:35 +0000364/* A helper that adds the instrumentation for a detail. guard ::
365 Ity_I1 is the guarding condition for the event. If NULL it is
366 assumed to mean "always True". */
367static void instrument_detail(IRSB* sb, Op op, IRType type, IRAtom* guard)
sewardj7a26f022005-11-01 17:52:34 +0000368{
369 IRDirty* di;
370 IRExpr** argv;
371 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000372
sewardj7a26f022005-11-01 17:52:34 +0000373 tl_assert(op < N_OPS);
374 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000375
sewardj7a26f022005-11-01 17:52:34 +0000376 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000377 di = unsafeIRDirty_0_N( 1, "increment_detail",
378 VG_(fnptr_to_fnentry)( &increment_detail ),
379 argv);
sewardjcafe5052013-01-17 14:24:35 +0000380 if (guard) di->guard = guard;
sewardj5d1c9012007-02-12 08:42:13 +0000381 addStmtToIRSB( sb, IRStmt_Dirty(di) );
sewardj7a26f022005-11-01 17:52:34 +0000382}
njn25e49d8e72002-09-23 09:36:25 +0000383
sewardj7a26f022005-11-01 17:52:34 +0000384/* Summarize and print the details. */
sewardj7a26f022005-11-01 17:52:34 +0000385static void print_details ( void )
386{
387 Int typeIx;
sewardjb5dc2d62009-07-15 14:51:48 +0000388 VG_(umsg)(" Type Loads Stores AluOps\n");
389 VG_(umsg)(" -------------------------------------------\n");
sewardj7a26f022005-11-01 17:52:34 +0000390 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
florian866862a2014-12-13 18:35:00 +0000391 VG_(umsg)(" %-4s %'12llu %'12llu %'12llu\n",
sewardjb5dc2d62009-07-15 14:51:48 +0000392 nameOfTypeIndex( typeIx ),
393 detailCounts[OpLoad ][typeIx],
394 detailCounts[OpStore][typeIx],
395 detailCounts[OpAlu ][typeIx]
sewardj7a26f022005-11-01 17:52:34 +0000396 );
397 }
398}
njn25e49d8e72002-09-23 09:36:25 +0000399
sewardj7a26f022005-11-01 17:52:34 +0000400
njnd99644d2006-04-07 11:52:55 +0000401/*------------------------------------------------------------*/
njneaf0ca92006-04-09 01:23:29 +0000402/*--- Stuff for --trace-mem ---*/
njnd99644d2006-04-07 11:52:55 +0000403/*------------------------------------------------------------*/
njnfd73ebb2005-12-30 22:39:58 +0000404
njneaf0ca92006-04-09 01:23:29 +0000405#define MAX_DSIZE 512
406
njneaf0ca92006-04-09 01:23:29 +0000407typedef
408 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
409 EventKind;
410
411typedef
412 struct {
413 EventKind ekind;
414 IRAtom* addr;
415 Int size;
sewardjcafe5052013-01-17 14:24:35 +0000416 IRAtom* guard; /* :: Ity_I1, or NULL=="always True" */
njneaf0ca92006-04-09 01:23:29 +0000417 }
418 Event;
419
420/* Up to this many unnotified events are allowed. Must be at least two,
421 so that reads and writes to the same address can be merged into a modify.
422 Beyond that, larger numbers just potentially induce more spilling due to
423 extending live ranges of address temporaries. */
424#define N_EVENTS 4
425
426/* Maintain an ordered list of memory events which are outstanding, in
427 the sense that no IR has yet been generated to do the relevant
sewardj5d1c9012007-02-12 08:42:13 +0000428 helper calls. The SB is scanned top to bottom and memory events
njneaf0ca92006-04-09 01:23:29 +0000429 are added to the end of the list, merging with the most recent
430 notified event where possible (Dw immediately following Dr and
431 having the same size and EA can be merged).
432
433 This merging is done so that for architectures which have
434 load-op-store instructions (x86, amd64), the instr is treated as if
435 it makes just one memory reference (a modify), rather than two (a
436 read followed by a write at the same address).
437
438 At various points the list will need to be flushed, that is, IR
439 generated from it. That must happen before any possible exit from
440 the block (the end, or an IRStmt_Exit). Flushing also takes place
weidendod4053322012-11-26 18:16:58 +0000441 when there is no space to add a new event, and before entering a
442 RMW (read-modify-write) section on processors supporting LL/SC.
njneaf0ca92006-04-09 01:23:29 +0000443
444 If we require the simulation statistics to be up to date with
445 respect to possible memory exceptions, then the list would have to
446 be flushed before each memory reference. That's a pain so we don't
447 bother.
448
449 Flushing the list consists of walking it start to end and emitting
450 instrumentation IR for each event, in the order in which they
451 appear. */
452
453static Event events[N_EVENTS];
454static Int events_used = 0;
455
456
457static VG_REGPARM(2) void trace_instr(Addr addr, SizeT size)
458{
njn8a7b41b2007-09-23 00:51:24 +0000459 VG_(printf)("I %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000460}
461
njnfd73ebb2005-12-30 22:39:58 +0000462static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
463{
njn8a7b41b2007-09-23 00:51:24 +0000464 VG_(printf)(" L %08lx,%lu\n", addr, size);
njnfd73ebb2005-12-30 22:39:58 +0000465}
466
467static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
468{
njn8a7b41b2007-09-23 00:51:24 +0000469 VG_(printf)(" S %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000470}
471
472static VG_REGPARM(2) void trace_modify(Addr addr, SizeT size)
473{
njn8a7b41b2007-09-23 00:51:24 +0000474 VG_(printf)(" M %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000475}
476
477
sewardj5d1c9012007-02-12 08:42:13 +0000478static void flushEvents(IRSB* sb)
njneaf0ca92006-04-09 01:23:29 +0000479{
480 Int i;
florian19f91bb2012-11-10 22:29:54 +0000481 const HChar* helperName;
njneaf0ca92006-04-09 01:23:29 +0000482 void* helperAddr;
483 IRExpr** argv;
484 IRDirty* di;
485 Event* ev;
486
487 for (i = 0; i < events_used; i++) {
488
489 ev = &events[i];
490
491 // Decide on helper fn to call and args to pass it.
492 switch (ev->ekind) {
493 case Event_Ir: helperName = "trace_instr";
494 helperAddr = trace_instr; break;
495
496 case Event_Dr: helperName = "trace_load";
497 helperAddr = trace_load; break;
498
499 case Event_Dw: helperName = "trace_store";
500 helperAddr = trace_store; break;
501
502 case Event_Dm: helperName = "trace_modify";
503 helperAddr = trace_modify; break;
504 default:
505 tl_assert(0);
506 }
507
508 // Add the helper.
509 argv = mkIRExprVec_2( ev->addr, mkIRExpr_HWord( ev->size ) );
510 di = unsafeIRDirty_0_N( /*regparms*/2,
511 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
512 argv );
sewardjcafe5052013-01-17 14:24:35 +0000513 if (ev->guard) {
514 di->guard = ev->guard;
515 }
sewardj5d1c9012007-02-12 08:42:13 +0000516 addStmtToIRSB( sb, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000517 }
518
519 events_used = 0;
520}
521
522// WARNING: If you aren't interested in instruction reads, you can omit the
523// code that adds calls to trace_instr() in flushEvents(). However, you
524// must still call this function, addEvent_Ir() -- it is necessary to add
525// the Ir events to the events list so that merging of paired load/store
526// events into modify events works correctly.
sewardj5d1c9012007-02-12 08:42:13 +0000527static void addEvent_Ir ( IRSB* sb, IRAtom* iaddr, UInt isize )
njneaf0ca92006-04-09 01:23:29 +0000528{
529 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000530 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000531 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
532 || VG_CLREQ_SZB == isize );
533 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000534 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000535 tl_assert(events_used >= 0 && events_used < N_EVENTS);
536 evt = &events[events_used];
537 evt->ekind = Event_Ir;
538 evt->addr = iaddr;
539 evt->size = isize;
sewardjcafe5052013-01-17 14:24:35 +0000540 evt->guard = NULL;
njneaf0ca92006-04-09 01:23:29 +0000541 events_used++;
542}
543
sewardjcafe5052013-01-17 14:24:35 +0000544/* Add a guarded read event. */
njneaf0ca92006-04-09 01:23:29 +0000545static
sewardjcafe5052013-01-17 14:24:35 +0000546void addEvent_Dr_guarded ( IRSB* sb, IRAtom* daddr, Int dsize, IRAtom* guard )
njneaf0ca92006-04-09 01:23:29 +0000547{
548 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000549 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000550 tl_assert(isIRAtom(daddr));
551 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
552 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000553 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000554 tl_assert(events_used >= 0 && events_used < N_EVENTS);
555 evt = &events[events_used];
556 evt->ekind = Event_Dr;
557 evt->addr = daddr;
558 evt->size = dsize;
sewardjcafe5052013-01-17 14:24:35 +0000559 evt->guard = guard;
njneaf0ca92006-04-09 01:23:29 +0000560 events_used++;
561}
562
sewardjcafe5052013-01-17 14:24:35 +0000563/* Add an ordinary read event, by adding a guarded read event with an
564 always-true guard. */
565static
566void addEvent_Dr ( IRSB* sb, IRAtom* daddr, Int dsize )
567{
568 addEvent_Dr_guarded(sb, daddr, dsize, NULL);
569}
570
571/* Add a guarded write event. */
572static
573void addEvent_Dw_guarded ( IRSB* sb, IRAtom* daddr, Int dsize, IRAtom* guard )
574{
575 Event* evt;
576 tl_assert(clo_trace_mem);
577 tl_assert(isIRAtom(daddr));
578 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
579 if (events_used == N_EVENTS)
580 flushEvents(sb);
581 tl_assert(events_used >= 0 && events_used < N_EVENTS);
582 evt = &events[events_used];
583 evt->ekind = Event_Dw;
584 evt->addr = daddr;
585 evt->size = dsize;
586 evt->guard = guard;
587 events_used++;
588}
589
590/* Add an ordinary write event. Try to merge it with an immediately
591 preceding ordinary read event of the same size to the same
592 address. */
njneaf0ca92006-04-09 01:23:29 +0000593static
sewardj5d1c9012007-02-12 08:42:13 +0000594void addEvent_Dw ( IRSB* sb, IRAtom* daddr, Int dsize )
njneaf0ca92006-04-09 01:23:29 +0000595{
596 Event* lastEvt;
597 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000598 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000599 tl_assert(isIRAtom(daddr));
600 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
601
602 // Is it possible to merge this write with the preceding read?
603 lastEvt = &events[events_used-1];
604 if (events_used > 0
sewardjcafe5052013-01-17 14:24:35 +0000605 && lastEvt->ekind == Event_Dr
606 && lastEvt->size == dsize
607 && lastEvt->guard == NULL
608 && eqIRAtom(lastEvt->addr, daddr))
njneaf0ca92006-04-09 01:23:29 +0000609 {
610 lastEvt->ekind = Event_Dm;
611 return;
612 }
613
614 // No. Add as normal.
615 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000616 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000617 tl_assert(events_used >= 0 && events_used < N_EVENTS);
618 evt = &events[events_used];
619 evt->ekind = Event_Dw;
620 evt->size = dsize;
621 evt->addr = daddr;
sewardjcafe5052013-01-17 14:24:35 +0000622 evt->guard = NULL;
njneaf0ca92006-04-09 01:23:29 +0000623 events_used++;
njnfd73ebb2005-12-30 22:39:58 +0000624}
625
njnd99644d2006-04-07 11:52:55 +0000626
627/*------------------------------------------------------------*/
sewardj5d1c9012007-02-12 08:42:13 +0000628/*--- Stuff for --trace-superblocks ---*/
629/*------------------------------------------------------------*/
630
631static void trace_superblock(Addr addr)
632{
633 VG_(printf)("SB %08lx\n", addr);
634}
635
636
637/*------------------------------------------------------------*/
njnd99644d2006-04-07 11:52:55 +0000638/*--- Basic tool functions ---*/
639/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000640
641static void lk_post_clo_init(void)
642{
643 Int op, tyIx;
644
njnd99644d2006-04-07 11:52:55 +0000645 if (clo_detailed_counts) {
646 for (op = 0; op < N_OPS; op++)
647 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
648 detailCounts[op][tyIx] = 0;
649 }
sewardj7a26f022005-11-01 17:52:34 +0000650}
651
sewardj4ba057c2005-10-18 12:04:18 +0000652static
sewardj0b9d74a2006-12-24 02:24:11 +0000653IRSB* lk_instrument ( VgCallbackClosure* closure,
sewardj5d1c9012007-02-12 08:42:13 +0000654 IRSB* sbIn,
florian3c0c9472014-09-24 12:06:55 +0000655 const VexGuestLayout* layout,
656 const VexGuestExtents* vge,
657 const VexArchInfo* archinfo_host,
sewardj461df9c2006-01-17 02:06:39 +0000658 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000659{
njneaf0ca92006-04-09 01:23:29 +0000660 IRDirty* di;
661 Int i;
sewardj5d1c9012007-02-12 08:42:13 +0000662 IRSB* sbOut;
sewardj5d1c9012007-02-12 08:42:13 +0000663 IRTypeEnv* tyenv = sbIn->tyenv;
weidendoba5b3b22007-02-16 11:13:53 +0000664 Addr iaddr = 0, dst;
665 UInt ilen = 0;
666 Bool condition_inverted = False;
sewardjd54babf2005-03-21 00:55:49 +0000667
668 if (gWordTy != hWordTy) {
669 /* We don't currently support this case. */
670 VG_(tool_panic)("host/guest word size mismatch");
671 }
sewardj9f649aa2004-11-22 20:38:40 +0000672
sewardj5d1c9012007-02-12 08:42:13 +0000673 /* Set up SB */
674 sbOut = deepCopyIRSBExceptStmts(sbIn);
sewardj9f649aa2004-11-22 20:38:40 +0000675
sewardj7a26f022005-11-01 17:52:34 +0000676 // Copy verbatim any IR preamble preceding the first IMark
677 i = 0;
sewardj5d1c9012007-02-12 08:42:13 +0000678 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
679 addStmtToIRSB( sbOut, sbIn->stmts[i] );
sewardj7a26f022005-11-01 17:52:34 +0000680 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000681 }
sewardj9f649aa2004-11-22 20:38:40 +0000682
njnd99644d2006-04-07 11:52:55 +0000683 if (clo_basic_counts) {
sewardj5d1c9012007-02-12 08:42:13 +0000684 /* Count this superblock. */
685 di = unsafeIRDirty_0_N( 0, "add_one_SB_entered",
686 VG_(fnptr_to_fnentry)( &add_one_SB_entered ),
njnd99644d2006-04-07 11:52:55 +0000687 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000688 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
689 }
690
691 if (clo_trace_sbs) {
692 /* Print this superblock's address. */
693 di = unsafeIRDirty_0_N(
694 0, "trace_superblock",
695 VG_(fnptr_to_fnentry)( &trace_superblock ),
696 mkIRExprVec_1( mkIRExpr_HWord( vge->base[0] ) )
697 );
698 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000699 }
sewardj9f649aa2004-11-22 20:38:40 +0000700
njneaf0ca92006-04-09 01:23:29 +0000701 if (clo_trace_mem) {
702 events_used = 0;
703 }
704
sewardj5d1c9012007-02-12 08:42:13 +0000705 for (/*use current i*/; i < sbIn->stmts_used; i++) {
706 IRStmt* st = sbIn->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000707 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000708
njnd99644d2006-04-07 11:52:55 +0000709 if (clo_basic_counts) {
710 /* Count one VEX statement. */
711 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
712 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
713 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000714 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000715 }
sewardj7a26f022005-11-01 17:52:34 +0000716
sewardj9f649aa2004-11-22 20:38:40 +0000717 switch (st->tag) {
njneaf0ca92006-04-09 01:23:29 +0000718 case Ist_NoOp:
719 case Ist_AbiHint:
720 case Ist_Put:
721 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +0000722 case Ist_MBE:
sewardj5d1c9012007-02-12 08:42:13 +0000723 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000724 break;
725
sewardj7a26f022005-11-01 17:52:34 +0000726 case Ist_IMark:
njnd99644d2006-04-07 11:52:55 +0000727 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000728 /* Needed to be able to check for inverted condition in Ist_Exit */
729 iaddr = st->Ist.IMark.addr;
730 ilen = st->Ist.IMark.len;
731
njnd99644d2006-04-07 11:52:55 +0000732 /* Count guest instruction. */
733 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
734 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
735 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000736 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000737
738 /* An unconditional branch to a known destination in the
sewardj0b9d74a2006-12-24 02:24:11 +0000739 * guest's instructions can be represented, in the IRSB to
njnd99644d2006-04-07 11:52:55 +0000740 * instrument, by the VEX statements that are the
741 * translation of that known destination. This feature is
sewardj5d1c9012007-02-12 08:42:13 +0000742 * called 'SB chasing' and can be influenced by command
njnd99644d2006-04-07 11:52:55 +0000743 * line option --vex-guest-chase-thresh.
744 *
745 * To get an accurate count of the calls to a specific
sewardj5d1c9012007-02-12 08:42:13 +0000746 * function, taking SB chasing into account, we need to
njnd99644d2006-04-07 11:52:55 +0000747 * check for each guest instruction (Ist_IMark) if it is
748 * the entry point of a function.
749 */
750 tl_assert(clo_fnname);
751 tl_assert(clo_fnname[0]);
florian46cc0452014-10-25 19:20:38 +0000752 const HChar *fnname;
njnd99644d2006-04-07 11:52:55 +0000753 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
florian46cc0452014-10-25 19:20:38 +0000754 &fnname)
njnd99644d2006-04-07 11:52:55 +0000755 && 0 == VG_(strcmp)(fnname, clo_fnname)) {
756 di = unsafeIRDirty_0_N(
757 0, "add_one_func_call",
758 VG_(fnptr_to_fnentry)( &add_one_func_call ),
759 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000760 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000761 }
sewardj7a26f022005-11-01 17:52:34 +0000762 }
njnd99644d2006-04-07 11:52:55 +0000763 if (clo_trace_mem) {
njneaf0ca92006-04-09 01:23:29 +0000764 // WARNING: do not remove this function call, even if you
765 // aren't interested in instruction reads. See the comment
766 // above the function itself for more detail.
sewardj5d1c9012007-02-12 08:42:13 +0000767 addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
njneaf0ca92006-04-09 01:23:29 +0000768 st->Ist.IMark.len );
njnfd73ebb2005-12-30 22:39:58 +0000769 }
sewardj5d1c9012007-02-12 08:42:13 +0000770 addStmtToIRSB( sbOut, st );
sewardj7a26f022005-11-01 17:52:34 +0000771 break;
772
sewardj0b9d74a2006-12-24 02:24:11 +0000773 case Ist_WrTmp:
njnfd73ebb2005-12-30 22:39:58 +0000774 // Add a call to trace_load() if --trace-mem=yes.
njnd99644d2006-04-07 11:52:55 +0000775 if (clo_trace_mem) {
sewardj0b9d74a2006-12-24 02:24:11 +0000776 IRExpr* data = st->Ist.WrTmp.data;
njnfd73ebb2005-12-30 22:39:58 +0000777 if (data->tag == Iex_Load) {
sewardj5d1c9012007-02-12 08:42:13 +0000778 addEvent_Dr( sbOut, data->Iex.Load.addr,
njneaf0ca92006-04-09 01:23:29 +0000779 sizeofIRType(data->Iex.Load.ty) );
njnfd73ebb2005-12-30 22:39:58 +0000780 }
781 }
njnd99644d2006-04-07 11:52:55 +0000782 if (clo_detailed_counts) {
sewardj0b9d74a2006-12-24 02:24:11 +0000783 IRExpr* expr = st->Ist.WrTmp.data;
sewardjcafe5052013-01-17 14:24:35 +0000784 IRType type = typeOfIRExpr(sbOut->tyenv, expr);
sewardj7a26f022005-11-01 17:52:34 +0000785 tl_assert(type != Ity_INVALID);
786 switch (expr->tag) {
787 case Iex_Load:
sewardjcafe5052013-01-17 14:24:35 +0000788 instrument_detail( sbOut, OpLoad, type, NULL/*guard*/ );
sewardj7a26f022005-11-01 17:52:34 +0000789 break;
790 case Iex_Unop:
791 case Iex_Binop:
sewardje91cea72006-02-08 19:32:02 +0000792 case Iex_Triop:
793 case Iex_Qop:
florian5686b2d2013-01-29 03:57:40 +0000794 case Iex_ITE:
sewardjcafe5052013-01-17 14:24:35 +0000795 instrument_detail( sbOut, OpAlu, type, NULL/*guard*/ );
sewardj7a26f022005-11-01 17:52:34 +0000796 break;
797 default:
798 break;
799 }
800 }
sewardj5d1c9012007-02-12 08:42:13 +0000801 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000802 break;
803
sewardjcafe5052013-01-17 14:24:35 +0000804 case Ist_Store: {
805 IRExpr* data = st->Ist.Store.data;
806 IRType type = typeOfIRExpr(tyenv, data);
807 tl_assert(type != Ity_INVALID);
njneaf0ca92006-04-09 01:23:29 +0000808 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000809 addEvent_Dw( sbOut, st->Ist.Store.addr,
sewardjcafe5052013-01-17 14:24:35 +0000810 sizeofIRType(type) );
njneaf0ca92006-04-09 01:23:29 +0000811 }
812 if (clo_detailed_counts) {
sewardjcafe5052013-01-17 14:24:35 +0000813 instrument_detail( sbOut, OpStore, type, NULL/*guard*/ );
njneaf0ca92006-04-09 01:23:29 +0000814 }
sewardj5d1c9012007-02-12 08:42:13 +0000815 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000816 break;
sewardjcafe5052013-01-17 14:24:35 +0000817 }
818
819 case Ist_StoreG: {
820 IRStoreG* sg = st->Ist.StoreG.details;
821 IRExpr* data = sg->data;
822 IRType type = typeOfIRExpr(tyenv, data);
823 tl_assert(type != Ity_INVALID);
824 if (clo_trace_mem) {
825 addEvent_Dw_guarded( sbOut, sg->addr,
826 sizeofIRType(type), sg->guard );
827 }
828 if (clo_detailed_counts) {
829 instrument_detail( sbOut, OpStore, type, sg->guard );
830 }
831 addStmtToIRSB( sbOut, st );
832 break;
833 }
834
835 case Ist_LoadG: {
836 IRLoadG* lg = st->Ist.LoadG.details;
837 IRType type = Ity_INVALID; /* loaded type */
838 IRType typeWide = Ity_INVALID; /* after implicit widening */
839 typeOfIRLoadGOp(lg->cvt, &typeWide, &type);
840 tl_assert(type != Ity_INVALID);
841 if (clo_trace_mem) {
842 addEvent_Dr_guarded( sbOut, lg->addr,
843 sizeofIRType(type), lg->guard );
844 }
845 if (clo_detailed_counts) {
846 instrument_detail( sbOut, OpLoad, type, lg->guard );
847 }
848 addStmtToIRSB( sbOut, st );
849 break;
850 }
njneaf0ca92006-04-09 01:23:29 +0000851
852 case Ist_Dirty: {
njndbb9c8e2007-02-12 11:28:38 +0000853 if (clo_trace_mem) {
854 Int dsize;
855 IRDirty* d = st->Ist.Dirty.details;
856 if (d->mFx != Ifx_None) {
857 // This dirty helper accesses memory. Collect the details.
858 tl_assert(d->mAddr != NULL);
859 tl_assert(d->mSize != 0);
860 dsize = d->mSize;
861 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
862 addEvent_Dr( sbOut, d->mAddr, dsize );
863 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
864 addEvent_Dw( sbOut, d->mAddr, dsize );
865 } else {
866 tl_assert(d->mAddr == NULL);
867 tl_assert(d->mSize == 0);
868 }
njneaf0ca92006-04-09 01:23:29 +0000869 }
sewardj5d1c9012007-02-12 08:42:13 +0000870 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000871 break;
872 }
873
sewardj1c0ce7a2009-07-01 08:10:49 +0000874 case Ist_CAS: {
875 /* We treat it as a read and a write of the location. I
876 think that is the same behaviour as it was before IRCAS
877 was introduced, since prior to that point, the Vex
878 front ends would translate a lock-prefixed instruction
879 into a (normal) read followed by a (normal) write. */
sewardjdb5907d2009-11-26 17:20:21 +0000880 Int dataSize;
881 IRType dataTy;
882 IRCAS* cas = st->Ist.CAS.details;
883 tl_assert(cas->addr != NULL);
884 tl_assert(cas->dataLo != NULL);
885 dataTy = typeOfIRExpr(tyenv, cas->dataLo);
886 dataSize = sizeofIRType(dataTy);
887 if (cas->dataHi != NULL)
888 dataSize *= 2; /* since it's a doubleword-CAS */
sewardj1c0ce7a2009-07-01 08:10:49 +0000889 if (clo_trace_mem) {
sewardj1c0ce7a2009-07-01 08:10:49 +0000890 addEvent_Dr( sbOut, cas->addr, dataSize );
891 addEvent_Dw( sbOut, cas->addr, dataSize );
892 }
sewardjdb5907d2009-11-26 17:20:21 +0000893 if (clo_detailed_counts) {
sewardjcafe5052013-01-17 14:24:35 +0000894 instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
sewardjdb5907d2009-11-26 17:20:21 +0000895 if (cas->dataHi != NULL) /* dcas */
sewardjcafe5052013-01-17 14:24:35 +0000896 instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
897 instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
sewardjdb5907d2009-11-26 17:20:21 +0000898 if (cas->dataHi != NULL) /* dcas */
sewardjcafe5052013-01-17 14:24:35 +0000899 instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
sewardjdb5907d2009-11-26 17:20:21 +0000900 }
901 addStmtToIRSB( sbOut, st );
902 break;
903 }
904
905 case Ist_LLSC: {
906 IRType dataTy;
907 if (st->Ist.LLSC.storedata == NULL) {
908 /* LL */
909 dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
weidendod4053322012-11-26 18:16:58 +0000910 if (clo_trace_mem) {
sewardjdb5907d2009-11-26 17:20:21 +0000911 addEvent_Dr( sbOut, st->Ist.LLSC.addr,
912 sizeofIRType(dataTy) );
weidendod4053322012-11-26 18:16:58 +0000913 /* flush events before LL, helps SC to succeed */
914 flushEvents(sbOut);
915 }
sewardjdb5907d2009-11-26 17:20:21 +0000916 if (clo_detailed_counts)
sewardjcafe5052013-01-17 14:24:35 +0000917 instrument_detail( sbOut, OpLoad, dataTy, NULL/*guard*/ );
sewardjdb5907d2009-11-26 17:20:21 +0000918 } else {
919 /* SC */
920 dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
921 if (clo_trace_mem)
922 addEvent_Dw( sbOut, st->Ist.LLSC.addr,
923 sizeofIRType(dataTy) );
924 if (clo_detailed_counts)
sewardjcafe5052013-01-17 14:24:35 +0000925 instrument_detail( sbOut, OpStore, dataTy, NULL/*guard*/ );
sewardjdb5907d2009-11-26 17:20:21 +0000926 }
sewardj1c0ce7a2009-07-01 08:10:49 +0000927 addStmtToIRSB( sbOut, st );
928 break;
929 }
930
njneaf0ca92006-04-09 01:23:29 +0000931 case Ist_Exit:
932 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000933 // The condition of a branch was inverted by VEX if a taken
934 // branch is in fact a fall trough according to client address
935 tl_assert(iaddr != 0);
936 dst = (sizeof(Addr) == 4) ? st->Ist.Exit.dst->Ico.U32 :
937 st->Ist.Exit.dst->Ico.U64;
938 condition_inverted = (dst == iaddr + ilen);
939
njneaf0ca92006-04-09 01:23:29 +0000940 /* Count Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000941 if (!condition_inverted)
942 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
njneaf0ca92006-04-09 01:23:29 +0000943 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
944 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000945 else
946 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc",
sewardjdb5907d2009-11-26 17:20:21 +0000947 VG_(fnptr_to_fnentry)(
948 &add_one_inverted_Jcc ),
weidendoba5b3b22007-02-16 11:13:53 +0000949 mkIRExprVec_0() );
950
sewardj5d1c9012007-02-12 08:42:13 +0000951 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000952 }
953 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000954 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000955 }
956
sewardj5d1c9012007-02-12 08:42:13 +0000957 addStmtToIRSB( sbOut, st ); // Original statement
njneaf0ca92006-04-09 01:23:29 +0000958
959 if (clo_basic_counts) {
960 /* Count non-taken Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000961 if (!condition_inverted)
962 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
njneaf0ca92006-04-09 01:23:29 +0000963 VG_(fnptr_to_fnentry)(
964 &add_one_Jcc_untaken ),
965 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000966 else
967 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc_untaken",
968 VG_(fnptr_to_fnentry)(
969 &add_one_inverted_Jcc_untaken ),
970 mkIRExprVec_0() );
971
sewardj5d1c9012007-02-12 08:42:13 +0000972 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000973 }
sewardj9f649aa2004-11-22 20:38:40 +0000974 break;
975
976 default:
sewardjcafe5052013-01-17 14:24:35 +0000977 ppIRStmt(st);
njneaf0ca92006-04-09 01:23:29 +0000978 tl_assert(0);
sewardj9f649aa2004-11-22 20:38:40 +0000979 }
980 }
981
njnd99644d2006-04-07 11:52:55 +0000982 if (clo_basic_counts) {
983 /* Count this basic block. */
sewardj5d1c9012007-02-12 08:42:13 +0000984 di = unsafeIRDirty_0_N( 0, "add_one_SB_completed",
985 VG_(fnptr_to_fnentry)( &add_one_SB_completed ),
njnd99644d2006-04-07 11:52:55 +0000986 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000987 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000988 }
sewardj7a26f022005-11-01 17:52:34 +0000989
njneaf0ca92006-04-09 01:23:29 +0000990 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000991 /* At the end of the sbIn. Flush outstandings. */
992 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000993 }
994
sewardj5d1c9012007-02-12 08:42:13 +0000995 return sbOut;
njn25e49d8e72002-09-23 09:36:25 +0000996}
997
njn51d827b2005-05-09 01:02:08 +0000998static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000999{
njnd99644d2006-04-07 11:52:55 +00001000 tl_assert(clo_fnname);
1001 tl_assert(clo_fnname[0]);
njn25e49d8e72002-09-23 09:36:25 +00001002
njnd99644d2006-04-07 11:52:55 +00001003 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +00001004 ULong total_Jccs = n_Jccs + n_IJccs;
1005 ULong taken_Jccs = (n_Jccs - n_Jccs_untaken) + n_IJccs_untaken;
1006
njn6fb923b2009-08-05 06:57:45 +00001007 VG_(umsg)("Counted %'llu call%s to %s()\n",
1008 n_func_calls, ( n_func_calls==1 ? "" : "s" ), clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +00001009
sewardjb5dc2d62009-07-15 14:51:48 +00001010 VG_(umsg)("\n");
1011 VG_(umsg)("Jccs:\n");
1012 VG_(umsg)(" total: %'llu\n", total_Jccs);
florian227a1ec2014-12-12 19:32:10 +00001013 VG_(umsg)(" taken: %'llu (%.0f%%)\n",
Elliott Hughesed398002017-06-21 14:41:24 -07001014 taken_Jccs, taken_Jccs * 100.0 / (total_Jccs ? total_Jccs : 1));
njnd99644d2006-04-07 11:52:55 +00001015
sewardjb5dc2d62009-07-15 14:51:48 +00001016 VG_(umsg)("\n");
1017 VG_(umsg)("Executed:\n");
1018 VG_(umsg)(" SBs entered: %'llu\n", n_SBs_entered);
1019 VG_(umsg)(" SBs completed: %'llu\n", n_SBs_completed);
1020 VG_(umsg)(" guest instrs: %'llu\n", n_guest_instrs);
1021 VG_(umsg)(" IRStmts: %'llu\n", n_IRStmts);
njnd99644d2006-04-07 11:52:55 +00001022
sewardjb5dc2d62009-07-15 14:51:48 +00001023 VG_(umsg)("\n");
1024 VG_(umsg)("Ratios:\n");
sewardj5d1c9012007-02-12 08:42:13 +00001025 tl_assert(n_SBs_entered); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +00001026 VG_(umsg)(" guest instrs : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +00001027 10 * n_guest_instrs / n_SBs_entered);
sewardjb5dc2d62009-07-15 14:51:48 +00001028 VG_(umsg)(" IRStmts : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +00001029 10 * n_IRStmts / n_SBs_entered);
njnd99644d2006-04-07 11:52:55 +00001030 tl_assert(n_guest_instrs); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +00001031 VG_(umsg)(" IRStmts : guest instr = %'llu : 10\n",
njnd99644d2006-04-07 11:52:55 +00001032 10 * n_IRStmts / n_guest_instrs);
1033 }
1034
1035 if (clo_detailed_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +00001036 VG_(umsg)("\n");
1037 VG_(umsg)("IR-level counts by type:\n");
sewardj7a26f022005-11-01 17:52:34 +00001038 print_details();
1039 }
njn25e49d8e72002-09-23 09:36:25 +00001040
njnd99644d2006-04-07 11:52:55 +00001041 if (clo_basic_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +00001042 VG_(umsg)("\n");
1043 VG_(umsg)("Exit code: %d\n", exitcode);
njnd99644d2006-04-07 11:52:55 +00001044 }
njn25e49d8e72002-09-23 09:36:25 +00001045}
1046
njn51d827b2005-05-09 01:02:08 +00001047static void lk_pre_clo_init(void)
1048{
1049 VG_(details_name) ("Lackey");
1050 VG_(details_version) (NULL);
1051 VG_(details_description) ("an example Valgrind tool");
1052 VG_(details_copyright_author)(
Elliott Hughesed398002017-06-21 14:41:24 -07001053 "Copyright (C) 2002-2017, and GNU GPL'd, by Nicholas Nethercote.");
njn51d827b2005-05-09 01:02:08 +00001054 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj40823562006-10-17 02:21:17 +00001055 VG_(details_avg_translation_sizeB) ( 200 );
njn51d827b2005-05-09 01:02:08 +00001056
1057 VG_(basic_tool_funcs) (lk_post_clo_init,
1058 lk_instrument,
1059 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +00001060 VG_(needs_command_line_options)(lk_process_cmd_line_option,
1061 lk_print_usage,
1062 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +00001063}
1064
sewardj45f4e7c2005-09-27 19:20:21 +00001065VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00001066
njn25e49d8e72002-09-23 09:36:25 +00001067/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00001068/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00001069/*--------------------------------------------------------------------*/