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