| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1 |  | 
 | 2 | /*--------------------------------------------------------------------*/ | 
 | 3 | /*--- Callgrind                                                    ---*/ | 
 | 4 | /*---                                                       main.c ---*/ | 
 | 5 | /*--------------------------------------------------------------------*/ | 
 | 6 |  | 
 | 7 | /* | 
 | 8 |    This file is part of Callgrind, a Valgrind tool for call graph | 
 | 9 |    profiling programs. | 
 | 10 |  | 
| sewardj | 9eecbbb | 2010-05-03 21:37:12 +0000 | [diff] [blame] | 11 |    Copyright (C) 2002-2010, Josef Weidendorfer (Josef.Weidendorfer@gmx.de) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 12 |  | 
| njn | 9a0cba4 | 2007-04-15 22:15:57 +0000 | [diff] [blame] | 13 |    This tool is derived from and contains code from Cachegrind | 
| sewardj | 9eecbbb | 2010-05-03 21:37:12 +0000 | [diff] [blame] | 14 |    Copyright (C) 2002-2010 Nicholas Nethercote (njn@valgrind.org) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 15 |  | 
 | 16 |    This program is free software; you can redistribute it and/or | 
 | 17 |    modify it under the terms of the GNU General Public License as | 
 | 18 |    published by the Free Software Foundation; either version 2 of the | 
 | 19 |    License, or (at your option) any later version. | 
 | 20 |  | 
 | 21 |    This program is distributed in the hope that it will be useful, but | 
 | 22 |    WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 23 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 24 |    General Public License for more details. | 
 | 25 |  | 
 | 26 |    You should have received a copy of the GNU General Public License | 
 | 27 |    along with this program; if not, write to the Free Software | 
 | 28 |    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | 
 | 29 |    02111-1307, USA. | 
 | 30 |  | 
 | 31 |    The GNU General Public License is contained in the file COPYING. | 
 | 32 | */ | 
 | 33 |  | 
 | 34 | #include "config.h" | 
 | 35 | #include "callgrind.h" | 
 | 36 | #include "global.h" | 
 | 37 |  | 
 | 38 | #include <pub_tool_threadstate.h> | 
 | 39 |  | 
 | 40 | /*------------------------------------------------------------*/ | 
 | 41 | /*--- Global variables                                     ---*/ | 
 | 42 | /*------------------------------------------------------------*/ | 
 | 43 |  | 
 | 44 | /* for all threads */ | 
 | 45 | CommandLineOptions CLG_(clo); | 
 | 46 | Statistics CLG_(stat); | 
 | 47 | Bool CLG_(instrument_state) = True; /* Instrumentation on ? */ | 
 | 48 |  | 
 | 49 | /* thread and signal handler specific */ | 
 | 50 | exec_state CLG_(current_state); | 
 | 51 |  | 
 | 52 |  | 
 | 53 | /*------------------------------------------------------------*/ | 
 | 54 | /*--- Statistics                                           ---*/ | 
 | 55 | /*------------------------------------------------------------*/ | 
 | 56 |  | 
 | 57 | static void CLG_(init_statistics)(Statistics* s) | 
 | 58 | { | 
 | 59 |   s->call_counter        = 0; | 
 | 60 |   s->jcnd_counter        = 0; | 
 | 61 |   s->jump_counter        = 0; | 
 | 62 |   s->rec_call_counter    = 0; | 
 | 63 |   s->ret_counter         = 0; | 
 | 64 |   s->bb_executions       = 0; | 
 | 65 |  | 
 | 66 |   s->context_counter     = 0; | 
 | 67 |   s->bb_retranslations   = 0; | 
 | 68 |  | 
 | 69 |   s->distinct_objs       = 0; | 
 | 70 |   s->distinct_files      = 0; | 
 | 71 |   s->distinct_fns        = 0; | 
 | 72 |   s->distinct_contexts   = 0; | 
 | 73 |   s->distinct_bbs        = 0; | 
 | 74 |   s->distinct_bbccs      = 0; | 
 | 75 |   s->distinct_instrs     = 0; | 
 | 76 |   s->distinct_skips      = 0; | 
 | 77 |  | 
 | 78 |   s->bb_hash_resizes     = 0; | 
 | 79 |   s->bbcc_hash_resizes   = 0; | 
 | 80 |   s->jcc_hash_resizes    = 0; | 
 | 81 |   s->cxt_hash_resizes    = 0; | 
 | 82 |   s->fn_array_resizes    = 0; | 
 | 83 |   s->call_stack_resizes  = 0; | 
 | 84 |   s->fn_stack_resizes    = 0; | 
 | 85 |  | 
 | 86 |   s->full_debug_BBs      = 0; | 
 | 87 |   s->file_line_debug_BBs = 0; | 
 | 88 |   s->fn_name_debug_BBs   = 0; | 
 | 89 |   s->no_debug_BBs        = 0; | 
 | 90 |   s->bbcc_lru_misses     = 0; | 
 | 91 |   s->jcc_lru_misses      = 0; | 
 | 92 |   s->cxt_lru_misses      = 0; | 
 | 93 |   s->bbcc_clones         = 0; | 
 | 94 | } | 
 | 95 |  | 
 | 96 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 97 | /*------------------------------------------------------------*/ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 98 | /*--- Instrumentation structures and event queue handling  ---*/ | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 99 | /*------------------------------------------------------------*/ | 
 | 100 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 101 | /* Maintain an ordered list of memory events which are outstanding, in | 
 | 102 |    the sense that no IR has yet been generated to do the relevant | 
 | 103 |    helper calls.  The BB is scanned top to bottom and memory events | 
 | 104 |    are added to the end of the list, merging with the most recent | 
 | 105 |    notified event where possible (Dw immediately following Dr and | 
 | 106 |    having the same size and EA can be merged). | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 107 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 108 |    This merging is done so that for architectures which have | 
 | 109 |    load-op-store instructions (x86, amd64), the insn is treated as if | 
 | 110 |    it makes just one memory reference (a modify), rather than two (a | 
 | 111 |    read followed by a write at the same address). | 
 | 112 |  | 
 | 113 |    At various points the list will need to be flushed, that is, IR | 
 | 114 |    generated from it.  That must happen before any possible exit from | 
 | 115 |    the block (the end, or an IRStmt_Exit).  Flushing also takes place | 
 | 116 |    when there is no space to add a new event. | 
 | 117 |  | 
 | 118 |    If we require the simulation statistics to be up to date with | 
 | 119 |    respect to possible memory exceptions, then the list would have to | 
 | 120 |    be flushed before each memory reference.  That would however lose | 
 | 121 |    performance by inhibiting event-merging during flushing. | 
 | 122 |  | 
 | 123 |    Flushing the list consists of walking it start to end and emitting | 
 | 124 |    instrumentation IR for each event, in the order in which they | 
 | 125 |    appear.  It may be possible to emit a single call for two adjacent | 
 | 126 |    events in order to reduce the number of helper function calls made. | 
 | 127 |    For example, it could well be profitable to handle two adjacent Ir | 
 | 128 |    events with a single helper call.  */ | 
 | 129 |  | 
 | 130 | typedef | 
 | 131 |    IRExpr | 
 | 132 |    IRAtom; | 
 | 133 |  | 
 | 134 | typedef | 
 | 135 |    enum { | 
 | 136 |       Ev_Ir,  // Instruction read | 
 | 137 |       Ev_Dr,  // Data read | 
 | 138 |       Ev_Dw,  // Data write | 
 | 139 |       Ev_Dm,  // Data modify (read then write) | 
 | 140 |    } | 
 | 141 |    EventTag; | 
 | 142 |  | 
 | 143 | typedef | 
 | 144 |    struct { | 
 | 145 |       EventTag   tag; | 
 | 146 |       InstrInfo* inode; | 
 | 147 |       union { | 
 | 148 | 	 struct { | 
 | 149 | 	 } Ir; | 
 | 150 | 	 struct { | 
 | 151 | 	    IRAtom* ea; | 
 | 152 | 	    Int     szB; | 
 | 153 | 	 } Dr; | 
 | 154 | 	 struct { | 
 | 155 | 	    IRAtom* ea; | 
 | 156 | 	    Int     szB; | 
 | 157 | 	 } Dw; | 
 | 158 | 	 struct { | 
 | 159 | 	    IRAtom* ea; | 
 | 160 | 	    Int     szB; | 
 | 161 | 	 } Dm; | 
 | 162 |       } Ev; | 
 | 163 |    } | 
 | 164 |    Event; | 
 | 165 |  | 
 | 166 | static void init_Event ( Event* ev ) { | 
 | 167 |    VG_(memset)(ev, 0, sizeof(Event)); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 168 | } | 
 | 169 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 170 | static IRAtom* get_Event_dea ( Event* ev ) { | 
 | 171 |    switch (ev->tag) { | 
 | 172 |       case Ev_Dr: return ev->Ev.Dr.ea; | 
 | 173 |       case Ev_Dw: return ev->Ev.Dw.ea; | 
 | 174 |       case Ev_Dm: return ev->Ev.Dm.ea; | 
 | 175 |       default:    tl_assert(0); | 
 | 176 |    } | 
 | 177 | } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 178 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 179 | static Int get_Event_dszB ( Event* ev ) { | 
 | 180 |    switch (ev->tag) { | 
 | 181 |       case Ev_Dr: return ev->Ev.Dr.szB; | 
 | 182 |       case Ev_Dw: return ev->Ev.Dw.szB; | 
 | 183 |       case Ev_Dm: return ev->Ev.Dm.szB; | 
 | 184 |       default:    tl_assert(0); | 
 | 185 |    } | 
 | 186 | } | 
 | 187 |  | 
 | 188 |  | 
 | 189 | /* Up to this many unnotified events are allowed.  Number is | 
 | 190 |    arbitrary.  Larger numbers allow more event merging to occur, but | 
 | 191 |    potentially induce more spilling due to extending live ranges of | 
 | 192 |    address temporaries. */ | 
 | 193 | #define N_EVENTS 16 | 
 | 194 |  | 
 | 195 |  | 
 | 196 | /* A struct which holds all the running state during instrumentation. | 
 | 197 |    Mostly to avoid passing loads of parameters everywhere. */ | 
 | 198 | typedef struct { | 
 | 199 |     /* The current outstanding-memory-event list. */ | 
 | 200 |     Event events[N_EVENTS]; | 
 | 201 |     Int   events_used; | 
 | 202 |  | 
 | 203 |     /* The array of InstrInfo's is part of BB struct. */ | 
 | 204 |     BB* bb; | 
 | 205 |  | 
 | 206 |     /* BB seen before (ie. re-instrumentation) */ | 
 | 207 |     Bool seen_before; | 
 | 208 |  | 
 | 209 |     /* Number InstrInfo bins 'used' so far. */ | 
 | 210 |     UInt ii_index; | 
 | 211 |  | 
 | 212 |     // current offset of guest instructions from BB start | 
 | 213 |     UInt instr_offset; | 
 | 214 |  | 
 | 215 |     /* The output SB being constructed. */ | 
 | 216 |     IRSB* sbOut; | 
 | 217 | } ClgState; | 
 | 218 |  | 
 | 219 |  | 
 | 220 | static void showEvent ( Event* ev ) | 
 | 221 | { | 
 | 222 |    switch (ev->tag) { | 
 | 223 |       case Ev_Ir: | 
 | 224 | 	 VG_(printf)("Ir (InstrInfo %p) at +%d\n", | 
 | 225 | 		     ev->inode, ev->inode->instr_offset); | 
 | 226 | 	 break; | 
 | 227 |       case Ev_Dr: | 
 | 228 | 	 VG_(printf)("Dr (InstrInfo %p) at +%d %d EA=", | 
 | 229 | 		     ev->inode, ev->inode->instr_offset, ev->Ev.Dr.szB); | 
 | 230 | 	 ppIRExpr(ev->Ev.Dr.ea); | 
 | 231 | 	 VG_(printf)("\n"); | 
 | 232 | 	 break; | 
 | 233 |       case Ev_Dw: | 
 | 234 | 	 VG_(printf)("Dw (InstrInfo %p) at +%d %d EA=", | 
 | 235 | 		     ev->inode, ev->inode->instr_offset, ev->Ev.Dw.szB); | 
 | 236 | 	 ppIRExpr(ev->Ev.Dw.ea); | 
 | 237 | 	 VG_(printf)("\n"); | 
 | 238 | 	 break; | 
 | 239 |       case Ev_Dm: | 
 | 240 | 	 VG_(printf)("Dm (InstrInfo %p) at +%d %d EA=", | 
 | 241 | 		     ev->inode, ev->inode->instr_offset, ev->Ev.Dm.szB); | 
 | 242 | 	 ppIRExpr(ev->Ev.Dm.ea); | 
 | 243 | 	 VG_(printf)("\n"); | 
 | 244 | 	 break; | 
 | 245 |       default: | 
 | 246 | 	 tl_assert(0); | 
 | 247 | 	 break; | 
 | 248 |    } | 
 | 249 | } | 
 | 250 |  | 
 | 251 | /* Generate code for all outstanding memory events, and mark the queue | 
 | 252 |    empty.  Code is generated into cgs->sbOut, and this activity | 
 | 253 |    'consumes' slots in cgs->bb. */ | 
 | 254 |  | 
 | 255 | static void flushEvents ( ClgState* clgs ) | 
 | 256 | { | 
 | 257 |    Int        i, regparms, inew; | 
 | 258 |    Char*      helperName; | 
 | 259 |    void*      helperAddr; | 
 | 260 |    IRExpr**   argv; | 
 | 261 |    IRExpr*    i_node_expr; | 
 | 262 |    IRDirty*   di; | 
 | 263 |    Event*     ev; | 
 | 264 |    Event*     ev2; | 
 | 265 |    Event*     ev3; | 
 | 266 |  | 
 | 267 |    if (!clgs->seen_before) { | 
 | 268 |        // extend event sets as needed | 
 | 269 |        // available sets: D0 Dr | 
 | 270 |        for(i=0; i<clgs->events_used; i++) { | 
 | 271 | 	   ev  = &clgs->events[i]; | 
 | 272 | 	   switch(ev->tag) { | 
 | 273 | 	   case Ev_Ir: | 
 | 274 | 	       // Ir event always is first for a guest instruction | 
 | 275 | 	       CLG_ASSERT(ev->inode->eventset == 0); | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 276 | 	       ev->inode->eventset = CLG_(sets).base; | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 277 | 	       break; | 
 | 278 | 	   case Ev_Dr: | 
 | 279 | 	       // extend event set by Dr counter | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 280 | 	       ev->inode->eventset = CLG_(add_event_group)(ev->inode->eventset, | 
 | 281 | 							   EG_DR); | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 282 | 	       break; | 
 | 283 | 	   case Ev_Dw: | 
 | 284 | 	   case Ev_Dm: | 
 | 285 | 	       // extend event set by Dw counter | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 286 | 	       ev->inode->eventset = CLG_(add_event_group)(ev->inode->eventset, | 
 | 287 | 							   EG_DW); | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 288 | 	       break; | 
 | 289 | 	   default: | 
 | 290 | 	       tl_assert(0); | 
 | 291 | 	   } | 
 | 292 |        } | 
 | 293 |    } | 
 | 294 |  | 
 | 295 |    for(i = 0; i < clgs->events_used; i = inew) { | 
 | 296 |  | 
 | 297 |       helperName = NULL; | 
 | 298 |       helperAddr = NULL; | 
 | 299 |       argv       = NULL; | 
 | 300 |       regparms   = 0; | 
 | 301 |  | 
 | 302 |       /* generate IR to notify event i and possibly the ones | 
 | 303 | 	 immediately following it. */ | 
 | 304 |       tl_assert(i >= 0 && i < clgs->events_used); | 
 | 305 |  | 
 | 306 |       ev  = &clgs->events[i]; | 
 | 307 |       ev2 = ( i < clgs->events_used-1 ? &clgs->events[i+1] : NULL ); | 
 | 308 |       ev3 = ( i < clgs->events_used-2 ? &clgs->events[i+2] : NULL ); | 
 | 309 |  | 
 | 310 |       CLG_DEBUGIF(5) { | 
 | 311 | 	 VG_(printf)("   flush "); | 
 | 312 | 	 showEvent( ev ); | 
 | 313 |       } | 
 | 314 |  | 
 | 315 |       i_node_expr = mkIRExpr_HWord( (HWord)ev->inode ); | 
 | 316 |  | 
 | 317 |       /* Decide on helper fn to call and args to pass it, and advance | 
 | 318 | 	 i appropriately. | 
 | 319 | 	 Dm events have same effect as Dw events */ | 
 | 320 |       switch (ev->tag) { | 
 | 321 | 	 case Ev_Ir: | 
 | 322 | 	    /* Merge an Ir with a following Dr. */ | 
 | 323 | 	    if (ev2 && ev2->tag == Ev_Dr) { | 
 | 324 | 	       /* Why is this true?  It's because we're merging an Ir | 
 | 325 | 		  with a following Dr.  The Ir derives from the | 
 | 326 | 		  instruction's IMark and the Dr from data | 
 | 327 | 		  references which follow it.  In short it holds | 
 | 328 | 		  because each insn starts with an IMark, hence an | 
 | 329 | 		  Ev_Ir, and so these Dr must pertain to the | 
 | 330 | 		  immediately preceding Ir.  Same applies to analogous | 
 | 331 | 		  assertions in the subsequent cases. */ | 
 | 332 | 	       tl_assert(ev2->inode == ev->inode); | 
 | 333 | 	       helperName = CLG_(cachesim).log_1I1Dr_name; | 
 | 334 | 	       helperAddr = CLG_(cachesim).log_1I1Dr; | 
 | 335 | 	       argv = mkIRExprVec_3( i_node_expr, | 
 | 336 | 				     get_Event_dea(ev2), | 
 | 337 | 				     mkIRExpr_HWord( get_Event_dszB(ev2) ) ); | 
 | 338 | 	       regparms = 3; | 
 | 339 | 	       inew = i+2; | 
 | 340 | 	    } | 
 | 341 | 	    /* Merge an Ir with a following Dw/Dm. */ | 
 | 342 | 	    else | 
 | 343 | 	    if (ev2 && (ev2->tag == Ev_Dw || ev2->tag == Ev_Dm)) { | 
 | 344 | 	       tl_assert(ev2->inode == ev->inode); | 
 | 345 | 	       helperName = CLG_(cachesim).log_1I1Dw_name; | 
 | 346 | 	       helperAddr = CLG_(cachesim).log_1I1Dw; | 
 | 347 | 	       argv = mkIRExprVec_3( i_node_expr, | 
 | 348 | 				     get_Event_dea(ev2), | 
 | 349 | 				     mkIRExpr_HWord( get_Event_dszB(ev2) ) ); | 
 | 350 | 	       regparms = 3; | 
 | 351 | 	       inew = i+2; | 
 | 352 | 	    } | 
 | 353 | 	    /* Merge an Ir with two following Irs. */ | 
 | 354 | 	    else | 
 | 355 | 	    if (ev2 && ev3 && ev2->tag == Ev_Ir && ev3->tag == Ev_Ir) { | 
 | 356 | 	       helperName = CLG_(cachesim).log_3I0D_name; | 
 | 357 | 	       helperAddr = CLG_(cachesim).log_3I0D; | 
 | 358 | 	       argv = mkIRExprVec_3( i_node_expr, | 
 | 359 | 				     mkIRExpr_HWord( (HWord)ev2->inode ), | 
 | 360 | 				     mkIRExpr_HWord( (HWord)ev3->inode ) ); | 
 | 361 | 	       regparms = 3; | 
 | 362 | 	       inew = i+3; | 
 | 363 | 	    } | 
 | 364 | 	    /* Merge an Ir with one following Ir. */ | 
 | 365 | 	    else | 
 | 366 | 	    if (ev2 && ev2->tag == Ev_Ir) { | 
 | 367 | 	       helperName = CLG_(cachesim).log_2I0D_name; | 
 | 368 | 	       helperAddr = CLG_(cachesim).log_2I0D; | 
 | 369 | 	       argv = mkIRExprVec_2( i_node_expr, | 
 | 370 | 				     mkIRExpr_HWord( (HWord)ev2->inode ) ); | 
 | 371 | 	       regparms = 2; | 
 | 372 | 	       inew = i+2; | 
 | 373 | 	    } | 
 | 374 | 	    /* No merging possible; emit as-is. */ | 
 | 375 | 	    else { | 
 | 376 | 	       helperName = CLG_(cachesim).log_1I0D_name; | 
 | 377 | 	       helperAddr = CLG_(cachesim).log_1I0D; | 
 | 378 | 	       argv = mkIRExprVec_1( i_node_expr ); | 
 | 379 | 	       regparms = 1; | 
 | 380 | 	       inew = i+1; | 
 | 381 | 	    } | 
 | 382 | 	    break; | 
 | 383 | 	 case Ev_Dr: | 
 | 384 | 	    /* Data read or modify */ | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 385 | 	    helperName = CLG_(cachesim).log_0I1Dr_name; | 
 | 386 | 	    helperAddr = CLG_(cachesim).log_0I1Dr; | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 387 | 	    argv = mkIRExprVec_3( i_node_expr, | 
 | 388 | 				  get_Event_dea(ev), | 
 | 389 | 				  mkIRExpr_HWord( get_Event_dszB(ev) ) ); | 
 | 390 | 	    regparms = 3; | 
 | 391 | 	    inew = i+1; | 
 | 392 | 	    break; | 
 | 393 | 	 case Ev_Dw: | 
 | 394 | 	 case Ev_Dm: | 
 | 395 | 	    /* Data write */ | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 396 | 	    helperName = CLG_(cachesim).log_0I1Dw_name; | 
 | 397 | 	    helperAddr = CLG_(cachesim).log_0I1Dw; | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 398 | 	    argv = mkIRExprVec_3( i_node_expr, | 
 | 399 | 				  get_Event_dea(ev), | 
 | 400 | 				  mkIRExpr_HWord( get_Event_dszB(ev) ) ); | 
 | 401 | 	    regparms = 3; | 
 | 402 | 	    inew = i+1; | 
 | 403 | 	    break; | 
 | 404 | 	 default: | 
 | 405 | 	    tl_assert(0); | 
 | 406 |       } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 407 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 408 |       CLG_DEBUGIF(5) { | 
 | 409 | 	  if (inew > i+1) { | 
 | 410 | 	      VG_(printf)("   merge "); | 
 | 411 | 	      showEvent( ev2 ); | 
 | 412 | 	  } | 
 | 413 | 	  if (inew > i+2) { | 
 | 414 | 	      VG_(printf)("   merge "); | 
 | 415 | 	      showEvent( ev3 ); | 
 | 416 | 	  } | 
 | 417 | 	  if (helperAddr) | 
 | 418 | 	      VG_(printf)("   call  %s (%p)\n", | 
 | 419 | 			  helperName, helperAddr); | 
 | 420 |       } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 421 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 422 |       /* helper could be unset depending on the simulator used */ | 
 | 423 |       if (helperAddr == 0) continue; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 424 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 425 |       /* Add the helper. */ | 
 | 426 |       tl_assert(helperName); | 
 | 427 |       tl_assert(helperAddr); | 
 | 428 |       tl_assert(argv); | 
 | 429 |       di = unsafeIRDirty_0_N( regparms, | 
 | 430 | 			      helperName, VG_(fnptr_to_fnentry)( helperAddr ), | 
 | 431 | 			      argv ); | 
 | 432 |       addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 433 |    } | 
 | 434 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 435 |    clgs->events_used = 0; | 
 | 436 | } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 437 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 438 | static void addEvent_Ir ( ClgState* clgs, InstrInfo* inode ) | 
 | 439 | { | 
 | 440 |    Event* evt; | 
 | 441 |    tl_assert(clgs->seen_before || (inode->eventset == 0)); | 
 | 442 |    if (!CLG_(clo).simulate_cache) return; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 443 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 444 |    if (clgs->events_used == N_EVENTS) | 
 | 445 |       flushEvents(clgs); | 
 | 446 |    tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS); | 
 | 447 |    evt = &clgs->events[clgs->events_used]; | 
 | 448 |    init_Event(evt); | 
 | 449 |    evt->tag      = Ev_Ir; | 
 | 450 |    evt->inode    = inode; | 
 | 451 |    clgs->events_used++; | 
 | 452 | } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 453 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 454 | static | 
 | 455 | void addEvent_Dr ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea ) | 
 | 456 | { | 
 | 457 |    Event* evt; | 
 | 458 |    tl_assert(isIRAtom(ea)); | 
 | 459 |    tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE); | 
 | 460 |    if (!CLG_(clo).simulate_cache) return; | 
