fn.c revision 85f79da547f4b5755061429e970941fbe2803548
1/*--------------------------------------------------------------------*/
2/*--- Callgrind                                                    ---*/
3/*---                                                      ct_fn.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7   This file is part of Callgrind, a Valgrind tool for call tracing.
8
9   Copyright (C) 2002-2009, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
10
11   This program is free software; you can redistribute it and/or
12   modify it under the terms of the GNU General Public License as
13   published by the Free Software Foundation; either version 2 of the
14   License, or (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful, but
17   WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24   02111-1307, USA.
25
26   The GNU General Public License is contained in the file COPYING.
27*/
28
29#include "global.h"
30
31#define N_INITIAL_FN_ARRAY_SIZE 10071
32
33static fn_array current_fn_active;
34
35static Addr runtime_resolve_addr = 0;
36static int  runtime_resolve_length = 0;
37
38// a code pattern is a list of tuples (start offset, length)
39struct chunk_t { int start, len; };
40struct pattern
41{
42    const char* name;
43    int len;
44    struct chunk_t chunk[];
45};
46
47/* Scan for a pattern in the code of an ELF object.
48 * If found, return true and set runtime_resolve_{addr,length}
49 */
50__attribute__((unused))    // Possibly;  depends on the platform.
51static Bool check_code(obj_node* obj,
52		       unsigned char code[], struct pattern* pat)
53{
54    Bool found;
55    Addr addr, end;
56    int chunk, start, len;
57
58    /* first chunk of pattern should always start at offset 0 and
59     * have at least 3 bytes */
60    CLG_ASSERT((pat->chunk[0].start == 0) && (pat->chunk[0].len >2));
61
62    CLG_DEBUG(1, "check_code: %s, pattern %s, check %d bytes of [%x %x %x...]\n",
63              obj->name, pat->name, pat->chunk[0].len, code[0], code[1], code[2]);
64
65    end = obj->start + obj->size - pat->len;
66    addr = obj->start;
67    while(addr < end) {
68	found = (VG_(memcmp)( (void*)addr, code, pat->chunk[0].len) == 0);
69
70        if (found) {
71	    chunk = 1;
72	    while(1) {
73		start = pat->chunk[chunk].start;
74		len   = pat->chunk[chunk].len;
75		if (len == 0) break;
76
77		CLG_ASSERT(len >2);
78                CLG_DEBUG(1, " found chunk %d at %#lx, checking %d bytes of [%x %x %x...]\n",
79                          chunk-1, addr - obj->start, len,
80			  code[start], code[start+1], code[start+2]);
81
82                if (VG_(memcmp)( (void*)(addr+start), code+start, len) != 0) {
83                    found = False;
84                    break;
85                }
86		chunk++;
87	    }
88
89            if (found) {
90		CLG_DEBUG(1, "found at offset %#lx.\n", addr - obj->start);
91		if (VG_(clo_verbosity) > 1)
92		    VG_(message)(Vg_DebugMsg, "Found runtime_resolve (%s): %s +%#lx=%#lx, length %d",
93				 pat->name, obj->name + obj->last_slash_pos,
94				 addr - obj->start, addr, pat->len);
95
96		runtime_resolve_addr   = addr;
97		runtime_resolve_length = pat->len;
98		return True;
99	    }
100        }
101        addr++;
102    }
103    CLG_DEBUG(1, " found nothing.\n");
104    return False;
105}
106
107
108/* _ld_runtime_resolve, located in ld.so, needs special handling:
109 * The jump at end into the resolved function should not be
110 * represented as a call (as usually done in callgrind with jumps),
111 * but as a return + call. Otherwise, the repeated existance of
112 * _ld_runtime_resolve in call chains will lead to huge cycles,
113 * making the profile almost worthless.
114 *
115 * If ld.so is stripped, the symbol will not appear. But as this
116 * function is handcrafted assembler, we search for it.
117 *
118 * We stop if the ELF object name does not seem to be the runtime linker
119 */
120static Bool search_runtime_resolve(obj_node* obj)
121{
122#if defined(VGP_x86_linux)
123    static unsigned char code[] = {
124	/* 0*/ 0x50, 0x51, 0x52, 0x8b, 0x54, 0x24, 0x10, 0x8b,
125	/* 8*/ 0x44, 0x24, 0x0c, 0xe8, 0x70, 0x01, 0x00, 0x00,
126	/*16*/ 0x5a, 0x59, 0x87, 0x04, 0x24, 0xc2, 0x08, 0x00 };
127    /* Check ranges [0-11] and [16-23] ([12-15] is an absolute address) */
128    static struct pattern pat = {
129	"x86-def", 24, {{ 0,12 }, { 16,8 }, { 24,0}} };
130
131    /* Pattern for glibc-2.8 on OpenSuse11.0 */
132    static unsigned char code_28[] = {
133	/* 0*/ 0x50, 0x51, 0x52, 0x8b, 0x54, 0x24, 0x10, 0x8b,
134	/* 8*/ 0x44, 0x24, 0x0c, 0xe8, 0x70, 0x01, 0x00, 0x00,
135	/*16*/ 0x5a, 0x8b, 0x0c, 0x24, 0x89, 0x04, 0x24, 0x8b,
136	/*24*/ 0x44, 0x24, 0x04, 0xc2, 0x0c, 0x00 };
137    static struct pattern pat_28 = {
138	"x86-glibc2.8", 30, {{ 0,12 }, { 16,14 }, { 30,0}} };
139
140    if (VG_(strncmp)(obj->name, "/lib/ld", 7) != 0) return False;
141    if (check_code(obj, code, &pat)) return True;
142    if (check_code(obj, code_28, &pat_28)) return True;
143    return False;
144#endif
145
146#if defined(VGP_ppc32_linux)
147    static unsigned char code[] = {
148	/* 0*/ 0x94, 0x21, 0xff, 0xc0, 0x90, 0x01, 0x00, 0x0c,
149	/* 8*/ 0x90, 0x61, 0x00, 0x10, 0x90, 0x81, 0x00, 0x14,
150	/*16*/ 0x7d, 0x83, 0x63, 0x78, 0x90, 0xa1, 0x00, 0x18,
151	/*24*/ 0x7d, 0x64, 0x5b, 0x78, 0x90, 0xc1, 0x00, 0x1c,
152	/*32*/ 0x7c, 0x08, 0x02, 0xa6, 0x90, 0xe1, 0x00, 0x20,
153	/*40*/ 0x90, 0x01, 0x00, 0x30, 0x91, 0x01, 0x00, 0x24,
154	/*48*/ 0x7c, 0x00, 0x00, 0x26, 0x91, 0x21, 0x00, 0x28,
155	/*56*/ 0x91, 0x41, 0x00, 0x2c, 0x90, 0x01, 0x00, 0x08,
156	/*64*/ 0x48, 0x00, 0x02, 0x91, 0x7c, 0x69, 0x03, 0xa6, /* at 64: bl aff0 <fixup> */
157	/*72*/ 0x80, 0x01, 0x00, 0x30, 0x81, 0x41, 0x00, 0x2c,
158	/*80*/ 0x81, 0x21, 0x00, 0x28, 0x7c, 0x08, 0x03, 0xa6,
159	/*88*/ 0x81, 0x01, 0x00, 0x24, 0x80, 0x01, 0x00, 0x08,
160	/*96*/ 0x80, 0xe1, 0x00, 0x20, 0x80, 0xc1, 0x00, 0x1c,
161	/*104*/0x7c, 0x0f, 0xf1, 0x20, 0x80, 0xa1, 0x00, 0x18,
162	/*112*/0x80, 0x81, 0x00, 0x14, 0x80, 0x61, 0x00, 0x10,
163	/*120*/0x80, 0x01, 0x00, 0x0c, 0x38, 0x21, 0x00, 0x40,
164	/*128*/0x4e, 0x80, 0x04, 0x20 };
165    static struct pattern pat = {
166	"ppc32-def", 132, {{ 0,65 }, { 68,64 }, { 132,0 }} };
167
168    if (VG_(strncmp)(obj->name, "/lib/ld", 7) != 0) return False;
169    return check_code(obj, code, &pat);
170#endif
171
172#if defined(VGP_amd64_linux)
173    static unsigned char code[] = {
174	/* 0*/ 0x48, 0x83, 0xec, 0x38, 0x48, 0x89, 0x04, 0x24,
175	/* 8*/ 0x48, 0x89, 0x4c, 0x24, 0x08, 0x48, 0x89, 0x54, 0x24, 0x10,
176	/*18*/ 0x48, 0x89, 0x74, 0x24, 0x18, 0x48, 0x89, 0x7c, 0x24, 0x20,
177	/*28*/ 0x4c, 0x89, 0x44, 0x24, 0x28, 0x4c, 0x89, 0x4c, 0x24, 0x30,
178	/*38*/ 0x48, 0x8b, 0x74, 0x24, 0x40, 0x49, 0x89, 0xf3,
179	/*46*/ 0x4c, 0x01, 0xde, 0x4c, 0x01, 0xde, 0x48, 0xc1, 0xe6, 0x03,
180	/*56*/ 0x48, 0x8b, 0x7c, 0x24, 0x38, 0xe8, 0xee, 0x01, 0x00, 0x00,
181	/*66*/ 0x49, 0x89, 0xc3, 0x4c, 0x8b, 0x4c, 0x24, 0x30,
182	/*74*/ 0x4c, 0x8b, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x7c, 0x24, 0x20,
183	/*84*/ 0x48, 0x8b, 0x74, 0x24, 0x18, 0x48, 0x8b, 0x54, 0x24, 0x10,
184	/*94*/ 0x48, 0x8b, 0x4c, 0x24, 0x08, 0x48, 0x8b, 0x04, 0x24,
185	/*103*/0x48, 0x83, 0xc4, 0x48, 0x41, 0xff, 0xe3 };
186    static struct pattern pat = {
187	"amd64-def", 110, {{ 0,62 }, { 66,44 }, { 110,0 }} };
188
189    if ((VG_(strncmp)(obj->name, "/lib/ld", 7) != 0) &&
190	(VG_(strncmp)(obj->name, "/lib64/ld", 9) != 0)) return False;
191    return check_code(obj, code, &pat);
192#endif
193
194    /* For other platforms, no patterns known */
195    return False;
196}
197
198
199/*------------------------------------------------------------*/
200/*--- Object/File/Function hash entry operations           ---*/
201/*------------------------------------------------------------*/
202
203/* Object hash table, fixed */
204static obj_node* obj_table[N_OBJ_ENTRIES];
205
206void CLG_(init_obj_table)()
207{
208    Int i;
209    for (i = 0; i < N_OBJ_ENTRIES; i++)
210	obj_table[i] = 0;
211}
212
213#define HASH_CONSTANT   256
214
215static UInt str_hash(const Char *s, UInt table_size)
216{
217    int hash_value = 0;
218    for ( ; *s; s++)
219        hash_value = (HASH_CONSTANT * hash_value + *s) % table_size;
220    return hash_value;
221}
222
223
224static Char* anonymous_obj = "???";
225
226static __inline__
227obj_node* new_obj_node(DebugInfo* di, obj_node* next)
228{
229   Int i;
230   obj_node* new;
231
232   new = (obj_node*) CLG_MALLOC("cl.fn.non.1", sizeof(obj_node));
233   new->name  = di ? VG_(strdup)( "cl.fn.non.2",VG_(seginfo_filename)(di) )
234                     : anonymous_obj;
235   for (i = 0; i < N_FILE_ENTRIES; i++) {
236      new->files[i] = NULL;
237   }
238   CLG_(stat).distinct_objs ++;
239   new->number  = CLG_(stat).distinct_objs;
240   /* JRS 2008 Feb 19: maybe rename .start/.size/.offset to
241      .text_avma/.text_size/.test_bias to make it clearer what these
242      fields really mean */
243   new->start   = di ? VG_(seginfo_get_text_avma)(di) : 0;
244   new->size    = di ? VG_(seginfo_get_text_size)(di) : 0;
245   new->offset  = di ? VG_(seginfo_get_text_bias)(di) : 0;
246   new->next    = next;
247
248   // not only used for debug output (see static.c)
249   new->last_slash_pos = 0;
250   i = 0;
251   while(new->name[i]) {
252	if (new->name[i]=='/') new->last_slash_pos = i+1;
253	i++;
254   }
255
256   if (runtime_resolve_addr == 0) search_runtime_resolve(new);
257
258   return new;
259}
260
261obj_node* CLG_(get_obj_node)(DebugInfo* di)
262{
263    obj_node*    curr_obj_node;
264    UInt         objname_hash;
265    const UChar* obj_name;
266
267    obj_name = di ? (Char*) VG_(seginfo_filename)(di) : anonymous_obj;
268
269    /* lookup in obj hash */
270    objname_hash = str_hash(obj_name, N_OBJ_ENTRIES);
271    curr_obj_node = obj_table[objname_hash];
272    while (NULL != curr_obj_node &&
273	   VG_(strcmp)(obj_name, curr_obj_node->name) != 0) {
274	curr_obj_node = curr_obj_node->next;
275    }
276    if (NULL == curr_obj_node) {
277	obj_table[objname_hash] = curr_obj_node =
278	    new_obj_node(di, obj_table[objname_hash]);
279    }
280
281    return curr_obj_node;
282}
283
284
285static __inline__
286file_node* new_file_node(Char filename[FILENAME_LEN],
287			 obj_node* obj, file_node* next)
288{
289  Int i;
290  file_node* new = (file_node*) CLG_MALLOC("cl.fn.nfn.1",
291                                           sizeof(file_node));
292  new->name  = VG_(strdup)("cl.fn.nfn.2", filename);
293  for (i = 0; i < N_FN_ENTRIES; i++) {
294    new->fns[i] = NULL;
295  }
296  CLG_(stat).distinct_files++;
297  new->number  = CLG_(stat).distinct_files;
298  new->obj     = obj;
299  new->next      = next;
300  return new;
301}
302
303
304file_node* CLG_(get_file_node)(obj_node* curr_obj_node,
305			      Char filename[FILENAME_LEN])
306{
307    file_node* curr_file_node;
308    UInt       filename_hash;
309
310    /* lookup in file hash */
311    filename_hash = str_hash(filename, N_FILE_ENTRIES);
312    curr_file_node = curr_obj_node->files[filename_hash];
313    while (NULL != curr_file_node &&
314	   VG_(strcmp)(filename, curr_file_node->name) != 0) {
315	curr_file_node = curr_file_node->next;
316    }
317    if (NULL == curr_file_node) {
318	curr_obj_node->files[filename_hash] = curr_file_node =
319	    new_file_node(filename, curr_obj_node,
320			  curr_obj_node->files[filename_hash]);
321    }
322
323    return curr_file_node;
324}
325
326/* forward decl. */
327static void resize_fn_array(void);
328
329static __inline__
330fn_node* new_fn_node(Char fnname[FILENAME_LEN],
331		     file_node* file, fn_node* next)
332{
333    fn_node* new = (fn_node*) CLG_MALLOC("cl.fn.nfnnd.1",
334                                         sizeof(fn_node));
335    new->name = VG_(strdup)("cl.fn.nfnnd.2", fnname);
336
337    CLG_(stat).distinct_fns++;
338    new->number   = CLG_(stat).distinct_fns;
339    new->last_cxt = 0;
340    new->pure_cxt = 0;
341    new->file     = file;
342    new->next     = next;
343
344    new->dump_before  = False;
345    new->dump_after   = False;
346    new->zero_before  = False;
347    new->toggle_collect = False;
348    new->skip         = False;
349    new->pop_on_jump  = CLG_(clo).pop_on_jump;
350    new->is_malloc    = False;
351    new->is_realloc   = False;
352    new->is_free      = False;
353
354    new->group        = 0;
355    new->separate_callers    = CLG_(clo).separate_callers;
356    new->separate_recursions = CLG_(clo).separate_recursions;
357
358#if CLG_ENABLE_DEBUG
359    new->verbosity    = -1;
360#endif
361
362    if (CLG_(stat).distinct_fns >= current_fn_active.size)
363	resize_fn_array();
364
365    return new;
366}
367
368
369/* Get a function node in hash2 with known file node.
370 * hash nodes are created if needed
371 */
372static
373fn_node* get_fn_node_infile(file_node* curr_file_node,
374			    Char fnname[FN_NAME_LEN])
375{
376    fn_node* curr_fn_node;
377    UInt     fnname_hash;
378
379    CLG_ASSERT(curr_file_node != 0);
380
381    /* lookup in function hash */
382    fnname_hash = str_hash(fnname, N_FN_ENTRIES);
383    curr_fn_node = curr_file_node->fns[fnname_hash];
384    while (NULL != curr_fn_node &&
385	   VG_(strcmp)(fnname, curr_fn_node->name) != 0) {
386	curr_fn_node = curr_fn_node->next;
387    }
388    if (NULL == curr_fn_node) {
389	curr_file_node->fns[fnname_hash] = curr_fn_node =
390            new_fn_node(fnname, curr_file_node,
391			curr_file_node->fns[fnname_hash]);
392    }
393
394    return curr_fn_node;
395}
396
397
398/* Get a function node in a Segment.
399 * Hash nodes are created if needed.
400 */
401static __inline__
402fn_node* get_fn_node_inseg(DebugInfo* di,
403			   Char filename[FILENAME_LEN],
404			   Char fnname[FN_NAME_LEN])
405{
406  obj_node  *obj  = CLG_(get_obj_node)(di);
407  file_node *file = CLG_(get_file_node)(obj, filename);
408  fn_node   *fn   = get_fn_node_infile(file, fnname);
409
410  return fn;
411}
412
413
414Bool CLG_(get_debug_info)(Addr instr_addr,
415			 Char file[FILENAME_LEN],
416			 Char fn_name[FN_NAME_LEN], UInt* line_num,
417			 DebugInfo** pDebugInfo)
418{
419  Bool found_file_line, found_fn, found_dirname, result = True;
420  Char dir[FILENAME_LEN];
421  UInt line;
422
423  CLG_DEBUG(6, "  + get_debug_info(%#lx)\n", instr_addr);
424
425  if (pDebugInfo) {
426      *pDebugInfo = VG_(find_seginfo)(instr_addr);
427
428      // for generated code in anonymous space, pSegInfo is 0
429   }
430
431   found_file_line = VG_(get_filename_linenum)(instr_addr,
432					       file, FILENAME_LEN,
433					       dir, FILENAME_LEN,
434					       &found_dirname,
435					       &line);
436   found_fn = VG_(get_fnname)(instr_addr,
437			      fn_name, FN_NAME_LEN);
438
439   if (found_dirname) {
440       // +1 for the '/'.
441       CLG_ASSERT(VG_(strlen)(dir) + VG_(strlen)(file) + 1 < FILENAME_LEN);
442       VG_(strcat)(dir, "/");         // Append '/'
443       VG_(strcat)(dir, file);    // Append file to dir
444       VG_(strcpy)(file, dir);    // Move dir+file to file
445   }
446
447   if (!found_file_line && !found_fn) {
448     CLG_(stat).no_debug_BBs++;
449     VG_(strcpy)(file, "???");
450     VG_(strcpy)(fn_name,  "???");
451     if (line_num) *line_num=0;
452     result = False;
453
454   } else if ( found_file_line &&  found_fn) {
455     CLG_(stat).full_debug_BBs++;
456     if (line_num) *line_num=line;
457
458   } else if ( found_file_line && !found_fn) {
459     CLG_(stat).file_line_debug_BBs++;
460     VG_(strcpy)(fn_name,  "???");
461     if (line_num) *line_num=line;
462
463   } else  /*(!found_file_line &&  found_fn)*/ {
464     CLG_(stat).fn_name_debug_BBs++;
465     VG_(strcpy)(file, "???");
466     if (line_num) *line_num=0;
467   }
468
469   CLG_DEBUG(6, "  - get_debug_info(%#lx): seg '%s', fn %s\n",
470	    instr_addr,
471	    !pDebugInfo   ? (const UChar*)"-" :
472	    (*pDebugInfo) ? VG_(seginfo_filename)(*pDebugInfo) :
473	    (const UChar*)"(None)",
474	    fn_name);
475
476  return result;
477}
478
479/* for _libc_freeres_wrapper => _exit renaming */
480static BB* exit_bb = 0;
481
482
483/*
484 * Attach function struct to a BB from debug info.
485 */
486fn_node* CLG_(get_fn_node)(BB* bb)
487{
488    Char       filename[FILENAME_LEN], fnname[FN_NAME_LEN];
489    DebugInfo* di;
490    UInt       line_num;
491    fn_node*   fn;
492
493    /* fn from debug info is idempotent for a BB */
494    if (bb->fn) return bb->fn;
495
496    CLG_DEBUG(3,"+ get_fn_node(BB %#lx)\n", bb_addr(bb));
497
498    /* get function/file name, line number and object of
499     * the BB according to debug information
500     */
501    CLG_(get_debug_info)(bb_addr(bb),
502			filename, fnname, &line_num, &di);
503
504    if (0 == VG_(strcmp)(fnname, "???")) {
505	int p;
506
507	/* Use address as found in library */
508	if (sizeof(Addr) == 4)
509	    p = VG_(sprintf)(fnname, "%#08lx", bb->offset);
510	else
511	    // 64bit address
512	    p = VG_(sprintf)(fnname, "%#016lx", bb->offset);
513
514	VG_(sprintf)(fnname+p, "%s",
515		     (bb->sect_kind == Vg_SectData) ? " [Data]" :
516		     (bb->sect_kind == Vg_SectBSS)  ? " [BSS]"  :
517		     (bb->sect_kind == Vg_SectGOT)  ? " [GOT]"  :
518		     (bb->sect_kind == Vg_SectPLT)  ? " [PLT]"  : "");
519    }
520    else {
521      if (VG_(get_fnname_if_entry)(bb_addr(bb), fnname, FN_NAME_LEN))
522	bb->is_entry = 1;
523    }
524
525    /* HACK for correct _exit:
526     * _exit is redirected to VG_(__libc_freeres_wrapper) by valgrind,
527     * so we rename it back again :-)
528     */
529    if (0 == VG_(strcmp)(fnname, "vgPlain___libc_freeres_wrapper")
530	&& exit_bb) {
531      CLG_(get_debug_info)(bb_addr(exit_bb),
532			  filename, fnname, &line_num, &di);
533
534	CLG_DEBUG(1, "__libc_freeres_wrapper renamed to _exit\n");
535    }
536    if (0 == VG_(strcmp)(fnname, "_exit") && !exit_bb)
537	exit_bb = bb;
538
539    if (runtime_resolve_addr &&
540	(bb_addr(bb) >= runtime_resolve_addr) &&
541	(bb_addr(bb) < runtime_resolve_addr + runtime_resolve_length)) {
542	/* BB in runtime_resolve found by code check; use this name */
543	VG_(sprintf)(fnname, "_dl_runtime_resolve");
544    }
545
546    /* get fn_node struct for this function */
547    fn = get_fn_node_inseg( di, filename, fnname);
548
549    /* if this is the 1st time the function is seen,
550     * some attributes are set */
551    if (fn->pure_cxt == 0) {
552
553      /* Every function gets a "pure" context, i.e. a context with stack
554       * depth 1 only with this function. This is for compression of mangled
555       * names
556       */
557      fn_node* pure[2];
558      pure[0] = 0;
559      pure[1] = fn;
560      fn->pure_cxt = CLG_(get_cxt)(pure+1);
561
562      if (bb->sect_kind == Vg_SectPLT)
563	fn->skip = CLG_(clo).skip_plt;
564
565      if (VG_(strcmp)(fn->name, "_dl_runtime_resolve")==0) {
566	  fn->pop_on_jump = True;
567
568	  if (VG_(clo_verbosity) > 1)
569	      VG_(message)(Vg_DebugMsg, "Symbol match: found runtime_resolve: %s +%#lx=%#lx",
570		      bb->obj->name + bb->obj->last_slash_pos,
571		      bb->offset, bb_addr(bb));
572      }
573
574      fn->is_malloc  = (VG_(strcmp)(fn->name, "malloc")==0);
575      fn->is_realloc = (VG_(strcmp)(fn->name, "realloc")==0);
576      fn->is_free    = (VG_(strcmp)(fn->name, "free")==0);
577
578      /* apply config options from function name patterns
579       * given on command line */
580      CLG_(update_fn_config)(fn);
581    }
582
583
584    bb->fn   = fn;
585    bb->line = line_num;
586
587    CLG_DEBUG(3,"- get_fn_node(BB %#lx): %s (in %s:%u)\n",
588	     bb_addr(bb), fnname, filename, line_num);
589
590    return fn;
591}
592
593
594/*------------------------------------------------------------*/
595/*--- Active function array operations                     ---*/
596/*------------------------------------------------------------*/
597
598/* The active function array is a thread-specific array
599 * of UInts, mapping function numbers to the active count of
600 * functions.
601 * The active count is the number of times a function appears
602 * in the current call stack, and is used when costs for recursion
603 * levels should be separated.
604 */
605
606UInt* CLG_(get_fn_entry)(Int n)
607{
608  CLG_ASSERT(n < current_fn_active.size);
609  return current_fn_active.array + n;
610}
611
612void CLG_(init_fn_array)(fn_array* a)
613{
614  Int i;
615
616  CLG_ASSERT(a != 0);
617
618  a->size = N_INITIAL_FN_ARRAY_SIZE;
619  if (a->size <= CLG_(stat).distinct_fns)
620    a->size = CLG_(stat).distinct_fns+1;
621
622  a->array = (UInt*) CLG_MALLOC("cl.fn.gfe.1",
623                                a->size * sizeof(UInt));
624  for(i=0;i<a->size;i++)
625    a->array[i] = 0;
626}
627
628void CLG_(copy_current_fn_array)(fn_array* dst)
629{
630  CLG_ASSERT(dst != 0);
631
632  dst->size  = current_fn_active.size;
633  dst->array = current_fn_active.array;
634}
635
636fn_array* CLG_(get_current_fn_array)()
637{
638  return &current_fn_active;
639}
640
641void CLG_(set_current_fn_array)(fn_array* a)
642{
643  CLG_ASSERT(a != 0);
644
645  current_fn_active.size  = a->size;
646  current_fn_active.array = a->array;
647  if (current_fn_active.size <= CLG_(stat).distinct_fns)
648    resize_fn_array();
649}
650
651/* ensure that active_array is big enough:
652 *  <distinct_fns> is the highest index, so <fn_active_array_size>
653 *  has to be bigger than that.
654 */
655static void resize_fn_array(void)
656{
657    UInt* new;
658    Int i, newsize;
659
660    newsize = current_fn_active.size;
661    while (newsize <= CLG_(stat).distinct_fns) newsize *=2;
662
663    CLG_DEBUG(0, "Resize fn_active_array: %d => %d\n",
664	     current_fn_active.size, newsize);
665
666    new = (UInt*) CLG_MALLOC("cl.fn.rfa.1", newsize * sizeof(UInt));
667    for(i=0;i<current_fn_active.size;i++)
668      new[i] = current_fn_active.array[i];
669    while(i<newsize)
670	new[i++] = 0;
671
672    VG_(free)(current_fn_active.array);
673    current_fn_active.size = newsize;
674    current_fn_active.array = new;
675    CLG_(stat).fn_array_resizes++;
676}
677
678
679