blob: 975fb5730bff709db424d06b37dec21104363224 [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
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2002-2005 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//
njnd99644d2006-04-07 11:52:55 +000033// There are three kinds of instrumentation it can do. They can be turned
34// 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.
41//
42// The code for each kind of instrumentation is guarded by a clo_* variable:
43// clo_basic_counts, clo_detailed_counts and clo_trace_mem.
44//
45// If you want to modify any of the instrumentation code, look for the code
46// that is guarded by the relevant clo_* variable (eg. clo_trace_mem)
47// If you're not interested in the other kinds of instrumentation you can
48// remove them. If you want to do more complex modifications, please read
49// VEX/pub/libvex_ir.h to understand the intermediate representation.
50//
51//
52// Specific Details about --trace-mem=yes
53// --------------------------------------
54// The address trace produced by --trace-mem=yes is good, but not perfect;
55// see Section 3.3.7 of Nicholas Nethercote's PhD dissertation "Dynamic
56// Binary Analysis and Instrumentation", 2004, for details about the few
57// loads and stores that it misses, and other caveats about the accuracy of
58// the address trace.
njnfd73ebb2005-12-30 22:39:58 +000059//
njn9dd72772006-03-11 06:48:20 +000060// [Actually, the traces aren't quite right because instructions that modify
61// a memory location are treated like a load followed by a store.]
62//
njnfd73ebb2005-12-30 22:39:58 +000063// For further inspiration, you should look at cachegrind/cg_main.c which
64// handles memory accesses in a more sophisticated way -- it groups them
65// together for processing into twos and threes so that fewer C calls are
66// made and things run faster.
67
njnc7561b92005-06-19 01:24:32 +000068#include "pub_tool_basics.h"
njn43b9a8a2005-05-10 04:37:01 +000069#include "pub_tool_tooliface.h"
njnf39e9a32005-06-12 02:43:17 +000070#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000071#include "pub_tool_libcprint.h"
sewardj7a26f022005-11-01 17:52:34 +000072#include "pub_tool_debuginfo.h"
73#include "pub_tool_libcbase.h"
74#include "pub_tool_options.h"
sewardj5fed8c02005-12-23 12:56:11 +000075#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry)
sewardj7a26f022005-11-01 17:52:34 +000076
njnd99644d2006-04-07 11:52:55 +000077/*------------------------------------------------------------*/
78/*--- Command line options ---*/
79/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +000080
njnd99644d2006-04-07 11:52:55 +000081/* Command line options controlling instrumentation kinds, as described at
82 * the top of this file. */
83static Bool clo_basic_counts = True;
84static Bool clo_detailed_counts = False;
85static Bool clo_trace_mem = False;
sewardj7a26f022005-11-01 17:52:34 +000086
njnd99644d2006-04-07 11:52:55 +000087/* The name of the function of which the number of calls (under
88 * --basic-counts=yes) is to be counted, with default. Override with command
89 * line option --fnname. */
90static Char* clo_fnname = "_dl_runtime_resolve";
sewardj7a26f022005-11-01 17:52:34 +000091
92static Bool lk_process_cmd_line_option(Char* arg)
93{
njnd99644d2006-04-07 11:52:55 +000094 VG_STR_CLO(arg, "--fnname", clo_fnname)
95 else VG_BOOL_CLO(arg, "--basic-counts", clo_basic_counts)
96 else VG_BOOL_CLO(arg, "--detailed-counts", clo_detailed_counts)
97 else VG_BOOL_CLO(arg, "--trace-mem", clo_trace_mem)
sewardj7a26f022005-11-01 17:52:34 +000098 else
99 return False;
100
njnd99644d2006-04-07 11:52:55 +0000101 tl_assert(clo_fnname);
102 tl_assert(clo_fnname[0]);
sewardj7a26f022005-11-01 17:52:34 +0000103 return True;
104}
105
106static void lk_print_usage(void)
107{
108 VG_(printf)(
njnd99644d2006-04-07 11:52:55 +0000109" --basic-counts=no|yes count instructions, jumps, etc. [no]\n"
sewardj7a26f022005-11-01 17:52:34 +0000110" --detailed-counts=no|yes count loads, stores and alu ops [no]\n"
njnd99644d2006-04-07 11:52:55 +0000111" --trace-mem=no|yes trace all loads and stores [no]\n"
112" --fnname=<name> count calls to <name> (only used if\n"
113" --basic-count=yes) [_dl_runtime_resolve]\n"
114
sewardj7a26f022005-11-01 17:52:34 +0000115 );
116}
117
118static void lk_print_debug_usage(void)
119{
120}
121
njnd99644d2006-04-07 11:52:55 +0000122/*------------------------------------------------------------*/
123/*--- Data and helpers for --basic-counts ---*/
124/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000125
njn25e49d8e72002-09-23 09:36:25 +0000126/* Nb: use ULongs because the numbers can get very big */
sewardj7a26f022005-11-01 17:52:34 +0000127static ULong n_func_calls = 0;
128static ULong n_BBs_entered = 0;
129static ULong n_BBs_completed = 0;
130static ULong n_IRStmts = 0;
131static ULong n_guest_instrs = 0;
132static ULong n_Jccs = 0;
133static ULong n_Jccs_untaken = 0;
njn25e49d8e72002-09-23 09:36:25 +0000134
sewardj7a26f022005-11-01 17:52:34 +0000135static void add_one_func_call(void)
njn25e49d8e72002-09-23 09:36:25 +0000136{
sewardj7a26f022005-11-01 17:52:34 +0000137 n_func_calls++;
njn25e49d8e72002-09-23 09:36:25 +0000138}
139
sewardj7a26f022005-11-01 17:52:34 +0000140static void add_one_BB_entered(void)
njn25e49d8e72002-09-23 09:36:25 +0000141{
sewardj7a26f022005-11-01 17:52:34 +0000142 n_BBs_entered++;
143}
144
145static void add_one_BB_completed(void)
146{
147 n_BBs_completed++;
njn25e49d8e72002-09-23 09:36:25 +0000148}
149
sewardj7a26f022005-11-01 17:52:34 +0000150static void add_one_IRStmt(void)
njn25e49d8e72002-09-23 09:36:25 +0000151{
sewardj7a26f022005-11-01 17:52:34 +0000152 n_IRStmts++;
njn25e49d8e72002-09-23 09:36:25 +0000153}
154
sewardj9f649aa2004-11-22 20:38:40 +0000155static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +0000156{
sewardj9f649aa2004-11-22 20:38:40 +0000157 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +0000158}
159
160static void add_one_Jcc(void)
161{
162 n_Jccs++;
163}
164
165static void add_one_Jcc_untaken(void)
166{
167 n_Jccs_untaken++;
168}
169
njnd99644d2006-04-07 11:52:55 +0000170/*------------------------------------------------------------*/
171/*--- Data and helpers for --detailed-counts ---*/
172/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000173
174/* --- Operations --- */
175
176typedef enum { OpLoad=0, OpStore=1, OpAlu=2 } Op;
177
178#define N_OPS 3
179
180
181/* --- Types --- */
182
183#define N_TYPES 9
184
185static Int type2index ( IRType ty )
njn25e49d8e72002-09-23 09:36:25 +0000186{
sewardj7a26f022005-11-01 17:52:34 +0000187 switch (ty) {
188 case Ity_I1: return 0;
189 case Ity_I8: return 1;
190 case Ity_I16: return 2;
191 case Ity_I32: return 3;
192 case Ity_I64: return 4;
193 case Ity_I128: return 5;
194 case Ity_F32: return 6;
195 case Ity_F64: return 7;
196 case Ity_V128: return 8;
197 default: tl_assert(0); break;
198 }
njn25e49d8e72002-09-23 09:36:25 +0000199}
200
sewardj7a26f022005-11-01 17:52:34 +0000201static HChar* nameOfTypeIndex ( IRType ty )
202{
203 switch (ty) {
204 case 0: return "I1"; break;
205 case 1: return "I8"; break;
206 case 2: return "I16"; break;
207 case 3: return "I32"; break;
208 case 4: return "I64"; break;
209 case 5: return "I128"; break;
210 case 6: return "F32"; break;
211 case 7: return "F64"; break;
212 case 8: return "V128"; break;
213 default: tl_assert(0); break;
214 }
215}
njn25e49d8e72002-09-23 09:36:25 +0000216
njn25e49d8e72002-09-23 09:36:25 +0000217
sewardj7a26f022005-11-01 17:52:34 +0000218/* --- Counts --- */
njn25e49d8e72002-09-23 09:36:25 +0000219
sewardj7a26f022005-11-01 17:52:34 +0000220static ULong detailCounts[N_OPS][N_TYPES];
njn25e49d8e72002-09-23 09:36:25 +0000221
sewardj7a26f022005-11-01 17:52:34 +0000222/* The helper that is called from the instrumented code. */
223static VG_REGPARM(1)
224void increment_detail(ULong* detail)
225{
226 (*detail)++;
227}
njn25e49d8e72002-09-23 09:36:25 +0000228
sewardj7a26f022005-11-01 17:52:34 +0000229/* A helper that adds the instrumentation for a detail. */
230static void instrument_detail(IRBB* bb, Op op, IRType type)
231{
232 IRDirty* di;
233 IRExpr** argv;
234 const UInt typeIx = type2index(type);
njn25e49d8e72002-09-23 09:36:25 +0000235
sewardj7a26f022005-11-01 17:52:34 +0000236 tl_assert(op < N_OPS);
237 tl_assert(typeIx < N_TYPES);
njn25e49d8e72002-09-23 09:36:25 +0000238
sewardj7a26f022005-11-01 17:52:34 +0000239 argv = mkIRExprVec_1( mkIRExpr_HWord( (HWord)&detailCounts[op][typeIx] ) );
sewardj5fed8c02005-12-23 12:56:11 +0000240 di = unsafeIRDirty_0_N( 1, "increment_detail",
241 VG_(fnptr_to_fnentry)( &increment_detail ),
242 argv);
sewardj7a26f022005-11-01 17:52:34 +0000243 addStmtToIRBB( bb, IRStmt_Dirty(di) );
244}
njn25e49d8e72002-09-23 09:36:25 +0000245
sewardj7a26f022005-11-01 17:52:34 +0000246/* Summarize and print the details. */
njn25e49d8e72002-09-23 09:36:25 +0000247
sewardj7a26f022005-11-01 17:52:34 +0000248static void print_details ( void )
249{
250 Int typeIx;
251 VG_(message)(Vg_UserMsg,
252 " Type Loads Stores AluOps");
253 VG_(message)(Vg_UserMsg,
254 " -------------------------------------------");
255 for (typeIx = 0; typeIx < N_TYPES; typeIx++) {
256 VG_(message)(Vg_UserMsg,
257 " %4s %,12llu %,12llu %,12llu",
258 nameOfTypeIndex( typeIx ),
259 detailCounts[OpLoad ][typeIx],
260 detailCounts[OpStore][typeIx],
261 detailCounts[OpAlu ][typeIx]
262 );
263 }
264}
njn25e49d8e72002-09-23 09:36:25 +0000265
sewardj7a26f022005-11-01 17:52:34 +0000266
njnd99644d2006-04-07 11:52:55 +0000267/*------------------------------------------------------------*/
268/*--- Data and helpers for --trace-mem ---*/
269/*------------------------------------------------------------*/
njnfd73ebb2005-12-30 22:39:58 +0000270
271static VG_REGPARM(2) void trace_load(Addr addr, SizeT size)
272{
273 VG_(printf)("load : %p, %d\n", addr, size);
274}
275
276static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
277{
278 VG_(printf)("store: %p, %d\n", addr, size);
279}
280
njnd99644d2006-04-07 11:52:55 +0000281
282/*------------------------------------------------------------*/
283/*--- Basic tool functions ---*/
284/*------------------------------------------------------------*/
sewardj7a26f022005-11-01 17:52:34 +0000285
286static void lk_post_clo_init(void)
287{
288 Int op, tyIx;
289
njnd99644d2006-04-07 11:52:55 +0000290 if (clo_detailed_counts) {
291 for (op = 0; op < N_OPS; op++)
292 for (tyIx = 0; tyIx < N_TYPES; tyIx++)
293 detailCounts[op][tyIx] = 0;
294 }
sewardj7a26f022005-11-01 17:52:34 +0000295}
296
sewardj4ba057c2005-10-18 12:04:18 +0000297static
sewardj461df9c2006-01-17 02:06:39 +0000298IRBB* lk_instrument ( VgCallbackClosure* closure,
299 IRBB* bb_in,
300 VexGuestLayout* layout,
301 VexGuestExtents* vge,
302 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000303{
sewardj9f649aa2004-11-22 20:38:40 +0000304 IRDirty* di;
305 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000306 IRBB* bb;
sewardj7a26f022005-11-01 17:52:34 +0000307 Char fnname[100];
308 IRType type;
njnfd73ebb2005-12-30 22:39:58 +0000309 IRExpr** argv;
310 IRExpr* addr_expr;
311 IRExpr* size_expr;
sewardjd54babf2005-03-21 00:55:49 +0000312
313 if (gWordTy != hWordTy) {
314 /* We don't currently support this case. */
315 VG_(tool_panic)("host/guest word size mismatch");
316 }
sewardj9f649aa2004-11-22 20:38:40 +0000317
318 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000319 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000320 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
321 bb->next = dopyIRExpr(bb_in->next);
322 bb->jumpkind = bb_in->jumpkind;
323
sewardj7a26f022005-11-01 17:52:34 +0000324 // Copy verbatim any IR preamble preceding the first IMark
325 i = 0;
326 while (i < bb_in->stmts_used && bb_in->stmts[i]->tag != Ist_IMark) {
327 addStmtToIRBB( bb, bb_in->stmts[i] );
328 i++;
sewardj9f649aa2004-11-22 20:38:40 +0000329 }
sewardj9f649aa2004-11-22 20:38:40 +0000330
njnd99644d2006-04-07 11:52:55 +0000331 if (clo_basic_counts) {
332 /* Count this basic block. */
333 di = unsafeIRDirty_0_N( 0, "add_one_BB_entered",
334 VG_(fnptr_to_fnentry)( &add_one_BB_entered ),
335 mkIRExprVec_0() );
336 addStmtToIRBB( bb, IRStmt_Dirty(di) );
337 }
sewardj9f649aa2004-11-22 20:38:40 +0000338
sewardj7a26f022005-11-01 17:52:34 +0000339 for (/*use current i*/; i < bb_in->stmts_used; i++) {
sewardj9f649aa2004-11-22 20:38:40 +0000340 IRStmt* st = bb_in->stmts[i];
sewardj7a26f022005-11-01 17:52:34 +0000341 if (!st || st->tag == Ist_NoOp) continue;
sewardj9f649aa2004-11-22 20:38:40 +0000342
njnd99644d2006-04-07 11:52:55 +0000343 if (clo_basic_counts) {
344 /* Count one VEX statement. */
345 di = unsafeIRDirty_0_N( 0, "add_one_IRStmt",
346 VG_(fnptr_to_fnentry)( &add_one_IRStmt ),
347 mkIRExprVec_0() );
348 addStmtToIRBB( bb, IRStmt_Dirty(di) );
349 }
sewardj7a26f022005-11-01 17:52:34 +0000350
sewardj9f649aa2004-11-22 20:38:40 +0000351 switch (st->tag) {
sewardj7a26f022005-11-01 17:52:34 +0000352 case Ist_IMark:
njnd99644d2006-04-07 11:52:55 +0000353 if (clo_basic_counts) {
354 /* Count guest instruction. */
355 di = unsafeIRDirty_0_N( 0, "add_one_guest_instr",
356 VG_(fnptr_to_fnentry)( &add_one_guest_instr ),
357 mkIRExprVec_0() );
sewardj7a26f022005-11-01 17:52:34 +0000358 addStmtToIRBB( bb, IRStmt_Dirty(di) );
njnd99644d2006-04-07 11:52:55 +0000359
360 /* An unconditional branch to a known destination in the
361 * guest's instructions can be represented, in the IRBB to
362 * instrument, by the VEX statements that are the
363 * translation of that known destination. This feature is
364 * called 'BB chasing' and can be influenced by command
365 * line option --vex-guest-chase-thresh.
366 *
367 * To get an accurate count of the calls to a specific
368 * function, taking BB chasing into account, we need to
369 * check for each guest instruction (Ist_IMark) if it is
370 * the entry point of a function.
371 */
372 tl_assert(clo_fnname);
373 tl_assert(clo_fnname[0]);
374 if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr,
375 fnname, sizeof(fnname))
376 && 0 == VG_(strcmp)(fnname, clo_fnname)) {
377 di = unsafeIRDirty_0_N(
378 0, "add_one_func_call",
379 VG_(fnptr_to_fnentry)( &add_one_func_call ),
380 mkIRExprVec_0() );
381 addStmtToIRBB( bb, IRStmt_Dirty(di) );
382 }
sewardj7a26f022005-11-01 17:52:34 +0000383 }
384 addStmtToIRBB( bb, st );
385 break;
386
sewardj9f649aa2004-11-22 20:38:40 +0000387 case Ist_Exit:
njnd99644d2006-04-07 11:52:55 +0000388 if (clo_basic_counts) {
389 /* Count Jcc */
390 di = unsafeIRDirty_0_N( 0, "add_one_Jcc",
391 VG_(fnptr_to_fnentry)( &add_one_Jcc ),
392 mkIRExprVec_0() );
393 addStmtToIRBB( bb, IRStmt_Dirty(di) );
394 }
sewardj7a26f022005-11-01 17:52:34 +0000395
396 addStmtToIRBB( bb, st );
397
njnd99644d2006-04-07 11:52:55 +0000398 if (clo_basic_counts) {
399 /* Count non-taken Jcc */
400 di = unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken",
401 VG_(fnptr_to_fnentry)(
402 &add_one_Jcc_untaken ),
403 mkIRExprVec_0() );
404 addStmtToIRBB( bb, IRStmt_Dirty(di) );
405 }
sewardj7a26f022005-11-01 17:52:34 +0000406 break;
407
sewardj7a26f022005-11-01 17:52:34 +0000408 case Ist_Store:
njnfd73ebb2005-12-30 22:39:58 +0000409 // Add a call to trace_store() if --trace-mem=yes.
njnd99644d2006-04-07 11:52:55 +0000410 if (clo_trace_mem) {
njnfd73ebb2005-12-30 22:39:58 +0000411 addr_expr = st->Ist.Store.addr;
412 size_expr = mkIRExpr_HWord(
413 sizeofIRType(
414 typeOfIRExpr(bb->tyenv, st->Ist.Store.data)));
415 argv = mkIRExprVec_2( addr_expr, size_expr );
416 di = unsafeIRDirty_0_N( /*regparms*/2,
417 "trace_store",
418 VG_(fnptr_to_fnentry)( trace_store ),
419 argv );
420 addStmtToIRBB( bb, IRStmt_Dirty(di) );
421 }
njnd99644d2006-04-07 11:52:55 +0000422 if (clo_detailed_counts) {
sewardj7a26f022005-11-01 17:52:34 +0000423 type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data);
424 tl_assert(type != Ity_INVALID);
425 instrument_detail( bb, OpStore, type );
426 }
427 addStmtToIRBB( bb, st );
428 break;
429
430 case Ist_Tmp:
njnfd73ebb2005-12-30 22:39:58 +0000431 // Add a call to trace_load() if --trace-mem=yes.
njnd99644d2006-04-07 11:52:55 +0000432 if (clo_trace_mem) {
njnfd73ebb2005-12-30 22:39:58 +0000433 IRExpr* data = st->Ist.Tmp.data;
434 if (data->tag == Iex_Load) {
435 addr_expr = data->Iex.Load.addr;
436 size_expr = mkIRExpr_HWord( sizeofIRType(data->Iex.Load.ty) );
437 argv = mkIRExprVec_2( addr_expr, size_expr );
438 di = unsafeIRDirty_0_N( /*regparms*/2,
439 "trace_load",
440 VG_(fnptr_to_fnentry)( trace_load ),
441 argv );
442 addStmtToIRBB( bb, IRStmt_Dirty(di) );
443 }
444 }
njnd99644d2006-04-07 11:52:55 +0000445 if (clo_detailed_counts) {
sewardj7a26f022005-11-01 17:52:34 +0000446 IRExpr* expr = st->Ist.Tmp.data;
447 type = typeOfIRExpr(bb->tyenv, expr);
448 tl_assert(type != Ity_INVALID);
449 switch (expr->tag) {
450 case Iex_Load:
451 instrument_detail( bb, OpLoad, type );
452 break;
453 case Iex_Unop:
454 case Iex_Binop:
sewardje91cea72006-02-08 19:32:02 +0000455 case Iex_Triop:
456 case Iex_Qop:
sewardj7a26f022005-11-01 17:52:34 +0000457 case Iex_Mux0X:
458 instrument_detail( bb, OpAlu, type );
459 break;
460 default:
461 break;
462 }
463 }
464 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000465 break;
466
467 default:
sewardjbd598e12005-01-07 12:10:21 +0000468 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000469 }
470 }
471
njnd99644d2006-04-07 11:52:55 +0000472 if (clo_basic_counts) {
473 /* Count this basic block. */
474 di = unsafeIRDirty_0_N( 0, "add_one_BB_completed",
475 VG_(fnptr_to_fnentry)( &add_one_BB_completed ),
476 mkIRExprVec_0() );
477 addStmtToIRBB( bb, IRStmt_Dirty(di) );
478 }
sewardj7a26f022005-11-01 17:52:34 +0000479
sewardj9f649aa2004-11-22 20:38:40 +0000480 return bb;
njn25e49d8e72002-09-23 09:36:25 +0000481}
482
njn51d827b2005-05-09 01:02:08 +0000483static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000484{
sewardj7a26f022005-11-01 17:52:34 +0000485 char percentify_buf[4]; /* Two digits, '%' and 0. */
486 const int percentify_size = sizeof(percentify_buf);
487 const int percentify_decs = 0;
488
njnd99644d2006-04-07 11:52:55 +0000489 tl_assert(clo_fnname);
490 tl_assert(clo_fnname[0]);
njn25e49d8e72002-09-23 09:36:25 +0000491
njnd99644d2006-04-07 11:52:55 +0000492 if (clo_basic_counts) {
493 VG_(message)(Vg_UserMsg,
494 "Counted %,llu calls to %s()", n_func_calls, clo_fnname);
njn25e49d8e72002-09-23 09:36:25 +0000495
njnd99644d2006-04-07 11:52:55 +0000496 VG_(message)(Vg_UserMsg, "");
497 VG_(message)(Vg_UserMsg, "Jccs:");
498 VG_(message)(Vg_UserMsg, " total: %,llu", n_Jccs);
499 VG_(percentify)((n_Jccs - n_Jccs_untaken), (n_Jccs ? n_Jccs : 1),
500 percentify_decs, percentify_size, percentify_buf);
501 VG_(message)(Vg_UserMsg, " taken: %,llu (%s)",
502 (n_Jccs - n_Jccs_untaken), percentify_buf);
503
504 VG_(message)(Vg_UserMsg, "");
505 VG_(message)(Vg_UserMsg, "Executed:");
506 VG_(message)(Vg_UserMsg, " BBs entered: %,llu", n_BBs_entered);
507 VG_(message)(Vg_UserMsg, " BBs completed: %,llu", n_BBs_completed);
508 VG_(message)(Vg_UserMsg, " guest instrs: %,llu", n_guest_instrs);
509 VG_(message)(Vg_UserMsg, " IRStmts: %,llu", n_IRStmts);
510
511 VG_(message)(Vg_UserMsg, "");
512 VG_(message)(Vg_UserMsg, "Ratios:");
513 tl_assert(n_BBs_entered); // Paranoia time.
514 VG_(message)(Vg_UserMsg, " guest instrs : BB entered = %3u : 10",
515 10 * n_guest_instrs / n_BBs_entered);
516 VG_(message)(Vg_UserMsg, " IRStmts : BB entered = %3u : 10",
517 10 * n_IRStmts / n_BBs_entered);
518 tl_assert(n_guest_instrs); // Paranoia time.
519 VG_(message)(Vg_UserMsg, " IRStmts : guest instr = %3u : 10",
520 10 * n_IRStmts / n_guest_instrs);
521 }
522
523 if (clo_detailed_counts) {
sewardj7a26f022005-11-01 17:52:34 +0000524 VG_(message)(Vg_UserMsg, "");
525 VG_(message)(Vg_UserMsg, "IR-level counts by type:");
526 print_details();
527 }
njn25e49d8e72002-09-23 09:36:25 +0000528
njnd99644d2006-04-07 11:52:55 +0000529 if (clo_basic_counts) {
530 VG_(message)(Vg_UserMsg, "");
531 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
532 }
njn25e49d8e72002-09-23 09:36:25 +0000533}
534
njn51d827b2005-05-09 01:02:08 +0000535static void lk_pre_clo_init(void)
536{
537 VG_(details_name) ("Lackey");
538 VG_(details_version) (NULL);
539 VG_(details_description) ("an example Valgrind tool");
540 VG_(details_copyright_author)(
541 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
542 VG_(details_bug_reports_to) (VG_BUGS_TO);
543 VG_(details_avg_translation_sizeB) ( 175 );
544
545 VG_(basic_tool_funcs) (lk_post_clo_init,
546 lk_instrument,
547 lk_fini);
sewardj7a26f022005-11-01 17:52:34 +0000548 VG_(needs_command_line_options)(lk_process_cmd_line_option,
549 lk_print_usage,
550 lk_print_debug_usage);
njn51d827b2005-05-09 01:02:08 +0000551}
552
sewardj45f4e7c2005-09-27 19:20:21 +0000553VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000554
njn25e49d8e72002-09-23 09:36:25 +0000555/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000556/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000557/*--------------------------------------------------------------------*/