blob: d2110b6e230a37a122c5a3bd32d8ddbf66f32a54 [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
njn9f207462009-03-10 22:02:09 +000010 Copyright (C) 2002-2009 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. */
njn6fb923b2009-08-05 06:57:45 +0000195static Char* clo_fnname = "main";
sewardj7a26f022005-11-01 17:52:34 +0000196
197static Bool lk_process_cmd_line_option(Char* arg)
198{
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
304#define N_TYPES 9
305
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;
317 case Ity_V128: return 8;
njnf36ae992007-11-22 23:33:20 +0000318 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000319 }
njn25e49d8e72002-09-23 09:36:25 +0000320}
321
njnab9c37e2007-08-27 22:18:58 +0000322static HChar* nameOfTypeIndex ( Int i )
sewardj7a26f022005-11-01 17:52:34 +0000323{
njnab9c37e2007-08-27 22:18:58 +0000324 switch (i) {
sewardj7a26f022005-11-01 17:52:34 +0000325 case 0: return "I1"; break;
326 case 1: return "I8"; break;
327 case 2: return "I16"; break;
328 case 3: return "I32"; break;
329 case 4: return "I64"; break;
330 case 5: return "I128"; break;
331 case 6: return "F32"; break;
332 case 7: return "F64"; break;
333 case 8: return "V128"; break;
njnf36ae992007-11-22 23:33:20 +0000334 default: tl_assert(0);
sewardj7a26f022005-11-01 17:52:34 +0000335 }
336}
njn25e49d8e72002-09-23 09:36:25 +0000337
njn25e49d8e72002-09-23 09:36:25 +0000338
sewardj7a26f022005-11-01 17:52:34 +0000339/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000340
sewardj7a26f022005-11-01 17:52:34 +0000341static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000342
sewardj7a26f022005-11-01 17:52:34 +0000343/* The helper that is called from the instrumented code. */
344static VG_REGPARM(1)
345void increment_detail(ULong* detail)
346{
347 (*detail)++;
348}
njn25e49d8e72002-09-23 09:36:25 +0000349
sewardj7a26f022005-11-01 17:52:34 +0000350/* A helper that adds the instrumentation for a detail. */
sewardj5d1c9012007-02-12 08:42:13 +0000351static void instrument_detail(IRSB* sb, Op op, IRType type)
sewardj7a26f022005-11-01 17:52:34 +0000352{
353 IRDirty* di;
354 IRExpr** argv;
355 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000356
sewardj7a26f022005-11-01 17:52:34 +0000357 tl_assert(op < N_OPS);
358 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000359
sewardj7a26f022005-11-01 17:52:34 +0000360 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000361 di = unsafeIRDirty_0_N( 1, "increment_detail",
362 VG_(fnptr_to_fnentry)( &increment_detail ),
363 argv);
sewardj5d1c9012007-02-12 08:42:13 +0000364 addStmtToIRSB( sb, IRStmt_Dirty(di) );
sewardj7a26f022005-11-01 17:52:34 +0000365}
njn25e49d8e72002-09-23 09:36:25 +0000366
sewardj7a26f022005-11-01 17:52:34 +0000367/* Summarize and print the details. */
sewardj7a26f022005-11-01 17:52:34 +0000368static void print_details ( void )
369{
370 Int typeIx;
sewardjb5dc2d62009-07-15 14:51:48 +0000371 VG_(umsg)(" Type Loads Stores AluOps\n");
372 VG_(umsg)(" -------------------------------------------\n");
sewardj7a26f022005-11-01 17:52:34 +0000373 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
sewardjb5dc2d62009-07-15 14:51:48 +0000374 VG_(umsg)(" %4s %'12llu %'12llu %'12llu\n",
375 nameOfTypeIndex( typeIx ),
376 detailCounts[OpLoad ][typeIx],
377 detailCounts[OpStore][typeIx],
378 detailCounts[OpAlu ][typeIx]
sewardj7a26f022005-11-01 17:52:34 +0000379 );
380 }
381}
njn25e49d8e72002-09-23 09:36:25 +0000382
sewardj7a26f022005-11-01 17:52:34 +0000383
njnd99644d2006-04-07 11:52:55 +0000384/*------------------------------------------------------------*/
njneaf0ca92006-04-09 01:23:29 +0000385/*--- Stuff for --trace-mem ---*/
njnd99644d2006-04-07 11:52:55 +0000386/*------------------------------------------------------------*/
njnfd73ebb2005-12-30 22:39:58 +0000387
njneaf0ca92006-04-09 01:23:29 +0000388#define MAX_DSIZE 512
389
390typedef
391 IRExpr
392 IRAtom;
393
394typedef
395 enum { Event_Ir, Event_Dr, Event_Dw, Event_Dm }
396 EventKind;
397
398typedef
399 struct {
400 EventKind ekind;
401 IRAtom* addr;
402 Int size;
403 }
404 Event;
405
406/* Up to this many unnotified events are allowed. Must be at least two,
407 so that reads and writes to the same address can be merged into a modify.
408 Beyond that, larger numbers just potentially induce more spilling due to
409 extending live ranges of address temporaries. */
410#define N_EVENTS 4
411
412/* Maintain an ordered list of memory events which are outstanding, in
413 the sense that no IR has yet been generated to do the relevant
sewardj5d1c9012007-02-12 08:42:13 +0000414 helper calls. The SB is scanned top to bottom and memory events
njneaf0ca92006-04-09 01:23:29 +0000415 are added to the end of the list, merging with the most recent
416 notified event where possible (Dw immediately following Dr and
417 having the same size and EA can be merged).
418
419 This merging is done so that for architectures which have
420 load-op-store instructions (x86, amd64), the instr is treated as if
421 it makes just one memory reference (a modify), rather than two (a
422 read followed by a write at the same address).
423
424 At various points the list will need to be flushed, that is, IR
425 generated from it. That must happen before any possible exit from
426 the block (the end, or an IRStmt_Exit). Flushing also takes place
427 when there is no space to add a new event.
428
429 If we require the simulation statistics to be up to date with
430 respect to possible memory exceptions, then the list would have to
431 be flushed before each memory reference. That's a pain so we don't
432 bother.
433
434 Flushing the list consists of walking it start to end and emitting
435 instrumentation IR for each event, in the order in which they
436 appear. */
437
438static Event events[N_EVENTS];
439static Int events_used = 0;
440
441
442static VG_REGPARM(2) void trace_instr(Addr addr, SizeT size)
443{
njn8a7b41b2007-09-23 00:51:24 +0000444 VG_(printf)("I %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000445}
446
njnfd73ebb2005-12-30 22:39:58 +0000447static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
448{
njn8a7b41b2007-09-23 00:51:24 +0000449 VG_(printf)(" L %08lx,%lu\n", addr, size);
njnfd73ebb2005-12-30 22:39:58 +0000450}
451
452static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
453{
njn8a7b41b2007-09-23 00:51:24 +0000454 VG_(printf)(" S %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000455}
456
457static VG_REGPARM(2) void trace_modify(Addr addr, SizeT size)
458{
njn8a7b41b2007-09-23 00:51:24 +0000459 VG_(printf)(" M %08lx,%lu\n", addr, size);
njneaf0ca92006-04-09 01:23:29 +0000460}
461
462
sewardj5d1c9012007-02-12 08:42:13 +0000463static void flushEvents(IRSB* sb)
njneaf0ca92006-04-09 01:23:29 +0000464{
465 Int i;
466 Char* helperName;
467 void* helperAddr;
468 IRExpr** argv;
469 IRDirty* di;
470 Event* ev;
471
472 for (i = 0; i < events_used; i++) {
473
474 ev = &events[i];
475
476 // Decide on helper fn to call and args to pass it.
477 switch (ev->ekind) {
478 case Event_Ir: helperName = "trace_instr";
479 helperAddr = trace_instr; break;
480
481 case Event_Dr: helperName = "trace_load";
482 helperAddr = trace_load; break;
483
484 case Event_Dw: helperName = "trace_store";
485 helperAddr = trace_store; break;
486
487 case Event_Dm: helperName = "trace_modify";
488 helperAddr = trace_modify; break;
489 default:
490 tl_assert(0);
491 }
492
493 // Add the helper.
494 argv = mkIRExprVec_2( ev->addr, mkIRExpr_HWord( ev->size ) );
495 di = unsafeIRDirty_0_N( /*regparms*/2,
496 helperName, VG_(fnptr_to_fnentry)( helperAddr ),
497 argv );
sewardj5d1c9012007-02-12 08:42:13 +0000498 addStmtToIRSB( sb, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000499 }
500
501 events_used = 0;
502}
503
504// WARNING: If you aren't interested in instruction reads, you can omit the
505// code that adds calls to trace_instr() in flushEvents(). However, you
506// must still call this function, addEvent_Ir() -- it is necessary to add
507// the Ir events to the events list so that merging of paired load/store
508// events into modify events works correctly.
sewardj5d1c9012007-02-12 08:42:13 +0000509static void addEvent_Ir ( IRSB* sb, IRAtom* iaddr, UInt isize )
njneaf0ca92006-04-09 01:23:29 +0000510{
511 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000512 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000513 tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB)
514 || VG_CLREQ_SZB == isize );
515 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000516 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000517 tl_assert(events_used >= 0 && events_used < N_EVENTS);
518 evt = &events[events_used];
519 evt->ekind = Event_Ir;
520 evt->addr = iaddr;
521 evt->size = isize;
522 events_used++;
523}
524
525static
sewardj5d1c9012007-02-12 08:42:13 +0000526void addEvent_Dr ( IRSB* sb, IRAtom* daddr, Int dsize )
njneaf0ca92006-04-09 01:23:29 +0000527{
528 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000529 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000530 tl_assert(isIRAtom(daddr));
531 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
532 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000533 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000534 tl_assert(events_used >= 0 && events_used < N_EVENTS);
535 evt = &events[events_used];
536 evt->ekind = Event_Dr;
537 evt->addr = daddr;
538 evt->size = dsize;
539 events_used++;
540}
541
542static
sewardj5d1c9012007-02-12 08:42:13 +0000543void addEvent_Dw ( IRSB* sb, IRAtom* daddr, Int dsize )
njneaf0ca92006-04-09 01:23:29 +0000544{
545 Event* lastEvt;
546 Event* evt;
njndbb9c8e2007-02-12 11:28:38 +0000547 tl_assert(clo_trace_mem);
njneaf0ca92006-04-09 01:23:29 +0000548 tl_assert(isIRAtom(daddr));
549 tl_assert(dsize >= 1 && dsize <= MAX_DSIZE);
550
551 // Is it possible to merge this write with the preceding read?
552 lastEvt = &events[events_used-1];
553 if (events_used > 0
554 && lastEvt->ekind == Event_Dr
555 && lastEvt->size == dsize
556 && eqIRAtom(lastEvt->addr, daddr))
557 {
558 lastEvt->ekind = Event_Dm;
559 return;
560 }
561
562 // No. Add as normal.
563 if (events_used == N_EVENTS)
sewardj5d1c9012007-02-12 08:42:13 +0000564 flushEvents(sb);
njneaf0ca92006-04-09 01:23:29 +0000565 tl_assert(events_used >= 0 && events_used < N_EVENTS);
566 evt = &events[events_used];
567 evt->ekind = Event_Dw;
568 evt->size = dsize;
569 evt->addr = daddr;
570 events_used++;
njnfd73ebb2005-12-30 22:39:58 +0000571}
572
njnd99644d2006-04-07 11:52:55 +0000573
574/*------------------------------------------------------------*/
sewardj5d1c9012007-02-12 08:42:13 +0000575/*--- Stuff for --trace-superblocks ---*/
576/*------------------------------------------------------------*/
577
578static void trace_superblock(Addr addr)
579{
580 VG_(printf)("SB %08lx\n", addr);
581}
582
583
584/*------------------------------------------------------------*/
njnd99644d2006-04-07 11:52:55 +0000585/*--- Basic tool functions ---*/
586/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000587
588static void lk_post_clo_init(void)
589{
590 Int op, tyIx;
591
njnd99644d2006-04-07 11:52:55 +0000592 if (clo_detailed_counts) {
593 for (op = 0; op < N_OPS; op++)
594 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
595 detailCounts[op][tyIx] = 0;
596 }
sewardj7a26f022005-11-01 17:52:34 +0000597}
598
sewardj4ba057c2005-10-18 12:04:18 +0000599static
sewardj0b9d74a2006-12-24 02:24:11 +0000600IRSB* lk_instrument ( VgCallbackClosure* closure,
sewardj5d1c9012007-02-12 08:42:13 +0000601 IRSB* sbIn,
sewardj461df9c2006-01-17 02:06:39 +0000602 VexGuestLayout* layout,
603 VexGuestExtents* vge,
604 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000605{
njneaf0ca92006-04-09 01:23:29 +0000606 IRDirty* di;
607 Int i;
sewardj5d1c9012007-02-12 08:42:13 +0000608 IRSB* sbOut;
njneaf0ca92006-04-09 01:23:29 +0000609 Char fnname[100];
610 IRType type;
sewardj5d1c9012007-02-12 08:42:13 +0000611 IRTypeEnv* tyenv = sbIn->tyenv;
weidendoba5b3b22007-02-16 11:13:53 +0000612 Addr iaddr = 0, dst;
613 UInt ilen = 0;
614 Bool condition_inverted = False;
sewardjd54babf2005-03-21 00:55:49 +0000615
616 if (gWordTy != hWordTy) {
617 /* We don't currently support this case. */
618 VG_(tool_panic)("host/guest word size mismatch");
619 }
sewardj9f649aa2004-11-22 20:38:40 +0000620
sewardj5d1c9012007-02-12 08:42:13 +0000621 /* Set up SB */
622 sbOut = deepCopyIRSBExceptStmts(sbIn);
sewardj9f649aa2004-11-22 20:38:40 +0000623
sewardj7a26f022005-11-01 17:52:34 +0000624 // Copy verbatim any IR preamble preceding the first IMark
625 i = 0;
sewardj5d1c9012007-02-12 08:42:13 +0000626 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
627 addStmtToIRSB( sbOut, sbIn->stmts[i] );
sewardj7a26f022005-11-01 17:52:34 +0000628 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000629 }
sewardj9f649aa2004-11-22 20:38:40 +0000630
njnd99644d2006-04-07 11:52:55 +0000631 if (clo_basic_counts) {
sewardj5d1c9012007-02-12 08:42:13 +0000632 /* Count this superblock. */
633 di = unsafeIRDirty_0_N( 0, "add_one_SB_entered",
634 VG_(fnptr_to_fnentry)( &add_one_SB_entered ),
njnd99644d2006-04-07 11:52:55 +0000635 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000636 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
637 }
638
639 if (clo_trace_sbs) {
640 /* Print this superblock's address. */
641 di = unsafeIRDirty_0_N(
642 0, "trace_superblock",
643 VG_(fnptr_to_fnentry)( &trace_superblock ),
644 mkIRExprVec_1( mkIRExpr_HWord( vge->base[0] ) )
645 );
646 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000647 }
sewardj9f649aa2004-11-22 20:38:40 +0000648
njneaf0ca92006-04-09 01:23:29 +0000649 if (clo_trace_mem) {
650 events_used = 0;
651 }
652
sewardj5d1c9012007-02-12 08:42:13 +0000653 for (/*use current i*/; i < sbIn->stmts_used; i++) {
654 IRStmt* st = sbIn->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000655 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000656
njnd99644d2006-04-07 11:52:55 +0000657 if (clo_basic_counts) {
658 /* Count one VEX statement. */
659 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
660 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
661 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000662 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000663 }
sewardj7a26f022005-11-01 17:52:34 +0000664
sewardj9f649aa2004-11-22 20:38:40 +0000665 switch (st->tag) {
njneaf0ca92006-04-09 01:23:29 +0000666 case Ist_NoOp:
667 case Ist_AbiHint:
668 case Ist_Put:
669 case Ist_PutI:
sewardj72d75132007-11-09 23:06:35 +0000670 case Ist_MBE:
sewardj5d1c9012007-02-12 08:42:13 +0000671 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000672 break;
673
sewardj7a26f022005-11-01 17:52:34 +0000674 case Ist_IMark:
njnd99644d2006-04-07 11:52:55 +0000675 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000676 /* Needed to be able to check for inverted condition in Ist_Exit */
677 iaddr = st->Ist.IMark.addr;
678 ilen = st->Ist.IMark.len;
679
njnd99644d2006-04-07 11:52:55 +0000680 /* Count guest instruction. */
681 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
682 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
683 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000684 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000685
686 /* An unconditional branch to a known destination in the
sewardj0b9d74a2006-12-24 02:24:11 +0000687 * guest's instructions can be represented, in the IRSB to
njnd99644d2006-04-07 11:52:55 +0000688 * instrument, by the VEX statements that are the
689 * translation of that known destination. This feature is
sewardj5d1c9012007-02-12 08:42:13 +0000690 * called 'SB chasing' and can be influenced by command
njnd99644d2006-04-07 11:52:55 +0000691 * line option --vex-guest-chase-thresh.
692 *
693 * To get an accurate count of the calls to a specific
sewardj5d1c9012007-02-12 08:42:13 +0000694 * function, taking SB chasing into account, we need to
njnd99644d2006-04-07 11:52:55 +0000695 * check for each guest instruction (Ist_IMark) if it is
696 * the entry point of a function.
697 */
698 tl_assert(clo_fnname);
699 tl_assert(clo_fnname[0]);
700 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
701 fnname, sizeof(fnname))
702 && 0 == VG_(strcmp)(fnname, clo_fnname)) {
703 di = unsafeIRDirty_0_N(
704 0, "add_one_func_call",
705 VG_(fnptr_to_fnentry)( &add_one_func_call ),
706 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000707 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000708 }
sewardj7a26f022005-11-01 17:52:34 +0000709 }
njnd99644d2006-04-07 11:52:55 +0000710 if (clo_trace_mem) {
njneaf0ca92006-04-09 01:23:29 +0000711 // WARNING: do not remove this function call, even if you
712 // aren't interested in instruction reads. See the comment
713 // above the function itself for more detail.
sewardj5d1c9012007-02-12 08:42:13 +0000714 addEvent_Ir( sbOut, mkIRExpr_HWord( (HWord)st->Ist.IMark.addr ),
njneaf0ca92006-04-09 01:23:29 +0000715 st->Ist.IMark.len );
njnfd73ebb2005-12-30 22:39:58 +0000716 }
sewardj5d1c9012007-02-12 08:42:13 +0000717 addStmtToIRSB( sbOut, st );
sewardj7a26f022005-11-01 17:52:34 +0000718 break;
719
sewardj0b9d74a2006-12-24 02:24:11 +0000720 case Ist_WrTmp:
njnfd73ebb2005-12-30 22:39:58 +0000721 // Add a call to trace_load() if --trace-mem=yes.
njnd99644d2006-04-07 11:52:55 +0000722 if (clo_trace_mem) {
sewardj0b9d74a2006-12-24 02:24:11 +0000723 IRExpr* data = st->Ist.WrTmp.data;
njnfd73ebb2005-12-30 22:39:58 +0000724 if (data->tag == Iex_Load) {
sewardj5d1c9012007-02-12 08:42:13 +0000725 addEvent_Dr( sbOut, data->Iex.Load.addr,
njneaf0ca92006-04-09 01:23:29 +0000726 sizeofIRType(data->Iex.Load.ty) );
njnfd73ebb2005-12-30 22:39:58 +0000727 }
728 }
njnd99644d2006-04-07 11:52:55 +0000729 if (clo_detailed_counts) {
sewardj0b9d74a2006-12-24 02:24:11 +0000730 IRExpr* expr = st->Ist.WrTmp.data;
sewardj5d1c9012007-02-12 08:42:13 +0000731 type = typeOfIRExpr(sbOut->tyenv, expr);
sewardj7a26f022005-11-01 17:52:34 +0000732 tl_assert(type != Ity_INVALID);
733 switch (expr->tag) {
734 case Iex_Load:
sewardj5d1c9012007-02-12 08:42:13 +0000735 instrument_detail( sbOut, OpLoad, type );
sewardj7a26f022005-11-01 17:52:34 +0000736 break;
737 case Iex_Unop:
738 case Iex_Binop:
sewardje91cea72006-02-08 19:32:02 +0000739 case Iex_Triop:
740 case Iex_Qop:
sewardj7a26f022005-11-01 17:52:34 +0000741 case Iex_Mux0X:
sewardj5d1c9012007-02-12 08:42:13 +0000742 instrument_detail( sbOut, OpAlu, type );
sewardj7a26f022005-11-01 17:52:34 +0000743 break;
744 default:
745 break;
746 }
747 }
sewardj5d1c9012007-02-12 08:42:13 +0000748 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000749 break;
750
751 case Ist_Store:
752 if (clo_trace_mem) {
753 IRExpr* data = st->Ist.Store.data;
sewardj5d1c9012007-02-12 08:42:13 +0000754 addEvent_Dw( sbOut, st->Ist.Store.addr,
njneaf0ca92006-04-09 01:23:29 +0000755 sizeofIRType(typeOfIRExpr(tyenv, data)) );
756 }
757 if (clo_detailed_counts) {
sewardj5d1c9012007-02-12 08:42:13 +0000758 type = typeOfIRExpr(sbOut->tyenv, st->Ist.Store.data);
njneaf0ca92006-04-09 01:23:29 +0000759 tl_assert(type != Ity_INVALID);
sewardj5d1c9012007-02-12 08:42:13 +0000760 instrument_detail( sbOut, OpStore, type );
njneaf0ca92006-04-09 01:23:29 +0000761 }
sewardj5d1c9012007-02-12 08:42:13 +0000762 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000763 break;
764
765 case Ist_Dirty: {
njndbb9c8e2007-02-12 11:28:38 +0000766 if (clo_trace_mem) {
767 Int dsize;
768 IRDirty* d = st->Ist.Dirty.details;
769 if (d->mFx != Ifx_None) {
770 // This dirty helper accesses memory. Collect the details.
771 tl_assert(d->mAddr != NULL);
772 tl_assert(d->mSize != 0);
773 dsize = d->mSize;
774 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify)
775 addEvent_Dr( sbOut, d->mAddr, dsize );
776 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify)
777 addEvent_Dw( sbOut, d->mAddr, dsize );
778 } else {
779 tl_assert(d->mAddr == NULL);
780 tl_assert(d->mSize == 0);
781 }
njneaf0ca92006-04-09 01:23:29 +0000782 }
sewardj5d1c9012007-02-12 08:42:13 +0000783 addStmtToIRSB( sbOut, st );
njneaf0ca92006-04-09 01:23:29 +0000784 break;
785 }
786
sewardj1c0ce7a2009-07-01 08:10:49 +0000787 case Ist_CAS: {
788 /* We treat it as a read and a write of the location. I
789 think that is the same behaviour as it was before IRCAS
790 was introduced, since prior to that point, the Vex
791 front ends would translate a lock-prefixed instruction
792 into a (normal) read followed by a (normal) write. */
793 if (clo_trace_mem) {
794 Int dataSize;
795 IRCAS* cas = st->Ist.CAS.details;
796 tl_assert(cas->addr != NULL);
797 tl_assert(cas->dataLo != NULL);
798 dataSize = sizeofIRType(typeOfIRExpr(tyenv, cas->dataLo));
799 if (cas->dataHi != NULL)
800 dataSize *= 2; /* since it's a doubleword-CAS */
801 addEvent_Dr( sbOut, cas->addr, dataSize );
802 addEvent_Dw( sbOut, cas->addr, dataSize );
803 }
804 addStmtToIRSB( sbOut, st );
805 break;
806 }
807
njneaf0ca92006-04-09 01:23:29 +0000808 case Ist_Exit:
809 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000810 // The condition of a branch was inverted by VEX if a taken
811 // branch is in fact a fall trough according to client address
812 tl_assert(iaddr != 0);
813 dst = (sizeof(Addr) == 4) ? st->Ist.Exit.dst->Ico.U32 :
814 st->Ist.Exit.dst->Ico.U64;
815 condition_inverted = (dst == iaddr + ilen);
816
njneaf0ca92006-04-09 01:23:29 +0000817 /* Count Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000818 if (!condition_inverted)
819 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
njneaf0ca92006-04-09 01:23:29 +0000820 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
821 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000822 else
823 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc",
824 VG_(fnptr_to_fnentry)( &add_one_inverted_Jcc ),
825 mkIRExprVec_0() );
826
sewardj5d1c9012007-02-12 08:42:13 +0000827 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000828 }
829 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000830 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000831 }
832
sewardj5d1c9012007-02-12 08:42:13 +0000833 addStmtToIRSB( sbOut, st ); // Original statement
njneaf0ca92006-04-09 01:23:29 +0000834
835 if (clo_basic_counts) {
836 /* Count non-taken Jcc */
weidendoba5b3b22007-02-16 11:13:53 +0000837 if (!condition_inverted)
838 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
njneaf0ca92006-04-09 01:23:29 +0000839 VG_(fnptr_to_fnentry)(
840 &add_one_Jcc_untaken ),
841 mkIRExprVec_0() );
weidendoba5b3b22007-02-16 11:13:53 +0000842 else
843 di = unsafeIRDirty_0_N( 0, "add_one_inverted_Jcc_untaken",
844 VG_(fnptr_to_fnentry)(
845 &add_one_inverted_Jcc_untaken ),
846 mkIRExprVec_0() );
847
sewardj5d1c9012007-02-12 08:42:13 +0000848 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njneaf0ca92006-04-09 01:23:29 +0000849 }
sewardj9f649aa2004-11-22 20:38:40 +0000850 break;
851
852 default:
njneaf0ca92006-04-09 01:23:29 +0000853 tl_assert(0);
sewardj9f649aa2004-11-22 20:38:40 +0000854 }
855 }
856
njnd99644d2006-04-07 11:52:55 +0000857 if (clo_basic_counts) {
858 /* Count this basic block. */
sewardj5d1c9012007-02-12 08:42:13 +0000859 di = unsafeIRDirty_0_N( 0, "add_one_SB_completed",
860 VG_(fnptr_to_fnentry)( &add_one_SB_completed ),
njnd99644d2006-04-07 11:52:55 +0000861 mkIRExprVec_0() );
sewardj5d1c9012007-02-12 08:42:13 +0000862 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000863 }
sewardj7a26f022005-11-01 17:52:34 +0000864
njneaf0ca92006-04-09 01:23:29 +0000865 if (clo_trace_mem) {
sewardj5d1c9012007-02-12 08:42:13 +0000866 /* At the end of the sbIn. Flush outstandings. */
867 flushEvents(sbOut);
njneaf0ca92006-04-09 01:23:29 +0000868 }
869
sewardj5d1c9012007-02-12 08:42:13 +0000870 return sbOut;
njn25e49d8e72002-09-23 09:36:25 +0000871}
872
njn51d827b2005-05-09 01:02:08 +0000873static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000874{
sewardj7a26f022005-11-01 17:52:34 +0000875 char percentify_buf[4]; /* Two digits, '%' and 0. */
876 const int percentify_size = sizeof(percentify_buf);
877 const int percentify_decs = 0;
878
njnd99644d2006-04-07 11:52:55 +0000879 tl_assert(clo_fnname);
880 tl_assert(clo_fnname[0]);
njn25e49d8e72002-09-23 09:36:25 +0000881
njnd99644d2006-04-07 11:52:55 +0000882 if (clo_basic_counts) {
weidendoba5b3b22007-02-16 11:13:53 +0000883 ULong total_Jccs = n_Jccs + n_IJccs;
884 ULong taken_Jccs = (n_Jccs - n_Jccs_untaken) + n_IJccs_untaken;
885
njn6fb923b2009-08-05 06:57:45 +0000886 VG_(umsg)("Counted %'llu call%s to %s()\n",
887 n_func_calls, ( n_func_calls==1 ? "" : "s" ), clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000888
sewardjb5dc2d62009-07-15 14:51:48 +0000889 VG_(umsg)("\n");
890 VG_(umsg)("Jccs:\n");
891 VG_(umsg)(" total: %'llu\n", total_Jccs);
weidendoba5b3b22007-02-16 11:13:53 +0000892 VG_(percentify)(taken_Jccs, (total_Jccs ? total_Jccs : 1),
njnd99644d2006-04-07 11:52:55 +0000893 percentify_decs, percentify_size, percentify_buf);
sewardjb5dc2d62009-07-15 14:51:48 +0000894 VG_(umsg)(" taken: %'llu (%s)\n",
weidendoba5b3b22007-02-16 11:13:53 +0000895 taken_Jccs, percentify_buf);
njnd99644d2006-04-07 11:52:55 +0000896
sewardjb5dc2d62009-07-15 14:51:48 +0000897 VG_(umsg)("\n");
898 VG_(umsg)("Executed:\n");
899 VG_(umsg)(" SBs entered: %'llu\n", n_SBs_entered);
900 VG_(umsg)(" SBs completed: %'llu\n", n_SBs_completed);
901 VG_(umsg)(" guest instrs: %'llu\n", n_guest_instrs);
902 VG_(umsg)(" IRStmts: %'llu\n", n_IRStmts);
njnd99644d2006-04-07 11:52:55 +0000903
sewardjb5dc2d62009-07-15 14:51:48 +0000904 VG_(umsg)("\n");
905 VG_(umsg)("Ratios:\n");
sewardj5d1c9012007-02-12 08:42:13 +0000906 tl_assert(n_SBs_entered); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +0000907 VG_(umsg)(" guest instrs : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +0000908 10 * n_guest_instrs / n_SBs_entered);
sewardjb5dc2d62009-07-15 14:51:48 +0000909 VG_(umsg)(" IRStmts : SB entered = %'llu : 10\n",
sewardj5d1c9012007-02-12 08:42:13 +0000910 10 * n_IRStmts / n_SBs_entered);
njnd99644d2006-04-07 11:52:55 +0000911 tl_assert(n_guest_instrs); // Paranoia time.
sewardjb5dc2d62009-07-15 14:51:48 +0000912 VG_(umsg)(" IRStmts : guest instr = %'llu : 10\n",
njnd99644d2006-04-07 11:52:55 +0000913 10 * n_IRStmts / n_guest_instrs);
914 }
915
916 if (clo_detailed_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +0000917 VG_(umsg)("\n");
918 VG_(umsg)("IR-level counts by type:\n");
sewardj7a26f022005-11-01 17:52:34 +0000919 print_details();
920 }
njn25e49d8e72002-09-23 09:36:25 +0000921
njnd99644d2006-04-07 11:52:55 +0000922 if (clo_basic_counts) {
sewardjb5dc2d62009-07-15 14:51:48 +0000923 VG_(umsg)("\n");
924 VG_(umsg)("Exit code: %d\n", exitcode);
njnd99644d2006-04-07 11:52:55 +0000925 }
njn25e49d8e72002-09-23 09:36:25 +0000926}
927
njn51d827b2005-05-09 01:02:08 +0000928static void lk_pre_clo_init(void)
929{
930 VG_(details_name) ("Lackey");
931 VG_(details_version) (NULL);
932 VG_(details_description) ("an example Valgrind tool");
933 VG_(details_copyright_author)(
njn9f207462009-03-10 22:02:09 +0000934 "Copyright (C) 2002-2009, and GNU GPL'd, by Nicholas Nethercote.");
njn51d827b2005-05-09 01:02:08 +0000935 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj40823562006-10-17 02:21:17 +0000936 VG_(details_avg_translation_sizeB) ( 200 );
njn51d827b2005-05-09 01:02:08 +0000937
938 VG_(basic_tool_funcs) (lk_post_clo_init,
939 lk_instrument,
940 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000941 VG_(needs_command_line_options)(lk_process_cmd_line_option,
942 lk_print_usage,
943 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000944}
945
sewardj45f4e7c2005-09-27 19:20:21 +0000946VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000947
njn25e49d8e72002-09-23 09:36:25 +0000948/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000949/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000950/*--------------------------------------------------------------------*/