| weidendo | c8e7615 | 2006-05-27 15:30:58 +0000 | [diff] [blame] | 461 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 462 |    if (clgs->events_used == N_EVENTS) | 
 | 463 |       flushEvents(clgs); | 
 | 464 |    tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS); | 
 | 465 |    evt = &clgs->events[clgs->events_used]; | 
 | 466 |    init_Event(evt); | 
 | 467 |    evt->tag       = Ev_Dr; | 
 | 468 |    evt->inode     = inode; | 
 | 469 |    evt->Ev.Dr.szB = datasize; | 
 | 470 |    evt->Ev.Dr.ea  = ea; | 
 | 471 |    clgs->events_used++; | 
 | 472 | } | 
| weidendo | c8e7615 | 2006-05-27 15:30:58 +0000 | [diff] [blame] | 473 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 474 | static | 
 | 475 | void addEvent_Dw ( ClgState* clgs, InstrInfo* inode, Int datasize, IRAtom* ea ) | 
 | 476 | { | 
 | 477 |    Event* lastEvt; | 
 | 478 |    Event* evt; | 
 | 479 |    tl_assert(isIRAtom(ea)); | 
 | 480 |    tl_assert(datasize >= 1 && datasize <= MIN_LINE_SIZE); | 
 | 481 |    if (!CLG_(clo).simulate_cache) return; | 
| weidendo | c8e7615 | 2006-05-27 15:30:58 +0000 | [diff] [blame] | 482 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 483 |    /* Is it possible to merge this write with the preceding read? */ | 
 | 484 |    lastEvt = &clgs->events[clgs->events_used-1]; | 
 | 485 |    if (clgs->events_used > 0 | 
 | 486 |        && lastEvt->tag       == Ev_Dr | 
 | 487 |        && lastEvt->Ev.Dr.szB == datasize | 
 | 488 |        && lastEvt->inode     == inode | 
 | 489 |        && eqIRAtom(lastEvt->Ev.Dr.ea, ea)) | 
 | 490 |    { | 
 | 491 |       lastEvt->tag   = Ev_Dm; | 
 | 492 |       return; | 
 | 493 |    } | 
| weidendo | c8e7615 | 2006-05-27 15:30:58 +0000 | [diff] [blame] | 494 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 495 |    /* No.  Add as normal. */ | 
 | 496 |    if (clgs->events_used == N_EVENTS) | 
 | 497 |       flushEvents(clgs); | 
 | 498 |    tl_assert(clgs->events_used >= 0 && clgs->events_used < N_EVENTS); | 
 | 499 |    evt = &clgs->events[clgs->events_used]; | 
 | 500 |    init_Event(evt); | 
 | 501 |    evt->tag       = Ev_Dw; | 
 | 502 |    evt->inode     = inode; | 
 | 503 |    evt->Ev.Dw.szB = datasize; | 
 | 504 |    evt->Ev.Dw.ea  = ea; | 
 | 505 |    clgs->events_used++; | 
 | 506 | } | 
 | 507 |  | 
 | 508 | /* Initialise or check (if already seen before) an InstrInfo for next insn. | 
 | 509 |    We only can set instr_offset/instr_size here. The required event set and | 
 | 510 |    resulting cost offset depend on events (Ir/Dr/Dw/Dm) in guest | 
 | 511 |    instructions. The event set is extended as required on flush of the event | 
 | 512 |    queue (when Dm events were determined), cost offsets are determined at | 
 | 513 |    end of BB instrumentation. */ | 
 | 514 | static | 
 | 515 | InstrInfo* next_InstrInfo ( ClgState* clgs, UInt instr_size ) | 
 | 516 | { | 
 | 517 |    InstrInfo* ii; | 
 | 518 |    tl_assert(clgs->ii_index >= 0); | 
 | 519 |    tl_assert(clgs->ii_index < clgs->bb->instr_count); | 
 | 520 |    ii = &clgs->bb->instr[ clgs->ii_index ]; | 
 | 521 |  | 
 | 522 |    if (clgs->seen_before) { | 
 | 523 |        CLG_ASSERT(ii->instr_offset == clgs->instr_offset); | 
 | 524 |        CLG_ASSERT(ii->instr_size == instr_size); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 525 |    } | 
 | 526 |    else { | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 527 |        ii->instr_offset = clgs->instr_offset; | 
 | 528 |        ii->instr_size = instr_size; | 
 | 529 |        ii->cost_offset = 0; | 
 | 530 |        ii->eventset = 0; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 531 |    } | 
 | 532 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 533 |    clgs->ii_index++; | 
 | 534 |    clgs->instr_offset += instr_size; | 
 | 535 |    CLG_(stat).distinct_instrs++; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 536 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 537 |    return ii; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 538 | } | 
 | 539 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 540 | // return total number of cost values needed for this BB | 
 | 541 | static | 
 | 542 | UInt update_cost_offsets( ClgState* clgs ) | 
 | 543 | { | 
 | 544 |     Int i; | 
 | 545 |     InstrInfo* ii; | 
 | 546 |     UInt cost_offset = 0; | 
 | 547 |  | 
 | 548 |     CLG_ASSERT(clgs->bb->instr_count == clgs->ii_index); | 
 | 549 |     for(i=0; i<clgs->ii_index; i++) { | 
 | 550 | 	ii = &clgs->bb->instr[i]; | 
 | 551 | 	if (clgs->seen_before) { | 
 | 552 | 	    CLG_ASSERT(ii->cost_offset == cost_offset); | 
 | 553 | 	} else | 
 | 554 | 	    ii->cost_offset = cost_offset; | 
 | 555 | 	cost_offset += ii->eventset ? ii->eventset->size : 0; | 
 | 556 |     } | 
 | 557 |  | 
 | 558 |     return cost_offset; | 
 | 559 | } | 
 | 560 |  | 
 | 561 | /*------------------------------------------------------------*/ | 
 | 562 | /*--- Instrumentation                                      ---*/ | 
 | 563 | /*------------------------------------------------------------*/ | 
 | 564 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 565 | #if defined(VG_BIGENDIAN) | 
 | 566 | # define CLGEndness Iend_BE | 
 | 567 | #elif defined(VG_LITTLEENDIAN) | 
 | 568 | # define CLGEndness Iend_LE | 
 | 569 | #else | 
 | 570 | # error "Unknown endianness" | 
 | 571 | #endif | 
 | 572 |  | 
 | 573 | static | 
 | 574 | Addr IRConst2Addr(IRConst* con) | 
 | 575 | { | 
 | 576 |     Addr addr; | 
 | 577 |  | 
 | 578 |     if (sizeof(Addr) == 4) { | 
 | 579 | 	CLG_ASSERT( con->tag == Ico_U32 ); | 
 | 580 | 	addr = con->Ico.U32; | 
 | 581 |     } | 
 | 582 |     else if (sizeof(Addr) == 8) { | 
 | 583 | 	CLG_ASSERT( con->tag == Ico_U64 ); | 
 | 584 | 	addr = con->Ico.U64; | 
 | 585 |     } | 
 | 586 |     else | 
 | 587 | 	VG_(tool_panic)("Callgrind: invalid Addr type"); | 
 | 588 |  | 
 | 589 |     return addr; | 
 | 590 | } | 
 | 591 |  | 
 | 592 | /* First pass over a BB to instrument, counting instructions and jumps | 
 | 593 |  * This is needed for the size of the BB struct to allocate | 
 | 594 |  * | 
 | 595 |  * Called from CLG_(get_bb) | 
 | 596 |  */ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 597 | void CLG_(collectBlockInfo)(IRSB* sbIn, | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 598 | 			    /*INOUT*/ UInt* instrs, | 
 | 599 | 			    /*INOUT*/ UInt* cjmps, | 
 | 600 | 			    /*INOUT*/ Bool* cjmp_inverted) | 
 | 601 | { | 
 | 602 |     Int i; | 
 | 603 |     IRStmt* st; | 
 | 604 |     Addr instrAddr =0, jumpDst; | 
 | 605 |     UInt instrLen = 0; | 
 | 606 |     Bool toNextInstr = False; | 
 | 607 |  | 
 | 608 |     // Ist_Exit has to be ignored in preamble code, before first IMark: | 
 | 609 |     // preamble code is added by VEX for self modifying code, and has | 
 | 610 |     // nothing to do with client code | 
 | 611 |     Bool inPreamble = True; | 
 | 612 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 613 |     if (!sbIn) return; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 614 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 615 |     for (i = 0; i < sbIn->stmts_used; i++) { | 
 | 616 | 	  st = sbIn->stmts[i]; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 617 | 	  if (Ist_IMark == st->tag) { | 
 | 618 | 	      inPreamble = False; | 
 | 619 |  | 
 | 620 | 	      instrAddr = (Addr)ULong_to_Ptr(st->Ist.IMark.addr); | 
 | 621 | 	      instrLen  = st->Ist.IMark.len; | 
 | 622 |  | 
 | 623 | 	      (*instrs)++; | 
 | 624 | 	      toNextInstr = False; | 
 | 625 | 	  } | 
 | 626 | 	  if (inPreamble) continue; | 
 | 627 | 	  if (Ist_Exit == st->tag) { | 
 | 628 | 	      jumpDst = IRConst2Addr(st->Ist.Exit.dst); | 
 | 629 | 	      toNextInstr =  (jumpDst == instrAddr + instrLen); | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 630 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 631 | 	      (*cjmps)++; | 
 | 632 | 	  } | 
 | 633 |     } | 
 | 634 |  | 
 | 635 |     /* if the last instructions of BB conditionally jumps to next instruction | 
 | 636 |      * (= first instruction of next BB in memory), this is a inverted by VEX. | 
 | 637 |      */ | 
 | 638 |     *cjmp_inverted = toNextInstr; | 
 | 639 | } | 
 | 640 |  | 
 | 641 | static | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 642 | void addConstMemStoreStmt( IRSB* bbOut, UWord addr, UInt val, IRType hWordTy) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 643 | { | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 644 |     addStmtToIRSB( bbOut, | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 645 | 		   IRStmt_Store(CLGEndness, | 
 | 646 | 				IRExpr_Const(hWordTy == Ity_I32 ? | 
 | 647 | 					     IRConst_U32( addr ) : | 
 | 648 | 					     IRConst_U64( addr )), | 
 | 649 | 				IRExpr_Const(IRConst_U32(val)) )); | 
 | 650 | }    | 
 | 651 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 652 |  | 
 | 653 | /* add helper call to setup_bbcc, with pointer to BB struct as argument | 
 | 654 |  * | 
 | 655 |  * precondition for setup_bbcc: | 
 | 656 |  * - jmps_passed has number of cond.jumps passed in last executed BB | 
 | 657 |  * - current_bbcc has a pointer to the BBCC of the last executed BB | 
 | 658 |  *   Thus, if bbcc_jmpkind is != -1 (JmpNone), | 
 | 659 |  *     current_bbcc->bb->jmp_addr | 
 | 660 |  *   gives the address of the jump source. | 
 | 661 |  * | 
 | 662 |  * the setup does 2 things: | 
 | 663 |  * - trace call: | 
 | 664 |  *   * Unwind own call stack, i.e sync our ESP with real ESP | 
 | 665 |  *     This is for ESP manipulation (longjmps, C++ exec handling) and RET | 
 | 666 |  *   * For CALLs or JMPs crossing objects, record call arg + | 
 | 667 |  *     push are on own call stack | 
 | 668 |  * | 
 | 669 |  * - prepare for cache log functions: | 
 | 670 |  *   set current_bbcc to BBCC that gets the costs for this BB execution | 
 | 671 |  *   attached | 
 | 672 |  */ | 
 | 673 | static | 
 | 674 | void addBBSetupCall(ClgState* clgs) | 
 | 675 | { | 
 | 676 |    IRDirty* di; | 
 | 677 |    IRExpr  *arg1, **argv; | 
 | 678 |  | 
 | 679 |    arg1 = mkIRExpr_HWord( (HWord)clgs->bb ); | 
 | 680 |    argv = mkIRExprVec_1(arg1); | 
 | 681 |    di = unsafeIRDirty_0_N( 1, "setup_bbcc", | 
 | 682 | 			      VG_(fnptr_to_fnentry)( & CLG_(setup_bbcc) ), | 
 | 683 | 			      argv); | 
 | 684 |    addStmtToIRSB( clgs->sbOut, IRStmt_Dirty(di) ); | 
 | 685 | } | 
 | 686 |  | 
 | 687 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 688 | static | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 689 | IRSB* CLG_(instrument)( VgCallbackClosure* closure, | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 690 | 			IRSB* sbIn, | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 691 | 			VexGuestLayout* layout, | 
 | 692 | 			VexGuestExtents* vge, | 
 | 693 | 			IRType gWordTy, IRType hWordTy ) | 
 | 694 | { | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 695 |    Int      i, isize; | 
 | 696 |    IRStmt*  st; | 
 | 697 |    Addr     origAddr; | 
 | 698 |    InstrInfo* curr_inode = NULL; | 
 | 699 |    ClgState clgs; | 
 | 700 |    UInt     cJumps = 0; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 701 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 702 |  | 
 | 703 |    if (gWordTy != hWordTy) { | 
 | 704 |       /* We don't currently support this case. */ | 
 | 705 |       VG_(tool_panic)("host/guest word size mismatch"); | 
 | 706 |    } | 
 | 707 |  | 
 | 708 |    // No instrumentation if it is switched off | 
 | 709 |    if (! CLG_(instrument_state)) { | 
| bart | a0b6b2c | 2008-07-07 06:49:24 +0000 | [diff] [blame] | 710 |        CLG_DEBUG(5, "instrument(BB %#lx) [Instrumentation OFF]\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 711 | 		 (Addr)closure->readdr); | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 712 |        return sbIn; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 713 |    } | 
 | 714 |  | 
| bart | a0b6b2c | 2008-07-07 06:49:24 +0000 | [diff] [blame] | 715 |    CLG_DEBUG(3, "+ instrument(BB %#lx)\n", (Addr)closure->readdr); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 716 |  | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 717 |    /* Set up SB for instrumented IR */ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 718 |    clgs.sbOut = deepCopyIRSBExceptStmts(sbIn); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 719 |  | 
 | 720 |    // Copy verbatim any IR preamble preceding the first IMark | 
 | 721 |    i = 0; | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 722 |    while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) { | 
 | 723 |       addStmtToIRSB( clgs.sbOut, sbIn->stmts[i] ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 724 |       i++; | 
 | 725 |    } | 
 | 726 |  | 
 | 727 |    // Get the first statement, and origAddr from it | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 728 |    CLG_ASSERT(sbIn->stmts_used >0); | 
 | 729 |    CLG_ASSERT(i < sbIn->stmts_used); | 
 | 730 |    st = sbIn->stmts[i]; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 731 |    CLG_ASSERT(Ist_IMark == st->tag); | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 732 |  | 
 | 733 |    origAddr = (Addr)st->Ist.IMark.addr; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 734 |    CLG_ASSERT(origAddr == st->Ist.IMark.addr);  // XXX: check no overflow | 
 | 735 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 736 |    /* Get BB struct (creating if necessary). | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 737 |     * JS: The hash table is keyed with orig_addr_noredir -- important! | 
 | 738 |     * JW: Why? If it is because of different chasing of the redirection, | 
 | 739 |     *     this is not needed, as chasing is switched off in callgrind | 
 | 740 |     */ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 741 |    clgs.bb = CLG_(get_bb)(origAddr, sbIn, &(clgs.seen_before)); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 742 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 743 |    addBBSetupCall(&clgs); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 744 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 745 |    // Set up running state | 
 | 746 |    clgs.events_used = 0; | 
 | 747 |    clgs.ii_index = 0; | 
 | 748 |    clgs.instr_offset = 0; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 749 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 750 |    for (/*use current i*/; i < sbIn->stmts_used; i++) { | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 751 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 752 |       st = sbIn->stmts[i]; | 
 | 753 |       CLG_ASSERT(isFlatIRStmt(st)); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 754 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 755 |       switch (st->tag) { | 
 | 756 | 	 case Ist_NoOp: | 
 | 757 | 	 case Ist_AbiHint: | 
 | 758 | 	 case Ist_Put: | 
 | 759 | 	 case Ist_PutI: | 
 | 760 | 	 case Ist_MBE: | 
 | 761 | 	    break; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 762 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 763 | 	 case Ist_IMark: { | 
 | 764 | 	    CLG_ASSERT(clgs.instr_offset == (Addr)st->Ist.IMark.addr - origAddr); | 
 | 765 | 	    isize = st->Ist.IMark.len; | 
 | 766 | 	    // If Vex fails to decode an instruction, the size will be zero. | 
 | 767 | 	    // Pretend otherwise. | 
 | 768 | 	    if (isize == 0) isize = VG_MIN_INSTR_SZB; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 769 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 770 | 	    // Sanity-check size. | 
 | 771 | 	    tl_assert( (VG_MIN_INSTR_SZB <= isize && isize <= VG_MAX_INSTR_SZB) | 
 | 772 | 		     || VG_CLREQ_SZB == isize ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 773 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 774 | 	    // Init the inode, record it as the current one. | 
 | 775 | 	    // Subsequent Dr/Dw/Dm events from the same instruction will | 
 | 776 | 	    // also use it. | 
 | 777 | 	    curr_inode = next_InstrInfo (&clgs, isize); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 778 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 779 | 	    addEvent_Ir( &clgs, curr_inode ); | 
 | 780 | 	    break; | 
 | 781 | 	 } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 782 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 783 | 	 case Ist_WrTmp: { | 
 | 784 | 	    IRExpr* data = st->Ist.WrTmp.data; | 
 | 785 | 	    if (data->tag == Iex_Load) { | 
 | 786 | 	       IRExpr* aexpr = data->Iex.Load.addr; | 
 | 787 | 	       // Note also, endianness info is ignored.  I guess | 
 | 788 | 	       // that's not interesting. | 
 | 789 | 	       addEvent_Dr( &clgs, curr_inode, | 
 | 790 | 			    sizeofIRType(data->Iex.Load.ty), aexpr ); | 
 | 791 | 	    } | 
 | 792 | 	    break; | 
 | 793 | 	 } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 794 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 795 | 	 case Ist_Store: { | 
 | 796 | 	    IRExpr* data  = st->Ist.Store.data; | 
 | 797 | 	    IRExpr* aexpr = st->Ist.Store.addr; | 
 | 798 | 	    addEvent_Dw( &clgs, curr_inode, | 
 | 799 | 			 sizeofIRType(typeOfIRExpr(sbIn->tyenv, data)), aexpr ); | 
 | 800 | 	    break; | 
 | 801 | 	 } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 802 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 803 | 	 case Ist_Dirty: { | 
 | 804 | 	    Int      dataSize; | 
 | 805 | 	    IRDirty* d = st->Ist.Dirty.details; | 
 | 806 | 	    if (d->mFx != Ifx_None) { | 
 | 807 | 	       /* This dirty helper accesses memory.  Collect the details. */ | 
 | 808 | 	       tl_assert(d->mAddr != NULL); | 
 | 809 | 	       tl_assert(d->mSize != 0); | 
 | 810 | 	       dataSize = d->mSize; | 
 | 811 | 	       // Large (eg. 28B, 108B, 512B on x86) data-sized | 
 | 812 | 	       // instructions will be done inaccurately, but they're | 
 | 813 | 	       // very rare and this avoids errors from hitting more | 
 | 814 | 	       // than two cache lines in the simulation. | 
 | 815 | 	       if (dataSize > MIN_LINE_SIZE) | 
 | 816 | 		  dataSize = MIN_LINE_SIZE; | 
 | 817 | 	       if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) | 
 | 818 | 		  addEvent_Dr( &clgs, curr_inode, dataSize, d->mAddr ); | 
 | 819 | 	       if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) | 
 | 820 | 		  addEvent_Dw( &clgs, curr_inode, dataSize, d->mAddr ); | 
 | 821 | 	    } else { | 
 | 822 | 	       tl_assert(d->mAddr == NULL); | 
 | 823 | 	       tl_assert(d->mSize == 0); | 
 | 824 | 	    } | 
 | 825 | 	    break; | 
 | 826 | 	 } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 827 |  | 
| sewardj | 1c0ce7a | 2009-07-01 08:10:49 +0000 | [diff] [blame] | 828 |          case Ist_CAS: { | 
 | 829 |             /* We treat it as a read and a write of the location.  I | 
 | 830 |                think that is the same behaviour as it was before IRCAS | 
 | 831 |                was introduced, since prior to that point, the Vex | 
 | 832 |                front ends would translate a lock-prefixed instruction | 
 | 833 |                into a (normal) read followed by a (normal) write. */ | 
 | 834 |             Int    dataSize; | 
 | 835 |             IRCAS* cas = st->Ist.CAS.details; | 
 | 836 |             CLG_ASSERT(cas->addr && isIRAtom(cas->addr)); | 
 | 837 |             CLG_ASSERT(cas->dataLo); | 
 | 838 |             dataSize = sizeofIRType(typeOfIRExpr(sbIn->tyenv, cas->dataLo)); | 
 | 839 |             if (cas->dataHi != NULL) | 
 | 840 |                dataSize *= 2; /* since this is a doubleword-cas */ | 
 | 841 |             addEvent_Dr( &clgs, curr_inode, dataSize, cas->addr ); | 
 | 842 |             addEvent_Dw( &clgs, curr_inode, dataSize, cas->addr ); | 
 | 843 |             break; | 
 | 844 |          } | 
| sewardj | db5907d | 2009-11-26 17:20:21 +0000 | [diff] [blame] | 845 |  | 
 | 846 |          case Ist_LLSC: { | 
 | 847 |             IRType dataTy; | 
 | 848 |             if (st->Ist.LLSC.storedata == NULL) { | 
 | 849 |                /* LL */ | 
 | 850 |                dataTy = typeOfIRTemp(sbIn->tyenv, st->Ist.LLSC.result); | 
 | 851 |                addEvent_Dr( &clgs, curr_inode, | 
 | 852 |                             sizeofIRType(dataTy), st->Ist.LLSC.addr ); | 
 | 853 |             } else { | 
 | 854 |                /* SC */ | 
 | 855 |                dataTy = typeOfIRExpr(sbIn->tyenv, st->Ist.LLSC.storedata); | 
 | 856 |                addEvent_Dw( &clgs, curr_inode, | 
 | 857 |                             sizeofIRType(dataTy), st->Ist.LLSC.addr ); | 
 | 858 |             } | 
 | 859 |             break; | 
 | 860 |          } | 
 | 861 |  | 
 | 862 |  	 case Ist_Exit: { | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 863 | 	    UInt jmps_passed; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 864 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 865 | 	    /* We may never reach the next statement, so need to flush | 
 | 866 | 	       all outstanding transactions now. */ | 
 | 867 | 	    flushEvents( &clgs ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 868 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 869 | 	    CLG_ASSERT(clgs.ii_index>0); | 
 | 870 | 	    if (!clgs.seen_before) { | 
 | 871 | 		clgs.bb->jmp[cJumps].instr = clgs.ii_index-1; | 
 | 872 | 		clgs.bb->jmp[cJumps].skip = False; | 
 | 873 | 	    } | 
 | 874 |  | 
 | 875 | 	    /* Update global variable jmps_passed before the jump | 
 | 876 | 	     * A correction is needed if VEX inverted the last jump condition | 
 | 877 | 	    */ | 
 | 878 | 	    jmps_passed = cJumps; | 
 | 879 | 	    if ((cJumps+1 == clgs.bb->cjmp_count) && clgs.bb->cjmp_inverted) | 
 | 880 | 		jmps_passed++; | 
 | 881 | 	    addConstMemStoreStmt( clgs.sbOut, | 
 | 882 | 				  (UWord) &CLG_(current_state).jmps_passed, | 
 | 883 | 				  jmps_passed, hWordTy); | 
 | 884 | 	    cJumps++; | 
 | 885 |  | 
 | 886 | 	    break; | 
 | 887 | 	 } | 
 | 888 |  | 
 | 889 | 	 default: | 
 | 890 | 	    tl_assert(0); | 
 | 891 | 	    break; | 
 | 892 |       } | 
 | 893 |  | 
 | 894 |       /* Copy the original statement */ | 
 | 895 |       addStmtToIRSB( clgs.sbOut, st ); | 
 | 896 |  | 
 | 897 |       CLG_DEBUGIF(5) { | 
 | 898 | 	 VG_(printf)("   pass  "); | 
 | 899 | 	 ppIRStmt(st); | 
 | 900 | 	 VG_(printf)("\n"); | 
 | 901 |       } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 902 |    } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 903 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 904 |    /* At the end of the bb.  Flush outstandings. */ | 
 | 905 |    flushEvents( &clgs ); | 
 | 906 |  | 
 | 907 |    /* Always update global variable jmps_passed at end of bb. | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 908 |     * A correction is needed if VEX inverted the last jump condition | 
 | 909 |     */ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 910 |    { | 
 | 911 |       UInt jmps_passed = cJumps; | 
 | 912 |       if (clgs.bb->cjmp_inverted) jmps_passed--; | 
 | 913 |       addConstMemStoreStmt( clgs.sbOut, | 
 | 914 | 			    (UWord) &CLG_(current_state).jmps_passed, | 
 | 915 | 			    jmps_passed, hWordTy); | 
 | 916 |    } | 
 | 917 |    CLG_ASSERT(clgs.bb->cjmp_count == cJumps); | 
 | 918 |    CLG_ASSERT(clgs.bb->instr_count = clgs.ii_index); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 919 |  | 
 | 920 |    /* This stores the instr of the call/ret at BB end */ | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 921 |    clgs.bb->jmp[cJumps].instr = clgs.ii_index-1; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 922 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 923 |    if (clgs.seen_before) { | 
 | 924 |        CLG_ASSERT(clgs.bb->cost_count == update_cost_offsets(&clgs)); | 
 | 925 |        CLG_ASSERT(clgs.bb->instr_len = clgs.instr_offset); | 
 | 926 |        CLG_ASSERT(clgs.bb->jmpkind == sbIn->jumpkind); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 927 |    } | 
 | 928 |    else { | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 929 |        clgs.bb->cost_count = update_cost_offsets(&clgs); | 
 | 930 |        clgs.bb->instr_len = clgs.instr_offset; | 
 | 931 |        clgs.bb->jmpkind = sbIn->jumpkind; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 932 |    } | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 933 |  | 
| bart | a0b6b2c | 2008-07-07 06:49:24 +0000 | [diff] [blame] | 934 |    CLG_DEBUG(3, "- instrument(BB %#lx): byteLen %u, CJumps %u, CostLen %u\n", | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 935 | 	     origAddr, clgs.bb->instr_len, | 
 | 936 | 	     clgs.bb->cjmp_count, clgs.bb->cost_count); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 937 |    if (cJumps>0) { | 
 | 938 |        CLG_DEBUG(3, "                     [ "); | 
 | 939 |        for (i=0;i<cJumps;i++) | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 940 | 	   CLG_DEBUG(3, "%d ", clgs.bb->jmp[i].instr); | 
 | 941 |        CLG_DEBUG(3, "], last inverted: %s \n", | 
 | 942 | 		 clgs.bb->cjmp_inverted ? "yes":"no"); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 943 |    } | 
 | 944 |  | 
| weidendo | 0a1951d | 2009-06-15 00:16:36 +0000 | [diff] [blame] | 945 |   return clgs.sbOut; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 946 | } | 
 | 947 |  | 
 | 948 | /*--------------------------------------------------------------------*/ | 
 | 949 | /*--- Discarding BB info                                           ---*/ | 
 | 950 | /*--------------------------------------------------------------------*/ | 
 | 951 |  | 
 | 952 | // Called when a translation is removed from the translation cache for | 
 | 953 | // any reason at all: to free up space, because the guest code was | 
 | 954 | // unmapped or modified, or for any arbitrary reason. | 
 | 955 | static | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 956 | void clg_discard_superblock_info ( Addr64 orig_addr64, VexGuestExtents vge ) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 957 | { | 
 | 958 |     Addr orig_addr = (Addr)orig_addr64; | 
 | 959 |  | 
 | 960 |     tl_assert(vge.n_used > 0); | 
 | 961 |  | 
 | 962 |    if (0) | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 963 |       VG_(printf)( "discard_superblock_info: %p, %p, %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 964 |                    (void*)(Addr)orig_addr, | 
 | 965 |                    (void*)(Addr)vge.base[0], (ULong)vge.len[0]); | 
 | 966 |  | 
 | 967 |    // Get BB info, remove from table, free BB info.  Simple!  Note that we | 
 | 968 |    // use orig_addr, not the first instruction address in vge. | 
 | 969 |    CLG_(delete_bb)(orig_addr); | 
 | 970 | } | 
 | 971 |  | 
 | 972 |  | 
 | 973 | /*------------------------------------------------------------*/ | 
 | 974 | /*--- CLG_(fini)() and related function                     ---*/ | 
 | 975 | /*------------------------------------------------------------*/ | 
 | 976 |  | 
 | 977 |  | 
 | 978 |  | 
 | 979 | static void zero_thread_cost(thread_info* t) | 
 | 980 | { | 
 | 981 |   Int i; | 
 | 982 |  | 
 | 983 |   for(i = 0; i < CLG_(current_call_stack).sp; i++) { | 
 | 984 |     if (!CLG_(current_call_stack).entry[i].jcc) continue; | 
 | 985 |  | 
 | 986 |     /* reset call counters to current for active calls */ | 
 | 987 |     CLG_(copy_cost)( CLG_(sets).full,  | 
 | 988 | 		    CLG_(current_call_stack).entry[i].enter_cost, | 
 | 989 | 		    CLG_(current_state).cost ); | 
| weidendo | ceb06de | 2009-08-11 20:53:57 +0000 | [diff] [blame] | 990 |     CLG_(current_call_stack).entry[i].jcc->call_counter = 0; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 991 |   } | 
 | 992 |  | 
 | 993 |   CLG_(forall_bbccs)(CLG_(zero_bbcc)); | 
 | 994 |  | 
 | 995 |   /* set counter for last dump */ | 
 | 996 |   CLG_(copy_cost)( CLG_(sets).full,  | 
 | 997 | 		  t->lastdump_cost, CLG_(current_state).cost ); | 
 | 998 | } | 
 | 999 |  | 
 | 1000 | void CLG_(zero_all_cost)(Bool only_current_thread) | 
 | 1001 | { | 
 | 1002 |   if (VG_(clo_verbosity) > 1) | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1003 |     VG_(message)(Vg_DebugMsg, "  Zeroing costs...\n"); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1004 |  | 
 | 1005 |   if (only_current_thread) | 
 | 1006 |     zero_thread_cost(CLG_(get_current_thread)()); | 
 | 1007 |   else | 
 | 1008 |     CLG_(forall_threads)(zero_thread_cost); | 
 | 1009 |  | 
 | 1010 |   if (VG_(clo_verbosity) > 1) | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1011 |     VG_(message)(Vg_DebugMsg, "  ...done\n"); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1012 | } | 
 | 1013 |  | 
 | 1014 | static | 
 | 1015 | void unwind_thread(thread_info* t) | 
 | 1016 | { | 
 | 1017 |   /* unwind signal handlers */ | 
 | 1018 |   while(CLG_(current_state).sig !=0) | 
 | 1019 |     CLG_(post_signal)(CLG_(current_tid),CLG_(current_state).sig); | 
 | 1020 |  | 
 | 1021 |   /* unwind regular call stack */ | 
 | 1022 |   while(CLG_(current_call_stack).sp>0) | 
 | 1023 |     CLG_(pop_call_stack)(); | 
| weidendo | f3e0b49 | 2006-09-10 22:34:20 +0000 | [diff] [blame] | 1024 |  | 
 | 1025 |   /* reset context and function stack for context generation */ | 
 | 1026 |   CLG_(init_exec_state)( &CLG_(current_state) ); | 
 | 1027 |   CLG_(current_fn_stack).top = CLG_(current_fn_stack).bottom; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1028 | } | 
 | 1029 |  | 
| weidendo | e891487 | 2009-08-11 20:53:59 +0000 | [diff] [blame] | 1030 | static | 
 | 1031 | void zero_state_cost(thread_info* t) | 
 | 1032 | { | 
 | 1033 |     CLG_(zero_cost)( CLG_(sets).full, CLG_(current_state).cost ); | 
 | 1034 | } | 
 | 1035 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1036 | /* Ups, this can go wrong... */ | 
 | 1037 | extern void VG_(discard_translations) ( Addr64 start, ULong range ); | 
 | 1038 |  | 
 | 1039 | void CLG_(set_instrument_state)(Char* reason, Bool state) | 
 | 1040 | { | 
 | 1041 |   if (CLG_(instrument_state) == state) { | 
 | 1042 |     CLG_DEBUG(2, "%s: instrumentation already %s\n", | 
 | 1043 | 	     reason, state ? "ON" : "OFF"); | 
 | 1044 |     return; | 
 | 1045 |   } | 
 | 1046 |   CLG_(instrument_state) = state; | 
 | 1047 |   CLG_DEBUG(2, "%s: Switching instrumentation %s ...\n", | 
 | 1048 | 	   reason, state ? "ON" : "OFF"); | 
 | 1049 |  | 
 | 1050 |   VG_(discard_translations)( (Addr64)0x1000, (ULong) ~0xfffl); | 
 | 1051 |  | 
 | 1052 |   /* reset internal state: call stacks, simulator */ | 
 | 1053 |   CLG_(forall_threads)(unwind_thread); | 
| weidendo | e891487 | 2009-08-11 20:53:59 +0000 | [diff] [blame] | 1054 |   CLG_(forall_threads)(zero_state_cost); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1055 |   (*CLG_(cachesim).clear)(); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1056 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1057 |   if (VG_(clo_verbosity) > 1) | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1058 |     VG_(message)(Vg_DebugMsg, "%s: instrumentation switched %s\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1059 | 		 reason, state ? "ON" : "OFF"); | 
 | 1060 | } | 
 | 1061 |    | 
 | 1062 |  | 
 | 1063 | static | 
 | 1064 | Bool CLG_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret) | 
 | 1065 | { | 
 | 1066 |    if (!VG_IS_TOOL_USERREQ('C','T',args[0])) | 
 | 1067 |       return False; | 
 | 1068 |  | 
 | 1069 |    switch(args[0]) { | 
 | 1070 |    case VG_USERREQ__DUMP_STATS:      | 
 | 1071 |       CLG_(dump_profile)("Client Request", True); | 
 | 1072 |       *ret = 0;                 /* meaningless */ | 
 | 1073 |       break; | 
 | 1074 |  | 
 | 1075 |    case VG_USERREQ__DUMP_STATS_AT: | 
 | 1076 |      { | 
 | 1077 |        Char buf[512]; | 
| njn | 8a7b41b | 2007-09-23 00:51:24 +0000 | [diff] [blame] | 1078 |        VG_(sprintf)(buf,"Client Request: %s", (Char*)args[1]); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1079 |        CLG_(dump_profile)(buf, True); | 
 | 1080 |        *ret = 0;                 /* meaningless */ | 
 | 1081 |      } | 
 | 1082 |      break; | 
 | 1083 |  | 
 | 1084 |    case VG_USERREQ__ZERO_STATS: | 
 | 1085 |      CLG_(zero_all_cost)(True); | 
 | 1086 |       *ret = 0;                 /* meaningless */ | 
 | 1087 |       break; | 
 | 1088 |  | 
 | 1089 |    case VG_USERREQ__TOGGLE_COLLECT: | 
 | 1090 |      CLG_(current_state).collect = !CLG_(current_state).collect; | 
 | 1091 |      CLG_DEBUG(2, "Client Request: toggled collection state to %s\n", | 
 | 1092 | 	      CLG_(current_state).collect ? "ON" : "OFF"); | 
 | 1093 |      *ret = 0;                 /* meaningless */ | 
 | 1094 |      break; | 
 | 1095 |  | 
 | 1096 |    case VG_USERREQ__START_INSTRUMENTATION: | 
 | 1097 |      CLG_(set_instrument_state)("Client Request", True); | 
 | 1098 |      *ret = 0;                 /* meaningless */ | 
 | 1099 |      break; | 
 | 1100 |  | 
 | 1101 |    case VG_USERREQ__STOP_INSTRUMENTATION: | 
 | 1102 |      CLG_(set_instrument_state)("Client Request", False); | 
 | 1103 |      *ret = 0;                 /* meaningless */ | 
 | 1104 |      break; | 
 | 1105 |  | 
 | 1106 |    default: | 
 | 1107 |       return False; | 
 | 1108 |    } | 
 | 1109 |  | 
 | 1110 |    return True; | 
 | 1111 | } | 
 | 1112 |  | 
 | 1113 |  | 
 | 1114 | /* Syscall Timing */ | 
 | 1115 |  | 
 | 1116 | /* struct timeval syscalltime[VG_N_THREADS]; */ | 
 | 1117 | #if CLG_MICROSYSTIME | 
 | 1118 | #include <sys/time.h> | 
 | 1119 | #include <sys/syscall.h> | 
 | 1120 | extern Int VG_(do_syscall) ( UInt, ... ); | 
 | 1121 |  | 
 | 1122 | ULong syscalltime[VG_N_THREADS]; | 
 | 1123 | #else | 
 | 1124 | UInt syscalltime[VG_N_THREADS]; | 
 | 1125 | #endif | 
 | 1126 |  | 
 | 1127 | static | 
| sewardj | 1c0ce7a | 2009-07-01 08:10:49 +0000 | [diff] [blame] | 1128 | void CLG_(pre_syscalltime)(ThreadId tid, UInt syscallno, | 
 | 1129 |                            UWord* args, UInt nArgs) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1130 | { | 
 | 1131 |   if (CLG_(clo).collect_systime) { | 
 | 1132 | #if CLG_MICROSYSTIME | 
 | 1133 |     struct vki_timeval tv_now; | 
 | 1134 |     VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL); | 
 | 1135 |     syscalltime[tid] = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec; | 
 | 1136 | #else | 
 | 1137 |     syscalltime[tid] = VG_(read_millisecond_timer)(); | 
 | 1138 | #endif | 
 | 1139 |   } | 
 | 1140 | } | 
 | 1141 |  | 
 | 1142 | static | 
| sewardj | 1c0ce7a | 2009-07-01 08:10:49 +0000 | [diff] [blame] | 1143 | void CLG_(post_syscalltime)(ThreadId tid, UInt syscallno, | 
 | 1144 |                             UWord* args, UInt nArgs, SysRes res) | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1145 | { | 
| weidendo | ae0bb6f | 2007-02-16 13:12:43 +0000 | [diff] [blame] | 1146 |   if (CLG_(clo).collect_systime && | 
 | 1147 |       CLG_(current_state).bbcc) { | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 1148 |       Int o; | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1149 | #if CLG_MICROSYSTIME | 
 | 1150 |     struct vki_timeval tv_now; | 
 | 1151 |     ULong diff; | 
 | 1152 |      | 
 | 1153 |     VG_(do_syscall)(__NR_gettimeofday, (UInt)&tv_now, (UInt)NULL); | 
 | 1154 |     diff = (tv_now.tv_sec * 1000000ULL + tv_now.tv_usec) - syscalltime[tid]; | 
 | 1155 | #else | 
 | 1156 |     UInt diff = VG_(read_millisecond_timer)() - syscalltime[tid]; | 
 | 1157 | #endif   | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 1158 |  | 
 | 1159 |     /* offset o is for "SysCount", o+1 for "SysTime" */ | 
 | 1160 |     o = fullOffset(EG_SYS); | 
 | 1161 |     CLG_ASSERT(o>=0); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1162 |     CLG_DEBUG(0,"   Time (Off %d) for Syscall %d: %ull\n", o, syscallno, diff); | 
 | 1163 |      | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1164 |     CLG_(current_state).cost[o] ++; | 
 | 1165 |     CLG_(current_state).cost[o+1] += diff; | 
 | 1166 |     if (!CLG_(current_state).bbcc->skipped) | 
 | 1167 |       CLG_(init_cost_lz)(CLG_(sets).full, | 
 | 1168 | 			&(CLG_(current_state).bbcc->skipped)); | 
 | 1169 |     CLG_(current_state).bbcc->skipped[o] ++; | 
 | 1170 |     CLG_(current_state).bbcc->skipped[o+1] += diff; | 
 | 1171 |   } | 
 | 1172 | } | 
 | 1173 |  | 
 | 1174 | static | 
 | 1175 | void finish(void) | 
 | 1176 | { | 
 | 1177 |   char buf[RESULTS_BUF_LEN]; | 
 | 1178 |  | 
 | 1179 |   CLG_DEBUG(0, "finish()\n"); | 
 | 1180 |  | 
 | 1181 |   (*CLG_(cachesim).finish)(); | 
 | 1182 |  | 
 | 1183 |   /* pop all remaining items from CallStack for correct sum | 
 | 1184 |    */ | 
 | 1185 |   CLG_(forall_threads)(unwind_thread); | 
| sewardj | e45a799 | 2006-10-17 02:24:18 +0000 | [diff] [blame] | 1186 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1187 |   CLG_(dump_profile)(0, False); | 
| sewardj | e45a799 | 2006-10-17 02:24:18 +0000 | [diff] [blame] | 1188 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1189 |   CLG_(finish_command)(); | 
| sewardj | e45a799 | 2006-10-17 02:24:18 +0000 | [diff] [blame] | 1190 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1191 |   if (VG_(clo_verbosity) == 0) return; | 
 | 1192 |    | 
 | 1193 |   /* Hash table stats */ | 
| sewardj | 2d9e874 | 2009-08-07 15:46:56 +0000 | [diff] [blame] | 1194 |   if (VG_(clo_stats)) { | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1195 |     int BB_lookups = | 
 | 1196 |       CLG_(stat).full_debug_BBs + | 
 | 1197 |       CLG_(stat).fn_name_debug_BBs + | 
 | 1198 |       CLG_(stat).file_line_debug_BBs + | 
 | 1199 |       CLG_(stat).no_debug_BBs; | 
 | 1200 |      | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1201 |     VG_(message)(Vg_DebugMsg, "\n"); | 
 | 1202 |     VG_(message)(Vg_DebugMsg, "Distinct objects: %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1203 | 		 CLG_(stat).distinct_objs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1204 |     VG_(message)(Vg_DebugMsg, "Distinct files:   %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1205 | 		 CLG_(stat).distinct_files); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1206 |     VG_(message)(Vg_DebugMsg, "Distinct fns:     %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1207 | 		 CLG_(stat).distinct_fns); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1208 |     VG_(message)(Vg_DebugMsg, "Distinct contexts:%d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1209 | 		 CLG_(stat).distinct_contexts); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1210 |     VG_(message)(Vg_DebugMsg, "Distinct BBs:     %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1211 | 		 CLG_(stat).distinct_bbs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1212 |     VG_(message)(Vg_DebugMsg, "Cost entries:     %d (Chunks %d)\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1213 | 		 CLG_(costarray_entries), CLG_(costarray_chunks)); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1214 |     VG_(message)(Vg_DebugMsg, "Distinct BBCCs:   %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1215 | 		 CLG_(stat).distinct_bbccs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1216 |     VG_(message)(Vg_DebugMsg, "Distinct JCCs:    %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1217 | 		 CLG_(stat).distinct_jccs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1218 |     VG_(message)(Vg_DebugMsg, "Distinct skips:   %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1219 | 		 CLG_(stat).distinct_skips); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1220 |     VG_(message)(Vg_DebugMsg, "BB lookups:       %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1221 | 		 BB_lookups); | 
 | 1222 |     if (BB_lookups>0) { | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1223 |       VG_(message)(Vg_DebugMsg, "With full      debug info:%3d%% (%d)\n",  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1224 | 		   CLG_(stat).full_debug_BBs    * 100 / BB_lookups, | 
 | 1225 | 		   CLG_(stat).full_debug_BBs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1226 |       VG_(message)(Vg_DebugMsg, "With file/line debug info:%3d%% (%d)\n",  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1227 | 		   CLG_(stat).file_line_debug_BBs * 100 / BB_lookups, | 
 | 1228 | 		   CLG_(stat).file_line_debug_BBs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1229 |       VG_(message)(Vg_DebugMsg, "With fn name   debug info:%3d%% (%d)\n",  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1230 | 		   CLG_(stat).fn_name_debug_BBs * 100 / BB_lookups, | 
 | 1231 | 		   CLG_(stat).fn_name_debug_BBs); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1232 |       VG_(message)(Vg_DebugMsg, "With no        debug info:%3d%% (%d)\n",  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1233 | 		   CLG_(stat).no_debug_BBs      * 100 / BB_lookups, | 
 | 1234 | 		   CLG_(stat).no_debug_BBs); | 
 | 1235 |     } | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1236 |     VG_(message)(Vg_DebugMsg, "BBCC Clones:       %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1237 | 		 CLG_(stat).bbcc_clones); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1238 |     VG_(message)(Vg_DebugMsg, "BBs Retranslated:  %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1239 | 		 CLG_(stat).bb_retranslations); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1240 |     VG_(message)(Vg_DebugMsg, "Distinct instrs:   %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1241 | 		 CLG_(stat).distinct_instrs); | 
 | 1242 |     VG_(message)(Vg_DebugMsg, ""); | 
 | 1243 |      | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1244 |     VG_(message)(Vg_DebugMsg, "LRU Contxt Misses: %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1245 | 		 CLG_(stat).cxt_lru_misses); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1246 |     VG_(message)(Vg_DebugMsg, "LRU BBCC Misses:   %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1247 | 		 CLG_(stat).bbcc_lru_misses); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1248 |     VG_(message)(Vg_DebugMsg, "LRU JCC Misses:    %d\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1249 | 		 CLG_(stat).jcc_lru_misses); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1250 |     VG_(message)(Vg_DebugMsg, "BBs Executed:      %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1251 | 		 CLG_(stat).bb_executions); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1252 |     VG_(message)(Vg_DebugMsg, "Calls:             %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1253 | 		 CLG_(stat).call_counter); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1254 |     VG_(message)(Vg_DebugMsg, "CondJMP followed:  %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1255 | 		 CLG_(stat).jcnd_counter); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1256 |     VG_(message)(Vg_DebugMsg, "Boring JMPs:       %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1257 | 		 CLG_(stat).jump_counter); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1258 |     VG_(message)(Vg_DebugMsg, "Recursive calls:   %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1259 | 		 CLG_(stat).rec_call_counter); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1260 |     VG_(message)(Vg_DebugMsg, "Returns:           %llu\n", | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1261 | 		 CLG_(stat).ret_counter); | 
 | 1262 |  | 
 | 1263 |     VG_(message)(Vg_DebugMsg, ""); | 
 | 1264 |   } | 
 | 1265 |  | 
 | 1266 |   CLG_(sprint_eventmapping)(buf, CLG_(dumpmap)); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1267 |   VG_(message)(Vg_UserMsg, "Events    : %s\n", buf); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1268 |   CLG_(sprint_mappingcost)(buf, CLG_(dumpmap), CLG_(total_cost)); | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1269 |   VG_(message)(Vg_UserMsg, "Collected : %s\n", buf); | 
 | 1270 |   VG_(message)(Vg_UserMsg, "\n"); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1271 |  | 
 | 1272 |   //  if (CLG_(clo).simulate_cache) | 
 | 1273 |   (*CLG_(cachesim).printstat)(); | 
 | 1274 | } | 
 | 1275 |  | 
 | 1276 |  | 
 | 1277 | void CLG_(fini)(Int exitcode) | 
 | 1278 | { | 
 | 1279 |   finish(); | 
 | 1280 | } | 
 | 1281 |  | 
 | 1282 |  | 
 | 1283 | /*--------------------------------------------------------------------*/ | 
 | 1284 | /*--- Setup                                                        ---*/ | 
 | 1285 | /*--------------------------------------------------------------------*/ | 
 | 1286 |  | 
| njn | 3e32c87 | 2006-12-24 07:51:17 +0000 | [diff] [blame] | 1287 | static void clg_start_client_code_callback ( ThreadId tid, ULong blocks_done ) | 
| sewardj | 9756181 | 2006-12-23 01:21:12 +0000 | [diff] [blame] | 1288 | { | 
| weidendo | 134657c | 2006-12-23 23:11:20 +0000 | [diff] [blame] | 1289 |    static ULong last_blocks_done = 0; | 
 | 1290 |  | 
| sewardj | 9756181 | 2006-12-23 01:21:12 +0000 | [diff] [blame] | 1291 |    if (0) | 
| njn | 3e32c87 | 2006-12-24 07:51:17 +0000 | [diff] [blame] | 1292 |       VG_(printf)("%d R %llu\n", (Int)tid, blocks_done); | 
| weidendo | 134657c | 2006-12-23 23:11:20 +0000 | [diff] [blame] | 1293 |  | 
 | 1294 |    /* throttle calls to CLG_(run_thread) by number of BBs executed */ | 
 | 1295 |    if (blocks_done - last_blocks_done < 5000) return; | 
 | 1296 |    last_blocks_done = blocks_done; | 
 | 1297 |  | 
 | 1298 |    CLG_(run_thread)( tid ); | 
| sewardj | 9756181 | 2006-12-23 01:21:12 +0000 | [diff] [blame] | 1299 | } | 
 | 1300 |  | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1301 | static | 
 | 1302 | void CLG_(post_clo_init)(void) | 
 | 1303 | { | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1304 |    VG_(clo_vex_control).iropt_unroll_thresh = 0; | 
 | 1305 |    VG_(clo_vex_control).guest_chase_thresh = 0; | 
 | 1306 |  | 
 | 1307 |    CLG_DEBUG(1, "  dump threads: %s\n", CLG_(clo).separate_threads ? "Yes":"No"); | 
 | 1308 |    CLG_DEBUG(1, "  call sep. : %d\n", CLG_(clo).separate_callers); | 
 | 1309 |    CLG_DEBUG(1, "  rec. sep. : %d\n", CLG_(clo).separate_recursions); | 
 | 1310 |  | 
 | 1311 |    if (!CLG_(clo).dump_line && !CLG_(clo).dump_instr && !CLG_(clo).dump_bb) { | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1312 |        VG_(message)(Vg_UserMsg, "Using source line as position.\n"); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1313 |        CLG_(clo).dump_line = True; | 
 | 1314 |    } | 
 | 1315 |  | 
| weidendo | 4ce5e79 | 2006-09-20 21:29:39 +0000 | [diff] [blame] | 1316 |    CLG_(init_dumps)(); | 
 | 1317 |    CLG_(init_command)(); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1318 |  | 
 | 1319 |    (*CLG_(cachesim).post_clo_init)(); | 
 | 1320 |  | 
| weidendo | 5bba525 | 2010-06-09 22:32:53 +0000 | [diff] [blame^] | 1321 |    CLG_(init_eventsets)(); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1322 |    CLG_(init_statistics)(& CLG_(stat)); | 
 | 1323 |    CLG_(init_cost_lz)( CLG_(sets).full, &CLG_(total_cost) ); | 
 | 1324 |  | 
 | 1325 |    /* initialize hash tables */ | 
 | 1326 |    CLG_(init_obj_table)(); | 
 | 1327 |    CLG_(init_cxt_table)(); | 
 | 1328 |    CLG_(init_bb_hash)(); | 
 | 1329 |  | 
 | 1330 |    CLG_(init_threads)(); | 
 | 1331 |    CLG_(run_thread)(1); | 
 | 1332 |  | 
 | 1333 |    CLG_(instrument_state) = CLG_(clo).instrument_atstart; | 
 | 1334 |  | 
| weidendo | ca472c5 | 2006-03-31 19:34:51 +0000 | [diff] [blame] | 1335 |    if (VG_(clo_verbosity > 0)) { | 
| weidendo | ca472c5 | 2006-03-31 19:34:51 +0000 | [diff] [blame] | 1336 |       VG_(message)(Vg_UserMsg, | 
| sewardj | 0f33adf | 2009-07-15 14:51:03 +0000 | [diff] [blame] | 1337 |                    "For interactive control, run 'callgrind_control -h'.\n"); | 
| weidendo | ca472c5 | 2006-03-31 19:34:51 +0000 | [diff] [blame] | 1338 |    } | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1339 | } | 
 | 1340 |  | 
 | 1341 | static | 
 | 1342 | void CLG_(pre_clo_init)(void) | 
 | 1343 | { | 
 | 1344 |     VG_(details_name)            ("Callgrind"); | 
| weidendo | ca472c5 | 2006-03-31 19:34:51 +0000 | [diff] [blame] | 1345 |     VG_(details_version)         (NULL); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1346 |     VG_(details_description)     ("a call-graph generating cache profiler"); | 
| sewardj | 9eecbbb | 2010-05-03 21:37:12 +0000 | [diff] [blame] | 1347 |     VG_(details_copyright_author)("Copyright (C) 2002-2010, and GNU GPL'd, " | 
| weidendo | ca472c5 | 2006-03-31 19:34:51 +0000 | [diff] [blame] | 1348 | 				  "by Josef Weidendorfer et al."); | 
| weidendo | db70ed7 | 2006-05-27 15:39:45 +0000 | [diff] [blame] | 1349 |     VG_(details_bug_reports_to)  (VG_BUGS_TO); | 
| sewardj | e45a799 | 2006-10-17 02:24:18 +0000 | [diff] [blame] | 1350 |     VG_(details_avg_translation_sizeB) ( 500 ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1351 |  | 
 | 1352 |     VG_(basic_tool_funcs)        (CLG_(post_clo_init), | 
 | 1353 |                                   CLG_(instrument), | 
 | 1354 |                                   CLG_(fini)); | 
 | 1355 |  | 
| sewardj | 0b9d74a | 2006-12-24 02:24:11 +0000 | [diff] [blame] | 1356 |     VG_(needs_superblock_discards)(clg_discard_superblock_info); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1357 |  | 
 | 1358 |  | 
 | 1359 |     VG_(needs_command_line_options)(CLG_(process_cmd_line_option), | 
 | 1360 | 				    CLG_(print_usage), | 
 | 1361 | 				    CLG_(print_debug_usage)); | 
 | 1362 |  | 
 | 1363 |     VG_(needs_client_requests)(CLG_(handle_client_request)); | 
 | 1364 |     VG_(needs_syscall_wrapper)(CLG_(pre_syscalltime), | 
 | 1365 | 			       CLG_(post_syscalltime)); | 
 | 1366 |  | 
| njn | 3e32c87 | 2006-12-24 07:51:17 +0000 | [diff] [blame] | 1367 |     VG_(track_start_client_code)  ( & clg_start_client_code_callback ); | 
 | 1368 |     VG_(track_pre_deliver_signal) ( & CLG_(pre_signal) ); | 
 | 1369 |     VG_(track_post_deliver_signal)( & CLG_(post_signal) ); | 
| weidendo | a17f2a3 | 2006-03-20 10:27:30 +0000 | [diff] [blame] | 1370 |  | 
 | 1371 |     CLG_(set_clo_defaults)(); | 
 | 1372 | } | 
 | 1373 |  | 
 | 1374 | VG_DETERMINE_INTERFACE_VERSION(CLG_(pre_clo_init)) | 
 | 1375 |  | 
 | 1376 | /*--------------------------------------------------------------------*/ | 
 | 1377 | /*--- end                                                   main.c ---*/ | 
 | 1378 | /*--------------------------------------------------------------------*/ |