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
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2006-2011 Vince Weaver
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vince _at_ csl.cornell.edu
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pcfile code is Copyright (C) 2006-2011 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 */
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar *clo_bb_out_file="bb.out.%p";
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar *clo_pc_out_file="pc.out.%p";
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar *pc_out_file=NULL;
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar *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 */
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar 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 */
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar      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;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar 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
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned char *inst_pointer;
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned char 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
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   inst_pointer=(unsigned char *)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
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   inst_pointer=(unsigned char *)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,
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRType gWordTy, IRType hWordTy )
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      i,n_instrs=1;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB     *sbOut;
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt   *st;
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct BB_info  *bbInfo;
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64   origAddr,ourAddr;
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty  *di;
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr   **argv, *arg1;
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      regparms,opcode_type;
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We don't handle a host/guest word size mismatch */
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gWordTy != hWordTy) {
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("host/guest word size mismatch");
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set up SB */
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sbOut = deepCopyIRSBExceptStmts(sbIn);
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Copy verbatim any IR preamble preceding the first IMark */
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   i = 0;
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (i < sbIn->stmts_used) && (sbIn->stmts[i]->tag!=Ist_IMark)) {
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, sbIn->stmts[i] );
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      i++;
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get the first statement */
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sbIn->stmts_used > 0);
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   st = sbIn->stmts[i];
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* double check we are at a Mark statement */
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(Ist_IMark == st->tag);
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   origAddr=st->Ist.IMark.addr;
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get the BB_info */
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbInfo = VG_(OSetGen_Lookup)(instr_info_table, &origAddr);
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bbInfo==NULL) {
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* BB never translated before (at this address, at least;          */
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* could have been unloaded and then reloaded elsewhere in memory) */
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* allocate and initialize a new basic block structure */
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo=VG_(OSetGen_AllocNode)(instr_info_table, sizeof(struct BB_info));
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo->BB_addr = origAddr;
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo->n_instrs = n_instrs;
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo->inst_counter=VG_(calloc)("bbv_instrument",
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       allocated_threads,
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       sizeof(Int));
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* assign a unique block number */
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo->block_num=block_num;
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      block_num++;
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* get function name and entry point information */
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_fnname)(origAddr,bbInfo->fn_name,FUNCTION_NAME_LENGTH);
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbInfo->is_entry=VG_(get_fnname_if_entry)(origAddr, bbInfo->fn_name,
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                FUNCTION_NAME_LENGTH);
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* insert structure into table */
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(OSetGen_Insert)( instr_info_table, bbInfo );
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Iterate through the basic block, putting the original   */
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* instructions in place, plus putting a call to updateBBV */
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* for each original instruction                           */
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less efficient than only instrumenting the BB   */
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* But it gives proper results given the fact that         */
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* valgrind uses superblocks (not basic blocks) by default */
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while(i < sbIn->stmts_used) {
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st=sbIn->stmts[i];
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_IMark) {
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ourAddr = st->Ist.IMark.addr;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opcode_type=get_inst_type(st->Ist.IMark.len,ourAddr);
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regparms=1;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         arg1= mkIRExpr_HWord( (HWord)bbInfo);
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         argv= mkIRExprVec_1(arg1);
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opcode_type&REP_INSTRUCTION) {
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            arg1= mkIRExpr_HWord(ourAddr);
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            argv= mkIRExprVec_1(arg1);
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV_rep",
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                VG_(fnptr_to_fnentry)( &per_instruction_BBV_rep ),
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                argv);
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (opcode_type&FLDCW_INSTRUCTION) {
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV_fldcw",
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                VG_(fnptr_to_fnentry)( &per_instruction_BBV_fldcw ),
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                argv);
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         di= unsafeIRDirty_0_N( regparms, "per_instruction_BBV",
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                VG_(fnptr_to_fnentry)( &per_instruction_BBV ),
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                argv);
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Insert our call */
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( sbOut,  IRStmt_Dirty(di));
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Insert the original instruction */
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( sbOut, st );
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      i++;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sbOut;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic struct thread_info *allocate_new_thread(struct thread_info *old,
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     Int old_number, Int new_number)
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct thread_info *temp;
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct BB_info   *bb_elem;
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   temp=VG_(realloc)("bbv_main.c allocate_threads",
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     old,
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     new_number*sizeof(struct thread_info));
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* init the new thread */
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We loop in case the new thread is not contiguous */
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for(i=old_number;i<new_number;i++) {
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].last_rep_addr=0;
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].dyn_instr=0;
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].total_instr=0;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].global_rep_count=0;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].unique_rep_count=0;
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].rep_count=0;
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].fldcw_count=0;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      temp[i].bbtrace_fd=-1;
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* expand the inst_counter on all allocated basic blocks */
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(OSetGen_ResetIter)(instr_info_table);
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb_elem->inst_counter =
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_(realloc)("bbv_main.c inst_counter",
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 bb_elem->inst_counter,
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 new_number*sizeof(Int));
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for(i=old_number;i<new_number;i++) {
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bb_elem->inst_counter[i]=0;
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return temp;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_thread_called ( ThreadId tid, ULong nDisp )
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tid >= allocated_threads) {
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bbv_thread=allocate_new_thread(bbv_thread,allocated_threads,tid+1);
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allocated_threads=tid+1;
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   current_thread=tid;
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Setup                                                        ---*/
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_post_clo_init(void)
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb_out_file =
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          VG_(expand_file_name)("--bb-out-file", clo_bb_out_file);
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Try a closer approximation of basic blocks  */
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the same as the command line option */
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --vex-guest-chase-thresh=0                  */
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(clo_vex_control).guest_chase_thresh = 0;
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Parse the command line options */
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool bbv_process_cmd_line_option(Char* arg)
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if VG_INT_CLO       (arg, "--interval-size",    interval_size) {}
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO  (arg, "--bb-out-file",      clo_bb_out_file) {}
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_STR_CLO  (arg, "--pc-out-file",      clo_pc_out_file) {
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      generate_pc_file = True;
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if VG_BOOL_CLO (arg, "--instr-count-only", instr_count_only) {}
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_print_usage(void)
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)(
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   --bb-out-file=<file>       filename for BBV info\n"
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   --pc-out-file=<file>       filename for BB addresses and function names\n"
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   --interval-size=<num>      interval size\n"
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown"   --instr-count-only=yes|no  only print total instruction count\n"
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_print_debug_usage(void)
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("    (none)\n");
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_fini(Int exitcode)
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (generate_pc_file) {
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dumpPcFile();
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for(i=0;i<allocated_threads;i++) {
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (bbv_thread[i].total_instr!=0) {
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(sprintf)(buf,"\n\n"
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "# Thread %d\n"
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "#   Total intervals: %d (Interval Size %d)\n"
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "#   Total instructions: %lld\n"
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "#   Total reps: %lld\n"
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "#   Unique reps: %lld\n"
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "#   Total fldcw instructions: %lld\n\n",
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                i,
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (Int)(bbv_thread[i].total_instr/(ULong)interval_size),
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                interval_size,
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                bbv_thread[i].total_instr,
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                bbv_thread[i].global_rep_count,
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                bbv_thread[i].unique_rep_count,
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                bbv_thread[i].fldcw_count);
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Print results to display */
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(umsg)("%s\n", buf);
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* open the output file if it hasn't already */
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (bbv_thread[i].bbtrace_fd < 0) {
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bbv_thread[i].bbtrace_fd=open_tracefile(i);
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Also print to results file */
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(write)(bbv_thread[i].bbtrace_fd,(void*)buf,VG_(strlen)(buf));
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(close)(bbv_thread[i].bbtrace_fd);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void bbv_pre_clo_init(void)
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_name)            ("exp-bbv");
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_version)         (NULL);
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_description)     ("a SimPoint basic block vector generator");
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_copyright_author)(
610b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      "Copyright (C) 2006-2011 Vince Weaver");
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(details_bug_reports_to)  (VG_BUGS_TO);
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(basic_tool_funcs)          (bbv_post_clo_init,
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   bbv_instrument,
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   bbv_fini);
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(needs_command_line_options)(bbv_process_cmd_line_option,
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   bbv_print_usage,
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   bbv_print_debug_usage);
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(track_start_client_code)( bbv_thread_called );
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instr_info_table = VG_(OSetGen_Create)(/*keyOff*/0,
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          NULL,
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          VG_(malloc), "bbv.1", VG_(free));
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bbv_thread=allocate_new_thread(bbv_thread,0,allocated_threads);
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_DETERMINE_INTERFACE_VERSION(bbv_pre_clo_init)
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
636