Home | History | Annotate | Download | only in callgrind
      1 /*
      2    This file is part of Callgrind, a Valgrind tool for call graph
      3    profiling programs.
      4 
      5    Copyright (C) 2002-2010, 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 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     char 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 %d" ,cxt->base_number + rec_index);
     87     if (*pactive>0)
     88       VG_(printf)(" [active=%d]", *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 	      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 %d (%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 %d)\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", 0);
    301 	return;
    302     }
    303 
    304     VG_(printf)("%08lx/%c  %d:", 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)(":%d", 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)("[%d]=%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 %2d 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     Char fl_buf[FILENAME_LEN];
    377     Char fn_buf[FN_NAME_LEN];
    378     const UChar* obj_name;
    379     DebugInfo* di;
    380     int ln, i=0, opos=0;
    381 
    382     if (addr == 0) {
    383 	VG_(printf)("%08lx", addr);
    384 	return;
    385     }
    386 
    387     CLG_(get_debug_info)(addr, fl_buf, fn_buf, &ln, &di);
    388 
    389     if (VG_(strcmp)(fn_buf,"???")==0)
    390 	VG_(printf)("%#lx", addr);
    391     else
    392 	VG_(printf)("%#lx %s", addr, fn_buf);
    393 
    394     if (di) {
    395       obj_name = VG_(DebugInfo_get_filename)(di);
    396       if (obj_name) {
    397 	while(obj_name[i]) {
    398 	  if (obj_name[i]=='/') opos = i+1;
    399 	  i++;
    400 	}
    401 	if (obj_name[0])
    402 	  VG_(printf)(" %s", obj_name+opos);
    403       }
    404     }
    405 
    406     if (ln>0)
    407     	VG_(printf)(" (%s:%u)", fl_buf,ln);
    408 }
    409 
    410 void CLG_(print_addr_ln)(Addr addr)
    411 {
    412   CLG_(print_addr)(addr);
    413   VG_(printf)("\n");
    414 }
    415 
    416 static ULong bb_written = 0;
    417 
    418 void CLG_(print_bbno)(void)
    419 {
    420   if (bb_written != CLG_(stat).bb_executions) {
    421     bb_written = CLG_(stat).bb_executions;
    422     VG_(printf)("BB# %llu\n",CLG_(stat).bb_executions);
    423   }
    424 }
    425 
    426 void CLG_(print_context)(void)
    427 {
    428   BBCC* bbcc;
    429 
    430   CLG_DEBUG(0,"In tid %d [%d] ",
    431 	   CLG_(current_tid),  CLG_(current_call_stack).sp);
    432   bbcc =  CLG_(current_state).bbcc;
    433   print_mangled_cxt(CLG_(current_state).cxt,
    434 		    bbcc ? bbcc->rec_index : 0);
    435   VG_(printf)("\n");
    436 }
    437 
    438 void* CLG_(malloc)(HChar* cc, UWord s, char* f)
    439 {
    440     CLG_DEBUG(3, "Malloc(%lu) in %s.\n", s, f);
    441     return VG_(malloc)(cc,s);
    442 }
    443 
    444 #else /* CLG_ENABLE_DEBUG */
    445 
    446 void CLG_(print_bbno)(void) {}
    447 void CLG_(print_context)(void) {}
    448 void CLG_(print_jcc)(int s, jCC* jcc) {}
    449 void CLG_(print_bbcc)(int s, BBCC* bbcc) {}
    450 void CLG_(print_bbcc_fn)(BBCC* bbcc) {}
    451 void CLG_(print_cost)(int s, EventSet* es, ULong* cost) {}
    452 void CLG_(print_bb)(int s, BB* bb) {}
    453 void CLG_(print_cxt)(int s, Context* cxt, int rec_index) {}
    454 void CLG_(print_short_jcc)(jCC* jcc) {}
    455 void CLG_(print_stackentry)(int s, int sp) {}
    456 void CLG_(print_addr)(Addr addr) {}
    457 void CLG_(print_addr_ln)(Addr addr) {}
    458 
    459 #endif
    460