blob: fa3a077e0ba63af07f38777a24fc8f302e1295fd [file] [log] [blame]
florian12d2eb52014-10-30 22:17:56 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
njndbebecc2009-07-14 01:39:54 +00003//--------------------------------------------------------------------*/
4//--- BBV: a SimPoint basic block vector generator bbv_main.c ---*/
5//--------------------------------------------------------------------*/
6
7/*
8 This file is part of BBV, a Valgrind tool for generating SimPoint
9 basic block vectors.
10
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright (C) 2006-2017 Vince Weaver
njndbebecc2009-07-14 01:39:54 +000012 vince _at_ csl.cornell.edu
13
Elliott Hughesed398002017-06-21 14:41:24 -070014 pcfile code is Copyright (C) 2006-2017 Oriol Prat
njndbebecc2009-07-14 01:39:54 +000015 oriol.prat _at _ bsc.es
16
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation; either version 2 of the
20 License, or (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 02111-1307, USA.
31
32 The GNU General Public License is contained in the file COPYING.
33*/
34
35
36#include "pub_tool_basics.h"
37#include "pub_tool_tooliface.h"
38#include "pub_tool_options.h" /* command line options */
39
florian12d2eb52014-10-30 22:17:56 +000040#include "pub_tool_vki.h" /* VKI_O_CREAT */
njndbebecc2009-07-14 01:39:54 +000041#include "pub_tool_libcbase.h" /* VG_(strlen) */
njndbebecc2009-07-14 01:39:54 +000042#include "pub_tool_libcprint.h" /* VG_(printf) */
43#include "pub_tool_libcassert.h" /* VG_(exit) */
florian12d2eb52014-10-30 22:17:56 +000044#include "pub_tool_mallocfree.h" /* VG_(malloc) */
njndbebecc2009-07-14 01:39:54 +000045#include "pub_tool_machine.h" /* VG_(fnptr_to_fnentry) */
46#include "pub_tool_debuginfo.h" /* VG_(get_fnname) */
47
48#include "pub_tool_oset.h" /* ordered set stuff */
49
50 /* instruction special cases */
51#define REP_INSTRUCTION 0x1
52#define FLDCW_INSTRUCTION 0x2
53
54 /* interval variables */
55#define DEFAULT_GRAIN_SIZE 100000000 /* 100 million by default */
56static Int interval_size=DEFAULT_GRAIN_SIZE;
57
58 /* filenames */
florian19f91bb2012-11-10 22:29:54 +000059static const HChar *clo_bb_out_file="bb.out.%p";
60static const HChar *clo_pc_out_file="pc.out.%p";
61static HChar *pc_out_file=NULL;
62static HChar *bb_out_file=NULL;
njndbebecc2009-07-14 01:39:54 +000063
64
65 /* output parameters */
66static Bool instr_count_only=False;
67static Bool generate_pc_file=False;
68
njndbebecc2009-07-14 01:39:54 +000069 /* Global values */
70static OSet* instr_info_table; /* table that holds the basic block info */
71static Int block_num=1; /* global next block number */
72static Int current_thread=0;
73static Int allocated_threads=1;
74struct thread_info *bbv_thread=NULL;
75
76 /* Per-thread variables */
77struct thread_info {
78 ULong dyn_instr; /* Current retired instruction count */
79 ULong total_instr; /* Total retired instruction count */
80 Addr last_rep_addr; /* rep counting values */
81 ULong rep_count;
82 ULong global_rep_count;
83 ULong unique_rep_count;
84 ULong fldcw_count; /* fldcw count */
florian12d2eb52014-10-30 22:17:56 +000085 VgFile *bbtrace_fp; /* file pointer */
njndbebecc2009-07-14 01:39:54 +000086};
87
njndbebecc2009-07-14 01:39:54 +000088struct BB_info {
89 Addr BB_addr; /* used as key, must be first */
90 Int n_instrs; /* instructions in the basic block */
91 Int block_num; /* unique block identifier */
92 Int *inst_counter; /* times entered * num_instructions */
93 Bool is_entry; /* is this block a function entry point */
florian46cc0452014-10-25 19:20:38 +000094 const HChar *fn_name; /* Function block is in */
njndbebecc2009-07-14 01:39:54 +000095};
96
97
98 /* dump the optional PC file, which contains basic block number to */
99 /* instruction address and function name mappings */
100static void dumpPcFile(void)
101{
102 struct BB_info *bb_elem;
florian12d2eb52014-10-30 22:17:56 +0000103 VgFile *fp;
njndbebecc2009-07-14 01:39:54 +0000104
105 pc_out_file =
106 VG_(expand_file_name)("--pc-out-file", clo_pc_out_file);
107
florian12d2eb52014-10-30 22:17:56 +0000108 fp = VG_(fopen)(pc_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
109 VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
110 if (fp == NULL) {
sewardj0cf3e782009-07-15 14:50:37 +0000111 VG_(umsg)("Error: cannot create pc file %s\n", pc_out_file);
njndbebecc2009-07-14 01:39:54 +0000112 VG_(exit)(1);
njndbebecc2009-07-14 01:39:54 +0000113 }
114
115 /* Loop through the table, printing the number, address, */
116 /* and function name for each basic block */
117 VG_(OSetGen_ResetIter)(instr_info_table);
118 while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
florian16eef852015-08-03 21:05:20 +0000119 VG_(fprintf)( fp, "F:%d:%lx:%s\n", bb_elem->block_num,
120 bb_elem->BB_addr, bb_elem->fn_name);
njndbebecc2009-07-14 01:39:54 +0000121 }
122
florian12d2eb52014-10-30 22:17:56 +0000123 VG_(fclose)(fp);
njndbebecc2009-07-14 01:39:54 +0000124}
125
florian12d2eb52014-10-30 22:17:56 +0000126static VgFile *open_tracefile(Int thread_num)
njndbebecc2009-07-14 01:39:54 +0000127{
florian12d2eb52014-10-30 22:17:56 +0000128 VgFile *fp;
129 // Allocate a buffer large enough for the general case "%s.%d" below
130 HChar temp_string[VG_(strlen)(bb_out_file) + 1 + 10 + 1];
njndbebecc2009-07-14 01:39:54 +0000131
132 /* For thread 1, don't append any thread number */
133 /* This lets the single-thread case not have any */
134 /* extra values appended to the file name. */
135 if (thread_num==1) {
florian12d2eb52014-10-30 22:17:56 +0000136 VG_(strcpy)(temp_string, bb_out_file);
njndbebecc2009-07-14 01:39:54 +0000137 }
138 else {
139 VG_(sprintf)(temp_string,"%s.%d",bb_out_file,thread_num);
140 }
141
florian12d2eb52014-10-30 22:17:56 +0000142 fp = VG_(fopen)(temp_string, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
143 VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
njndbebecc2009-07-14 01:39:54 +0000144
florian12d2eb52014-10-30 22:17:56 +0000145 if (fp == NULL) {
sewardj0cf3e782009-07-15 14:50:37 +0000146 VG_(umsg)("Error: cannot create bb file %s\n",temp_string);
njndbebecc2009-07-14 01:39:54 +0000147 VG_(exit)(1);
148 }
149
florian12d2eb52014-10-30 22:17:56 +0000150 return fp;
njndbebecc2009-07-14 01:39:54 +0000151}
152
153static void handle_overflow(void)
154{
155 struct BB_info *bb_elem;
156
157 if (bbv_thread[current_thread].dyn_instr > interval_size) {
158
159 if (!instr_count_only) {
160
florian12d2eb52014-10-30 22:17:56 +0000161 /* If our output file hasn't been opened, open it */
162 if (bbv_thread[current_thread].bbtrace_fp == NULL) {
163 bbv_thread[current_thread].bbtrace_fp=open_tracefile(current_thread);
njndbebecc2009-07-14 01:39:54 +0000164 }
165
166 /* put an entry to the bb.out file */
167
florian12d2eb52014-10-30 22:17:56 +0000168 VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "T");
njndbebecc2009-07-14 01:39:54 +0000169
170 VG_(OSetGen_ResetIter)(instr_info_table);
171 while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
172 if ( bb_elem->inst_counter[current_thread] != 0 ) {
florian12d2eb52014-10-30 22:17:56 +0000173 VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, ":%d:%d ",
174 bb_elem->block_num,
175 bb_elem->inst_counter[current_thread]);
njndbebecc2009-07-14 01:39:54 +0000176 bb_elem->inst_counter[current_thread] = 0;
177 }
178 }
179
florian12d2eb52014-10-30 22:17:56 +0000180 VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "\n");
njndbebecc2009-07-14 01:39:54 +0000181 }
182
183 bbv_thread[current_thread].dyn_instr -= interval_size;
184 }
185}
186
187
188static void close_out_reps(void)
189{
190 bbv_thread[current_thread].global_rep_count+=bbv_thread[current_thread].rep_count;
191 bbv_thread[current_thread].unique_rep_count++;
192 bbv_thread[current_thread].rep_count=0;
193}
194
195 /* Generic function to get called each instruction */
196static VG_REGPARM(1) void per_instruction_BBV(struct BB_info *bbInfo)
197{
198 Int n_instrs=1;
199
200 tl_assert(bbInfo);
201
202 /* we finished rep but didn't clear out count */
203 if (bbv_thread[current_thread].rep_count) {
204 n_instrs++;
205 close_out_reps();
206 }
207
208 bbInfo->inst_counter[current_thread]+=n_instrs;
209
210 bbv_thread[current_thread].total_instr+=n_instrs;
211 bbv_thread[current_thread].dyn_instr +=n_instrs;
212
213 handle_overflow();
214}
215
216 /* Function to get called if instruction has a rep prefix */
217static VG_REGPARM(1) void per_instruction_BBV_rep(Addr addr)
218{
219 /* handle back-to-back rep instructions */
220 if (bbv_thread[current_thread].last_rep_addr!=addr) {
221 if (bbv_thread[current_thread].rep_count) {
222 close_out_reps();
223 bbv_thread[current_thread].total_instr++;
224 bbv_thread[current_thread].dyn_instr++;
225 }
226 bbv_thread[current_thread].last_rep_addr=addr;
227 }
228
229 bbv_thread[current_thread].rep_count++;
230
231}
232
233 /* Function to call if our instruction has a fldcw instruction */
234static VG_REGPARM(1) void per_instruction_BBV_fldcw(struct BB_info *bbInfo)
235{
236 Int n_instrs=1;
237
238 tl_assert(bbInfo);
239
240 /* we finished rep but didn't clear out count */
241 if (bbv_thread[current_thread].rep_count) {
242 n_instrs++;
243 close_out_reps();
244 }
245
246 /* count fldcw instructions */
247 bbv_thread[current_thread].fldcw_count++;
248
249 bbInfo->inst_counter[current_thread]+=n_instrs;
250
251 bbv_thread[current_thread].total_instr+=n_instrs;
252 bbv_thread[current_thread].dyn_instr +=n_instrs;
253
254 handle_overflow();
255}
256
257 /* Check if the instruction pointed to is one that needs */
258 /* special handling. If so, set a bit in the return */
259 /* value indicating what type. */
florianf466eef2015-01-02 17:32:40 +0000260static Int get_inst_type(UInt len, Addr addr)
njndbebecc2009-07-14 01:39:54 +0000261{
262 int result=0;
263
264#if defined(VGA_x86) || defined(VGA_amd64)
265
florian19f91bb2012-11-10 22:29:54 +0000266 UChar *inst_pointer;
267 UChar inst_byte;
njndbebecc2009-07-14 01:39:54 +0000268 int i,possible_rep;
269
270 /* rep prefixed instructions are counted as one instruction on */
271 /* x86 processors and must be handled as a special case */
272
273 /* Also, the rep prefix is re-used as part of the opcode for */
274 /* SSE instructions. So we need to specifically check for */
275 /* the following: movs, cmps, scas, lods, stos, ins, outs */
276
florian19f91bb2012-11-10 22:29:54 +0000277 inst_pointer=(UChar *)addr;
njndbebecc2009-07-14 01:39:54 +0000278 i=0;
279 inst_byte=0;
280 possible_rep=0;
281
282 while (i<len) {
283
284 inst_byte=*inst_pointer;
285
286 if ( (inst_byte == 0x67) || /* size override prefix */
287 (inst_byte == 0x66) || /* size override prefix */
288 (inst_byte == 0x48) ) { /* 64-bit prefix */
289 } else if ( (inst_byte == 0xf2) || /* rep prefix */
290 (inst_byte == 0xf3) ) { /* repne prefix */
291 possible_rep=1;
292 } else {
293 break; /* other byte, exit */
294 }
295
296 i++;
297 inst_pointer++;
298 }
299
300 if ( possible_rep &&
301 ( ( (inst_byte >= 0xa4) && /* movs,cmps,scas */
302 (inst_byte <= 0xaf) ) || /* lods,stos */
303 ( (inst_byte >= 0x6c) &&
304 (inst_byte <= 0x6f) ) ) ) { /* ins,outs */
305
306 result|=REP_INSTRUCTION;
307 }
308
309 /* fldcw instructions are double-counted by the hardware */
310 /* performance counters on pentium 4 processors so it is */
311 /* useful to have that count when doing validation work. */
312
florian19f91bb2012-11-10 22:29:54 +0000313 inst_pointer=(UChar *)addr;
njndbebecc2009-07-14 01:39:54 +0000314 if (len>1) {
315 /* FLDCW detection */
316 /* opcode is 0xd9/5, ie 1101 1001 oo10 1mmm */
317 if ((*inst_pointer==0xd9) &&
318 (*(inst_pointer+1)<0xb0) && /* need this case of fldz, etc, count */
319 ( (*(inst_pointer+1) & 0x38) == 0x28)) {
320 result|=FLDCW_INSTRUCTION;
321 }
322 }
323
324#endif
325 return result;
326}
327
328
329
330 /* Our instrumentation function */
331 /* sbIn = super block to translate */
332 /* layout = guest layout */
333 /* gWordTy = size of guest word */
334 /* hWordTy = size of host word */
335static IRSB* bbv_instrument ( VgCallbackClosure* closure,
florian3c0c9472014-09-24 12:06:55 +0000336 IRSB* sbIn, const VexGuestLayout* layout,
337 const VexGuestExtents* vge,
338 const VexArchInfo* archinfo_host,
339 IRType gWordTy, IRType hWordTy )
njndbebecc2009-07-14 01:39:54 +0000340{
341 Int i,n_instrs=1;
342 IRSB *sbOut;
343 IRStmt *st;
344 struct BB_info *bbInfo;
florianf466eef2015-01-02 17:32:40 +0000345 Addr origAddr,ourAddr;
njndbebecc2009-07-14 01:39:54 +0000346 IRDirty *di;
347 IRExpr **argv, *arg1;
348 Int regparms,opcode_type;
349
350 /* We don't handle a host/guest word size mismatch */
351 if (gWordTy != hWordTy) {
352 VG_(tool_panic)("host/guest word size mismatch");
353 }
354
355 /* Set up SB */
356 sbOut = deepCopyIRSBExceptStmts(sbIn);
357
358 /* Copy verbatim any IR preamble preceding the first IMark */
359 i = 0;
360 while ( (i < sbIn->stmts_used) && (sbIn->stmts[i]->tag!=Ist_IMark)) {
361 addStmtToIRSB( sbOut, sbIn->stmts[i] );
362 i++;
363 }
364
365 /* Get the first statement */
366 tl_assert(sbIn->stmts_used > 0);
367 st = sbIn->stmts[i];
368
369 /* double check we are at a Mark statement */
370 tl_assert(Ist_IMark == st->tag);
371
372 origAddr=st->Ist.IMark.addr;
373
374 /* Get the BB_info */
375 bbInfo = VG_(OSetGen_Lookup)(instr_info_table, &origAddr);
376
377 if (bbInfo==NULL) {
378
379 /* BB never translated before (at this address, at least; */
380 /* could have been unloaded and then reloaded elsewhere in memory) */
381
382 /* allocate and initialize a new basic block structure */
383 bbInfo=VG_(OSetGen_AllocNode)(instr_info_table, sizeof(struct BB_info));
384 bbInfo->BB_addr = origAddr;
385 bbInfo->n_instrs = n_instrs;
386 bbInfo->inst_counter=VG_(calloc)("bbv_instrument",
387 allocated_threads,
388 sizeof(Int));
389
390 /* assign a unique block number */
391 bbInfo->block_num=block_num;
392 block_num++;
393 /* get function name and entry point information */
florian46cc0452014-10-25 19:20:38 +0000394 const HChar *fn_name;
floriandc4ff1a2015-03-12 18:56:21 +0000395 VG_(get_fnname)(origAddr, &fn_name);
florian46cc0452014-10-25 19:20:38 +0000396 bbInfo->is_entry=VG_(get_fnname_if_entry)(origAddr, &fn_name);
397 bbInfo->fn_name =VG_(strdup)("bbv_strings", fn_name);
njndbebecc2009-07-14 01:39:54 +0000398 /* insert structure into table */
399 VG_(OSetGen_Insert)( instr_info_table, bbInfo );
400 }
401
402 /* Iterate through the basic block, putting the original */
403 /* instructions in place, plus putting a call to updateBBV */
404 /* for each original instruction */
405
406 /* This is less efficient than only instrumenting the BB */
407 /* But it gives proper results given the fact that */
408 /* valgrind uses superblocks (not basic blocks) by default */
409
410
411 while(i < sbIn->stmts_used) {
412 st=sbIn->stmts[i];
413
414 if (st->tag == Ist_IMark) {
415
416 ourAddr = st->Ist.IMark.addr;
417
418 opcode_type=get_inst_type(st->Ist.IMark.len,ourAddr);
419
420 regparms=1;
421 arg1= mkIRExpr_HWord( (HWord)bbInfo);
422 argv= mkIRExprVec_1(arg1);
423
424
425 if (opcode_type&REP_INSTRUCTION) {
426 arg1= mkIRExpr_HWord(ourAddr);
427 argv= mkIRExprVec_1(arg1);
428 di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV_rep",
429 VG_(fnptr_to_fnentry)( &per_instruction_BBV_rep ),
430 argv);
431 }
432 else if (opcode_type&FLDCW_INSTRUCTION) {
433 di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV_fldcw",
434 VG_(fnptr_to_fnentry)( &per_instruction_BBV_fldcw ),
435 argv);
436 }
437 else {
438 di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV",
439 VG_(fnptr_to_fnentry)( &per_instruction_BBV ),
440 argv);
441 }
442
443
444 /* Insert our call */
445 addStmtToIRSB( sbOut, IRStmt_Dirty(di));
446 }
447
448 /* Insert the original instruction */
449 addStmtToIRSB( sbOut, st );
450
451 i++;
452 }
453
454 return sbOut;
455}
456
457static struct thread_info *allocate_new_thread(struct thread_info *old,
458 Int old_number, Int new_number)
459{
460 struct thread_info *temp;
461 struct BB_info *bb_elem;
462 Int i;
463
464 temp=VG_(realloc)("bbv_main.c allocate_threads",
465 old,
466 new_number*sizeof(struct thread_info));
467
468 /* init the new thread */
469 /* We loop in case the new thread is not contiguous */
470 for(i=old_number;i<new_number;i++) {
471 temp[i].last_rep_addr=0;
472 temp[i].dyn_instr=0;
473 temp[i].total_instr=0;
474 temp[i].global_rep_count=0;
475 temp[i].unique_rep_count=0;
476 temp[i].rep_count=0;
477 temp[i].fldcw_count=0;
florian12d2eb52014-10-30 22:17:56 +0000478 temp[i].bbtrace_fp=NULL;
njndbebecc2009-07-14 01:39:54 +0000479 }
480 /* expand the inst_counter on all allocated basic blocks */
481 VG_(OSetGen_ResetIter)(instr_info_table);
482 while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
483 bb_elem->inst_counter =
484 VG_(realloc)("bbv_main.c inst_counter",
485 bb_elem->inst_counter,
486 new_number*sizeof(Int));
487 for(i=old_number;i<new_number;i++) {
488 bb_elem->inst_counter[i]=0;
489 }
490 }
491
492 return temp;
493}
494
495static void bbv_thread_called ( ThreadId tid, ULong nDisp )
496{
497 if (tid >= allocated_threads) {
498 bbv_thread=allocate_new_thread(bbv_thread,allocated_threads,tid+1);
499 allocated_threads=tid+1;
500 }
501 current_thread=tid;
502}
503
504
505
506
507/*--------------------------------------------------------------------*/
508/*--- Setup ---*/
509/*--------------------------------------------------------------------*/
510
511static void bbv_post_clo_init(void)
512{
513 bb_out_file =
514 VG_(expand_file_name)("--bb-out-file", clo_bb_out_file);
515
516 /* Try a closer approximation of basic blocks */
517 /* This is the same as the command line option */
518 /* --vex-guest-chase-thresh=0 */
519 VG_(clo_vex_control).guest_chase_thresh = 0;
520}
521
522 /* Parse the command line options */
florian19f91bb2012-11-10 22:29:54 +0000523static Bool bbv_process_cmd_line_option(const HChar* arg)
njndbebecc2009-07-14 01:39:54 +0000524{
525 if VG_INT_CLO (arg, "--interval-size", interval_size) {}
526 else if VG_STR_CLO (arg, "--bb-out-file", clo_bb_out_file) {}
527 else if VG_STR_CLO (arg, "--pc-out-file", clo_pc_out_file) {
528 generate_pc_file = True;
529 }
njn738184a2009-08-05 23:59:05 +0000530 else if VG_BOOL_CLO (arg, "--instr-count-only", instr_count_only) {}
njndbebecc2009-07-14 01:39:54 +0000531 else {
532 return False;
533 }
534
535 return True;
536}
537
538static void bbv_print_usage(void)
539{
njn738184a2009-08-05 23:59:05 +0000540 VG_(printf)(
541" --bb-out-file=<file> filename for BBV info\n"
542" --pc-out-file=<file> filename for BB addresses and function names\n"
543" --interval-size=<num> interval size\n"
544" --instr-count-only=yes|no only print total instruction count\n"
545 );
njndbebecc2009-07-14 01:39:54 +0000546}
547
548static void bbv_print_debug_usage(void)
549{
550 VG_(printf)(" (none)\n");
551}
552
553static void bbv_fini(Int exitcode)
554{
555 Int i;
556
557 if (generate_pc_file) {
558 dumpPcFile();
559 }
560
561 for(i=0;i<allocated_threads;i++) {
562
563 if (bbv_thread[i].total_instr!=0) {
florian12d2eb52014-10-30 22:17:56 +0000564 HChar buf[500]; // large enough
njndbebecc2009-07-14 01:39:54 +0000565 VG_(sprintf)(buf,"\n\n"
566 "# Thread %d\n"
567 "# Total intervals: %d (Interval Size %d)\n"
florian16eef852015-08-03 21:05:20 +0000568 "# Total instructions: %llu\n"
569 "# Total reps: %llu\n"
570 "# Unique reps: %llu\n"
571 "# Total fldcw instructions: %llu\n\n",
njndbebecc2009-07-14 01:39:54 +0000572 i,
573 (Int)(bbv_thread[i].total_instr/(ULong)interval_size),
574 interval_size,
575 bbv_thread[i].total_instr,
576 bbv_thread[i].global_rep_count,
577 bbv_thread[i].unique_rep_count,
578 bbv_thread[i].fldcw_count);
579
580 /* Print results to display */
sewardj0cf3e782009-07-15 14:50:37 +0000581 VG_(umsg)("%s\n", buf);
njndbebecc2009-07-14 01:39:54 +0000582
583 /* open the output file if it hasn't already */
florian12d2eb52014-10-30 22:17:56 +0000584 if (bbv_thread[i].bbtrace_fp == NULL) {
585 bbv_thread[i].bbtrace_fp=open_tracefile(i);
njndbebecc2009-07-14 01:39:54 +0000586 }
587 /* Also print to results file */
florian12d2eb52014-10-30 22:17:56 +0000588 VG_(fprintf)(bbv_thread[i].bbtrace_fp, "%s", buf);
589 VG_(fclose)(bbv_thread[i].bbtrace_fp);
njndbebecc2009-07-14 01:39:54 +0000590 }
591 }
592}
593
594static void bbv_pre_clo_init(void)
595{
596 VG_(details_name) ("exp-bbv");
597 VG_(details_version) (NULL);
598 VG_(details_description) ("a SimPoint basic block vector generator");
599 VG_(details_copyright_author)(
Elliott Hughesed398002017-06-21 14:41:24 -0700600 "Copyright (C) 2006-2017 Vince Weaver");
njndbebecc2009-07-14 01:39:54 +0000601 VG_(details_bug_reports_to) (VG_BUGS_TO);
602
603 VG_(basic_tool_funcs) (bbv_post_clo_init,
604 bbv_instrument,
605 bbv_fini);
606
607 VG_(needs_command_line_options)(bbv_process_cmd_line_option,
608 bbv_print_usage,
609 bbv_print_debug_usage);
610
611 VG_(track_start_client_code)( bbv_thread_called );
612
613
614 instr_info_table = VG_(OSetGen_Create)(/*keyOff*/0,
615 NULL,
616 VG_(malloc), "bbv.1", VG_(free));
617
618 bbv_thread=allocate_new_thread(bbv_thread,0,allocated_threads);
619}
620
621VG_DETERMINE_INTERFACE_VERSION(bbv_pre_clo_init)
622
623/*--------------------------------------------------------------------*/
624/*--- end ---*/
625/*--------------------------------------------------------------------*/