blob: 3efafe6ed5fa15582b4b26af793f3481759a28ad [file] [log] [blame]
sewardjb5f6f512005-03-10 23:59:00 +00001
sewardjde4a1d02002-03-22 01:27:54 +00002/*--------------------------------------------------------------------*/
3/*--- Management of symbols and debugging information. ---*/
4/*--- vg_symtab2.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2000-2005 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
nethercotef1e5e152004-09-01 23:58:16 +000032#include "core.h"
jsgfcb1d1c02003-10-14 21:55:10 +000033#include "vg_symtypes.h"
34#include "vg_symtab2.h"
sewardjde4a1d02002-03-22 01:27:54 +000035
sewardj55f9d1a2005-04-25 11:11:44 +000036#include "pub_core_aspacemgr.h"
37
sewardjde4a1d02002-03-22 01:27:54 +000038#include <elf.h> /* ELF defns */
sewardjde4a1d02002-03-22 01:27:54 +000039
sewardjb5f6f512005-03-10 23:59:00 +000040static SegInfo* segInfo = NULL;
41
sewardj7a21c612005-02-18 09:38:08 +000042/*------------------------------------------------------------*/
43/*--- 32/64-bit parameterisation ---*/
44/*------------------------------------------------------------*/
45
46/* For all the ELF macros and types which specify '32' or '64',
47 select the correct variant for this platform and give it
48 an 'XX' name. Then use the 'XX' variant consistently in
49 the rest of this file.
50*/
51#if VGA_WORD_SIZE == 4
52# define ElfXX_Ehdr Elf32_Ehdr
53# define ElfXX_Shdr Elf32_Shdr
54# define ElfXX_Phdr Elf32_Phdr
55# define ElfXX_Sym Elf32_Sym
56# define ElfXX_Word Elf32_Word
57# define ElfXX_Addr Elf32_Addr
58# define ElfXX_Dyn Elf32_Dyn
59# define ELFXX_ST_BIND ELF32_ST_BIND
60# define ELFXX_ST_TYPE ELF32_ST_TYPE
61
62#elif VGA_WORD_SIZE == 8
63# define ElfXX_Ehdr Elf64_Ehdr
64# define ElfXX_Shdr Elf64_Shdr
65# define ElfXX_Phdr Elf64_Phdr
66# define ElfXX_Sym Elf64_Sym
67# define ElfXX_Word Elf64_Word
68# define ElfXX_Addr Elf64_Addr
69# define ElfXX_Dyn Elf64_Dyn
70# define ELFXX_ST_BIND ELF64_ST_BIND
71# define ELFXX_ST_TYPE ELF64_ST_TYPE
72
73#else
74# error "VGA_WORD_SIZE should be 4 or 8"
75#endif
76
77
78/*------------------------------------------------------------*/
79/*--- ---*/
80/*------------------------------------------------------------*/
81
rjwalshe4e779d2004-04-16 23:02:29 +000082static Bool
nethercoteb1e1ad42004-08-03 23:44:12 +000083intercept_demangle(const Char*, Char*, Int);
njn9aae6742002-04-30 13:44:01 +000084
sewardjde4a1d02002-03-22 01:27:54 +000085/* Majorly rewritten Sun 3 Feb 02 to enable loading symbols from
86 dlopen()ed libraries, which is something that KDE3 does a lot.
sewardjde4a1d02002-03-22 01:27:54 +000087
njn25e49d8e72002-09-23 09:36:25 +000088 Stabs reader greatly improved by Nick Nethercote, Apr 02.
sewardjde4a1d02002-03-22 01:27:54 +000089*/
90
sewardjde4a1d02002-03-22 01:27:54 +000091static void freeSegInfo ( SegInfo* si )
92{
jsgfcb1d1c02003-10-14 21:55:10 +000093 struct strchunk *chunk, *next;
sewardjde4a1d02002-03-22 01:27:54 +000094 vg_assert(si != NULL);
njn25e49d8e72002-09-23 09:36:25 +000095 if (si->filename) VG_(arena_free)(VG_AR_SYMTAB, si->filename);
96 if (si->symtab) VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
97 if (si->loctab) VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
jsgfcb1d1c02003-10-14 21:55:10 +000098 if (si->scopetab) VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
sewardj5c638c22005-04-30 07:55:58 +000099 if (si->cfisi) VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
jsgfcb1d1c02003-10-14 21:55:10 +0000100
101 for(chunk = si->strchunks; chunk != NULL; chunk = next) {
102 next = chunk->next;
103 VG_(arena_free)(VG_AR_SYMTAB, chunk);
104 }
njn25e49d8e72002-09-23 09:36:25 +0000105 VG_(arena_free)(VG_AR_SYMTAB, si);
sewardjde4a1d02002-03-22 01:27:54 +0000106}
107
108
109/*------------------------------------------------------------*/
110/*--- Adding stuff ---*/
111/*------------------------------------------------------------*/
112
113/* Add a str to the string table, including terminating zero, and
jsgfcb1d1c02003-10-14 21:55:10 +0000114 return pointer to the string in vg_strtab. Unless it's been seen
115 recently, in which case we find the old pointer and return that.
116 This avoids the most egregious duplications.
sewardjde4a1d02002-03-22 01:27:54 +0000117
jsgfcb1d1c02003-10-14 21:55:10 +0000118 JSGF: changed from returning an index to a pointer, and changed to
119 a chunking memory allocator rather than reallocating, so the
120 pointers are stable.
121*/
122
123Char *VG_(addStr) ( SegInfo* si, Char* str, Int len )
sewardjde4a1d02002-03-22 01:27:54 +0000124{
jsgfcb1d1c02003-10-14 21:55:10 +0000125# define EMPTY NULL
njn25e49d8e72002-09-23 09:36:25 +0000126# define NN 5
127
128 /* prevN[0] has the most recent, prevN[NN-1] the least recent */
jsgfcb1d1c02003-10-14 21:55:10 +0000129 static Char *prevN[NN] = { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY };
njn25e49d8e72002-09-23 09:36:25 +0000130 static SegInfo* curr_si = NULL;
jsgfcb1d1c02003-10-14 21:55:10 +0000131 struct strchunk *chunk;
132 Int i, space_needed;
njn25e49d8e72002-09-23 09:36:25 +0000133
jsgfcb1d1c02003-10-14 21:55:10 +0000134 if (len == -1)
135 len = VG_(strlen)(str);
njn25e49d8e72002-09-23 09:36:25 +0000136
137 /* Avoid gratuitous duplication: if we saw `str' within the last NN,
138 * within this segment, return that index. Saves about 200KB in glibc,
139 * extra time taken is too small to measure. --NJN 2002-Aug-30 */
140 if (curr_si == si) {
141 for (i = NN-1; i >= 0; i--) {
sewardjcda419b2002-10-01 08:59:36 +0000142 if (EMPTY != prevN[i]
jsgfcb1d1c02003-10-14 21:55:10 +0000143 && NULL != si->strchunks
jsgfa065a9c2003-10-14 22:07:31 +0000144 && 0 == VG_(memcmp)(str, prevN[i], len+1)) {
njn25e49d8e72002-09-23 09:36:25 +0000145 return prevN[i];
146 }
147 }
148 } else {
149 /* New segment */
150 curr_si = si;
sewardjcda419b2002-10-01 08:59:36 +0000151 for (i = 0; i < NN; i++) prevN[i] = EMPTY;
njn25e49d8e72002-09-23 09:36:25 +0000152 }
153 /* Shuffle prevous ones along, put new one in. */
jsgfcb1d1c02003-10-14 21:55:10 +0000154 for (i = NN-1; i > 0; i--)
155 prevN[i] = prevN[i-1];
njn25e49d8e72002-09-23 09:36:25 +0000156
157# undef EMPTY
158
jsgfcb1d1c02003-10-14 21:55:10 +0000159 space_needed = 1 + len;
njn25e49d8e72002-09-23 09:36:25 +0000160
jsgfcb1d1c02003-10-14 21:55:10 +0000161 if (si->strchunks == NULL ||
162 (si->strchunks->strtab_used + space_needed) > STRCHUNKSIZE) {
163 chunk = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*chunk));
164 chunk->strtab_used = 0;
165 chunk->next = si->strchunks;
166 si->strchunks = chunk;
sewardjde4a1d02002-03-22 01:27:54 +0000167 }
jsgfcb1d1c02003-10-14 21:55:10 +0000168 chunk = si->strchunks;
sewardjde4a1d02002-03-22 01:27:54 +0000169
jsgfcb1d1c02003-10-14 21:55:10 +0000170 prevN[0] = &chunk->strtab[chunk->strtab_used];
171 VG_(memcpy)(prevN[0], str, len);
172 chunk->strtab[chunk->strtab_used+len] = '\0';
173 chunk->strtab_used += space_needed;
sewardjde4a1d02002-03-22 01:27:54 +0000174
jsgfcb1d1c02003-10-14 21:55:10 +0000175 return prevN[0];
sewardjde4a1d02002-03-22 01:27:54 +0000176}
177
178/* Add a symbol to the symbol table. */
179
180static __inline__
181void addSym ( SegInfo* si, RiSym* sym )
182{
sewardj05bcdcb2003-05-18 10:05:38 +0000183 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000184 RiSym* new_tab;
185
186 /* Ignore zero-sized syms. */
187 if (sym->size == 0) return;
188
189 if (si->symtab_used == si->symtab_size) {
190 new_sz = 2 * si->symtab_size;
191 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000192 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiSym) );
sewardjde4a1d02002-03-22 01:27:54 +0000193 if (si->symtab != NULL) {
194 for (i = 0; i < si->symtab_used; i++)
195 new_tab[i] = si->symtab[i];
njn25e49d8e72002-09-23 09:36:25 +0000196 VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
sewardjde4a1d02002-03-22 01:27:54 +0000197 }
198 si->symtab = new_tab;
199 si->symtab_size = new_sz;
200 }
201
202 si->symtab[si->symtab_used] = *sym;
203 si->symtab_used++;
204 vg_assert(si->symtab_used <= si->symtab_size);
205}
206
207/* Add a location to the location table. */
208
209static __inline__
210void addLoc ( SegInfo* si, RiLoc* loc )
211{
sewardj05bcdcb2003-05-18 10:05:38 +0000212 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000213 RiLoc* new_tab;
214
njne0ee0712002-05-03 16:41:05 +0000215 /* Zero-sized locs should have been ignored earlier */
216 vg_assert(loc->size > 0);
sewardjde4a1d02002-03-22 01:27:54 +0000217
218 if (si->loctab_used == si->loctab_size) {
219 new_sz = 2 * si->loctab_size;
220 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000221 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiLoc) );
sewardjde4a1d02002-03-22 01:27:54 +0000222 if (si->loctab != NULL) {
223 for (i = 0; i < si->loctab_used; i++)
224 new_tab[i] = si->loctab[i];
njn25e49d8e72002-09-23 09:36:25 +0000225 VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
sewardjde4a1d02002-03-22 01:27:54 +0000226 }
227 si->loctab = new_tab;
228 si->loctab_size = new_sz;
229 }
230
231 si->loctab[si->loctab_used] = *loc;
232 si->loctab_used++;
233 vg_assert(si->loctab_used <= si->loctab_size);
234}
235
236
sewardjb51f2e62002-06-01 23:11:19 +0000237/* Top-level place to call to add a source-location mapping entry. */
238
jsgfcb1d1c02003-10-14 21:55:10 +0000239void VG_(addLineInfo) ( SegInfo* si,
240 Char* filename,
241 Addr this,
242 Addr next,
243 Int lineno,
244 Int entry /* only needed for debug printing */
245 )
sewardjb51f2e62002-06-01 23:11:19 +0000246{
jsgfcb1d1c02003-10-14 21:55:10 +0000247 static const Bool debug = False;
sewardjb51f2e62002-06-01 23:11:19 +0000248 RiLoc loc;
249 Int size = next - this;
250
251 /* Ignore zero-sized locs */
252 if (this == next) return;
253
jsgfcb1d1c02003-10-14 21:55:10 +0000254 if (debug)
255 VG_(printf)(" src %s line %d %p-%p\n", filename, lineno, this, next);
256
sewardjb51f2e62002-06-01 23:11:19 +0000257 /* Maximum sanity checking. Some versions of GNU as do a shabby
258 * job with stabs entries; if anything looks suspicious, revert to
259 * a size of 1. This should catch the instruction of interest
260 * (since if using asm-level debug info, one instruction will
261 * correspond to one line, unlike with C-level debug info where
262 * multiple instructions can map to the one line), but avoid
263 * catching any other instructions bogusly. */
thughesc1c57952004-11-01 17:36:15 +0000264 if (this > next) {
265 if (VG_(clo_verbosity) > 2) {
266 VG_(message)(Vg_DebugMsg,
267 "warning: line info addresses out of order "
268 "at entry %d: 0x%x 0x%x", entry, this, next);
269 }
sewardjb51f2e62002-06-01 23:11:19 +0000270 size = 1;
271 }
272
273 if (size > MAX_LOC_SIZE) {
sewardjd84606d2002-06-18 01:04:57 +0000274 if (0)
sewardjb51f2e62002-06-01 23:11:19 +0000275 VG_(message)(Vg_DebugMsg,
sewardj08a50f62002-06-17 02:21:20 +0000276 "warning: line info address range too large "
sewardjb51f2e62002-06-01 23:11:19 +0000277 "at entry %d: %d", entry, size);
278 size = 1;
279 }
280
sewardj08a50f62002-06-17 02:21:20 +0000281 /* vg_assert(this < si->start + si->size && next-1 >= si->start); */
njne306ffe2002-06-08 13:34:17 +0000282 if (this >= si->start + si->size || next-1 < si->start) {
sewardjd84606d2002-06-18 01:04:57 +0000283 if (0)
sewardj08a50f62002-06-17 02:21:20 +0000284 VG_(message)(Vg_DebugMsg,
285 "warning: ignoring line info entry falling "
286 "outside current SegInfo: %p %p %p %p",
287 si->start, si->start + si->size,
288 this, next-1);
njne306ffe2002-06-08 13:34:17 +0000289 return;
290 }
291
292 vg_assert(lineno >= 0);
293 if (lineno > MAX_LINENO) {
294 VG_(message)(Vg_UserMsg,
sewardj08a50f62002-06-17 02:21:20 +0000295 "warning: ignoring line info entry with "
296 "huge line number (%d)", lineno);
njne306ffe2002-06-08 13:34:17 +0000297 VG_(message)(Vg_UserMsg,
298 " Can't handle line numbers "
sewardj08a50f62002-06-17 02:21:20 +0000299 "greater than %d, sorry", MAX_LINENO);
njne306ffe2002-06-08 13:34:17 +0000300 return;
301 }
sewardjb51f2e62002-06-01 23:11:19 +0000302
303 loc.addr = this;
304 loc.size = (UShort)size;
305 loc.lineno = lineno;
jsgfcb1d1c02003-10-14 21:55:10 +0000306 loc.filename = filename;
sewardjb642dc22002-10-12 17:27:16 +0000307
308 if (0) VG_(message)(Vg_DebugMsg,
309 "addLoc: addr %p, size %d, line %d, file %s",
jsgfcb1d1c02003-10-14 21:55:10 +0000310 this,size,lineno,filename);
sewardjb642dc22002-10-12 17:27:16 +0000311
sewardjb51f2e62002-06-01 23:11:19 +0000312 addLoc ( si, &loc );
313}
314
jsgfcb1d1c02003-10-14 21:55:10 +0000315static __inline__
316void addScopeRange ( SegInfo* si, ScopeRange *range )
317{
318 Int new_sz, i;
319 ScopeRange* new_tab;
320
321 /* Zero-sized scopes should have been ignored earlier */
322 vg_assert(range->size > 0);
323
324 if (si->scopetab_used == si->scopetab_size) {
325 new_sz = 2 * si->scopetab_size;
326 if (new_sz == 0) new_sz = 500;
327 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(*new_tab) );
328 if (si->scopetab != NULL) {
329 for (i = 0; i < si->scopetab_used; i++)
330 new_tab[i] = si->scopetab[i];
331 VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
332 }
333 si->scopetab = new_tab;
334 si->scopetab_size = new_sz;
335 }
336
337 si->scopetab[si->scopetab_used] = *range;
338 si->scopetab_used++;
339 vg_assert(si->scopetab_used <= si->scopetab_size);
340}
341
342
343/* Top-level place to call to add a source-location mapping entry. */
344
345void VG_(addScopeInfo) ( SegInfo* si,
346 Addr this,
347 Addr next,
348 Scope *scope)
349{
350 static const Bool debug = False;
351 Int size = next - this;
352 ScopeRange range;
353
fitzhardinge83d8a712004-02-05 22:58:37 +0000354 /* Ignore zero-sized or negative scopes */
355 if (size <= 0) {
jsgfcb1d1c02003-10-14 21:55:10 +0000356 if (debug)
357 VG_(printf)("ignoring zero-sized range, scope %p at %p\n", scope, this);
358 return;
359 }
360
361 if (debug)
362 VG_(printf)("adding scope range %p-%p (size=%d) scope %p (%d)\n",
363 this, next, next-this, scope, scope->depth);
364
365 range.addr = this;
366 range.size = size;
367 range.scope = scope;
368
369 addScopeRange ( si, &range );
370}
371
sewardj35165532005-04-30 18:47:48 +0000372
373/* Top-level place to call to add a CFI summary record. The supplied
374 CfiSI is copied. */
375void VG_(addCfiSI) ( SegInfo* si, CfiSI* cfisi )
376{
377 static const Bool debug = False;
378
379 if (debug) {
380 VG_(printf)("adding CfiSI: ");
381 VG_(ppCfiSI)(cfisi);
382 }
383
sewardjbf603752005-05-02 00:36:27 +0000384 vg_assert(cfisi->len > 0 && cfisi->len < 1000000);
385
sewardj35165532005-04-30 18:47:48 +0000386 UInt new_sz, i;
387 CfiSI* new_tab;
388
389 if (si->cfisi_used == si->cfisi_size) {
390 new_sz = 2 * si->cfisi_size;
391 if (new_sz == 0) new_sz = 20;
392 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(CfiSI) );
393 if (si->cfisi != NULL) {
394 for (i = 0; i < si->cfisi_used; i++)
395 new_tab[i] = si->cfisi[i];
396 VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
397 }
398 si->cfisi = new_tab;
399 si->cfisi_size = new_sz;
400 }
401
402 si->cfisi[si->cfisi_used] = *cfisi;
403 si->cfisi_used++;
404 vg_assert(si->cfisi_used <= si->cfisi_size);
405}
406
407
sewardjde4a1d02002-03-22 01:27:54 +0000408/*------------------------------------------------------------*/
409/*--- Helpers ---*/
410/*------------------------------------------------------------*/
411
412/* Non-fatal -- use vg_panic if terminal. */
jsgfcb1d1c02003-10-14 21:55:10 +0000413void VG_(symerr) ( Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000414{
415 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +0000416 VG_(message)(Vg_DebugMsg,"%s", msg );
sewardjde4a1d02002-03-22 01:27:54 +0000417}
418
419
420/* Print a symbol. */
421static
422void printSym ( SegInfo* si, Int i )
423{
424 VG_(printf)( "%5d: %8p .. %8p (%d) %s\n",
425 i,
426 si->symtab[i].addr,
427 si->symtab[i].addr + si->symtab[i].size - 1, si->symtab[i].size,
jsgfcb1d1c02003-10-14 21:55:10 +0000428 si->symtab[i].name );
sewardjde4a1d02002-03-22 01:27:54 +0000429}
430
nethercote80f76782003-11-13 22:34:00 +0000431#define TRACE_SYMTAB(format, args...) \
432 if (VG_(clo_trace_symtab)) { VG_(printf)(format, ## args); }
433
sewardjde4a1d02002-03-22 01:27:54 +0000434
435#if 0
436/* Print the entire sym tab. */
437static __attribute__ ((unused))
438void printSymtab ( void )
439{
440 Int i;
441 VG_(printf)("\n------ BEGIN vg_symtab ------\n");
442 for (i = 0; i < vg_symtab_used; i++)
443 printSym(i);
444 VG_(printf)("------ BEGIN vg_symtab ------\n");
445}
446#endif
447
448#if 0
449/* Paranoid strcat. */
450static
451void safeCopy ( UChar* dst, UInt maxlen, UChar* src )
452{
453 UInt i = 0, j = 0;
454 while (True) {
455 if (i >= maxlen) return;
456 if (dst[i] == 0) break;
457 i++;
458 }
459 while (True) {
460 if (i >= maxlen) return;
461 dst[i] = src[j];
462 if (src[j] == 0) return;
463 i++; j++;
464 }
465}
466#endif
467
sewardjb51f2e62002-06-01 23:11:19 +0000468
sewardjde4a1d02002-03-22 01:27:54 +0000469/*------------------------------------------------------------*/
470/*--- Canonicalisers ---*/
471/*------------------------------------------------------------*/
472
473/* Sort the symtab by starting address, and emit warnings if any
nethercote80f76782003-11-13 22:34:00 +0000474 symbols have overlapping address ranges. We use that old chestnut,
475 shellsort. Mash the table around so as to establish the property
476 that addresses are in order and the ranges to not overlap. This
477 facilitates using binary search to map addresses to symbols when we
478 come to query the table.
sewardjde4a1d02002-03-22 01:27:54 +0000479*/
jsgfcb1d1c02003-10-14 21:55:10 +0000480static Int compare_RiSym(void *va, void *vb) {
481 RiSym *a = (RiSym *)va;
482 RiSym *b = (RiSym *)vb;
483
nethercote05fdfac2004-08-01 20:24:46 +0000484 if (a->addr < b->addr) return -1;
485 if (a->addr > b->addr) return 1;
486 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000487}
488
fitzhardinge1c76dc42003-12-15 09:00:21 +0000489/* Two symbols have the same address. Which name do we prefer?
490
sewardjb5f6f512005-03-10 23:59:00 +0000491 The general rule is to prefer the shorter symbol name. If the
492 symbol contains a '@', which means its versioned, then the length
493 up to the '@' is used for length comparison purposes (so
494 "foo@GLIBC_2.4.2" is considered shorter than "foobar"), but if two
495 symbols have the same length, the one with the version string is
496 preferred. If all else fails, use alphabetical ordering.
fitzhardinge1c76dc42003-12-15 09:00:21 +0000497 */
498static RiSym *prefersym(RiSym *a, RiSym *b)
499{
sewardjb5f6f512005-03-10 23:59:00 +0000500 Int lena, lenb; /* full length */
501 Int vlena, vlenb; /* length without version */
502 const Char *vpa, *vpb;
fitzhardingeefda47f2003-12-15 23:31:52 +0000503
sewardjb5f6f512005-03-10 23:59:00 +0000504 vlena = lena = VG_(strlen)(a->name);
505 vlenb = lenb = VG_(strlen)(b->name);
fitzhardinge1c76dc42003-12-15 09:00:21 +0000506
sewardjb5f6f512005-03-10 23:59:00 +0000507 vpa = VG_(strchr)(a->name, '@');
508 vpb = VG_(strchr)(b->name, '@');
fitzhardinge1c76dc42003-12-15 09:00:21 +0000509
sewardjb5f6f512005-03-10 23:59:00 +0000510 if (vpa)
511 vlena = vpa - a->name;
512 if (vpb)
513 vlenb = vpb - b->name;
fitzhardingeefda47f2003-12-15 23:31:52 +0000514
sewardjb5f6f512005-03-10 23:59:00 +0000515 /* Select the shortest unversioned name */
516 if (vlena < vlenb)
517 return a;
518 else if (vlenb < vlena)
fitzhardinge1c76dc42003-12-15 09:00:21 +0000519 return b;
520
sewardjb5f6f512005-03-10 23:59:00 +0000521 /* Equal lengths; select the versioned name */
522 if (vpa && !vpb)
523 return a;
524 if (vpb && !vpa)
525 return b;
526
527 /* Either both versioned or neither is versioned; select them
528 alphabetically */
529 if (VG_(strcmp)(a->name, b->name) < 0)
530 return a;
531 else
532 return b;
fitzhardinge1c76dc42003-12-15 09:00:21 +0000533}
534
sewardjde4a1d02002-03-22 01:27:54 +0000535static
536void canonicaliseSymtab ( SegInfo* si )
537{
jsgfcb1d1c02003-10-14 21:55:10 +0000538 Int i, j, n_merged, n_truncated;
sewardjde4a1d02002-03-22 01:27:54 +0000539 Addr s1, s2, e1, e2;
540
541# define SWAP(ty,aa,bb) \
542 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
543
jsgfcb1d1c02003-10-14 21:55:10 +0000544 if (si->symtab_used == 0)
545 return;
sewardjde4a1d02002-03-22 01:27:54 +0000546
nethercote3acbb5d2003-11-13 21:50:45 +0000547 VG_(ssort)(si->symtab, si->symtab_used, sizeof(*si->symtab), compare_RiSym);
sewardjde4a1d02002-03-22 01:27:54 +0000548
rjwalshe4e779d2004-04-16 23:02:29 +0000549 for (i = 0; i < si->symtab_used; i++) {
550 if(VG_(strncmp)(si->symtab[i].name, VG_INTERCEPT_PREFIX,
551 VG_INTERCEPT_PREFIX_LEN) == 0) {
552 int len = VG_(strlen)(si->symtab[i].name);
sewardjb5f6f512005-03-10 23:59:00 +0000553 char *buf = VG_(arena_malloc)(VG_AR_SYMTAB, len), *colon;
nethercoteb1e1ad42004-08-03 23:44:12 +0000554 intercept_demangle(si->symtab[i].name, buf, len);
rjwalshe4e779d2004-04-16 23:02:29 +0000555 colon = buf + VG_(strlen)(buf) - 1;
556 while(*colon != ':') colon--;
557 VG_(strncpy_safely)(si->symtab[i].name, colon+1, len);
sewardjb5f6f512005-03-10 23:59:00 +0000558 VG_(arena_free)(VG_AR_SYMTAB, buf);
rjwalshe4e779d2004-04-16 23:02:29 +0000559 }
560 }
561
sewardjde4a1d02002-03-22 01:27:54 +0000562 cleanup_more:
563
564 /* If two symbols have identical address ranges, favour the
fitzhardinge98abfc72003-12-16 02:05:15 +0000565 one with the longer name (unless the extra length is junk)
sewardjde4a1d02002-03-22 01:27:54 +0000566 */
567 do {
568 n_merged = 0;
569 j = si->symtab_used;
570 si->symtab_used = 0;
571 for (i = 0; i < j; i++) {
572 if (i < j-1
573 && si->symtab[i].addr == si->symtab[i+1].addr
574 && si->symtab[i].size == si->symtab[i+1].size) {
575 n_merged++;
576 /* merge the two into one */
fitzhardinge1c76dc42003-12-15 09:00:21 +0000577 si->symtab[si->symtab_used++] = *prefersym(&si->symtab[i], &si->symtab[i+1]);
sewardjde4a1d02002-03-22 01:27:54 +0000578 i++;
579 } else {
580 si->symtab[si->symtab_used++] = si->symtab[i];
581 }
582 }
nethercote80f76782003-11-13 22:34:00 +0000583 TRACE_SYMTAB( "%d merged\n", n_merged);
sewardjde4a1d02002-03-22 01:27:54 +0000584 }
585 while (n_merged > 0);
586
587 /* Detect and "fix" overlapping address ranges. */
588 n_truncated = 0;
589
sewardj05bcdcb2003-05-18 10:05:38 +0000590 for (i = 0; i < ((Int)si->symtab_used) -1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000591
592 vg_assert(si->symtab[i].addr <= si->symtab[i+1].addr);
593
594 /* Check for common (no overlap) case. */
595 if (si->symtab[i].addr + si->symtab[i].size
596 <= si->symtab[i+1].addr)
597 continue;
598
599 /* There's an overlap. Truncate one or the other. */
600 if (VG_(clo_trace_symtab)) {
601 VG_(printf)("overlapping address ranges in symbol table\n\t");
602 printSym(si,i);
603 VG_(printf)("\t");
604 printSym(si,i+1);
605 VG_(printf)("\n");
606 }
607
608 /* Truncate one or the other. */
609 s1 = si->symtab[i].addr;
610 s2 = si->symtab[i+1].addr;
611 e1 = s1 + si->symtab[i].size - 1;
612 e2 = s2 + si->symtab[i+1].size - 1;
613 if (s1 < s2) {
614 e1 = s2-1;
615 } else {
616 vg_assert(s1 == s2);
617 if (e1 > e2) {
618 s1 = e2+1; SWAP(Addr,s1,s2); SWAP(Addr,e1,e2);
619 } else
620 if (e1 < e2) {
621 s2 = e1+1;
622 } else {
623 /* e1 == e2. Identical addr ranges. We'll eventually wind
624 up back at cleanup_more, which will take care of it. */
625 }
626 }
627 si->symtab[i].addr = s1;
628 si->symtab[i+1].addr = s2;
629 si->symtab[i].size = e1 - s1 + 1;
630 si->symtab[i+1].size = e2 - s2 + 1;
631 vg_assert(s1 <= s2);
632 vg_assert(si->symtab[i].size > 0);
633 vg_assert(si->symtab[i+1].size > 0);
634 /* It may be that the i+1 entry now needs to be moved further
635 along to maintain the address order requirement. */
636 j = i+1;
sewardj05bcdcb2003-05-18 10:05:38 +0000637 while (j < ((Int)si->symtab_used)-1
sewardjde4a1d02002-03-22 01:27:54 +0000638 && si->symtab[j].addr > si->symtab[j+1].addr) {
639 SWAP(RiSym,si->symtab[j],si->symtab[j+1]);
640 j++;
641 }
642 n_truncated++;
643 }
644
645 if (n_truncated > 0) goto cleanup_more;
646
647 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000648 for (i = 0; i < ((Int)si->symtab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000649 /* No zero-sized symbols. */
650 vg_assert(si->symtab[i].size > 0);
651 /* In order. */
652 vg_assert(si->symtab[i].addr < si->symtab[i+1].addr);
653 /* No overlaps. */
654 vg_assert(si->symtab[i].addr + si->symtab[i].size - 1
655 < si->symtab[i+1].addr);
656 }
657# undef SWAP
658}
659
jsgfcb1d1c02003-10-14 21:55:10 +0000660/* Sort the scope range table by starting address. Mash the table
661 around so as to establish the property that addresses are in order
662 and the ranges do not overlap. This facilitates using binary
663 search to map addresses to scopes when we come to query the
664 table.
665*/
666static Int compare_ScopeRange(void *va, void *vb) {
667 ScopeRange *a = (ScopeRange *)va;
668 ScopeRange *b = (ScopeRange *)vb;
669
nethercote05fdfac2004-08-01 20:24:46 +0000670 if (a->addr < b->addr) return -1;
671 if (a->addr > b->addr) return 1;
672 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000673}
674
675static
676void canonicaliseScopetab ( SegInfo* si )
677{
678 Int i,j;
679
680 if (si->scopetab_used == 0)
681 return;
682
683 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000684 VG_(ssort)(si->scopetab, si->scopetab_used, sizeof(*si->scopetab),
685 compare_ScopeRange);
jsgfcb1d1c02003-10-14 21:55:10 +0000686
687 /* If two adjacent entries overlap, truncate the first. */
688 for (i = 0; i < si->scopetab_used-1; i++) {
689 if (si->scopetab[i].addr + si->scopetab[i].size > si->scopetab[i+1].addr) {
690 Int new_size = si->scopetab[i+1].addr - si->scopetab[i].addr;
691
692 if (new_size < 0)
693 si->scopetab[i].size = 0;
694 else
695 si->scopetab[i].size = new_size;
696 }
697 }
698
699 /* Zap any zero-sized entries resulting from the truncation
700 process. */
701 j = 0;
702 for (i = 0; i < si->scopetab_used; i++) {
703 if (si->scopetab[i].size > 0) {
704 si->scopetab[j] = si->scopetab[i];
705 j++;
706 }
707 }
708 si->scopetab_used = j;
709
710 /* Ensure relevant postconditions hold. */
711 for (i = 0; i < si->scopetab_used-1; i++) {
712 /*
713 VG_(printf)("%d (%d) %d 0x%x\n",
714 i, si->scopetab[i+1].confident,
715 si->scopetab[i+1].size, si->scopetab[i+1].addr );
716 */
717 /* No zero-sized symbols. */
718 vg_assert(si->scopetab[i].size > 0);
719 /* In order. */
720 if (si->scopetab[i].addr >= si->scopetab[i+1].addr)
721 VG_(printf)("si->scopetab[%d] = %p,size=%d [%d] = %p,size=%d\n",
722 i, si->scopetab[i].addr, si->scopetab[i].size,
723 i+1, si->scopetab[i+1].addr, si->scopetab[i+1].size);
724 vg_assert(si->scopetab[i].addr < si->scopetab[i+1].addr);
725 /* No overlaps. */
726 vg_assert(si->scopetab[i].addr + si->scopetab[i].size - 1
727 < si->scopetab[i+1].addr);
728 }
729}
sewardjde4a1d02002-03-22 01:27:54 +0000730
731
732/* Sort the location table by starting address. Mash the table around
733 so as to establish the property that addresses are in order and the
734 ranges do not overlap. This facilitates using binary search to map
sewardjb51f2e62002-06-01 23:11:19 +0000735 addresses to locations when we come to query the table.
736*/
jsgfcb1d1c02003-10-14 21:55:10 +0000737static Int compare_RiLoc(void *va, void *vb) {
738 RiLoc *a = (RiLoc *)va;
739 RiLoc *b = (RiLoc *)vb;
740
nethercote05fdfac2004-08-01 20:24:46 +0000741 if (a->addr < b->addr) return -1;
742 if (a->addr > b->addr) return 1;
743 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000744}
745
sewardjde4a1d02002-03-22 01:27:54 +0000746static
747void canonicaliseLoctab ( SegInfo* si )
748{
jsgfcb1d1c02003-10-14 21:55:10 +0000749 Int i, j;
sewardjde4a1d02002-03-22 01:27:54 +0000750
751# define SWAP(ty,aa,bb) \
752 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
753
jsgfcb1d1c02003-10-14 21:55:10 +0000754 if (si->loctab_used == 0)
755 return;
756
sewardjde4a1d02002-03-22 01:27:54 +0000757 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000758 VG_(ssort)(si->loctab, si->loctab_used, sizeof(*si->loctab), compare_RiLoc);
sewardjde4a1d02002-03-22 01:27:54 +0000759
760 /* If two adjacent entries overlap, truncate the first. */
sewardj05bcdcb2003-05-18 10:05:38 +0000761 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000762 vg_assert(si->loctab[i].size < 10000);
763 if (si->loctab[i].addr + si->loctab[i].size > si->loctab[i+1].addr) {
764 /* Do this in signed int32 because the actual .size fields
njna1685902005-03-16 04:09:21 +0000765 are only 12 bits. */
sewardjde4a1d02002-03-22 01:27:54 +0000766 Int new_size = si->loctab[i+1].addr - si->loctab[i].addr;
767 if (new_size < 0) {
768 si->loctab[i].size = 0;
769 } else
njna1685902005-03-16 04:09:21 +0000770 if (new_size > MAX_LOC_SIZE) {
771 si->loctab[i].size = MAX_LOC_SIZE;
sewardjde4a1d02002-03-22 01:27:54 +0000772 } else {
773 si->loctab[i].size = (UShort)new_size;
774 }
775 }
776 }
777
778 /* Zap any zero-sized entries resulting from the truncation
779 process. */
780 j = 0;
sewardj05bcdcb2003-05-18 10:05:38 +0000781 for (i = 0; i < (Int)si->loctab_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000782 if (si->loctab[i].size > 0) {
783 si->loctab[j] = si->loctab[i];
784 j++;
785 }
786 }
787 si->loctab_used = j;
788
789 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000790 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000791 /*
792 VG_(printf)("%d (%d) %d 0x%x\n",
793 i, si->loctab[i+1].confident,
794 si->loctab[i+1].size, si->loctab[i+1].addr );
795 */
796 /* No zero-sized symbols. */
797 vg_assert(si->loctab[i].size > 0);
798 /* In order. */
799 vg_assert(si->loctab[i].addr < si->loctab[i+1].addr);
800 /* No overlaps. */
801 vg_assert(si->loctab[i].addr + si->loctab[i].size - 1
802 < si->loctab[i+1].addr);
803 }
804# undef SWAP
805}
806
807
sewardj3a1c7db2005-05-02 09:43:44 +0000808/* Sort the call-frame-info table by starting address. Mash the table
809 around so as to establish the property that addresses are in order
810 and the ranges do not overlap. This facilitates using binary
811 search to map addresses to locations when we come to query the
812 table.
813
814 Also, set cfisi_minaddr and cfisi_maxaddr to be the min and max of
815 any of the address ranges contained in cfisi[0 .. cfisi_used-1], so
816 as to facilitate rapidly skipping this SegInfo when looking for an
817 address which falls outside that range.
818*/
819static Int compare_CfiSI(void *va, void *vb) {
820 CfiSI *a = (CfiSI*)va;
821 CfiSI *b = (CfiSI*)vb;
822
823 if (a->base < b->base) return -1;
824 if (a->base > b->base) return 1;
825 return 0;
826}
827
sewardjbf603752005-05-02 00:36:27 +0000828static
829void canonicaliseCfiSI ( SegInfo* si )
830{
831 Int i;
832 const Addr minAddr = 0;
833 const Addr maxAddr = ~minAddr;
834
835 /* Set cfisi_minaddr and cfisi_maxaddr to summarise the entire
836 address range contained in cfisi[0 .. cfisi_used-1]. */
837 si->cfisi_minaddr = maxAddr;
838 si->cfisi_maxaddr = minAddr;
839 for (i = 0; i < si->cfisi_used; i++) {
840 Addr here_min = si->cfisi[i].base;
841 Addr here_max = si->cfisi[i].base + si->cfisi[i].len - 1;
842 if (here_min < si->cfisi_minaddr)
843 si->cfisi_minaddr = here_min;
844 if (here_max > si->cfisi_maxaddr)
845 si->cfisi_maxaddr = here_max;
846 }
sewardj520e3492005-05-02 10:39:16 +0000847
848 if (VG_(clo_trace_cfi))
849 VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n",
850 si->cfisi_used,
851 si->cfisi_minaddr, si->cfisi_maxaddr);
sewardj3a1c7db2005-05-02 09:43:44 +0000852
853 /* Sort the cfisi array by base address. */
854 VG_(ssort)(si->cfisi, si->cfisi_used, sizeof(*si->cfisi), compare_CfiSI);
855
856 /* Ensure relevant postconditions hold. */
857 for (i = 0; i < si->cfisi_used; i++) {
858 /* No zero-length ranges. */
859 vg_assert(si->cfisi[i].len > 0);
860 /* Makes sense w.r.t. summary address range */
861 vg_assert(si->cfisi[i].base >= si->cfisi_minaddr);
862 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
863 <= si->cfisi_maxaddr);
864
865 if (i < si->cfisi_used - 1) {
866 /* In order. */
867 vg_assert(si->cfisi[i].base < si->cfisi[i+1].base);
868 /* No overlaps. */
869 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
870 < si->cfisi[i+1].base);
871 }
872 }
873
sewardjbf603752005-05-02 00:36:27 +0000874}
875
876
sewardjde4a1d02002-03-22 01:27:54 +0000877/*------------------------------------------------------------*/
sewardjb51f2e62002-06-01 23:11:19 +0000878/*--- Read info from a .so/exe file. ---*/
879/*------------------------------------------------------------*/
880
fitzhardinge98abfc72003-12-16 02:05:15 +0000881Bool VG_(is_object_file)(const void *buf)
882{
883 {
sewardj7a21c612005-02-18 09:38:08 +0000884 ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf;
fitzhardinge98abfc72003-12-16 02:05:15 +0000885 Int ok = 1;
886
887 ok &= (ehdr->e_ident[EI_MAG0] == 0x7F
888 && ehdr->e_ident[EI_MAG1] == 'E'
889 && ehdr->e_ident[EI_MAG2] == 'L'
890 && ehdr->e_ident[EI_MAG3] == 'F');
njn35172bc2005-03-26 00:04:03 +0000891 ok &= (ehdr->e_ident[EI_CLASS] == VGA_ELF_CLASS
892 && ehdr->e_ident[EI_DATA] == VGA_ELF_ENDIANNESS
fitzhardinge98abfc72003-12-16 02:05:15 +0000893 && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
894 ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN);
njn35172bc2005-03-26 00:04:03 +0000895 ok &= (ehdr->e_machine == VGA_ELF_MACHINE);
fitzhardinge98abfc72003-12-16 02:05:15 +0000896 ok &= (ehdr->e_version == EV_CURRENT);
897 ok &= (ehdr->e_shstrndx != SHN_UNDEF);
898 ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0);
899 ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0);
900
901 if (ok)
902 return True;
903 }
904
905 /* other file formats here? */
906
907 return False;
908}
909
sewardj9ee81f52005-04-02 17:38:59 +0000910/* Demangle an intercept symbol into library:func form
911 eg "_vgi_libcZdsoZd6__ZdlPv" --> "libc.so.6:_ZdlPv"
912 Uses the Z-encoding scheme described in vg_replace_malloc.c.
913 Returns True if demangle OK, False otherwise.
rjwalshe4e779d2004-04-16 23:02:29 +0000914 */
915
916static Bool
nethercoteb1e1ad42004-08-03 23:44:12 +0000917intercept_demangle(const Char* symbol, Char* result, Int nbytes)
rjwalshe4e779d2004-04-16 23:02:29 +0000918{
sewardj9ee81f52005-04-02 17:38:59 +0000919# define EMIT(ch) \
920 do { \
921 if (j >= nbytes) \
922 result[j-1] = 0; \
923 else \
924 result[j++] = ch; \
925 } while (0)
rjwalshe4e779d2004-04-16 23:02:29 +0000926
sewardj9ee81f52005-04-02 17:38:59 +0000927 Bool error = False;
928 Int i, j = 0;
929 Int len = VG_(strlen)(symbol);
930 if (0) VG_(printf)("idm: %s\n", symbol);
931
932 i = VG_INTERCEPT_PREFIX_LEN;
933
934 /* Chew though the Z-encoded soname part. */
935 while (True) {
936
937 if (i >= len)
938 break;
939
940 if (symbol[i] == '_')
941 /* We found the underscore following the Z-encoded soname.
942 Just copy the rest literally. */
943 break;
944
945 if (symbol[i] != 'Z') {
946 EMIT(symbol[i]);
rjwalshe4e779d2004-04-16 23:02:29 +0000947 i++;
sewardj9ee81f52005-04-02 17:38:59 +0000948 continue;
rjwalshe4e779d2004-04-16 23:02:29 +0000949 }
sewardj9ee81f52005-04-02 17:38:59 +0000950
951 /* We've got a Z-escape. Act accordingly. */
952 i++;
953 if (i >= len) {
954 /* Hmm, Z right at the end. Something's wrong. */
955 error = True;
956 EMIT('Z');
957 break;
rjwalshe4e779d2004-04-16 23:02:29 +0000958 }
sewardj9ee81f52005-04-02 17:38:59 +0000959 switch (symbol[i]) {
960 case 'a': EMIT('*'); break;
961 case 'p': EMIT('+'); break;
962 case 'c': EMIT(':'); break;
963 case 'd': EMIT('.'); break;
964 case 'u': EMIT('_'); break;
965 case 's': EMIT(' '); break;
966 case 'Z': EMIT('Z'); break;
967 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
968 }
969 i++;
rjwalshe4e779d2004-04-16 23:02:29 +0000970 }
sewardj9ee81f52005-04-02 17:38:59 +0000971
972 if (error || i >= len || symbol[i] != '_') {
973 /* Something's wrong. Give up. */
974 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
975 EMIT(0);
976 return False;
977 }
978
979 /* Copy the rest of the string verbatim. */
980 i++;
981 EMIT(':');
982 while (True) {
983 if (i >= len)
984 break;
985 EMIT(symbol[i]);
986 i++;
987 }
988
989 EMIT(0);
990 if (0) VG_(printf)("%s\n", result);
rjwalshe4e779d2004-04-16 23:02:29 +0000991 return True;
sewardj9ee81f52005-04-02 17:38:59 +0000992
993# undef EMIT
rjwalshe4e779d2004-04-16 23:02:29 +0000994}
995
996static
sewardj7a21c612005-02-18 09:38:08 +0000997void handle_intercept( SegInfo* si, Char* symbol, ElfXX_Sym* sym)
rjwalshe4e779d2004-04-16 23:02:29 +0000998{
sewardj9ee81f52005-04-02 17:38:59 +0000999 Bool ok;
1000 Int len = VG_(strlen)(symbol) + 1 - VG_INTERCEPT_PREFIX_LEN;
1001 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
rjwalshe4e779d2004-04-16 23:02:29 +00001002 Char *func;
1003
sewardj9ee81f52005-04-02 17:38:59 +00001004 /* Put "soname:" at the start of lib. */
1005 lib[0] = 's';
1006 lib[1] = 'o';
1007 lib[2] = 'n';
1008 lib[3] = 'a';
1009 lib[4] = 'm';
1010 lib[5] = 'e';
1011 lib[6] = ':';
1012 lib[7] = 0;
rjwalshe4e779d2004-04-16 23:02:29 +00001013
sewardj9ee81f52005-04-02 17:38:59 +00001014 ok = intercept_demangle(symbol, lib+7, len);
1015 if (ok) {
1016 func = lib + VG_(strlen)(lib)-1;
rjwalshe4e779d2004-04-16 23:02:29 +00001017
sewardj9ee81f52005-04-02 17:38:59 +00001018 while(*func != ':') func--;
1019 *func = '\0';
1020
1021 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func+1);
1022 VG_(add_redirect_sym_to_addr)(lib, func+1, si->offset + sym->st_value);
1023 }
1024
sewardjb5f6f512005-03-10 23:59:00 +00001025 VG_(arena_free)(VG_AR_SYMTAB, lib);
rjwalshe4e779d2004-04-16 23:02:29 +00001026}
1027
sewardjb5f6f512005-03-10 23:59:00 +00001028Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir)
rjwalshe4e779d2004-04-16 23:02:29 +00001029{
sewardjb5f6f512005-03-10 23:59:00 +00001030 SegInfo *si;
1031
1032 for(si = segInfo; si != NULL; si = si->next)
1033 if (VG_(resolve_redir)(redir, si))
1034 return True;
1035
1036 return False;
rjwalshe4e779d2004-04-16 23:02:29 +00001037}
1038
sewardjb5f6f512005-03-10 23:59:00 +00001039//static
1040//void handle_wrapper( SegInfo* si, Char* symbol, ElfXX_Sym* sym)
1041//{
1042// if (VG_(strcmp)(symbol, STR(VG_WRAPPER(freeres))) == 0)
1043// VGA_(intercept_libc_freeres_wrapper)((Addr)(si->offset + sym->st_value));
1044// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
1045// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
1046//}
1047
nethercote80f76782003-11-13 22:34:00 +00001048/* Read a symbol table (normal or dynamic) */
1049static
rjwalshe4e779d2004-04-16 23:02:29 +00001050void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts,
sewardj7a21c612005-02-18 09:38:08 +00001051 ElfXX_Sym* o_symtab, UInt o_symtab_sz,
nethercote80f76782003-11-13 22:34:00 +00001052 UChar* o_strtab, UInt o_strtab_sz )
1053{
1054 Int i;
1055 Addr sym_addr;
1056 RiSym risym;
mueller82df83e2003-11-19 22:05:35 +00001057 Char* t0;
1058 Char* name;
1059
nethercote80f76782003-11-13 22:34:00 +00001060 if (o_strtab == NULL || o_symtab == NULL) {
jseward0edbfb52003-12-12 06:22:06 +00001061 Char buf[80];
1062 vg_assert(VG_(strlen)(tab_name) < 40);
1063 VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
1064 VG_(symerr)(buf);
nethercote80f76782003-11-13 22:34:00 +00001065 return;
1066 }
1067
1068 TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name,
sewardj7a21c612005-02-18 09:38:08 +00001069 o_symtab_sz/sizeof(ElfXX_Sym) );
nethercote80f76782003-11-13 22:34:00 +00001070
1071 /* Perhaps should start at i = 1; ELF docs suggest that entry
1072 0 always denotes `unknown symbol'. */
sewardj7a21c612005-02-18 09:38:08 +00001073 for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) {
1074 ElfXX_Sym* sym = & o_symtab[i];
nethercote80f76782003-11-13 22:34:00 +00001075# if 1
tomf26d0682005-04-02 14:57:43 +00001076 sym_addr = si->offset + sym->st_value;
nethercote80f76782003-11-13 22:34:00 +00001077
1078 if (VG_(clo_trace_symtab)) {
1079 VG_(printf)("raw symbol [%d]: ", i);
sewardj7a21c612005-02-18 09:38:08 +00001080 switch (ELFXX_ST_BIND(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001081 case STB_LOCAL: VG_(printf)("LOC "); break;
1082 case STB_GLOBAL: VG_(printf)("GLO "); break;
1083 case STB_WEAK: VG_(printf)("WEA "); break;
1084 case STB_LOPROC: VG_(printf)("lop "); break;
1085 case STB_HIPROC: VG_(printf)("hip "); break;
1086 default: VG_(printf)("??? "); break;
1087 }
sewardj7a21c612005-02-18 09:38:08 +00001088 switch (ELFXX_ST_TYPE(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001089 case STT_NOTYPE: VG_(printf)("NOT "); break;
1090 case STT_OBJECT: VG_(printf)("OBJ "); break;
1091 case STT_FUNC: VG_(printf)("FUN "); break;
1092 case STT_SECTION: VG_(printf)("SEC "); break;
1093 case STT_FILE: VG_(printf)("FIL "); break;
1094 case STT_LOPROC: VG_(printf)("lop "); break;
1095 case STT_HIPROC: VG_(printf)("hip "); break;
1096 default: VG_(printf)("??? "); break;
1097 }
1098 VG_(printf)(
1099 ": value %p, size %d, name %s\n",
1100 sym_addr, sym->st_size,
1101 ( sym->st_name
1102 ? ((Char*)o_strtab+sym->st_name)
1103 : (Char*)"NONAME" ) );
1104 }
1105# endif
1106
rjwalshe4e779d2004-04-16 23:02:29 +00001107 /*
1108 * Is this symbol a magic valgrind-intercept symbol? If so,
1109 * hand this off to the interceptinator.
1110 */
1111 if (do_intercepts) {
1112 if (VG_(strncmp)((Char*)o_strtab+sym->st_name,
1113 VG_INTERCEPT_PREFIX,
1114 VG_INTERCEPT_PREFIX_LEN) == 0) {
1115 handle_intercept(si, (Char*)o_strtab+sym->st_name, sym);
sewardjb5f6f512005-03-10 23:59:00 +00001116 }
1117 //else if (VG_(strncmp)((Char*)o_strtab+sym->st_name,
1118 // VG_WRAPPER_PREFIX,
1119 // VG_WRAPPER_PREFIX_LEN) == 0) {
1120 // handle_wrapper(si, (Char*)o_strtab+sym->st_name, sym);
1121 //}
rjwalshe4e779d2004-04-16 23:02:29 +00001122 }
1123
nethercote80f76782003-11-13 22:34:00 +00001124 /* Figure out if we're interested in the symbol.
1125 Firstly, is it of the right flavour? */
sewardj7a21c612005-02-18 09:38:08 +00001126 if ( ! ( (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL ||
1127 ELFXX_ST_BIND(sym->st_info) == STB_LOCAL ||
1128 ELFXX_ST_BIND(sym->st_info) == STB_WEAK)
nethercote80f76782003-11-13 22:34:00 +00001129 &&
sewardj7a21c612005-02-18 09:38:08 +00001130 (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC ||
nethercote80f76782003-11-13 22:34:00 +00001131 (VG_(needs).data_syms
sewardj7a21c612005-02-18 09:38:08 +00001132 && ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT))
nethercote80f76782003-11-13 22:34:00 +00001133 )
1134 )
1135 continue;
1136
1137 /* Secondly, if it's apparently in a GOT or PLT, it's really
1138 a reference to a symbol defined elsewhere, so ignore it. */
1139 if (si->got_start != 0
1140 && sym_addr >= si->got_start
1141 && sym_addr < si->got_start + si->got_size) {
1142 TRACE_SYMTAB("in GOT: %s\n", o_strtab+sym->st_name);
1143 continue;
1144 }
1145 if (si->plt_start != 0
1146 && sym_addr >= si->plt_start
1147 && sym_addr < si->plt_start + si->plt_size) {
1148 TRACE_SYMTAB("in PLT: %s\n", o_strtab+sym->st_name);
1149 continue;
1150 }
1151
1152 /* Don't bother if nameless, or zero-sized. */
sewardj7a21c612005-02-18 09:38:08 +00001153 if (sym->st_name == (ElfXX_Word)NULL
nethercote80f76782003-11-13 22:34:00 +00001154 || /* VG_(strlen)(o_strtab+sym->st_name) == 0 */
1155 /* equivalent but cheaper ... */
1156 * ((UChar*)(o_strtab+sym->st_name)) == 0
1157 || sym->st_size == 0) {
1158 TRACE_SYMTAB("size=0: %s\n", o_strtab+sym->st_name);
1159 continue;
1160 }
1161
1162# if 0
1163 /* Avoid _dl_ junk. (Why?) */
1164 /* 01-02-24: disabled until I find out if it really helps. */
1165 if (VG_(strncmp)("_dl_", o_strtab+sym->st_name, 4) == 0
1166 || VG_(strncmp)("_r_debug",
1167 o_strtab+sym->st_name, 8) == 0) {
1168 TRACE_SYMTAB("_dl_ junk: %s\n", o_strtab+sym->st_name);
1169 continue;
1170 }
1171# endif
1172
1173 /* This seems to significantly reduce the number of junk
1174 symbols, and particularly reduces the number of
1175 overlapping address ranges. Don't ask me why ... */
1176 if ((Int)sym->st_value == 0) {
1177 TRACE_SYMTAB( "valu=0: %s\n", o_strtab+sym->st_name);
1178 continue;
1179 }
1180
1181 /* If no part of the symbol falls within the mapped range,
1182 ignore it. */
1183 if (sym_addr+sym->st_size <= si->start
1184 || sym_addr >= si->start+si->size) {
1185 TRACE_SYMTAB( "outside mapped range" );
1186 continue;
1187 }
1188
1189 /* If we reach here, it's an interesting symbol; record it. */
mueller82df83e2003-11-19 22:05:35 +00001190 t0 = sym->st_name
nethercote80f76782003-11-13 22:34:00 +00001191 ? (Char*)(o_strtab+sym->st_name)
1192 : (Char*)"NONAME";
mueller82df83e2003-11-19 22:05:35 +00001193 name = VG_(addStr) ( si, t0, -1 );
nethercote80f76782003-11-13 22:34:00 +00001194 vg_assert(name != NULL
1195 /* && 0==VG_(strcmp)(t0,&vg_strtab[nmoff]) */ );
nethercote80f76782003-11-13 22:34:00 +00001196 /* VG_(printf)("%p + %d: %p %s\n", si->start,
1197 (Int)sym->st_value, sym_addr, t0 ); */
1198 risym.addr = sym_addr;
1199 risym.size = sym->st_size;
1200 risym.name = name;
1201 addSym ( si, &risym );
1202 }
1203}
1204
thughesc035bd92004-06-13 09:59:02 +00001205/*
1206 * This routine for calculating the CRC for a separate debug file
1207 * is GPLed code borrowed from binutils.
1208 */
1209static UInt
1210calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
1211{
1212 static const UInt crc32_table[256] =
1213 {
1214 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
1215 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
1216 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
1217 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1218 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
1219 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1220 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
1221 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1222 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1223 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
1224 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
1225 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1226 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
1227 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
1228 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
1229 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1230 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
1231 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1232 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
1233 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1234 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
1235 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
1236 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
1237 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1238 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
1239 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
1240 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1241 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1242 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1243 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1244 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1245 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1246 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1247 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1248 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1249 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1250 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1251 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1252 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1253 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1254 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1255 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1256 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1257 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1258 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1259 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1260 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1261 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1262 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1263 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1264 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1265 0x2d02ef8d
1266 };
1267 const UChar *end;
1268
1269 crc = ~crc & 0xffffffff;
1270 for (end = buf + len; buf < end; ++ buf)
1271 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
1272 return ~crc & 0xffffffff;;
1273}
1274
1275/*
1276 * Try and open a separate debug file, ignoring any where the CRC does
1277 * not match the value from the main object file.
1278 */
1279static
1280Addr open_debug_file( Char* name, UInt crc, UInt* size )
1281{
1282 Int fd;
1283 struct vki_stat stat_buf;
1284 Addr addr;
sewardjb5f6f512005-03-10 23:59:00 +00001285 UInt calccrc;
thughesc035bd92004-06-13 09:59:02 +00001286
1287 if ((fd = VG_(open)(name, VKI_O_RDONLY, 0)) < 0)
1288 return 0;
1289
1290 if (VG_(fstat)(fd, &stat_buf) != 0) {
1291 VG_(close)(fd);
1292 return 0;
1293 }
1294
sewardjb5f6f512005-03-10 23:59:00 +00001295 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001296 VG_(message)(Vg_DebugMsg, "Reading debug info from %s...", name);
sewardjb5f6f512005-03-10 23:59:00 +00001297
thughesc035bd92004-06-13 09:59:02 +00001298 *size = stat_buf.st_size;
1299
1300 if ((addr = (Addr)VG_(mmap)(NULL, *size, VKI_PROT_READ,
nethercoteb4250ae2004-07-10 16:50:09 +00001301 VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1302 0, fd, 0)) == (Addr)-1)
1303 {
thughesc035bd92004-06-13 09:59:02 +00001304 VG_(close)(fd);
1305 return 0;
1306 }
1307
1308 VG_(close)(fd);
1309
sewardjb5f6f512005-03-10 23:59:00 +00001310 calccrc = calc_gnu_debuglink_crc32(0, (UChar*)addr, *size);
1311 if (calccrc != crc) {
nethercotee567e702004-07-10 17:49:17 +00001312 int res = VG_(munmap)((void*)addr, *size);
1313 vg_assert(0 == res);
sewardjb5f6f512005-03-10 23:59:00 +00001314 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001315 VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc);
thughesc035bd92004-06-13 09:59:02 +00001316 return 0;
1317 }
1318
1319 return addr;
1320}
1321
1322/*
nethercoteb1e1ad42004-08-03 23:44:12 +00001323 * Try to find a separate debug file for a given object file.
thughesc035bd92004-06-13 09:59:02 +00001324 */
1325static
1326Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size )
1327{
sewardjb5f6f512005-03-10 23:59:00 +00001328 Char *objdir = VG_(arena_strdup)(VG_AR_SYMTAB, objpath);
thughesc035bd92004-06-13 09:59:02 +00001329 Char *objdirptr;
1330 Char *debugpath;
1331 Addr addr = 0;
1332
1333 if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
1334 *objdirptr = '\0';
1335
sewardjb5f6f512005-03-10 23:59:00 +00001336 debugpath = VG_(arena_malloc)(VG_AR_SYMTAB, VG_(strlen)(objdir) + VG_(strlen)(debugname) + 16);
thughesc035bd92004-06-13 09:59:02 +00001337
1338 VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
1339
1340 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1341 VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
1342 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1343 VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
1344 addr = open_debug_file(debugpath, crc, size);
1345 }
1346 }
1347
sewardjb5f6f512005-03-10 23:59:00 +00001348 VG_(arena_free)(VG_AR_SYMTAB, debugpath);
1349 VG_(arena_free)(VG_AR_SYMTAB, objdir);
thughesc035bd92004-06-13 09:59:02 +00001350
1351 return addr;
1352}
nethercote80f76782003-11-13 22:34:00 +00001353
sewardjde4a1d02002-03-22 01:27:54 +00001354/* Read the symbols from the object/exe specified by the SegInfo into
1355 the tables within the supplied SegInfo. */
1356static
njn695c16e2005-03-27 03:40:28 +00001357Bool read_lib_symbols ( SegInfo* si )
sewardjde4a1d02002-03-22 01:27:54 +00001358{
nethercote80f76782003-11-13 22:34:00 +00001359 Bool res;
sewardj7a21c612005-02-18 09:38:08 +00001360 ElfXX_Ehdr* ehdr; /* The ELF header */
1361 ElfXX_Shdr* shdr; /* The section table */
sewardjde4a1d02002-03-22 01:27:54 +00001362 UChar* sh_strtab; /* The section table's string table */
sewardjde4a1d02002-03-22 01:27:54 +00001363 Int fd;
1364 Int i;
1365 Bool ok;
1366 Addr oimage;
sewardj05bcdcb2003-05-18 10:05:38 +00001367 UInt n_oimage;
thughesc035bd92004-06-13 09:59:02 +00001368 Addr dimage = 0;
1369 UInt n_dimage = 0;
sewardjb3586202002-05-09 17:38:13 +00001370 struct vki_stat stat_buf;
sewardjde4a1d02002-03-22 01:27:54 +00001371
sewardjde4a1d02002-03-22 01:27:54 +00001372 oimage = (Addr)NULL;
1373 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001374 VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", si->filename, si->start );
sewardjde4a1d02002-03-22 01:27:54 +00001375
1376 /* mmap the object image aboard, so that we can read symbols and
1377 line number info out of it. It will be munmapped immediately
1378 thereafter; it is only aboard transiently. */
1379
sewardjb3586202002-05-09 17:38:13 +00001380 i = VG_(stat)(si->filename, &stat_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001381 if (i != 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001382 VG_(symerr)("Can't stat .so/.exe (to determine its size)?!");
sewardj8fe15a32002-10-20 19:29:21 +00001383 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001384 }
1385 n_oimage = stat_buf.st_size;
1386
njn25e49d8e72002-09-23 09:36:25 +00001387 fd = VG_(open)(si->filename, VKI_O_RDONLY, 0);
jsgff3c3f1a2003-10-14 22:13:28 +00001388 if (fd < 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001389 VG_(symerr)("Can't open .so/.exe to read symbols?!");
sewardj8fe15a32002-10-20 19:29:21 +00001390 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001391 }
1392
sewardjb3586202002-05-09 17:38:13 +00001393 oimage = (Addr)VG_(mmap)( NULL, n_oimage,
nethercoteb4250ae2004-07-10 16:50:09 +00001394 VKI_PROT_READ, VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1395 0, fd, 0 );
fitzhardinge98abfc72003-12-16 02:05:15 +00001396
nethercote80f76782003-11-13 22:34:00 +00001397 VG_(close)(fd);
1398
sewardjde4a1d02002-03-22 01:27:54 +00001399 if (oimage == ((Addr)(-1))) {
njn1fd5eb22005-03-13 05:43:23 +00001400 VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename );
1401 VG_(message)(Vg_UserMsg, " no symbols or debug info loaded" );
sewardj8fe15a32002-10-20 19:29:21 +00001402 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001403 }
1404
sewardjde4a1d02002-03-22 01:27:54 +00001405 /* Ok, the object image is safely in oimage[0 .. n_oimage-1].
1406 Now verify that it is a valid ELF .so or executable image.
1407 */
nethercote80f76782003-11-13 22:34:00 +00001408 res = False;
sewardj7a21c612005-02-18 09:38:08 +00001409 ok = (n_oimage >= sizeof(ElfXX_Ehdr));
1410 ehdr = (ElfXX_Ehdr*)oimage;
sewardjde4a1d02002-03-22 01:27:54 +00001411
fitzhardinge98abfc72003-12-16 02:05:15 +00001412 if (ok)
1413 ok &= VG_(is_object_file)(ehdr);
sewardjde4a1d02002-03-22 01:27:54 +00001414
1415 if (!ok) {
jsgfcb1d1c02003-10-14 21:55:10 +00001416 VG_(symerr)("Invalid ELF header, or missing stringtab/sectiontab.");
nethercote80f76782003-11-13 22:34:00 +00001417 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001418 }
1419
1420 /* Walk the LOAD headers in the phdr and update the SegInfo to
1421 include them all, so that this segment also contains data and
1422 bss memory. Also computes correct symbol offset value for this
1423 ELF file. */
sewardj7a21c612005-02-18 09:38:08 +00001424 if (ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001425 VG_(symerr)("ELF program header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001426 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001427 }
1428 {
1429 Bool offset_set = False;
sewardj7a21c612005-02-18 09:38:08 +00001430 ElfXX_Addr prev_addr = 0;
fitzhardinge98abfc72003-12-16 02:05:15 +00001431 Addr baseaddr = 0;
sewardj8fe15a32002-10-20 19:29:21 +00001432
1433 si->offset = 0;
1434
nethercote80f76782003-11-13 22:34:00 +00001435 for (i = 0; i < ehdr->e_phnum; i++) {
sewardj7a21c612005-02-18 09:38:08 +00001436 ElfXX_Phdr *o_phdr;
1437 ElfXX_Addr mapped, mapped_end;
sewardj8fe15a32002-10-20 19:29:21 +00001438
sewardj7a21c612005-02-18 09:38:08 +00001439 o_phdr = &((ElfXX_Phdr *)(oimage + ehdr->e_phoff))[i];
sewardj8fe15a32002-10-20 19:29:21 +00001440
fitzhardinge98abfc72003-12-16 02:05:15 +00001441 if (o_phdr->p_type == PT_DYNAMIC && si->soname == NULL) {
sewardj7a21c612005-02-18 09:38:08 +00001442 const ElfXX_Dyn *dyn = (const ElfXX_Dyn *)(oimage + o_phdr->p_offset);
fitzhardinge98abfc72003-12-16 02:05:15 +00001443 Int stroff = -1;
1444 Char *strtab = NULL;
1445 Int j;
1446
1447 for(j = 0; dyn[j].d_tag != DT_NULL; j++) {
1448 switch(dyn[j].d_tag) {
1449 case DT_SONAME:
1450 stroff = dyn[j].d_un.d_val;
1451 break;
1452
1453 case DT_STRTAB:
1454 strtab = (Char *)oimage + dyn[j].d_un.d_ptr - baseaddr;
1455 break;
1456 }
1457 }
1458
1459 if (stroff != -1 && strtab != 0) {
1460 TRACE_SYMTAB("soname=%s\n", strtab+stroff);
1461 si->soname = VG_(arena_strdup)(VG_AR_SYMTAB, strtab+stroff);
1462 }
1463 }
1464
sewardj8fe15a32002-10-20 19:29:21 +00001465 if (o_phdr->p_type != PT_LOAD)
1466 continue;
1467
1468 if (!offset_set) {
1469 offset_set = True;
1470 si->offset = si->start - o_phdr->p_vaddr;
fitzhardinge98abfc72003-12-16 02:05:15 +00001471 baseaddr = o_phdr->p_vaddr;
sewardj8fe15a32002-10-20 19:29:21 +00001472 }
1473
1474 if (o_phdr->p_vaddr < prev_addr) {
jsgfcb1d1c02003-10-14 21:55:10 +00001475 VG_(symerr)("ELF Phdrs are out of order!?");
nethercote80f76782003-11-13 22:34:00 +00001476 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001477 }
1478 prev_addr = o_phdr->p_vaddr;
1479
1480 mapped = o_phdr->p_vaddr + si->offset;
1481 mapped_end = mapped + o_phdr->p_memsz;
1482
1483 if (si->data_start == 0 &&
1484 (o_phdr->p_flags & (PF_R|PF_W|PF_X)) == (PF_R|PF_W)) {
1485 si->data_start = mapped;
1486 si->data_size = o_phdr->p_filesz;
1487 si->bss_start = mapped + o_phdr->p_filesz;
1488 if (o_phdr->p_memsz > o_phdr->p_filesz)
1489 si->bss_size = o_phdr->p_memsz - o_phdr->p_filesz;
1490 else
1491 si->bss_size = 0;
1492 }
1493
nethercote73b526f2004-10-31 18:48:21 +00001494 mapped = mapped & ~(VKI_PAGE_SIZE-1);
1495 mapped_end = (mapped_end + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE-1);
sewardj8fe15a32002-10-20 19:29:21 +00001496
sewardj1024cf72005-02-28 14:39:21 +00001497#if 0
1498 /* 20050228: disabled this until VG_(next_segment) can be
1499 reinstated in some clean incarnation of the low level
1500 memory manager. */
sewardj8fe15a32002-10-20 19:29:21 +00001501 if (VG_(needs).data_syms &&
1502 (mapped >= si->start && mapped <= (si->start+si->size)) &&
1503 (mapped_end > (si->start+si->size))) {
1504 UInt newsz = mapped_end - si->start;
1505 if (newsz > si->size) {
fitzhardinge98abfc72003-12-16 02:05:15 +00001506 Segment *seg;
1507
sewardj8fe15a32002-10-20 19:29:21 +00001508 if (0)
1509 VG_(printf)("extending mapping %p..%p %d -> ..%p %d\n",
1510 si->start, si->start+si->size, si->size,
1511 si->start+newsz, newsz);
fitzhardinge98abfc72003-12-16 02:05:15 +00001512
sewardjb5f6f512005-03-10 23:59:00 +00001513 for(seg = VG_(find_segment_containing)(si->start);
fitzhardinge98abfc72003-12-16 02:05:15 +00001514 seg != NULL && VG_(seg_overlaps)(seg, si->start, si->size);
1515 seg = VG_(next_segment)(seg)) {
1516 if (seg->symtab == si)
1517 continue;
1518
1519 if (seg->symtab != NULL)
nethercote8991d5a2004-11-03 17:07:46 +00001520 VG_(symtab_decref)(seg->symtab, seg->addr);
fitzhardinge98abfc72003-12-16 02:05:15 +00001521
1522 VG_(symtab_incref)(si);
1523 seg->symtab = si;
1524
1525 if (0)
1526 VG_(printf)("adding symtab %p (%p-%p) to segment %p (%p-%p)\n",
1527 si, si->start, si->start+newsz,
1528 seg, seg->addr, seg->addr+seg->len);
1529 }
1530
sewardj8fe15a32002-10-20 19:29:21 +00001531 si->size = newsz;
1532 }
1533 }
sewardj1024cf72005-02-28 14:39:21 +00001534#endif
1535
sewardj8fe15a32002-10-20 19:29:21 +00001536 }
sewardjde4a1d02002-03-22 01:27:54 +00001537 }
1538
nethercote80f76782003-11-13 22:34:00 +00001539 TRACE_SYMTAB("shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n",
sewardj7a21c612005-02-18 09:38:08 +00001540 ehdr->e_shoff, ehdr->e_shnum, sizeof(ElfXX_Shdr), n_oimage );
sewardjde4a1d02002-03-22 01:27:54 +00001541
sewardj7a21c612005-02-18 09:38:08 +00001542 if (ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001543 VG_(symerr)("ELF section header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001544 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001545 }
1546
sewardj7a21c612005-02-18 09:38:08 +00001547 shdr = (ElfXX_Shdr*)(oimage + ehdr->e_shoff);
sewardjde4a1d02002-03-22 01:27:54 +00001548 sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset);
1549
nethercote80f76782003-11-13 22:34:00 +00001550 /* Find interesting sections, read the symbol table(s), read any debug
1551 information */
sewardjde4a1d02002-03-22 01:27:54 +00001552 {
nethercote80f76782003-11-13 22:34:00 +00001553 /* Pointers to start of sections */
1554 UChar* o_strtab = NULL; /* .strtab */
sewardj7a21c612005-02-18 09:38:08 +00001555 ElfXX_Sym* o_symtab = NULL; /* .symtab */
nethercote80f76782003-11-13 22:34:00 +00001556 UChar* o_dynstr = NULL; /* .dynstr */
sewardj7a21c612005-02-18 09:38:08 +00001557 ElfXX_Sym* o_dynsym = NULL; /* .dynsym */
thughesc035bd92004-06-13 09:59:02 +00001558 Char* debuglink = NULL; /* .gnu_debuglink */
nethercote80f76782003-11-13 22:34:00 +00001559 UChar* stab = NULL; /* .stab (stabs) */
1560 UChar* stabstr = NULL; /* .stabstr (stabs) */
1561 UChar* debug_line = NULL; /* .debug_line (dwarf2) */
jseward8b3131a2003-12-13 23:16:26 +00001562 UChar* dwarf1d = NULL; /* .debug (dwarf1) */
1563 UChar* dwarf1l = NULL; /* .line (dwarf1) */
sewardj5c638c22005-04-30 07:55:58 +00001564 UChar* ehframe = NULL; /* .eh_frame (dwarf2) */
sewardjde4a1d02002-03-22 01:27:54 +00001565
nethercote80f76782003-11-13 22:34:00 +00001566 /* Section sizes, in bytes */
1567 UInt o_strtab_sz = 0;
1568 UInt o_symtab_sz = 0;
1569 UInt o_dynstr_sz = 0;
1570 UInt o_dynsym_sz = 0;
thughesc035bd92004-06-13 09:59:02 +00001571 UInt debuglink_sz = 0;
nethercote80f76782003-11-13 22:34:00 +00001572 UInt stab_sz = 0;
1573 UInt stabstr_sz = 0;
1574 UInt debug_line_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001575 UInt dwarf1d_sz = 0;
1576 UInt dwarf1l_sz = 0;
sewardj5c638c22005-04-30 07:55:58 +00001577 UInt ehframe_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001578
tom2fd38902005-05-01 15:14:01 +00001579 /* Section virtual addresses */
1580 Addr dummy_addr = 0;
1581 Addr ehframe_addr = 0;
1582
jseward8b3131a2003-12-13 23:16:26 +00001583 Bool has_debuginfo = False;
sewardjde4a1d02002-03-22 01:27:54 +00001584
nethercote80f76782003-11-13 22:34:00 +00001585 /* Find all interesting sections */
sewardjde4a1d02002-03-22 01:27:54 +00001586 for (i = 0; i < ehdr->e_shnum; i++) {
tom2fd38902005-05-01 15:14:01 +00001587# define FIND(sec_name, sec_data, sec_size, sec_addr, in_exec, type) \
nethercote80f76782003-11-13 22:34:00 +00001588 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1589 if (0 != sec_data) \
1590 VG_(core_panic)("repeated section!\n"); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001591 if (in_exec) \
nethercote80f76782003-11-13 22:34:00 +00001592 sec_data = (type)(si->offset + shdr[i].sh_addr); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001593 else \
nethercote80f76782003-11-13 22:34:00 +00001594 sec_data = (type)(oimage + shdr[i].sh_offset); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001595 sec_size = shdr[i].sh_size; \
tom2fd38902005-05-01 15:14:01 +00001596 sec_addr = si->offset + shdr[i].sh_addr; \
nethercote80f76782003-11-13 22:34:00 +00001597 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1598 sec_name, sec_data, sec_data + sec_size - 1); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001599 if ( shdr[i].sh_offset + sec_size > n_oimage ) { \
nethercote80f76782003-11-13 22:34:00 +00001600 VG_(symerr)(" section beyond image end?!"); \
1601 goto out; \
1602 } \
sewardjde4a1d02002-03-22 01:27:54 +00001603 }
1604
nethercote80f76782003-11-13 22:34:00 +00001605 /* Nb: must find where .got and .plt sections will be in the
1606 * executable image, not in the object image transiently loaded. */
tom2fd38902005-05-01 15:14:01 +00001607 FIND(".dynsym", o_dynsym, o_dynsym_sz, dummy_addr, 0, ElfXX_Sym*)
1608 else FIND(".dynstr", o_dynstr, o_dynstr_sz, dummy_addr, 0, UChar*)
1609 else FIND(".symtab", o_symtab, o_symtab_sz, dummy_addr, 0, ElfXX_Sym*)
1610 else FIND(".strtab", o_strtab, o_strtab_sz, dummy_addr, 0, UChar*)
sewardjde4a1d02002-03-22 01:27:54 +00001611
tom2fd38902005-05-01 15:14:01 +00001612 else FIND(".gnu_debuglink", debuglink, debuglink_sz, dummy_addr, 0, Char*)
thughesc035bd92004-06-13 09:59:02 +00001613
tom2fd38902005-05-01 15:14:01 +00001614 else FIND(".stab", stab, stab_sz, dummy_addr, 0, UChar*)
1615 else FIND(".stabstr", stabstr, stabstr_sz, dummy_addr, 0, UChar*)
1616 else FIND(".debug_line", debug_line, debug_line_sz, dummy_addr, 0, UChar*)
1617 else FIND(".debug", dwarf1d, dwarf1d_sz, dummy_addr, 0, UChar*)
1618 else FIND(".line", dwarf1l, dwarf1l_sz, dummy_addr, 0, UChar*)
1619 else FIND(".eh_frame", ehframe, ehframe_sz, ehframe_addr, 0, UChar*)
nethercote80f76782003-11-13 22:34:00 +00001620
tom2fd38902005-05-01 15:14:01 +00001621 else FIND(".got", si->got_start, si->got_size, dummy_addr, 1, Addr)
1622 else FIND(".plt", si->plt_start, si->plt_size, dummy_addr, 1, Addr)
nethercote80f76782003-11-13 22:34:00 +00001623
jseward8b3131a2003-12-13 23:16:26 +00001624# undef FIND
nethercote80f76782003-11-13 22:34:00 +00001625
1626 /* Check some sizes */
sewardj7a21c612005-02-18 09:38:08 +00001627 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1628 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
sewardjde4a1d02002-03-22 01:27:54 +00001629 }
1630
rjwalshe4e779d2004-04-16 23:02:29 +00001631 read_symtab(si, "symbol table", False,
nethercote80f76782003-11-13 22:34:00 +00001632 o_symtab, o_symtab_sz,
1633 o_strtab, o_strtab_sz);
sewardjde4a1d02002-03-22 01:27:54 +00001634
rjwalshe4e779d2004-04-16 23:02:29 +00001635 read_symtab(si, "dynamic symbol table", True,
nethercote80f76782003-11-13 22:34:00 +00001636 o_dynsym, o_dynsym_sz,
1637 o_dynstr, o_dynstr_sz);
sewardj9b81a422003-04-26 21:42:09 +00001638
thughesc035bd92004-06-13 09:59:02 +00001639 /* Did we find a debuglink section? */
1640 if (debuglink != NULL) {
sewardjb5f6f512005-03-10 23:59:00 +00001641 UInt crc_offset = ROUNDUP(VG_(strlen)(debuglink)+1, 4);
thughesc035bd92004-06-13 09:59:02 +00001642 UInt crc;
1643
1644 vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
1645
1646 /* Extract the CRC from the debuglink section */
1647 crc = *(UInt *)(debuglink + crc_offset);
1648
1649 /* See if we can find a matching debug file */
1650 if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) {
sewardj7a21c612005-02-18 09:38:08 +00001651 ehdr = (ElfXX_Ehdr*)dimage;
thughesc035bd92004-06-13 09:59:02 +00001652
sewardj7a21c612005-02-18 09:38:08 +00001653 if (n_dimage >= sizeof(ElfXX_Ehdr) && VG_(is_object_file)(ehdr))
thughesc035bd92004-06-13 09:59:02 +00001654 {
sewardj7a21c612005-02-18 09:38:08 +00001655 shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff);
thughesc035bd92004-06-13 09:59:02 +00001656 sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset);
1657
1658 /* Find all interesting sections */
1659 for (i = 0; i < ehdr->e_shnum; i++) {
1660# define FIND(sec_name, sec_data, sec_size, type) \
1661 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1662 if (0 != sec_data) \
1663 VG_(core_panic)("repeated section!\n"); \
1664 sec_data = (type)(dimage + shdr[i].sh_offset); \
1665 sec_size = shdr[i].sh_size; \
1666 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1667 sec_name, sec_data, sec_data + sec_size - 1); \
1668 if ( shdr[i].sh_offset + sec_size > n_dimage ) { \
1669 VG_(symerr)(" section beyond image end?!"); \
1670 goto out; \
1671 } \
1672 }
1673
1674 /* Nb: must find where .got and .plt sections will be in the
1675 * executable image, not in the object image transiently loaded. */
1676 FIND(".stab", stab, stab_sz, UChar*)
1677 else FIND(".stabstr", stabstr, stabstr_sz, UChar*)
1678 else FIND(".debug_line", debug_line, debug_line_sz, UChar*)
1679 else FIND(".debug", dwarf1d, dwarf1d_sz, UChar*)
1680 else FIND(".line", dwarf1l, dwarf1l_sz, UChar*)
1681
1682# undef FIND
1683
1684 /* Check some sizes */
sewardj7a21c612005-02-18 09:38:08 +00001685 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1686 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
thughesc035bd92004-06-13 09:59:02 +00001687 }
1688 }
1689 }
1690 }
1691
sewardj5c638c22005-04-30 07:55:58 +00001692 /* Read .eh_frame (call-frame-info) if any */
1693 if (ehframe && ehframe_sz > 4) {
tom2fd38902005-05-01 15:14:01 +00001694 VG_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_addr );
sewardj5c638c22005-04-30 07:55:58 +00001695 }
1696
nethercote80f76782003-11-13 22:34:00 +00001697 /* Read the stabs and/or dwarf2 debug information, if any. */
1698 if (stab != NULL && stabstr != NULL) {
jseward8b3131a2003-12-13 23:16:26 +00001699 has_debuginfo = True;
1700 VG_(read_debuginfo_stabs) ( si, stab, stab_sz,
1701 stabstr, stabstr_sz );
1702 }
tom6f917fd2005-03-30 15:05:46 +00001703 if (debug_line) {
jseward8b3131a2003-12-13 23:16:26 +00001704 has_debuginfo = True;
nethercote80f76782003-11-13 22:34:00 +00001705 VG_(read_debuginfo_dwarf2) ( si, debug_line, debug_line_sz );
jseward8b3131a2003-12-13 23:16:26 +00001706 }
1707 if (dwarf1d && dwarf1l) {
1708 has_debuginfo = True;
1709 VG_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz,
1710 dwarf1l, dwarf1l_sz );
1711 }
1712 if (!has_debuginfo) {
sewardj5c638c22005-04-30 07:55:58 +00001713 VG_(symerr)(" object doesn't have any line number info");
nethercote80f76782003-11-13 22:34:00 +00001714 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001715 }
sewardj5c638c22005-04-30 07:55:58 +00001716
sewardjde4a1d02002-03-22 01:27:54 +00001717 }
nethercote80f76782003-11-13 22:34:00 +00001718 res = True;
sewardjde4a1d02002-03-22 01:27:54 +00001719
nethercotee567e702004-07-10 17:49:17 +00001720 out: {
1721 Int m_res;
thughesc035bd92004-06-13 09:59:02 +00001722 /* Last, but not least, heave the image(s) back overboard. */
nethercotee567e702004-07-10 17:49:17 +00001723 if (dimage) {
1724 m_res = VG_(munmap) ( (void*)dimage, n_dimage );
1725 vg_assert(0 == m_res);
1726 }
1727 m_res = VG_(munmap) ( (void*)oimage, n_oimage );
1728 vg_assert(0 == m_res);
nethercote80f76782003-11-13 22:34:00 +00001729 return res;
nethercotee567e702004-07-10 17:49:17 +00001730 }
sewardjde4a1d02002-03-22 01:27:54 +00001731}
1732
sewardjde4a1d02002-03-22 01:27:54 +00001733/*------------------------------------------------------------*/
1734/*--- Main entry point for symbols table reading. ---*/
1735/*------------------------------------------------------------*/
1736
1737/* The root structure for the entire symbol table system. It is a
1738 linked list of SegInfos. Note that this entire mechanism assumes
1739 that what we read from /proc/self/maps doesn't contain overlapping
1740 address ranges, and as a result the SegInfos in this list describe
1741 disjoint address ranges.
1742*/
fitzhardinge98abfc72003-12-16 02:05:15 +00001743SegInfo *VG_(read_seg_symbols) ( Segment *seg )
sewardjde4a1d02002-03-22 01:27:54 +00001744{
1745 SegInfo* si;
1746
fitzhardinge98abfc72003-12-16 02:05:15 +00001747 vg_assert(seg->symtab == NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001748
njnfa1016e2003-09-25 17:54:11 +00001749 VGP_PUSHCC(VgpReadSyms);
1750
sewardjde4a1d02002-03-22 01:27:54 +00001751 /* Get the record initialised right. */
njn25e49d8e72002-09-23 09:36:25 +00001752 si = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(SegInfo));
sewardjde4a1d02002-03-22 01:27:54 +00001753
sewardj8fe15a32002-10-20 19:29:21 +00001754 VG_(memset)(si, 0, sizeof(*si));
fitzhardinge98abfc72003-12-16 02:05:15 +00001755 si->start = seg->addr;
1756 si->size = seg->len;
1757 si->foffset = seg->offset;
fitzhardinge1a4adf02003-12-22 10:42:59 +00001758 si->filename = VG_(arena_strdup)(VG_AR_SYMTAB, seg->filename);
fitzhardinge98abfc72003-12-16 02:05:15 +00001759
1760 si->ref = 1;
sewardjde4a1d02002-03-22 01:27:54 +00001761
1762 si->symtab = NULL;
1763 si->symtab_size = si->symtab_used = 0;
1764 si->loctab = NULL;
1765 si->loctab_size = si->loctab_used = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001766 si->strchunks = NULL;
1767 si->scopetab = NULL;
1768 si->scopetab_size = si->scopetab_used = 0;
sewardj5c638c22005-04-30 07:55:58 +00001769 si->cfisi = NULL;
1770 si->cfisi_size = si->cfisi_used = 0;
sewardjbf603752005-05-02 00:36:27 +00001771 si->cfisi_minaddr = si->cfisi_maxaddr = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001772
fitzhardinge98abfc72003-12-16 02:05:15 +00001773 si->seg = seg;
1774
jsgfcb1d1c02003-10-14 21:55:10 +00001775 si->stab_typetab = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001776
nethercote80f76782003-11-13 22:34:00 +00001777 si->plt_start = si->plt_size = 0;
1778 si->got_start = si->got_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001779 si->data_start = si->data_size = 0;
nethercote80f76782003-11-13 22:34:00 +00001780 si->bss_start = si->bss_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001781
sewardjde4a1d02002-03-22 01:27:54 +00001782 /* And actually fill it up. */
njn695c16e2005-03-27 03:40:28 +00001783 if (!read_lib_symbols ( si ) && 0) {
sewardj8fe15a32002-10-20 19:29:21 +00001784 /* XXX this interacts badly with the prevN optimization in
1785 addStr(). Since this frees the si, the si pointer value can
1786 be recycled, which confuses the curr_si == si test. For now,
1787 this code is disabled, and everything is included in the
1788 segment list, even if it is a bad ELF file. Ironically,
1789 running this under valgrind itself hides the problem, because
1790 it doesn't recycle pointers... */
1791 freeSegInfo( si );
1792 } else {
1793 si->next = segInfo;
1794 segInfo = si;
1795
1796 canonicaliseSymtab ( si );
1797 canonicaliseLoctab ( si );
jsgfcb1d1c02003-10-14 21:55:10 +00001798 canonicaliseScopetab ( si );
sewardjbf603752005-05-02 00:36:27 +00001799 canonicaliseCfiSI ( si );
fitzhardinge98abfc72003-12-16 02:05:15 +00001800
1801 /* do redirects */
sewardjb5f6f512005-03-10 23:59:00 +00001802 VG_(resolve_seg_redirs)( si );
sewardj8fe15a32002-10-20 19:29:21 +00001803 }
njnfa1016e2003-09-25 17:54:11 +00001804 VGP_POPCC(VgpReadSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001805
1806 return si;
sewardjde4a1d02002-03-22 01:27:54 +00001807}
1808
1809
sewardjde4a1d02002-03-22 01:27:54 +00001810/* When an munmap() call happens, check to see whether it corresponds
1811 to a segment for a .so, and if so discard the relevant SegInfo.
1812 This might not be a very clever idea from the point of view of
1813 accuracy of error messages, but we need to do it in order to
sewardj18d75132002-05-16 11:06:21 +00001814 maintain the no-overlapping invariant.
sewardjde4a1d02002-03-22 01:27:54 +00001815*/
nethercote928a5f72004-11-03 18:10:37 +00001816static void unload_symbols ( Addr start, SizeT length )
sewardjde4a1d02002-03-22 01:27:54 +00001817{
1818 SegInfo *prev, *curr;
1819
sewardjde4a1d02002-03-22 01:27:54 +00001820 prev = NULL;
1821 curr = segInfo;
1822 while (True) {
1823 if (curr == NULL) break;
1824 if (start == curr->start) break;
1825 prev = curr;
1826 curr = curr->next;
1827 }
njnfa1016e2003-09-25 17:54:11 +00001828 if (curr == NULL) {
1829 VGP_POPCC(VgpReadSyms);
njn25e49d8e72002-09-23 09:36:25 +00001830 return;
njnfa1016e2003-09-25 17:54:11 +00001831 }
sewardjde4a1d02002-03-22 01:27:54 +00001832
mueller75c0ed62003-11-19 00:47:00 +00001833 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001834 VG_(message)(Vg_DebugMsg,
fitzhardinge98abfc72003-12-16 02:05:15 +00001835 "discard syms at %p-%p in %s due to munmap()",
1836 start, start+length, curr->filename ? curr->filename : (Char *)"???");
sewardjde4a1d02002-03-22 01:27:54 +00001837
1838 vg_assert(prev == NULL || prev->next == curr);
1839
1840 if (prev == NULL) {
1841 segInfo = curr->next;
1842 } else {
1843 prev->next = curr->next;
1844 }
1845
1846 freeSegInfo(curr);
njn25e49d8e72002-09-23 09:36:25 +00001847 return;
sewardjde4a1d02002-03-22 01:27:54 +00001848}
1849
nethercote8991d5a2004-11-03 17:07:46 +00001850void VG_(symtab_decref)(SegInfo *si, Addr start)
fitzhardinge98abfc72003-12-16 02:05:15 +00001851{
1852 vg_assert(si->ref >= 1);
1853 if (--si->ref == 0)
nethercote85cdd342004-08-01 22:36:40 +00001854 unload_symbols(si->start, si->size);
fitzhardinge98abfc72003-12-16 02:05:15 +00001855}
1856
1857void VG_(symtab_incref)(SegInfo *si)
1858{
1859 vg_assert(si->ref > 0);
1860 si->ref++;
1861}
sewardjde4a1d02002-03-22 01:27:54 +00001862
1863/*------------------------------------------------------------*/
1864/*--- Use of symbol table & location info to create ---*/
1865/*--- plausible-looking stack dumps. ---*/
1866/*------------------------------------------------------------*/
1867
1868/* Find a symbol-table index containing the specified pointer, or -1
1869 if not found. Binary search. */
1870
njn25e49d8e72002-09-23 09:36:25 +00001871static Int search_one_symtab ( SegInfo* si, Addr ptr,
1872 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001873{
1874 Addr a_mid_lo, a_mid_hi;
njn25e49d8e72002-09-23 09:36:25 +00001875 Int mid, size,
sewardjde4a1d02002-03-22 01:27:54 +00001876 lo = 0,
1877 hi = si->symtab_used-1;
1878 while (True) {
1879 /* current unsearched space is from lo to hi, inclusive. */
1880 if (lo > hi) return -1; /* not found */
1881 mid = (lo + hi) / 2;
1882 a_mid_lo = si->symtab[mid].addr;
njn25e49d8e72002-09-23 09:36:25 +00001883 size = ( match_anywhere_in_fun
1884 ? si->symtab[mid].size
1885 : 1);
1886 a_mid_hi = ((Addr)si->symtab[mid].addr) + size - 1;
sewardjde4a1d02002-03-22 01:27:54 +00001887
1888 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1889 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1890 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1891 return mid;
1892 }
1893}
1894
1895
sewardj25c7c3a2003-07-10 00:17:58 +00001896/* SLOW (Linear search). Try and map a symbol name to an address.
1897 Since this is searching in the direction opposite to which the
1898 table is designed we have no option but to do a complete linear
1899 scan of the table. Returns NULL if not found. */
1900
sewardjb5f6f512005-03-10 23:59:00 +00001901Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name )
sewardj25c7c3a2003-07-10 00:17:58 +00001902{
1903 UInt i;
1904 for (i = 0; i < si->symtab_used; i++) {
sewardjc8bf5fe2003-07-13 00:53:22 +00001905 if (0)
jsgfcb1d1c02003-10-14 21:55:10 +00001906 VG_(printf)("%p %s\n", si->symtab[i].addr, si->symtab[i].name);
1907 if (0 == VG_(strcmp)(name, si->symtab[i].name))
sewardj25c7c3a2003-07-10 00:17:58 +00001908 return si->symtab[i].addr;
1909 }
1910 return (Addr)NULL;
1911}
1912
1913
sewardjde4a1d02002-03-22 01:27:54 +00001914/* Search all symtabs that we know about to locate ptr. If found, set
1915 *psi to the relevant SegInfo, and *symno to the symtab entry number
1916 within that. If not found, *psi is set to NULL. */
1917
njn25e49d8e72002-09-23 09:36:25 +00001918static void search_all_symtabs ( Addr ptr, /*OUT*/SegInfo** psi,
1919 /*OUT*/Int* symno,
1920 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001921{
1922 Int sno;
1923 SegInfo* si;
fitzhardinge98abfc72003-12-16 02:05:15 +00001924 Segment *s;
njn25e49d8e72002-09-23 09:36:25 +00001925
njn25e49d8e72002-09-23 09:36:25 +00001926 VGP_PUSHCC(VgpSearchSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001927
1928 s = VG_(find_segment)(ptr);
1929
sewardjb5f6f512005-03-10 23:59:00 +00001930 if (s == NULL || s->symtab == NULL)
fitzhardinge98abfc72003-12-16 02:05:15 +00001931 goto not_found;
njn25e49d8e72002-09-23 09:36:25 +00001932
fitzhardinge98abfc72003-12-16 02:05:15 +00001933 si = s->symtab;
1934
1935 sno = search_one_symtab ( si, ptr, match_anywhere_in_fun );
1936 if (sno == -1) goto not_found;
1937
1938 *symno = sno;
1939 *psi = si;
1940 VGP_POPCC(VgpSearchSyms);
1941 return;
1942
sewardjde4a1d02002-03-22 01:27:54 +00001943 not_found:
1944 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00001945 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001946}
1947
1948
1949/* Find a location-table index containing the specified pointer, or -1
1950 if not found. Binary search. */
1951
1952static Int search_one_loctab ( SegInfo* si, Addr ptr )
1953{
1954 Addr a_mid_lo, a_mid_hi;
1955 Int mid,
1956 lo = 0,
1957 hi = si->loctab_used-1;
1958 while (True) {
1959 /* current unsearched space is from lo to hi, inclusive. */
1960 if (lo > hi) return -1; /* not found */
1961 mid = (lo + hi) / 2;
1962 a_mid_lo = si->loctab[mid].addr;
1963 a_mid_hi = ((Addr)si->loctab[mid].addr) + si->loctab[mid].size - 1;
1964
1965 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1966 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1967 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1968 return mid;
1969 }
1970}
1971
1972
1973/* Search all loctabs that we know about to locate ptr. If found, set
1974 *psi to the relevant SegInfo, and *locno to the loctab entry number
1975 within that. If not found, *psi is set to NULL.
1976*/
njn25e49d8e72002-09-23 09:36:25 +00001977static void search_all_loctabs ( Addr ptr, /*OUT*/SegInfo** psi,
1978 /*OUT*/Int* locno )
sewardjde4a1d02002-03-22 01:27:54 +00001979{
1980 Int lno;
1981 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00001982
1983 VGP_PUSHCC(VgpSearchSyms);
1984
sewardjde4a1d02002-03-22 01:27:54 +00001985 for (si = segInfo; si != NULL; si = si->next) {
1986 if (si->start <= ptr && ptr < si->start+si->size) {
1987 lno = search_one_loctab ( si, ptr );
1988 if (lno == -1) goto not_found;
1989 *locno = lno;
1990 *psi = si;
njn25e49d8e72002-09-23 09:36:25 +00001991 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001992 return;
1993 }
1994 }
1995 not_found:
1996 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00001997 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001998}
1999
2000
jsgfcb1d1c02003-10-14 21:55:10 +00002001/* Find a scope-table index containing the specified pointer, or -1
2002 if not found. Binary search. */
2003
2004static Int search_one_scopetab ( SegInfo* si, Addr ptr )
2005{
2006 Addr a_mid_lo, a_mid_hi;
2007 Int mid,
2008 lo = 0,
2009 hi = si->scopetab_used-1;
2010 while (True) {
2011 /* current unsearched space is from lo to hi, inclusive. */
2012 if (lo > hi) return -1; /* not found */
2013 mid = (lo + hi) / 2;
2014 a_mid_lo = si->scopetab[mid].addr;
2015 a_mid_hi = ((Addr)si->scopetab[mid].addr) + si->scopetab[mid].size - 1;
2016
2017 if (ptr < a_mid_lo) { hi = mid-1; continue; }
2018 if (ptr > a_mid_hi) { lo = mid+1; continue; }
2019 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2020 return mid;
2021 }
2022}
2023
2024
2025/* Search all scopetabs that we know about to locate ptr. If found, set
2026 *psi to the relevant SegInfo, and *locno to the scopetab entry number
2027 within that. If not found, *psi is set to NULL.
2028*/
2029static void search_all_scopetabs ( Addr ptr,
2030 /*OUT*/SegInfo** psi,
2031 /*OUT*/Int* scopeno )
2032{
2033 Int scno;
2034 SegInfo* si;
2035
2036 VGP_PUSHCC(VgpSearchSyms);
2037
2038 for (si = segInfo; si != NULL; si = si->next) {
2039 if (si->start <= ptr && ptr < si->start+si->size) {
2040 scno = search_one_scopetab ( si, ptr );
2041 if (scno == -1) goto not_found;
2042 *scopeno = scno;
2043 *psi = si;
2044 VGP_POPCC(VgpSearchSyms);
2045 return;
2046 }
2047 }
2048 not_found:
2049 *psi = NULL;
2050 VGP_POPCC(VgpSearchSyms);
2051}
2052
sewardj3a1c7db2005-05-02 09:43:44 +00002053
2054/* Find a CFI-table index containing the specified pointer, or -1
2055 if not found. Binary search. */
2056
2057static Int search_one_cfitab ( SegInfo* si, Addr ptr )
2058{
2059 Addr a_mid_lo, a_mid_hi;
2060 Int mid, size,
2061 lo = 0,
2062 hi = si->cfisi_used-1;
2063 while (True) {
2064 /* current unsearched space is from lo to hi, inclusive. */
2065 if (lo > hi) return -1; /* not found */
2066 mid = (lo + hi) / 2;
2067 a_mid_lo = si->cfisi[mid].base;
2068 size = si->cfisi[mid].len;
2069 a_mid_hi = a_mid_lo + size - 1;
2070 vg_assert(a_mid_hi >= a_mid_lo);
2071 if (ptr < a_mid_lo) { hi = mid-1; continue; }
2072 if (ptr > a_mid_hi) { lo = mid+1; continue; }
2073 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2074 return mid;
2075 }
2076}
2077
2078
sewardjde4a1d02002-03-22 01:27:54 +00002079/* The whole point of this whole big deal: map a code address to a
2080 plausible symbol name. Returns False if no idea; otherwise True.
njn25e49d8e72002-09-23 09:36:25 +00002081 Caller supplies buf and nbuf. If demangle is False, don't do
njn695c16e2005-03-27 03:40:28 +00002082 demangling, regardless of VG_(clo_demangle) -- probably because the
2083 call has come from VG_(get_fnname_nodemangle)(). */
njn25e49d8e72002-09-23 09:36:25 +00002084static
2085Bool get_fnname ( Bool demangle, Addr a, Char* buf, Int nbuf,
sewardj1771e172002-11-13 22:06:35 +00002086 Bool match_anywhere_in_fun, Bool show_offset)
sewardjde4a1d02002-03-22 01:27:54 +00002087{
2088 SegInfo* si;
2089 Int sno;
sewardj1771e172002-11-13 22:06:35 +00002090 Int offset;
2091
njn25e49d8e72002-09-23 09:36:25 +00002092 search_all_symtabs ( a, &si, &sno, match_anywhere_in_fun );
sewardjde4a1d02002-03-22 01:27:54 +00002093 if (si == NULL)
2094 return False;
njn25e49d8e72002-09-23 09:36:25 +00002095 if (demangle) {
jsgfcb1d1c02003-10-14 21:55:10 +00002096 VG_(demangle) ( si->symtab[sno].name, buf, nbuf );
njn25e49d8e72002-09-23 09:36:25 +00002097 } else {
njnbe73f432005-03-26 21:34:45 +00002098 VG_(strncpy_safely) ( buf, si->symtab[sno].name, nbuf );
sewardjde4a1d02002-03-22 01:27:54 +00002099 }
sewardj1771e172002-11-13 22:06:35 +00002100
2101 offset = a - si->symtab[sno].addr;
2102 if (show_offset && offset != 0) {
2103 Char buf2[12];
2104 Char* symend = buf + VG_(strlen)(buf);
2105 Char* end = buf + nbuf;
2106 Int len;
2107
2108 len = VG_(sprintf)(buf2, "%c%d",
2109 offset < 0 ? '-' : '+',
2110 offset < 0 ? -offset : offset);
sewardj05bcdcb2003-05-18 10:05:38 +00002111 vg_assert(len < (Int)sizeof(buf2));
sewardj1771e172002-11-13 22:06:35 +00002112
2113 if (len < (end - symend)) {
2114 Char *cp = buf2;
2115 VG_(memcpy)(symend, cp, len+1);
2116 }
2117 }
2118
sewardjde4a1d02002-03-22 01:27:54 +00002119 return True;
2120}
2121
nethercote7cc9c232004-01-21 15:08:04 +00002122/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002123 match anywhere in function, but don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002124Bool VG_(get_fnname) ( Addr a, Char* buf, Int nbuf )
2125{
2126 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002127 /*match_anywhere_in_fun*/True,
2128 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002129}
sewardjde4a1d02002-03-22 01:27:54 +00002130
nethercote7cc9c232004-01-21 15:08:04 +00002131/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002132 match anywhere in function, and show offset if nonzero. */
2133Bool VG_(get_fnname_w_offset) ( Addr a, Char* buf, Int nbuf )
2134{
2135 return get_fnname ( /*demangle*/True, a, buf, nbuf,
2136 /*match_anywhere_in_fun*/True,
2137 /*show offset?*/True );
2138}
2139
nethercote7cc9c232004-01-21 15:08:04 +00002140/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002141 only succeed if 'a' matches first instruction of function,
2142 and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002143Bool VG_(get_fnname_if_entry) ( Addr a, Char* buf, Int nbuf )
2144{
2145 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002146 /*match_anywhere_in_fun*/False,
2147 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002148}
2149
sewardj6e008cb2002-12-15 13:11:39 +00002150/* This is only available to core... don't demangle C++ names,
2151 match anywhere in function, and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002152Bool VG_(get_fnname_nodemangle) ( Addr a, Char* buf, Int nbuf )
2153{
2154 return get_fnname ( /*demangle*/False, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002155 /*match_anywhere_in_fun*/True,
2156 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002157}
2158
2159/* Map a code address to the name of a shared object file or the executable.
2160 Returns False if no idea; otherwise True. Doesn't require debug info.
2161 Caller supplies buf and nbuf. */
2162Bool VG_(get_objname) ( Addr a, Char* buf, Int nbuf )
sewardjde4a1d02002-03-22 01:27:54 +00002163{
2164 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00002165
sewardjde4a1d02002-03-22 01:27:54 +00002166 for (si = segInfo; si != NULL; si = si->next) {
2167 if (si->start <= a && a < si->start+si->size) {
2168 VG_(strncpy_safely)(buf, si->filename, nbuf);
2169 return True;
2170 }
2171 }
2172 return False;
2173}
2174
njnb877d492003-01-28 20:40:57 +00002175/* Map a code address to its SegInfo. Returns NULL if not found. Doesn't
2176 require debug info. */
2177SegInfo* VG_(get_obj) ( Addr a )
2178{
2179 SegInfo* si;
2180
njnb877d492003-01-28 20:40:57 +00002181 for (si = segInfo; si != NULL; si = si->next) {
2182 if (si->start <= a && a < si->start+si->size) {
2183 return si;
2184 }
2185 }
nethercote80f76782003-11-13 22:34:00 +00002186 return NULL;
njnb877d492003-01-28 20:40:57 +00002187}
2188
njn25e49d8e72002-09-23 09:36:25 +00002189
2190/* Map a code address to a filename. Returns True if successful. */
2191Bool VG_(get_filename)( Addr a, Char* filename, Int n_filename )
sewardjde4a1d02002-03-22 01:27:54 +00002192{
njn25e49d8e72002-09-23 09:36:25 +00002193 SegInfo* si;
2194 Int locno;
2195 search_all_loctabs ( a, &si, &locno );
2196 if (si == NULL)
2197 return False;
njnbe73f432005-03-26 21:34:45 +00002198 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
njn25e49d8e72002-09-23 09:36:25 +00002199 return True;
sewardjde4a1d02002-03-22 01:27:54 +00002200}
2201
njn25e49d8e72002-09-23 09:36:25 +00002202/* Map a code address to a line number. Returns True if successful. */
2203Bool VG_(get_linenum)( Addr a, UInt* lineno )
2204{
2205 SegInfo* si;
2206 Int locno;
2207 search_all_loctabs ( a, &si, &locno );
2208 if (si == NULL)
2209 return False;
2210 *lineno = si->loctab[locno].lineno;
2211
2212 return True;
2213}
sewardjde4a1d02002-03-22 01:27:54 +00002214
2215/* Map a code address to a (filename, line number) pair.
2216 Returns True if successful.
2217*/
njn25e49d8e72002-09-23 09:36:25 +00002218Bool VG_(get_filename_linenum)( Addr a,
2219 Char* filename, Int n_filename,
2220 UInt* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00002221{
2222 SegInfo* si;
2223 Int locno;
2224 search_all_loctabs ( a, &si, &locno );
2225 if (si == NULL)
2226 return False;
njnbe73f432005-03-26 21:34:45 +00002227 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
sewardjde4a1d02002-03-22 01:27:54 +00002228 *lineno = si->loctab[locno].lineno;
njn4f9c9342002-04-29 16:03:24 +00002229
sewardjde4a1d02002-03-22 01:27:54 +00002230 return True;
2231}
2232
jsgfcb1d1c02003-10-14 21:55:10 +00002233#ifndef TEST
2234
2235/* return a pointer to a register (now for 5 other impossible things
2236 before breakfast) */
2237static UInt *regaddr(ThreadId tid, Int regno)
2238{
2239 UInt *ret = 0;
2240
sewardj2a99cf62004-11-24 10:44:19 +00002241 ret = VGA_(reg_addr_from_tst)(regno, &VG_(threads)[tid].arch);
jsgfcb1d1c02003-10-14 21:55:10 +00002242
2243 if (ret == 0) {
2244 Char file[100];
2245 Int line;
njn67516132005-03-22 04:02:43 +00002246 Addr eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002247
2248 if (!VG_(get_filename_linenum)(eip, file, sizeof(file), &line))
2249 file[0] = 0;
2250 VG_(printf)("mysterious register %d used at %p %s:%d\n",
2251 regno, eip, file, line);
2252 }
2253
2254 return ret;
2255}
2256
2257/* Get a list of all variables in scope, working out from the directly
2258 current one */
2259Variable *VG_(get_scope_variables)(ThreadId tid)
2260{
2261 static const Bool debug = False;
2262 Variable *list, *end;
2263 Addr eip;
2264 SegInfo *si;
2265 Int scopeidx;
2266 Scope *scope;
2267 Int distance;
2268 static const Int maxsyms = 1000;
2269 Int nsyms = maxsyms;
2270
2271 list = end = NULL;
2272
njn67516132005-03-22 04:02:43 +00002273 eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002274
2275 search_all_scopetabs(eip, &si, &scopeidx);
2276
2277 if (debug)
2278 VG_(printf)("eip=%p si=%p (%s; offset=%p) scopeidx=%d\n",
2279 eip, si, si ? si->filename : (Char *)"???",
2280 si ? si->offset : 0x99999, scopeidx);
2281
2282 if (si == NULL)
2283 return NULL; /* nothing in scope (should use global scope at least) */
2284
2285 if (debug) {
2286 ScopeRange *sr = &si->scopetab[scopeidx];
2287 Char file[100];
2288 Int line;
2289
2290 if (!VG_(get_filename_linenum)(sr->addr, file, sizeof(file), &line))
2291 file[0] = 0;
2292
2293 VG_(printf)("found scope range %p: eip=%p (%s:%d) size=%d scope=%p\n",
2294 sr, sr->addr, file, line, sr->size, sr->scope);
2295 }
2296
2297 distance = 0;
2298 for(scope = si->scopetab[scopeidx].scope; scope != NULL; scope = scope->outer, distance++) {
2299 UInt i;
2300
2301 for(i = 0; i < scope->nsyms; i++) {
2302 Sym *sym = &scope->syms[i];
2303 Variable *v;
2304
2305 if (nsyms-- == 0) {
2306 VG_(printf)("max %d syms reached\n", maxsyms);
2307 return list;
2308 }
2309
2310 v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
2311
2312 v->next = NULL;
2313 v->distance = distance;
2314 v->type = VG_(st_basetype)(sym->type, False);
2315 v->name = VG_(arena_strdup)(VG_AR_SYMTAB, sym->name);
2316 v->container = NULL;
2317 v->size = VG_(st_sizeof)(sym->type);
2318
2319 if (debug && 0)
mueller5ed88f22004-01-06 16:02:29 +00002320 VG_(printf)("sym->name=%s sym->kind=%d offset=%d\n", sym->name, sym->kind, sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002321 switch(sym->kind) {
2322 UInt reg;
2323
2324 case SyGlobal:
2325 case SyStatic:
mueller5ed88f22004-01-06 16:02:29 +00002326 if (sym->u.addr == 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00002327 /* XXX lookup value */
2328 }
mueller5ed88f22004-01-06 16:02:29 +00002329 v->valuep = sym->u.addr;
jsgfcb1d1c02003-10-14 21:55:10 +00002330 break;
2331
2332 case SyReg:
mueller5ed88f22004-01-06 16:02:29 +00002333 v->valuep = (Addr)regaddr(tid, sym->u.regno);
jsgfcb1d1c02003-10-14 21:55:10 +00002334 break;
2335
2336 case SyEBPrel:
2337 case SyESPrel:
nethercotecd656042004-09-11 23:48:22 +00002338 reg = *regaddr(tid, sym->kind == SyESPrel ?
njndb9b7732005-03-26 00:32:29 +00002339 VGA_R_STACK_PTR : VGA_R_FRAME_PTR);
jsgfcb1d1c02003-10-14 21:55:10 +00002340 if (debug)
mueller5ed88f22004-01-06 16:02:29 +00002341 VG_(printf)("reg=%p+%d=%p\n", reg, sym->u.offset, reg+sym->u.offset);
2342 v->valuep = (Addr)(reg + sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002343 break;
2344
2345 case SyType:
2346 VG_(core_panic)("unexpected typedef in scope");
2347 }
2348
2349 if (v->valuep == 0) {
2350 /* not interesting or useful */
2351 VG_(arena_free)(VG_AR_SYMTAB, v);
2352 continue;
2353 }
2354
2355 /* append to end of list */
2356 if (list == NULL)
2357 list = end = v;
2358 else {
2359 end->next = v;
2360 end = v;
2361 }
2362 }
2363 }
2364
2365 return list;
2366}
2367#endif /* TEST */
2368
njn6c846552003-09-16 07:41:43 +00002369/* Print into buf info on code address, function name and filename */
njnd01fef72005-03-25 23:35:48 +00002370Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf)
sewardjde4a1d02002-03-22 01:27:54 +00002371{
njn6c846552003-09-16 07:41:43 +00002372#define APPEND(str) \
2373 { UChar* sss; \
2374 for (sss = str; n < n_buf-1 && *sss != 0; n++,sss++) \
2375 buf[n] = *sss; \
2376 buf[n] = '\0'; \
sewardjde4a1d02002-03-22 01:27:54 +00002377 }
nethercote80f76782003-11-13 22:34:00 +00002378 UInt lineno;
2379 UChar ibuf[20];
2380 UInt n = 0;
njn47b209a2005-03-25 23:47:16 +00002381 static UChar buf_fn[VG_ERRTXT_LEN];
2382 static UChar buf_obj[VG_ERRTXT_LEN];
2383 static UChar buf_srcloc[VG_ERRTXT_LEN];
2384 Bool know_fnname = VG_(get_fnname) (eip, buf_fn, VG_ERRTXT_LEN);
2385 Bool know_objname = VG_(get_objname)(eip, buf_obj, VG_ERRTXT_LEN);
2386 Bool know_srcloc = VG_(get_filename_linenum)(eip, buf_srcloc,
2387 VG_ERRTXT_LEN, &lineno);
sewardja4da2f32005-03-02 14:06:08 +00002388 VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip);
njn6c846552003-09-16 07:41:43 +00002389 APPEND(ibuf);
2390 if (know_fnname) {
2391 APPEND(buf_fn);
2392 if (!know_srcloc && know_objname) {
2393 APPEND(" (in ");
2394 APPEND(buf_obj);
2395 APPEND(")");
2396 }
2397 } else if (know_objname && !know_srcloc) {
2398 APPEND("(within ");
2399 APPEND(buf_obj);
2400 APPEND(")");
2401 } else {
2402 APPEND("???");
2403 }
2404 if (know_srcloc) {
2405 APPEND(" (");
2406 APPEND(buf_srcloc);
2407 APPEND(":");
2408 VG_(sprintf)(ibuf,"%d",lineno);
2409 APPEND(ibuf);
2410 APPEND(")");
2411 }
2412 return buf;
2413
2414#undef APPEND
2415}
2416
sewardj35165532005-04-30 18:47:48 +00002417/* Returns True if OK. If not OK, *{ip,sp,fp}P are not changed. */
2418
2419Bool VG_(use_CFI_info) ( /*MOD*/Addr* ipP,
2420 /*MOD*/Addr* spP,
2421 /*MOD*/Addr* fpP,
2422 Addr min_accessible,
2423 Addr max_accessible )
2424{
2425 Int i;
2426 SegInfo* si;
2427 CfiSI* cfisi = NULL;
2428 Addr cfa, ipHere, spHere, fpHere, ipPrev, spPrev, fpPrev;
2429
sewardjbf603752005-05-02 00:36:27 +00002430
sewardj35165532005-04-30 18:47:48 +00002431 if (0) VG_(printf)("search for %p\n", *ipP);
2432
2433 for (si = segInfo; si != NULL; si = si->next) {
sewardjbf603752005-05-02 00:36:27 +00002434 /* Use the per-SegInfo summary address ranges to skip
2435 inapplicable SegInfos quickly. */
2436 if (si->cfisi_used == 0)
2437 continue;
2438 if (*ipP < si->cfisi_minaddr || *ipP > si->cfisi_maxaddr)
2439 continue;
2440
sewardj3a1c7db2005-05-02 09:43:44 +00002441 i = search_one_cfitab( si, *ipP );
2442 if (i != -1) {
2443 vg_assert(i >= 0 && i < si->cfisi_used);
2444 cfisi = &si->cfisi[i];
2445 break;
sewardj35165532005-04-30 18:47:48 +00002446 }
2447 }
2448
sewardj35165532005-04-30 18:47:48 +00002449 if (cfisi == NULL)
2450 return False;
2451
2452 if (0) {
2453 VG_(printf)("found cfisi: ");
2454 VG_(ppCfiSI)(cfisi);
2455 }
2456
2457 ipPrev = spPrev = fpPrev = 0;
2458
2459 ipHere = *ipP;
2460 spHere = *spP;
2461 fpHere = *fpP;
2462
2463 cfa = cfisi->cfa_off + (cfisi->cfa_sprel ? spHere : fpHere);
2464
2465# define COMPUTE(_prev, _here, _how, _off) \
2466 do { \
2467 switch (_how) { \
2468 case CFIR_UNKNOWN: \
2469 return False; \
2470 case CFIR_SAME: \
2471 _prev = _here; break; \
2472 case CFIR_MEMCFAREL: { \
2473 Addr a = cfa + (Word)_off; \
2474 if (a < min_accessible \
2475 || a+sizeof(Addr) > max_accessible) \
2476 return False; \
2477 _prev = *(Addr*)a; \
2478 break; \
2479 } \
2480 case CFIR_CFAREL: \
2481 _prev = cfa + (Word)_off; \
2482 break; \
2483 } \
2484 } while (0)
2485
2486 COMPUTE(ipPrev, ipHere, cfisi->ra_how, cfisi->ra_off);
2487 COMPUTE(spPrev, spHere, cfisi->sp_how, cfisi->sp_off);
2488 COMPUTE(fpPrev, fpHere, cfisi->fp_how, cfisi->fp_off);
2489
2490# undef COMPUTE
2491
2492 *ipP = ipPrev;
2493 *spP = spPrev;
2494 *fpP = fpPrev;
2495 return True;
2496}
2497
2498
sewardj25c7c3a2003-07-10 00:17:58 +00002499/*------------------------------------------------------------*/
sewardj47104382002-10-20 18:35:48 +00002500/*--- SegInfo accessor functions ---*/
2501/*------------------------------------------------------------*/
2502
2503const SegInfo* VG_(next_seginfo)(const SegInfo* seg)
2504{
sewardj47104382002-10-20 18:35:48 +00002505 if (seg == NULL)
2506 return segInfo;
2507 return seg->next;
2508}
2509
2510Addr VG_(seg_start)(const SegInfo* seg)
2511{
2512 return seg->start;
2513}
2514
nethercote928a5f72004-11-03 18:10:37 +00002515SizeT VG_(seg_size)(const SegInfo* seg)
sewardj47104382002-10-20 18:35:48 +00002516{
2517 return seg->size;
2518}
2519
2520const UChar* VG_(seg_filename)(const SegInfo* seg)
2521{
2522 return seg->filename;
2523}
2524
nethercote928a5f72004-11-03 18:10:37 +00002525ULong VG_(seg_sym_offset)(const SegInfo* seg)
sewardj47104382002-10-20 18:35:48 +00002526{
2527 return seg->offset;
2528}
2529
2530VgSectKind VG_(seg_sect_kind)(Addr a)
2531{
2532 SegInfo* seg;
2533 VgSectKind ret = Vg_SectUnknown;
2534
sewardj47104382002-10-20 18:35:48 +00002535 for(seg = segInfo; seg != NULL; seg = seg->next) {
2536 if (a >= seg->start && a < (seg->start + seg->size)) {
2537 if (0)
sewardj8fe15a32002-10-20 19:29:21 +00002538 VG_(printf)("addr=%p seg=%p %s got=%p %d plt=%p %d data=%p %d bss=%p %d\n",
sewardj47104382002-10-20 18:35:48 +00002539 a, seg, seg->filename,
2540 seg->got_start, seg->got_size,
sewardj8fe15a32002-10-20 19:29:21 +00002541 seg->plt_start, seg->plt_size,
2542 seg->data_start, seg->data_size,
2543 seg->bss_start, seg->bss_size);
sewardj47104382002-10-20 18:35:48 +00002544 ret = Vg_SectText;
2545
sewardj8fe15a32002-10-20 19:29:21 +00002546 if (a >= seg->data_start && a < (seg->data_start + seg->data_size))
2547 ret = Vg_SectData;
2548 else if (a >= seg->bss_start && a < (seg->bss_start + seg->bss_size))
2549 ret = Vg_SectBSS;
2550 else if (a >= seg->plt_start && a < (seg->plt_start + seg->plt_size))
sewardj47104382002-10-20 18:35:48 +00002551 ret = Vg_SectPLT;
2552 else if (a >= seg->got_start && a < (seg->got_start + seg->got_size))
2553 ret = Vg_SectGOT;
2554 }
2555 }
2556
2557 return ret;
2558}
2559
sewardjde4a1d02002-03-22 01:27:54 +00002560/*--------------------------------------------------------------------*/
2561/*--- end vg_symtab2.c ---*/
2562/*--------------------------------------------------------------------*/