blob: 735bc3af1d0dc37e1c1dc862bb323730c4733aa8 [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
sewardj03f8d3f2012-08-05 15:46:46 +000010 Copyright (C) 2002-2012 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
295/* --- Operations --- */
296
297typedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
298
299#define N_OPS 3
300
301
302/* --- Types --- */
303
sewardj574d9a82012-05-21 13:44:54 +0000304#define N_TYPES 11
sewardj7a26f022005-11-01 17:52:34 +0000305
306static Int type2index ( IRType ty )
njn25e49d8e72002-09-23 09:36:25 +0000307{
sewardj7a26f022005-11-01 17:52:34 +0000308 switch (ty) {
309 case Ity_I1: return 0;
310 case Ity_I8: return 1;
311 case Ity_I16: return 2;
312 case Ity_I32: return 3;
313 case Ity_I64: return 4;
314 case Ity_I128: return 5;
315 case Ity_F32: return 6;
316 case Ity_F64: return 7;
sewardjb5b87402011-03-07 16:05:35 +0000317 case Ity_F128: return 8;
318 case Ity_V128: return 9;
sewardj574d9a82012-05-21 13:44:54 +0000319 case Ity_V256: return 10;
njnf36ae992007-11-22 23:33:20 +0000320 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000321 }
njn25e49d8e72002-09-23 09:36:25 +0000322}
323
florian19f91bb2012-11-10 22:29:54 +0000324static const HChar* nameOfTypeIndex ( Int i )
sewardj7a26f022005-11-01 17:52:34 +0000325{
njnab9c37e2007-08-27 22:18:58 +0000326 switch (i) {
sewardj7a26f022005-11-01 17:52:34 +0000327 case 0: return "I1"; break;
328 case 1: return "I8"; break;
329 case 2: return "I16"; break;
330 case 3: return "I32"; break;
331 case 4: return "I64"; break;
332 case 5: return "I128"; break;
333 case 6: return "F32"; break;
334 case 7: return "F64"; break;
sewardjb5b87402011-03-07 16:05:35 +0000335 case 8: return "F128"; break;
336 case 9: return "V128"; break;
sewardj574d9a82012-05-21 13:44:54 +0000337 case 10: return "V256"; break;
njnf36ae992007-11-22 23:33:20 +0000338 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000339 }
340}
njn25e49d8e72002-09-23 09:36:25 +0000341
njn25e49d8e72002-09-23 09:36:25 +0000342
sewardj7a26f022005-11-01 17:52:34 +0000343/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000344
sewardj7a26f022005-11-01 17:52:34 +0000345static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000346
sewardj7a26f022005-11-01 17:52:34 +0000347/* The helper that is called from the instrumented code. */
348static VG_REGPARM(1)
349void increment_detail(ULong* detail)
350{
351 (*detail)++;
352}
njn25e49d8e72002-09-23 09:36:25 +0000353
sewardj7a26f022005-11-01 17:52:34 +0000354/* A helper that adds the instrumentation for a detail. */
sewardj5d1c9012007-02-12 08:42:13 +0000355static void instrument_detail(IRSB* sb, Op op, IRType type)
sewardj7a26f022005-11-01 17:52:34 +0000356{
357 IRDirty* di;
358 IRExpr** argv;
359 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000360
sewardj7a26f022005-11-01 17:52:34 +0000361 tl_assert(op < N_OPS);
362 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000363
sewardj7a26f022005-11-01 17:52:34 +0000364 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000365 di = unsafeIRDirty_0_N( 1, "increment_detail",
366 VG_(fnptr_to_fnentry)( &increment_detail ),
367 argv);
sewardj5d1c9012007-02-12 08:42:13 +0000368 addStmtToIRSB( sb, IRStmt_Dirty(di) );
sewardj7a26f022005-11-01 17:52:34 +0000369}
njn25e49d8e72002-09-23 09:36:25 +0000370
sewardj7a26f022005-11-01 17:52:34 +0000371/* Summarize and print the details. */
sewardj7a26f022005-11-01 17:52:34 +0000372static void print_details ( void )
373{
374 Int typeIx;
sewardjb5dc2d62009-07-15 14:51:48 +0000375 VG_(umsg)(" Type Loads Stores AluOps\n");
376 VG_(umsg)(" -------------------------------------------\n");
sewardj7a26f022005-11-01 17:52:34 +0000377 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
sewardjb5dc2d62009-07-15 14:51:48 +0000378 VG_(umsg)(" %4s %'12llu %'12llu %'12llu\n",
379 nameOfTypeIndex( typeIx ),
380 detailCounts[OpLoad ][typeIx],
381 detailCounts[OpStore][typeIx],
382 detailCounts[OpAlu ][typeIx]
sewardj7a26f022005-11-01 17:52:34 +0000383 );
384 }
385}
njn25e49d8e72002-09-23 09:36:25 +0000386
sewardj7a26f022005-11-01 17:52:34 +0000387
njnd99644d2006-04-07 11:52:55 +0000388/*------------------------------------------------------------*/
njneaf0ca92006-04-09 01:23:29 +0000389/*--- Stuff for --trace-mem ---*/
njnd99644d2006-04-07 11:52:55 +0000390/*------------------------------------------------------------*/
njnfd73ebb2005-12-30 22:39:58 +0000391
njneaf0ca92006-04-09 01:23:29 +0000392#define MAX_DSIZE 512
393
394typedef
395 IRExpr
396 IRAtom;
397
398typedef
399 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
400 EventKind;
401
402typedef
403 struct {
404 EventKind ekind;
405 IRAtom* addr;
406 Int size;
407 }
408 Event;
409
410/* Up to this many unnotified events are allowed. Must be at least two,
411 so that reads and writes to the same address can be merged into a modify.
412 Beyond that, larger numbers just potentially induce more spilling due to
413 extending live ranges of address temporaries. */
414#define N_EVENTS 4
415
416/* Maintain an ordered list of memory events which are outstanding, in
417 the sense that no IR has yet been generated to do the relevant
sewardj5d1c9012007-02-12 08:42:13 +0000418 helper calls. The SB is scanned top to bottom and memory events
njneaf0ca92006-04-09 01:23:29 +0000419 are added to the end of the list, merging with the most recent
420 notified event where possible (Dw immediately following Dr and
421 having the same size and EA can be merged).
422
423 This merging is done so that for architectures which have
424 load-op-store instructions (x86, amd64), the instr is treated as if
425 it makes just one memory reference (a modify), rather than two (a
426 read followed by a write at the same address).
427
428 At various points the list will need to be flushed, that is, IR
429 generated from it. That must happen before any possible exit from
430 the block (the end, or an IRStmt_Exit). Flushing also takes place
weidendod4053322012-11-26 18:16:58 +0000431 when there is no space to add a new event, and before entering a
432 RMW (read-modify-write) section on processors supporting LL/SC.
njneaf0ca92006-04-09 01:23:29 +0000433
434 If we require the simulation statistics to be up to date with
435 respect to possible memory exceptions, then the list would have to
436 be flushed before each memory reference. That's a pain so we don't
437 bother.
438
439 Flushing the list consists of walking it start to end and emitting
440 instrumentation IR for each event, in the order in which they
441 appear. */
442
443static Event events[N_EVENTS];
444static Int events_used = 0;
445
446
447static VG_REGPARM(2) void trace_instr(Addr addr, SizeT size)
448{
njn8a7b41b2007-09-23 00:51:24 +0000449 VG_(printf)("I %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000450}
451
njnfd73ebb2005-12-30 22:39:58 +0000452static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
453{
njn8a7b41b2007-09-23 00:51:24 +0000454 VG_(printf)(" L %08lx,%lu\n", addr, size);
njnfd73ebb2005-12-30 22:39:58 +0000455}
456
457static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
458{
njn8a7b41b2007-09-23 00:51:24 +0000459 VG_(printf)(" S %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000460}
461
462static VG_REGPARM(2) void trace_modify(Addr addr, SizeT size)
463{
njn8a7b41b2007-09-23 00:51:24 +0000464 VG_(printf)(" M %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000465}
466
467
sewardj5d1c9012007-02-12 08:42:13 +0000468static void flushEvents(IRSB* sb)
njneaf0ca92006-04-09 01:23:29 +0000469{
470 Int i;
florian19f91bb2012-11-10 22:29:54 +0000471 const HChar* helperName;
njneaf0ca92006-04-09 01:23:29 +0000472 void* helperAddr;
473 IRExpr** argv;
474 IRDirty* di;
475 Event* ev;
476
477 for (i = 0; i < events_used; i++) {
478
479 ev = &events[i];
480
481 // Decide on helper fn to call and args to pass it.
482 switch (ev->ekind) {
483 case Event_Ir: helperName = "trace_instr";
484 helperAddr = trace_instr; break;
485
486 case Event_Dr: helperName = "trace_load";
487 helperAddr = trace_load; break;
488
489 case Event_Dw: helperName = "trace_store";
490 helperAddr = trace_store; break;
491
492 case Event_Dm: helperName = "trace_modify";
493 helperAddr = trace_modify; break;
494 default:
495 tl_assert(0);
496 }
497
498 // Add the helper.
499 argv = mkIRExprVec_2( ev->addr, mkIRExpr_HWord( ev->size ) );
500 di = unsafeIRDirty_0_N( /*regparms*/2,
501 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
502 argv );
sewardj5d1c9012007-02-12 08:42:13 +0000503 addStmtToIRSB( sb, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000504 }
505
506 events_used = 0;
507}
508
509// WARNING: If you aren't interested in instruction reads, you can omit the
510// code that adds calls to trace_instr() in flushEvents(). However, you
511// must still call this function, addEvent_Ir() -- it is necessary to add
512// the Ir events to the events list so that merging of paired load/store
513// events into modify events works correctly.
sewardj5d1c9012007-02-12 08:42:13 +0000514static void addEvent_Ir ( IRSB* sb, IRAtom* iaddr, UInt isize )
njneaf0ca92006-04-09 01:23:29 +0000515{
516 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000517 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000518 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
519 || VG_CLREQ_SZB == isize );
520 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000521 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000522 tl_assert(events_used >= 0 && events_used < N_EVENTS);
523 evt = &events[events_used];
524 evt->ekind = Event_Ir;
525 evt->addr = iaddr;
526 evt->size = isize;
527 events_used++;
528}
529
530static
sewardj5d1c9012007-02-12 08:42:13 +0000531void addEvent_Dr ( IRSB* sb, IRAtom* daddr, Int dsize )
njneaf0ca92006-04-09 01:23:29 +0000532{
533 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000534 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000535 tl_assert(isIRAtom(daddr));
536 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
537 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000538 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000539 tl_assert(events_used >= 0 && events_used < N_EVENTS);
540 evt = &events[events_used];
541 evt->ekind = Event_Dr;
542 evt->addr = daddr;
543 evt->size = dsize;
544 events_used++;
545}
546
547static
sewardj5d1c9012007-02-12 08:42:13 +0000548void addEvent_Dw ( IRSB* sb, IRAtom* daddr, Int dsize )
njneaf0ca92006-04-09 01:23:29 +0000549{
550 Event* lastEvt;
551 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000552 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000553 tl_assert(isIRAtom(daddr));
554 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
555
556 // Is it possible to merge this write with the preceding read?
557 lastEvt = &events[events_used-1];
558 if (events_used > 0
559 && lastEvt->ekind == Event_Dr
560 && lastEvt->size == dsize
561 && eqIRAtom(lastEvt->addr, daddr))
562 {
563 lastEvt->ekind = Event_Dm;
564 return;
565 }
566
567 // No. Add as normal.
568 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000569 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000570 tl_assert(events_used >= 0 && events_used < N_EVENTS);
571 evt = &events[events_used];
572 evt->ekind = Event_Dw;
573 evt->size = dsize;
574 evt->addr = daddr;
575 events_used++;
njnfd73ebb2005-12-30 22:39:58 +0000576}
577
njnd99644d2006-04-07 11:52:55 +0000578
579/*------------------------------------------------------------*/
sewardj5d1c9012007-02-12 08:42:13 +0000580/*--- Stuff for --trace-superblocks ---*/
581/*------------------------------------------------------------*/
582
583static void trace_superblock(Addr addr)
584{
585 VG_(printf)("SB %08lx\n", addr);
586}
587
588
589/*------------------------------------------------------------*/
njnd99644d2006-04-07 11:52:55 +0000590/*--- Basic tool functions ---*/
591/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000592
593static void lk_post_clo_init(void)
594{
595 Int op, tyIx;
596
njnd99644d2006-04-07 11:52:55 +0000597 if (clo_detailed_counts) {
598 for (op = 0; op < N_OPS; op++)
599 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
600 detailCounts[op][tyIx] = 0;
601 }
sewardj7a26f022005-11-01 17:52:34 +0000602}
603
sewardj4ba057c2005-10-18 12:04:18 +0000604static
sewardj0b9d74a2006-12-24 02:24:11 +0000605IRSB* lk_instrument ( VgCallbackClosure* closure,
sewardj5d1c9012007-02-12 08:42:13 +0000606 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000607 VexGuestLayout* layout,
608 VexGuestExtents* vge,
florianca503be2012-10-07 21:59:42 +0000609 VexArchInfo* archinfo_host,
sewardj461df9c2006-01-17 02:06:39 +0000610 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000611{
njneaf0ca92006-04-09 01:23:29 +0000612 IRDirty* di;
613 Int i;
sewardj5d1c9012007-02-12 08:42:13 +0000614 IRSB* sbOut;
florian19f91bb2012-11-10 22:29:54 +0000615 HChar fnname[100];
njneaf0ca92006-04-09 01:23:29 +0000616 IRType type;
sewardj5d1c9012007-02-12 08:42:13 +0000617 IRTypeEnv* tyenv = sbIn->tyenv;
weidendoba5b3b22007-02-16 11:13:53 +0000618 Addr iaddr = 0, dst;
619 UInt ilen = 0;
620 Bool condition_inverted = False;
sewardjd54babf2005-03-21 00:55:49 +0000621
622 if (gWordTy != hWordTy) {
623 /* We don't currently support this case. */
624 VG_(tool_panic)("host/guest word size mismatch");
625 }
sewardj9f649aa2004-11-22 20:38:40 +0000626
sewardj5d1c9012007-02-12 08:42:13 +0000627 /* Set up SB */
628 sbOut = deepCopyIRSBExceptStmts(sbIn);
sewardj9f649aa2004-11-22 20:38:40 +0000629
sewardj7a26f022005-11-01 17:52:34 +0000630 // Copy verbatim any IR preamble preceding the first IMark
631 i = 0;
sewardj5d1c9012007-02-12 08:42:13 +0000632 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
633 addStmtToIRSB( sbOut, sbIn->stmts[i] );
sewardj7a26f022005-11-01 17:52:34 +0000634 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000635 }
sewardj9f649aa2004-11-22 20:38:40 +0000636
njnd99644d2006-04-07 11:52:55 +0000637 if (clo_basic_counts) {
sewardj5d1c9012007-02-12 08:42:13 +0000638 /* Count this superblock. */
639 di = unsafeIRDirty_0_N( 0, "add_one_SB_entered",
640 VG_(fnptr_to_fnentry)( &add_one_SB_entered ),
njnd99644d2006-04-07 11:52:55 +0000641 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000642 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
643 }
644
645 if (clo_trace_sbs) {
646 /* Print this superblock's address. */
647 di = unsafeIRDirty_0_N(
648 0, "trace_superblock",
649 VG_(fnptr_to_fnentry)( &trace_superblock ),
650 mkIRExprVec_1( mkIRExpr_HWord( vge->base[0] ) )
651 );
652 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000653 }
sewardj9f649aa2004-11-22 20:38:40 +0000654
njneaf0ca92006-04-09 01:23:29 +0000655 if (clo_trace_mem) {
656 events_used = 0;
657 }
658
sewardj5d1c9012007-02-12 08:42:13 +0000659 for (/*use current i*/; i < sbIn->stmts_used; i++) {
660 IRStmt* st = sbIn->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000661 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000662
njnd99644d2006-04-07 11:52:55 +0000663 if (clo_basic_counts) {
664 /* Count one VEX statement. */
665 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
666 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
667 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000668 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000669 }
sewardj7a26f022005-11-01 17:52:34 +0000670
sewardj9f649aa2004-11-22 20:38:40 +0000671 switch (st->tag) {
njneaf0ca92006-04-09 01:23:29 +0000672 case Ist_NoOp:
673 case Ist_AbiHint:
674 case Ist_Put:
675 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +0000676 case Ist_MBE:
sewardj5d1c9012007-02-12 08:42:13 +0000677 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000678 break;
679
sewardj7a26f022005-11-01 17:52:34 +0000680 case Ist_IMark:
njnd99644d2006-04-07 11:52:55 +0000681 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000682 /* Needed to be able to check for inverted condition in Ist_Exit */
683 iaddr = st->Ist.IMark.addr;
684 ilen = st->Ist.IMark.len;
685
njnd99644d2006-04-07 11:52:55 +0000686 /* Count guest instruction. */
687 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
688 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
689 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000690 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000691
692 /* An unconditional branch to a known destination in the
sewardj0b9d74a2006-12-24 02:24:11 +0000693 * guest's instructions can be represented, in the IRSB to
njnd99644d2006-04-07 11:52:55 +0000694 * instrument, by the VEX statements that are the
695 * translation of that known destination. This feature is
sewardj5d1c9012007-02-12 08:42:13 +0000696 * called 'SB chasing' and can be influenced by command
njnd99644d2006-04-07 11:52:55 +0000697 * line option --vex-guest-chase-thresh.
698 *
699 * To get an accurate count of the calls to a specific
sewardj5d1c9012007-02-12 08:42:13 +0000700 * function, taking SB chasing into account, we need to
njnd99644d2006-04-07 11:52:55 +0000701 * check for each guest instruction (Ist_IMark) if it is
702 * the entry point of a function.
703 */
704 tl_assert(clo_fnname);
705 tl_assert(clo_fnname[0]);
706 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
707 fnname, sizeof(fnname))
708 && 0 == VG_(strcmp)(fnname, clo_fnname)) {
709 di = unsafeIRDirty_0_N(
710 0, "add_one_func_call",
711 VG_(fnptr_to_fnentry)( &add_one_func_call ),
712 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000713 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000714 }
sewardj7a26f022005-11-01 17:52:34 +0000715 }
njnd99644d2006-04-07 11:52:55 +0000716 if (clo_trace_mem) {
njneaf0ca92006-04-09 01:23:29 +0000717 // WARNING: do not remove this function call, even if you
718 // aren't interested in instruction reads. See the comment
719 // above the function itself for more detail.
sewardj5d1c9012007-02-12 08:42:13 +0000720 addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
njneaf0ca92006-04-09 01:23:29 +0000721 st->Ist.IMark.len );
njnfd73ebb2005-12-30 22:39:58 +0000722 }
sewardj5d1c9012007-02-12 08:42:13 +0000723 addStmtToIRSB( sbOut, st );
sewardj7a26f022005-11-01 17:52:34 +0000724 break;
725
sewardj0b9d74a2006-12-24 02:24:11 +0000726 case Ist_WrTmp:
njnfd73ebb2005-12-30 22:39:58 +0000727 // Add a call to trace_load() if --trace-mem=yes.
njnd99644d2006-04-07 11:52:55 +0000728 if (clo_trace_mem) {
sewardj0b9d74a2006-12-24 02:24:11 +0000729 IRExpr* data = st->Ist.WrTmp.data;
njnfd73ebb2005-12-30 22:39:58 +0000730 if (data->tag == Iex_Load) {
sewardj5d1c9012007-02-12 08:42:13 +0000731 addEvent_Dr( sbOut, data->Iex.Load.addr,
njneaf0ca92006-04-09 01:23:29 +0000732 sizeofIRType(data->Iex.Load.ty) );
njnfd73ebb2005-12-30 22:39:58 +0000733 }
734 }
njnd99644d2006-04-07 11:52:55 +0000735 if (clo_detailed_counts) {
sewardj0b9d74a2006-12-24 02:24:11 +0000736 IRExpr* expr = st->Ist.WrTmp.data;
sewardj5d1c9012007-02-12 08:42:13 +0000737 type = typeOfIRExpr(sbOut->tyenv, expr);
sewardj7a26f022005-11-01 17:52:34 +0000738 tl_assert(type != Ity_INVALID);
739 switch (expr->tag) {
740 case Iex_Load:
sewardj5d1c9012007-02-12 08:42:13 +0000741 instrument_detail( sbOut, OpLoad, type );
sewardj7a26f022005-11-01 17:52:34 +0000742 break;
743 case Iex_Unop:
744 case Iex_Binop:
sewardje91cea72006-02-08 19:32:02 +0000745 case Iex_Triop:
746 case Iex_Qop:
sewardj7a26f022005-11-01 17:52:34 +0000747 case Iex_Mux0X:
sewardj5d1c9012007-02-12 08:42:13 +0000748 instrument_detail( sbOut, OpAlu, type );
sewardj7a26f022005-11-01 17:52:34 +0000749 break;
750 default:
751 break;
752 }
753 }
sewardj5d1c9012007-02-12 08:42:13 +0000754 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000755 break;
756
757 case Ist_Store:
758 if (clo_trace_mem) {
759 IRExpr* data = st->Ist.Store.data;
sewardj5d1c9012007-02-12 08:42:13 +0000760 addEvent_Dw( sbOut, st->Ist.Store.addr,
njneaf0ca92006-04-09 01:23:29 +0000761 sizeofIRType(typeOfIRExpr(tyenv, data)) );
762 }
763 if (clo_detailed_counts) {
sewardj5d1c9012007-02-12 08:42:13 +0000764 type = typeOfIRExpr(sbOut->tyenv, st->Ist.Store.data);
njneaf0ca92006-04-09 01:23:29 +0000765 tl_assert(type != Ity_INVALID);
sewardj5d1c9012007-02-12 08:42:13 +0000766 instrument_detail( sbOut, OpStore, type );
njneaf0ca92006-04-09 01:23:29 +0000767 }
sewardj5d1c9012007-02-12 08:42:13 +0000768 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000769 break;
770
771 case Ist_Dirty: {
njndbb9c8e2007-02-12 11:28:38 +0000772 if (clo_trace_mem) {
773 Int dsize;
774 IRDirty* d = st->Ist.Dirty.details;
775 if (d->mFx != Ifx_None) {
776 // This dirty helper accesses memory. Collect the details.
777 tl_assert(d->mAddr != NULL);
778 tl_assert(d->mSize != 0);
779 dsize = d->mSize;
780 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
781 addEvent_Dr( sbOut, d->mAddr, dsize );
782 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
783 addEvent_Dw( sbOut, d->mAddr, dsize );
784 } else {
785 tl_assert(d->mAddr == NULL);
786 tl_assert(d->mSize == 0);
787 }
njneaf0ca92006-04-09 01:23:29 +0000788 }
sewardj5d1c9012007-02-12 08:42:13 +0000789 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000790 break;
791 }
792
sewardj1c0ce7a2009-07-01 08:10:49 +0000793 case Ist_CAS: {
794 /* We treat it as a read and a write of the location. I
795 think that is the same behaviour as it was before IRCAS
796 was introduced, since prior to that point, the Vex
797 front ends would translate a lock-prefixed instruction
798 into a (normal) read followed by a (normal) write. */
sewardjdb5907d2009-11-26 17:20:21 +0000799 Int dataSize;
800 IRType dataTy;
801 IRCAS* cas = st->Ist.CAS.details;
802 tl_assert(cas->addr != NULL);
803 tl_assert(cas->dataLo != NULL);
804 dataTy = typeOfIRExpr(tyenv, cas->dataLo);
805 dataSize = sizeofIRType(dataTy);
806 if (cas->dataHi != NULL)
807 dataSize *= 2; /* since it's a doubleword-CAS */
sewardj1c0ce7a2009-07-01 08:10:49 +0000808 if (clo_trace_mem) {
sewardj1c0ce7a2009-07-01 08:10:49 +0000809 addEvent_Dr( sbOut, cas->addr, dataSize );
810 addEvent_Dw( sbOut, cas->addr, dataSize );
811 }
sewardjdb5907d2009-11-26 17:20:21 +0000812 if (clo_detailed_counts) {
813 instrument_detail( sbOut, OpLoad, dataTy );
814 if (cas->dataHi != NULL) /* dcas */
815 instrument_detail( sbOut, OpLoad, dataTy );
816 instrument_detail( sbOut, OpStore, dataTy );
817 if (cas->dataHi != NULL) /* dcas */
818 instrument_detail( sbOut, OpStore, dataTy );
819 }
820 addStmtToIRSB( sbOut, st );
821 break;
822 }
823
824 case Ist_LLSC: {
825 IRType dataTy;
826 if (st->Ist.LLSC.storedata == NULL) {
827 /* LL */
828 dataTy = typeOfIRTemp(tyenv, st->Ist.LLSC.result);
weidendod4053322012-11-26 18:16:58 +0000829 if (clo_trace_mem) {
sewardjdb5907d2009-11-26 17:20:21 +0000830 addEvent_Dr( sbOut, st->Ist.LLSC.addr,
831 sizeofIRType(dataTy) );
weidendod4053322012-11-26 18:16:58 +0000832 /* flush events before LL, helps SC to succeed */
833 flushEvents(sbOut);
834 }
sewardjdb5907d2009-11-26 17:20:21 +0000835 if (clo_detailed_counts)
836 instrument_detail( sbOut, OpLoad, dataTy );
837 } else {
838 /* SC */
839 dataTy = typeOfIRExpr(tyenv, st->Ist.LLSC.storedata);
840 if (clo_trace_mem)
841 addEvent_Dw( sbOut, st->Ist.LLSC.addr,
842 sizeofIRType(dataTy) );
843 if (clo_detailed_counts)
844 instrument_detail( sbOut, OpStore, dataTy );
845 }
sewardj1c0ce7a2009-07-01 08:10:49 +0000846 addStmtToIRSB( sbOut, st );
847 break;
848 }
849
njneaf0ca92006-04-09 01:23:29 +0000850 case Ist_Exit:
851 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000852 // The condition of a branch was inverted by VEX if a taken
853 // branch is in fact a fall trough according to client address
854 tl_assert(iaddr != 0);
855 dst = (sizeof(Addr) == 4) ? st->Ist.Exit.dst->Ico.U32 :
856 st->Ist.Exit.dst->Ico.U64;
857 condition_inverted = (dst == iaddr + ilen);
858
njneaf0ca92006-04-09 01:23:29 +0000859 /* Count Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000860 if (!condition_inverted)
861 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
njneaf0ca92006-04-09 01:23:29 +0000862 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
863 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000864 else
865 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc",
sewardjdb5907d2009-11-26 17:20:21 +0000866 VG_(fnptr_to_fnentry)(
867 &add_one_inverted_Jcc ),
weidendoba5b3b22007-02-16 11:13:53 +0000868 mkIRExprVec_0() );
869
sewardj5d1c9012007-02-12 08:42:13 +0000870 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000871 }
872 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000873 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000874 }
875
sewardj5d1c9012007-02-12 08:42:13 +0000876 addStmtToIRSB( sbOut, st ); // Original statement
njneaf0ca92006-04-09 01:23:29 +0000877
878 if (clo_basic_counts) {
879 /* Count non-taken Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000880 if (!condition_inverted)
881 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
njneaf0ca92006-04-09 01:23:29 +0000882 VG_(fnptr_to_fnentry)(
883 &add_one_Jcc_untaken ),
884 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000885 else
886 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc_untaken",
887 VG_(fnptr_to_fnentry)(
888 &add_one_inverted_Jcc_untaken ),
889 mkIRExprVec_0() );
890
sewardj5d1c9012007-02-12 08:42:13 +0000891 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000892 }
sewardj9f649aa2004-11-22 20:38:40 +0000893 break;
894
895 default:
njneaf0ca92006-04-09 01:23:29 +0000896 tl_assert(0);
sewardj9f649aa2004-11-22 20:38:40 +0000897 }
898 }
899
njnd99644d2006-04-07 11:52:55 +0000900 if (clo_basic_counts) {
901 /* Count this basic block. */
sewardj5d1c9012007-02-12 08:42:13 +0000902 di = unsafeIRDirty_0_N( 0, "add_one_SB_completed",
903 VG_(fnptr_to_fnentry)( &add_one_SB_completed ),
njnd99644d2006-04-07 11:52:55 +0000904 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000905 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000906 }
sewardj7a26f022005-11-01 17:52:34 +0000907
njneaf0ca92006-04-09 01:23:29 +0000908 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000909 /* At the end of the sbIn. Flush outstandings. */
910 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000911 }
912
sewardj5d1c9012007-02-12 08:42:13 +0000913 return sbOut;
njn25e49d8e72002-09-23 09:36:25 +0000914}
915
njn51d827b2005-05-09 01:02:08 +0000916static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000917{
florian19f91bb2012-11-10 22:29:54 +0000918 HChar percentify_buf[5]; /* Two digits, '%' and 0. */
sewardj8a5c06b2011-09-30 07:11:13 +0000919 const int percentify_size = sizeof(percentify_buf) - 1;
sewardj7a26f022005-11-01 17:52:34 +0000920 const int percentify_decs = 0;
921
njnd99644d2006-04-07 11:52:55 +0000922 tl_assert(clo_fnname);
923 tl_assert(clo_fnname[0]);
njn25e49d8e72002-09-23 09:36:25 +0000924
njnd99644d2006-04-07 11:52:55 +0000925 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000926 ULong total_Jccs = n_Jccs + n_IJccs;
927 ULong taken_Jccs = (n_Jccs - n_Jccs_untaken) + n_IJccs_untaken;
928
njn6fb923b2009-08-05 06:57:45 +0000929 VG_(umsg)("Counted %'llu call%s to %s()\n",
930 n_func_calls, ( n_func_calls==1 ? "" : "s" ), clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000931
sewardjb5dc2d62009-07-15 14:51:48 +0000932 VG_(umsg)("\n");
933 VG_(umsg)("Jccs:\n");
934 VG_(umsg)(" total: %'llu\n", total_Jccs);
weidendoba5b3b22007-02-16 11:13:53 +0000935 VG_(percentify)(taken_Jccs, (total_Jccs ? total_Jccs : 1),
njnd99644d2006-04-07 11:52:55 +0000936 percentify_decs, percentify_size, percentify_buf);
sewardjb5dc2d62009-07-15 14:51:48 +0000937 VG_(umsg)(" taken: %'llu (%s)\n",
weidendoba5b3b22007-02-16 11:13:53 +0000938 taken_Jccs, percentify_buf);
njnd99644d2006-04-07 11:52:55 +0000939
sewardjb5dc2d62009-07-15 14:51:48 +0000940 VG_(umsg)("\n");
941 VG_(umsg)("Executed:\n");
942 VG_(umsg)(" SBs entered: %'llu\n", n_SBs_entered);
943 VG_(umsg)(" SBs completed: %'llu\n", n_SBs_completed);
944 VG_(umsg)(" guest instrs: %'llu\n", n_guest_instrs);
945 VG_(umsg)(" IRStmts: %'llu\n", n_IRStmts);
njnd99644d2006-04-07 11:52:55 +0000946
sewardjb5dc2d62009-07-15 14:51:48 +0000947 VG_(umsg)("\n");
948 VG_(umsg)("Ratios:\n");
sewardj5d1c9012007-02-12 08:42:13 +0000949 tl_assert(n_SBs_entered); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +0000950 VG_(umsg)(" guest instrs : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +0000951 10 * n_guest_instrs / n_SBs_entered);
sewardjb5dc2d62009-07-15 14:51:48 +0000952 VG_(umsg)(" IRStmts : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +0000953 10 * n_IRStmts / n_SBs_entered);
njnd99644d2006-04-07 11:52:55 +0000954 tl_assert(n_guest_instrs); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +0000955 VG_(umsg)(" IRStmts : guest instr = %'llu : 10\n",
njnd99644d2006-04-07 11:52:55 +0000956 10 * n_IRStmts / n_guest_instrs);
957 }
958
959 if (clo_detailed_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +0000960 VG_(umsg)("\n");
961 VG_(umsg)("IR-level counts by type:\n");
sewardj7a26f022005-11-01 17:52:34 +0000962 print_details();
963 }
njn25e49d8e72002-09-23 09:36:25 +0000964
njnd99644d2006-04-07 11:52:55 +0000965 if (clo_basic_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +0000966 VG_(umsg)("\n");
967 VG_(umsg)("Exit code: %d\n", exitcode);
njnd99644d2006-04-07 11:52:55 +0000968 }
njn25e49d8e72002-09-23 09:36:25 +0000969}
970
njn51d827b2005-05-09 01:02:08 +0000971static void lk_pre_clo_init(void)
972{
973 VG_(details_name) ("Lackey");
974 VG_(details_version) (NULL);
975 VG_(details_description) ("an example Valgrind tool");
976 VG_(details_copyright_author)(
sewardj03f8d3f2012-08-05 15:46:46 +0000977 "Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote.");
njn51d827b2005-05-09 01:02:08 +0000978 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj40823562006-10-17 02:21:17 +0000979 VG_(details_avg_translation_sizeB) ( 200 );
njn51d827b2005-05-09 01:02:08 +0000980
981 VG_(basic_tool_funcs) (lk_post_clo_init,
982 lk_instrument,
983 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000984 VG_(needs_command_line_options)(lk_process_cmd_line_option,
985 lk_print_usage,
986 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000987}
988
sewardj45f4e7c2005-09-27 19:20:21 +0000989VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000990
njn25e49d8e72002-09-23 09:36:25 +0000991/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000992/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000993/*--------------------------------------------------------------------*/