1 /*
2    This file is part of Callgrind, a Valgrind tool for call graph
3    profiling programs.
4 
5    Copyright (C) 2002-2013, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
6 
7    This tool is derived from and contains lot of code from Cachegrind
8    Copyright (C) 2002-2013 Nicholas Nethercote (njn@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 
print_indent(int s)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 
CLG_(print_bb)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
print_mangled_cxt(Context * cxt,int rec_index)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 
CLG_(print_cxt)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 
CLG_(print_execstate)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 
CLG_(print_bbcc)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 
CLG_(print_eventset)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 
CLG_(print_cost)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 
CLG_(print_short_jcc)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 
CLG_(print_jcc)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 */
CLG_(print_stackentry)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 
CLG_(print_bbcc_fn)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 
CLG_(print_bbcc_cost)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 */
CLG_(print_addr)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 
CLG_(print_addr_ln)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 
CLG_(print_bbno)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 
CLG_(print_context)429 void CLG_(print_context)(void)
430 {
431   BBCC* bbcc;
432 
433   CLG_DEBUG(0,"In tid %d [%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 
CLG_(malloc)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 
CLG_(print_bbno)449 void CLG_(print_bbno)(void) {}
CLG_(print_context)450 void CLG_(print_context)(void) {}
CLG_(print_jcc)451 void CLG_(print_jcc)(int s, jCC* jcc) {}
CLG_(print_bbcc)452 void CLG_(print_bbcc)(int s, BBCC* bbcc) {}
CLG_(print_bbcc_fn)453 void CLG_(print_bbcc_fn)(BBCC* bbcc) {}
CLG_(print_cost)454 void CLG_(print_cost)(int s, EventSet* es, ULong* cost) {}
CLG_(print_bb)455 void CLG_(print_bb)(int s, BB* bb) {}
CLG_(print_cxt)456 void CLG_(print_cxt)(int s, Context* cxt, int rec_index) {}
CLG_(print_short_jcc)457 void CLG_(print_short_jcc)(jCC* jcc) {}
CLG_(print_stackentry)458 void CLG_(print_stackentry)(int s, int sp) {}
CLG_(print_addr)459 void CLG_(print_addr)(Addr addr) {}
CLG_(print_addr_ln)460 void CLG_(print_addr_ln)(Addr addr) {}
461 
462 #endif
463