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