1 /* 2 This file is part of Callgrind, a Valgrind tool for call graph 3 profiling programs. 4 5 Copyright (C) 2002-2015, Josef Weidendorfer (Josef.Weidendorfer (at) gmx.de) 6 7 This tool is derived from and contains lot of code from Cachegrind 8 Copyright (C) 2002-2015 Nicholas Nethercote (njn (at) valgrind.org) 9 10 This program is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License as 12 published by the Free Software Foundation; either version 2 of the 13 License, or (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, but 16 WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 23 02111-1307, USA. 24 25 The GNU General Public License is contained in the file COPYING. 26 */ 27 28 #include "global.h" 29 #include "events.h" 30 31 /* If debugging mode of, dummy functions are provided (see below) 32 */ 33 #if CLG_ENABLE_DEBUG 34 35 /*------------------------------------------------------------*/ 36 /*--- Debug output helpers ---*/ 37 /*------------------------------------------------------------*/ 38 39 static void print_indent(int s) 40 { 41 /* max of 40 spaces */ 42 const HChar sp[] = " "; 43 if (s>40) s=40; 44 VG_(printf)("%s", sp+40-s); 45 } 46 47 void CLG_(print_bb)(int s, BB* bb) 48 { 49 if (s<0) { 50 s = -s; 51 print_indent(s); 52 } 53 54 VG_(printf)("BB %#lx (Obj '%s')", bb_addr(bb), bb->obj->name); 55 } 56 57 static 58 void print_mangled_cxt(Context* cxt, int rec_index) 59 { 60 int i; 61 62 if (!cxt) 63 VG_(printf)("(none)"); 64 else { 65 VG_(printf)("%s", cxt->fn[0]->name); 66 if (rec_index >0) 67 VG_(printf)("'%d", rec_index +1); 68 for(i=1;i<cxt->size;i++) 69 VG_(printf)("'%s", cxt->fn[i]->name); 70 } 71 } 72 73 74 75 void CLG_(print_cxt)(Int s, Context* cxt, int rec_index) 76 { 77 if (s<0) { 78 s = -s; 79 print_indent(s); 80 } 81 82 if (cxt) { 83 UInt *pactive = CLG_(get_fn_entry)(cxt->fn[0]->number); 84 CLG_ASSERT(rec_index < cxt->fn[0]->separate_recursions); 85 86 VG_(printf)("Cxt %u" ,cxt->base_number + rec_index); 87 if (*pactive>0) 88 VG_(printf)(" [active=%u]", *pactive); 89 VG_(printf)(": "); 90 print_mangled_cxt(cxt, rec_index); 91 VG_(printf)("\n"); 92 } 93 else 94 VG_(printf)("(no context)\n"); 95 } 96 97 void CLG_(print_execstate)(int s, exec_state* es) 98 { 99 if (s<0) { 100 s = -s; 101 print_indent(s); 102 } 103 104 if (!es) { 105 VG_(printf)("ExecState 0x0\n"); 106 return; 107 } 108 109 VG_(printf)("ExecState [Sig %d, collect %s, nonskipped %p]: jmps_passed %d\n", 110 es->sig, es->collect?"yes":"no", 111 es->nonskipped, es->jmps_passed); 112 } 113 114 115 void CLG_(print_bbcc)(int s, BBCC* bbcc) 116 { 117 BB* bb; 118 119 if (s<0) { 120 s = -s; 121 print_indent(s); 122 } 123 124 if (!bbcc) { 125 VG_(printf)("BBCC 0x0\n"); 126 return; 127 } 128 129 bb = bbcc->bb; 130 CLG_ASSERT(bb!=0); 131 132 VG_(printf)("%s +%#lx=%#lx, ", 133 bb->obj->name + bb->obj->last_slash_pos, 134 (UWord)bb->offset, bb_addr(bb)); 135 CLG_(print_cxt)(s+8, bbcc->cxt, bbcc->rec_index); 136 } 137 138 void CLG_(print_eventset)(int s, EventSet* es) 139 { 140 int i, j; 141 UInt mask; 142 EventGroup* eg; 143 144 if (s<0) { 145 s = -s; 146 print_indent(s); 147 } 148 149 if (!es) { 150 VG_(printf)("(EventSet not set)\n"); 151 return; 152 } 153 154 VG_(printf)("EventSet %u (%d groups, size %d):", 155 es->mask, es->count, es->size); 156 157 if (es->count == 0) { 158 VG_(printf)("-\n"); 159 return; 160 } 161 162 for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) { 163 if ((es->mask & mask)==0) continue; 164 eg = CLG_(get_event_group)(i); 165 if (!eg) continue; 166 VG_(printf)(" (%d: %s", i, eg->name[0]); 167 for(j=1; j<eg->size; j++) 168 VG_(printf)(" %s", eg->name[j]); 169 VG_(printf)(")"); 170 } 171 VG_(printf)("\n"); 172 } 173 174 175 void CLG_(print_cost)(int s, EventSet* es, ULong* c) 176 { 177 Int i, j, pos, off; 178 UInt mask; 179 EventGroup* eg; 180 181 if (s<0) { 182 s = -s; 183 print_indent(s); 184 } 185 186 if (!es) { 187 VG_(printf)("Cost (Nothing, EventSet not set)\n"); 188 return; 189 } 190 if (!c) { 191 VG_(printf)("Cost (Null, EventSet %u)\n", es->mask); 192 return; 193 } 194 195 if (es->size == 0) { 196 VG_(printf)("Cost (Nothing, EventSet with len 0)\n"); 197 return; 198 } 199 200 pos = s; 201 pos += VG_(printf)("Cost [%p]: ", c); 202 off = 0; 203 for(i=0, mask=1; i<MAX_EVENTGROUP_COUNT; i++, mask=mask<<1) { 204 if ((es->mask & mask)==0) continue; 205 eg = CLG_(get_event_group)(i); 206 if (!eg) continue; 207 for(j=0; j<eg->size; j++) { 208 209 if (off>0) { 210 if (pos > 70) { 211 VG_(printf)(",\n"); 212 print_indent(s+5); 213 pos = s+5; 214 } 215 else 216 pos += VG_(printf)(", "); 217 } 218 219 pos += VG_(printf)("%s %llu", eg->name[j], c[off++]); 220 } 221 } 222 VG_(printf)("\n"); 223 } 224 225 226 void CLG_(print_short_jcc)(jCC* jcc) 227 { 228 if (jcc) 229 VG_(printf)("%#lx => %#lx [calls %llu/Ir %llu, Dr %llu, Dw %llu]", 230 bb_jmpaddr(jcc->from->bb), 231 bb_addr(jcc->to->bb), 232 jcc->call_counter, 233 jcc->cost ? jcc->cost[fullOffset(EG_IR)]:0, 234 jcc->cost ? jcc->cost[fullOffset(EG_DR)]:0, 235 jcc->cost ? jcc->cost[fullOffset(EG_DW)]:0); 236 else 237 VG_(printf)("[Skipped JCC]"); 238 } 239 240 void CLG_(print_jcc)(int s, jCC* jcc) 241 { 242 if (s<0) { 243 s = -s; 244 print_indent(s); 245 } 246 247 if (!jcc) { 248 VG_(printf)("JCC to skipped function\n"); 249 return; 250 } 251 VG_(printf)("JCC %p from ", jcc); 252 CLG_(print_bbcc)(s+9, jcc->from); 253 print_indent(s+4); 254 VG_(printf)("to "); 255 CLG_(print_bbcc)(s+9, jcc->to); 256 print_indent(s+4); 257 VG_(printf)("Calls %llu\n", jcc->call_counter); 258 print_indent(s+4); 259 CLG_(print_cost)(s+9, CLG_(sets).full, jcc->cost); 260 } 261 262 /* dump out the current call stack */ 263 void CLG_(print_stackentry)(int s, int sp) 264 { 265 call_entry* ce; 266 267 if (s<0) { 268 s = -s; 269 print_indent(s); 270 } 271 272 ce = CLG_(get_call_entry)(sp); 273 VG_(printf)("[%-2d] SP %#lx, RA %#lx", sp, ce->sp, ce->ret_addr); 274 if (ce->nonskipped) 275 VG_(printf)(" NonSkipped BB %#lx / %s", 276 bb_addr(ce->nonskipped->bb), 277 ce->nonskipped->cxt->fn[0]->name); 278 VG_(printf)("\n"); 279 print_indent(s+5); 280 CLG_(print_jcc)(5,ce->jcc); 281 } 282 283 /* debug output */ 284 #if 0 285 static void print_call_stack() 286 { 287 int c; 288 289 VG_(printf)("Call Stack:\n"); 290 for(c=0;c<CLG_(current_call_stack).sp;c++) 291 CLG_(print_stackentry)(-2, c); 292 } 293 #endif 294 295 void CLG_(print_bbcc_fn)(BBCC* bbcc) 296 { 297 obj_node* obj; 298 299 if (!bbcc) { 300 VG_(printf)("%08x", 0u); 301 return; 302 } 303 304 VG_(printf)("%08lx/%c %u:", bb_addr(bbcc->bb), 305 (bbcc->bb->sect_kind == Vg_SectText) ? 'T' : 306 (bbcc->bb->sect_kind == Vg_SectData) ? 'D' : 307 (bbcc->bb->sect_kind == Vg_SectBSS) ? 'B' : 308 (bbcc->bb->sect_kind == Vg_SectGOT) ? 'G' : 309 (bbcc->bb->sect_kind == Vg_SectPLT) ? 'P' : 'U', 310 bbcc->cxt->base_number+bbcc->rec_index); 311 print_mangled_cxt(bbcc->cxt, bbcc->rec_index); 312 313 obj = bbcc->cxt->fn[0]->file->obj; 314 if (obj->name[0]) 315 VG_(printf)(" %s", obj->name+obj->last_slash_pos); 316 317 if (VG_(strcmp)(bbcc->cxt->fn[0]->file->name, "???") !=0) { 318 VG_(printf)(" %s", bbcc->cxt->fn[0]->file->name); 319 if ((bbcc->cxt->fn[0] == bbcc->bb->fn) && (bbcc->bb->line>0)) 320 VG_(printf)(":%u", bbcc->bb->line); 321 } 322 } 323 324 void CLG_(print_bbcc_cost)(int s, BBCC* bbcc) 325 { 326 BB* bb; 327 Int i, cjmpNo; 328 ULong ecounter; 329 330 if (s<0) { 331 s = -s; 332 print_indent(s); 333 } 334 335 if (!bbcc) { 336 VG_(printf)("BBCC 0x0\n"); 337 return; 338 } 339 340 bb = bbcc->bb; 341 CLG_ASSERT(bb!=0); 342 343 CLG_(print_bbcc)(s, bbcc); 344 345 ecounter = bbcc->ecounter_sum; 346 347 print_indent(s+2); 348 VG_(printf)("ECounter: sum %llu ", ecounter); 349 for(i=0; i<bb->cjmp_count; i++) { 350 VG_(printf)("[%u]=%llu ", 351 bb->jmp[i].instr, bbcc->jmp[i].ecounter); 352 } 353 VG_(printf)("\n"); 354 355 cjmpNo = 0; 356 for(i=0; i<bb->instr_count; i++) { 357 InstrInfo* ii = &(bb->instr[i]); 358 print_indent(s+2); 359 VG_(printf)("[%2d] IOff %2u ecnt %3llu ", 360 i, ii->instr_offset, ecounter); 361 CLG_(print_cost)(s+5, ii->eventset, bbcc->cost + ii->cost_offset); 362 363 /* update execution counter */ 364 if (cjmpNo < bb->cjmp_count) 365 if (bb->jmp[cjmpNo].instr == i) { 366 ecounter -= bbcc->jmp[cjmpNo].ecounter; 367 cjmpNo++; 368 } 369 } 370 } 371 372 373 /* dump out an address with source info if available */ 374 void CLG_(print_addr)(Addr addr) 375 { 376 const HChar *fn_buf, *fl_buf, *dir_buf; 377 const HChar* obj_name; 378 DebugInfo* di; 379 UInt ln, i=0, opos=0; 380 381 if (addr == 0) { 382 VG_(printf)("%08lx", addr); 383 return; 384 } 385 386 CLG_(get_debug_info)(addr, &dir_buf, &fl_buf, &fn_buf, &ln, &di); 387 388 if (VG_(strcmp)(fn_buf,"???")==0) 389 VG_(printf)("%#lx", addr); 390 else 391 VG_(printf)("%#lx %s", addr, fn_buf); 392 393 if (di) { 394 obj_name = VG_(DebugInfo_get_filename)(di); 395 if (obj_name) { 396 while(obj_name[i]) { 397 if (obj_name[i]=='/') opos = i+1; 398 i++; 399 } 400 if (obj_name[0]) 401 VG_(printf)(" %s", obj_name+opos); 402 } 403 } 404 405 if (ln>0) { 406 if (dir_buf[0]) 407 VG_(printf)(" (%s/%s:%u)", dir_buf, fl_buf, ln); 408 else 409 VG_(printf)(" (%s:%u)", fl_buf, ln); 410 } 411 } 412 413 void CLG_(print_addr_ln)(Addr addr) 414 { 415 CLG_(print_addr)(addr); 416 VG_(printf)("\n"); 417 } 418 419 static ULong bb_written = 0; 420 421 void CLG_(print_bbno)(void) 422 { 423 if (bb_written != CLG_(stat).bb_executions) { 424 bb_written = CLG_(stat).bb_executions; 425 VG_(printf)("BB# %llu\n",CLG_(stat).bb_executions); 426 } 427 } 428 429 void CLG_(print_context)(void) 430 { 431 BBCC* bbcc; 432 433 CLG_DEBUG(0,"In tid %u [%d] ", 434 CLG_(current_tid), CLG_(current_call_stack).sp); 435 bbcc = CLG_(current_state).bbcc; 436 print_mangled_cxt(CLG_(current_state).cxt, 437 bbcc ? bbcc->rec_index : 0); 438 VG_(printf)("\n"); 439 } 440 441 void* CLG_(malloc)(const HChar* cc, UWord s, const HChar* f) 442 { 443 CLG_DEBUG(3, "Malloc(%lu) in %s.\n", s, f); 444 return VG_(malloc)(cc,s); 445 } 446 447 #else /* CLG_ENABLE_DEBUG */ 448 449 void CLG_(print_bbno)(void) {} 450 void CLG_(print_context)(void) {} 451 void CLG_(print_jcc)(int s, jCC* jcc) {} 452 void CLG_(print_bbcc)(int s, BBCC* bbcc) {} 453 void CLG_(print_bbcc_fn)(BBCC* bbcc) {} 454 void CLG_(print_cost)(int s, EventSet* es, ULong* cost) {} 455 void CLG_(print_bb)(int s, BB* bb) {} 456 void CLG_(print_cxt)(int s, Context* cxt, int rec_index) {} 457 void CLG_(print_short_jcc)(jCC* jcc) {} 458 void CLG_(print_stackentry)(int s, int sp) {} 459 void CLG_(print_addr)(Addr addr) {} 460 void CLG_(print_addr_ln)(Addr addr) {} 461 462 #endif 463