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