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
39static 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
47void 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
57static
58void 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
75void 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
97void 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
115void 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
138void 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
175void 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
226void 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
240void 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 */
263void 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
285static 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
295void 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
324void 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 */
374void CLG_(print_addr)(Addr addr)
375{
376    HChar fl_buf[FILENAME_LEN];
377    HChar fn_buf[FN_NAME_LEN];
378    const HChar* obj_name;
379    DebugInfo* di;
380    UInt 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
410void CLG_(print_addr_ln)(Addr addr)
411{
412  CLG_(print_addr)(addr);
413  VG_(printf)("\n");
414}
415
416static ULong bb_written = 0;
417
418void 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
426void 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
438void* CLG_(malloc)(const HChar* cc, UWord s, const HChar* 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
446void CLG_(print_bbno)(void) {}
447void CLG_(print_context)(void) {}
448void CLG_(print_jcc)(int s, jCC* jcc) {}
449void CLG_(print_bbcc)(int s, BBCC* bbcc) {}
450void CLG_(print_bbcc_fn)(BBCC* bbcc) {}
451void CLG_(print_cost)(int s, EventSet* es, ULong* cost) {}
452void CLG_(print_bb)(int s, BB* bb) {}
453void CLG_(print_cxt)(int s, Context* cxt, int rec_index) {}
454void CLG_(print_short_jcc)(jCC* jcc) {}
455void CLG_(print_stackentry)(int s, int sp) {}
456void CLG_(print_addr)(Addr addr) {}
457void CLG_(print_addr_ln)(Addr addr) {}
458
459#endif
460