blob: 23d5a51fa287dcf86f8b21019b5c162692099620 [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
sewardjc4f204f2005-05-03 15:23:00 +0000389 /* Rule out ones which are completely outside the segment. These
390 probably indicate some kind of bug, but for the meantime ignore
391 them. */
392 if ( cfisi->base + cfisi->len - 1 < si->start
393 || si->start + si->size - 1 < cfisi->base ) {
sewardj55022aa2005-05-03 16:05:00 +0000394 static Int complaints = 3;
395 if (VG_(clo_trace_cfi) || complaints > 0) {
396 complaints--;
sewardjbe18a592005-05-06 17:01:21 +0000397 if (VG_(clo_verbosity) > 1) {
398 VG_(message)(
399 Vg_DebugMsg,
400 "warning: CfiSI %p .. %p outside segment %p .. %p",
401 cfisi->base,
402 cfisi->base + cfisi->len - 1,
403 si->start,
404 si->start + si->size - 1
405 );
406 }
sewardj55022aa2005-05-03 16:05:00 +0000407 if (VG_(clo_trace_cfi))
408 VG_(ppCfiSI)(cfisi);
sewardjc4f204f2005-05-03 15:23:00 +0000409 }
410 return;
411 }
412
sewardj35165532005-04-30 18:47:48 +0000413 if (si->cfisi_used == si->cfisi_size) {
414 new_sz = 2 * si->cfisi_size;
415 if (new_sz == 0) new_sz = 20;
416 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(CfiSI) );
417 if (si->cfisi != NULL) {
418 for (i = 0; i < si->cfisi_used; i++)
419 new_tab[i] = si->cfisi[i];
420 VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
421 }
422 si->cfisi = new_tab;
423 si->cfisi_size = new_sz;
424 }
425
426 si->cfisi[si->cfisi_used] = *cfisi;
427 si->cfisi_used++;
428 vg_assert(si->cfisi_used <= si->cfisi_size);
429}
430
431
sewardjde4a1d02002-03-22 01:27:54 +0000432/*------------------------------------------------------------*/
433/*--- Helpers ---*/
434/*------------------------------------------------------------*/
435
436/* Non-fatal -- use vg_panic if terminal. */
jsgfcb1d1c02003-10-14 21:55:10 +0000437void VG_(symerr) ( Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000438{
439 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +0000440 VG_(message)(Vg_DebugMsg,"%s", msg );
sewardjde4a1d02002-03-22 01:27:54 +0000441}
442
443
444/* Print a symbol. */
445static
446void printSym ( SegInfo* si, Int i )
447{
448 VG_(printf)( "%5d: %8p .. %8p (%d) %s\n",
449 i,
450 si->symtab[i].addr,
451 si->symtab[i].addr + si->symtab[i].size - 1, si->symtab[i].size,
jsgfcb1d1c02003-10-14 21:55:10 +0000452 si->symtab[i].name );
sewardjde4a1d02002-03-22 01:27:54 +0000453}
454
nethercote80f76782003-11-13 22:34:00 +0000455#define TRACE_SYMTAB(format, args...) \
456 if (VG_(clo_trace_symtab)) { VG_(printf)(format, ## args); }
457
sewardjde4a1d02002-03-22 01:27:54 +0000458
459#if 0
460/* Print the entire sym tab. */
461static __attribute__ ((unused))
462void printSymtab ( void )
463{
464 Int i;
465 VG_(printf)("\n------ BEGIN vg_symtab ------\n");
466 for (i = 0; i < vg_symtab_used; i++)
467 printSym(i);
468 VG_(printf)("------ BEGIN vg_symtab ------\n");
469}
470#endif
471
472#if 0
473/* Paranoid strcat. */
474static
475void safeCopy ( UChar* dst, UInt maxlen, UChar* src )
476{
477 UInt i = 0, j = 0;
478 while (True) {
479 if (i >= maxlen) return;
480 if (dst[i] == 0) break;
481 i++;
482 }
483 while (True) {
484 if (i >= maxlen) return;
485 dst[i] = src[j];
486 if (src[j] == 0) return;
487 i++; j++;
488 }
489}
490#endif
491
sewardjb51f2e62002-06-01 23:11:19 +0000492
sewardjde4a1d02002-03-22 01:27:54 +0000493/*------------------------------------------------------------*/
494/*--- Canonicalisers ---*/
495/*------------------------------------------------------------*/
496
497/* Sort the symtab by starting address, and emit warnings if any
nethercote80f76782003-11-13 22:34:00 +0000498 symbols have overlapping address ranges. We use that old chestnut,
499 shellsort. Mash the table around so as to establish the property
500 that addresses are in order and the ranges to not overlap. This
501 facilitates using binary search to map addresses to symbols when we
502 come to query the table.
sewardjde4a1d02002-03-22 01:27:54 +0000503*/
jsgfcb1d1c02003-10-14 21:55:10 +0000504static Int compare_RiSym(void *va, void *vb) {
505 RiSym *a = (RiSym *)va;
506 RiSym *b = (RiSym *)vb;
507
nethercote05fdfac2004-08-01 20:24:46 +0000508 if (a->addr < b->addr) return -1;
509 if (a->addr > b->addr) return 1;
510 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000511}
512
fitzhardinge1c76dc42003-12-15 09:00:21 +0000513/* Two symbols have the same address. Which name do we prefer?
514
sewardjb5f6f512005-03-10 23:59:00 +0000515 The general rule is to prefer the shorter symbol name. If the
516 symbol contains a '@', which means its versioned, then the length
517 up to the '@' is used for length comparison purposes (so
518 "foo@GLIBC_2.4.2" is considered shorter than "foobar"), but if two
519 symbols have the same length, the one with the version string is
520 preferred. If all else fails, use alphabetical ordering.
fitzhardinge1c76dc42003-12-15 09:00:21 +0000521 */
522static RiSym *prefersym(RiSym *a, RiSym *b)
523{
sewardjb5f6f512005-03-10 23:59:00 +0000524 Int lena, lenb; /* full length */
525 Int vlena, vlenb; /* length without version */
526 const Char *vpa, *vpb;
fitzhardingeefda47f2003-12-15 23:31:52 +0000527
sewardjb5f6f512005-03-10 23:59:00 +0000528 vlena = lena = VG_(strlen)(a->name);
529 vlenb = lenb = VG_(strlen)(b->name);
fitzhardinge1c76dc42003-12-15 09:00:21 +0000530
sewardjb5f6f512005-03-10 23:59:00 +0000531 vpa = VG_(strchr)(a->name, '@');
532 vpb = VG_(strchr)(b->name, '@');
fitzhardinge1c76dc42003-12-15 09:00:21 +0000533
sewardjb5f6f512005-03-10 23:59:00 +0000534 if (vpa)
535 vlena = vpa - a->name;
536 if (vpb)
537 vlenb = vpb - b->name;
fitzhardingeefda47f2003-12-15 23:31:52 +0000538
sewardjb5f6f512005-03-10 23:59:00 +0000539 /* Select the shortest unversioned name */
540 if (vlena < vlenb)
541 return a;
542 else if (vlenb < vlena)
fitzhardinge1c76dc42003-12-15 09:00:21 +0000543 return b;
544
sewardjb5f6f512005-03-10 23:59:00 +0000545 /* Equal lengths; select the versioned name */
546 if (vpa && !vpb)
547 return a;
548 if (vpb && !vpa)
549 return b;
550
551 /* Either both versioned or neither is versioned; select them
552 alphabetically */
553 if (VG_(strcmp)(a->name, b->name) < 0)
554 return a;
555 else
556 return b;
fitzhardinge1c76dc42003-12-15 09:00:21 +0000557}
558
sewardjde4a1d02002-03-22 01:27:54 +0000559static
560void canonicaliseSymtab ( SegInfo* si )
561{
jsgfcb1d1c02003-10-14 21:55:10 +0000562 Int i, j, n_merged, n_truncated;
sewardjde4a1d02002-03-22 01:27:54 +0000563 Addr s1, s2, e1, e2;
564
565# define SWAP(ty,aa,bb) \
566 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
567
jsgfcb1d1c02003-10-14 21:55:10 +0000568 if (si->symtab_used == 0)
569 return;
sewardjde4a1d02002-03-22 01:27:54 +0000570
nethercote3acbb5d2003-11-13 21:50:45 +0000571 VG_(ssort)(si->symtab, si->symtab_used, sizeof(*si->symtab), compare_RiSym);
sewardjde4a1d02002-03-22 01:27:54 +0000572
rjwalshe4e779d2004-04-16 23:02:29 +0000573 for (i = 0; i < si->symtab_used; i++) {
574 if(VG_(strncmp)(si->symtab[i].name, VG_INTERCEPT_PREFIX,
575 VG_INTERCEPT_PREFIX_LEN) == 0) {
576 int len = VG_(strlen)(si->symtab[i].name);
sewardjb5f6f512005-03-10 23:59:00 +0000577 char *buf = VG_(arena_malloc)(VG_AR_SYMTAB, len), *colon;
nethercoteb1e1ad42004-08-03 23:44:12 +0000578 intercept_demangle(si->symtab[i].name, buf, len);
rjwalshe4e779d2004-04-16 23:02:29 +0000579 colon = buf + VG_(strlen)(buf) - 1;
580 while(*colon != ':') colon--;
581 VG_(strncpy_safely)(si->symtab[i].name, colon+1, len);
sewardjb5f6f512005-03-10 23:59:00 +0000582 VG_(arena_free)(VG_AR_SYMTAB, buf);
rjwalshe4e779d2004-04-16 23:02:29 +0000583 }
584 }
585
sewardjde4a1d02002-03-22 01:27:54 +0000586 cleanup_more:
587
588 /* If two symbols have identical address ranges, favour the
fitzhardinge98abfc72003-12-16 02:05:15 +0000589 one with the longer name (unless the extra length is junk)
sewardjde4a1d02002-03-22 01:27:54 +0000590 */
591 do {
592 n_merged = 0;
593 j = si->symtab_used;
594 si->symtab_used = 0;
595 for (i = 0; i < j; i++) {
596 if (i < j-1
597 && si->symtab[i].addr == si->symtab[i+1].addr
598 && si->symtab[i].size == si->symtab[i+1].size) {
599 n_merged++;
600 /* merge the two into one */
fitzhardinge1c76dc42003-12-15 09:00:21 +0000601 si->symtab[si->symtab_used++] = *prefersym(&si->symtab[i], &si->symtab[i+1]);
sewardjde4a1d02002-03-22 01:27:54 +0000602 i++;
603 } else {
604 si->symtab[si->symtab_used++] = si->symtab[i];
605 }
606 }
nethercote80f76782003-11-13 22:34:00 +0000607 TRACE_SYMTAB( "%d merged\n", n_merged);
sewardjde4a1d02002-03-22 01:27:54 +0000608 }
609 while (n_merged > 0);
610
611 /* Detect and "fix" overlapping address ranges. */
612 n_truncated = 0;
613
sewardj05bcdcb2003-05-18 10:05:38 +0000614 for (i = 0; i < ((Int)si->symtab_used) -1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000615
616 vg_assert(si->symtab[i].addr <= si->symtab[i+1].addr);
617
618 /* Check for common (no overlap) case. */
619 if (si->symtab[i].addr + si->symtab[i].size
620 <= si->symtab[i+1].addr)
621 continue;
622
623 /* There's an overlap. Truncate one or the other. */
624 if (VG_(clo_trace_symtab)) {
625 VG_(printf)("overlapping address ranges in symbol table\n\t");
626 printSym(si,i);
627 VG_(printf)("\t");
628 printSym(si,i+1);
629 VG_(printf)("\n");
630 }
631
632 /* Truncate one or the other. */
633 s1 = si->symtab[i].addr;
634 s2 = si->symtab[i+1].addr;
635 e1 = s1 + si->symtab[i].size - 1;
636 e2 = s2 + si->symtab[i+1].size - 1;
637 if (s1 < s2) {
638 e1 = s2-1;
639 } else {
640 vg_assert(s1 == s2);
641 if (e1 > e2) {
642 s1 = e2+1; SWAP(Addr,s1,s2); SWAP(Addr,e1,e2);
643 } else
644 if (e1 < e2) {
645 s2 = e1+1;
646 } else {
647 /* e1 == e2. Identical addr ranges. We'll eventually wind
648 up back at cleanup_more, which will take care of it. */
649 }
650 }
651 si->symtab[i].addr = s1;
652 si->symtab[i+1].addr = s2;
653 si->symtab[i].size = e1 - s1 + 1;
654 si->symtab[i+1].size = e2 - s2 + 1;
655 vg_assert(s1 <= s2);
656 vg_assert(si->symtab[i].size > 0);
657 vg_assert(si->symtab[i+1].size > 0);
658 /* It may be that the i+1 entry now needs to be moved further
659 along to maintain the address order requirement. */
660 j = i+1;
sewardj05bcdcb2003-05-18 10:05:38 +0000661 while (j < ((Int)si->symtab_used)-1
sewardjde4a1d02002-03-22 01:27:54 +0000662 && si->symtab[j].addr > si->symtab[j+1].addr) {
663 SWAP(RiSym,si->symtab[j],si->symtab[j+1]);
664 j++;
665 }
666 n_truncated++;
667 }
668
669 if (n_truncated > 0) goto cleanup_more;
670
671 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000672 for (i = 0; i < ((Int)si->symtab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000673 /* No zero-sized symbols. */
674 vg_assert(si->symtab[i].size > 0);
675 /* In order. */
676 vg_assert(si->symtab[i].addr < si->symtab[i+1].addr);
677 /* No overlaps. */
678 vg_assert(si->symtab[i].addr + si->symtab[i].size - 1
679 < si->symtab[i+1].addr);
680 }
681# undef SWAP
682}
683
jsgfcb1d1c02003-10-14 21:55:10 +0000684/* Sort the scope range table by starting address. Mash the table
685 around so as to establish the property that addresses are in order
686 and the ranges do not overlap. This facilitates using binary
687 search to map addresses to scopes when we come to query the
688 table.
689*/
690static Int compare_ScopeRange(void *va, void *vb) {
691 ScopeRange *a = (ScopeRange *)va;
692 ScopeRange *b = (ScopeRange *)vb;
693
nethercote05fdfac2004-08-01 20:24:46 +0000694 if (a->addr < b->addr) return -1;
695 if (a->addr > b->addr) return 1;
696 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000697}
698
699static
700void canonicaliseScopetab ( SegInfo* si )
701{
702 Int i,j;
703
704 if (si->scopetab_used == 0)
705 return;
706
707 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000708 VG_(ssort)(si->scopetab, si->scopetab_used, sizeof(*si->scopetab),
709 compare_ScopeRange);
jsgfcb1d1c02003-10-14 21:55:10 +0000710
711 /* If two adjacent entries overlap, truncate the first. */
712 for (i = 0; i < si->scopetab_used-1; i++) {
713 if (si->scopetab[i].addr + si->scopetab[i].size > si->scopetab[i+1].addr) {
714 Int new_size = si->scopetab[i+1].addr - si->scopetab[i].addr;
715
716 if (new_size < 0)
717 si->scopetab[i].size = 0;
718 else
719 si->scopetab[i].size = new_size;
720 }
721 }
722
723 /* Zap any zero-sized entries resulting from the truncation
724 process. */
725 j = 0;
726 for (i = 0; i < si->scopetab_used; i++) {
727 if (si->scopetab[i].size > 0) {
728 si->scopetab[j] = si->scopetab[i];
729 j++;
730 }
731 }
732 si->scopetab_used = j;
733
734 /* Ensure relevant postconditions hold. */
735 for (i = 0; i < si->scopetab_used-1; i++) {
736 /*
737 VG_(printf)("%d (%d) %d 0x%x\n",
738 i, si->scopetab[i+1].confident,
739 si->scopetab[i+1].size, si->scopetab[i+1].addr );
740 */
741 /* No zero-sized symbols. */
742 vg_assert(si->scopetab[i].size > 0);
743 /* In order. */
744 if (si->scopetab[i].addr >= si->scopetab[i+1].addr)
745 VG_(printf)("si->scopetab[%d] = %p,size=%d [%d] = %p,size=%d\n",
746 i, si->scopetab[i].addr, si->scopetab[i].size,
747 i+1, si->scopetab[i+1].addr, si->scopetab[i+1].size);
748 vg_assert(si->scopetab[i].addr < si->scopetab[i+1].addr);
749 /* No overlaps. */
750 vg_assert(si->scopetab[i].addr + si->scopetab[i].size - 1
751 < si->scopetab[i+1].addr);
752 }
753}
sewardjde4a1d02002-03-22 01:27:54 +0000754
755
756/* Sort the location table by starting address. Mash the table around
757 so as to establish the property that addresses are in order and the
758 ranges do not overlap. This facilitates using binary search to map
sewardjb51f2e62002-06-01 23:11:19 +0000759 addresses to locations when we come to query the table.
760*/
jsgfcb1d1c02003-10-14 21:55:10 +0000761static Int compare_RiLoc(void *va, void *vb) {
762 RiLoc *a = (RiLoc *)va;
763 RiLoc *b = (RiLoc *)vb;
764
nethercote05fdfac2004-08-01 20:24:46 +0000765 if (a->addr < b->addr) return -1;
766 if (a->addr > b->addr) return 1;
767 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000768}
769
sewardjde4a1d02002-03-22 01:27:54 +0000770static
771void canonicaliseLoctab ( SegInfo* si )
772{
jsgfcb1d1c02003-10-14 21:55:10 +0000773 Int i, j;
sewardjde4a1d02002-03-22 01:27:54 +0000774
775# define SWAP(ty,aa,bb) \
776 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
777
jsgfcb1d1c02003-10-14 21:55:10 +0000778 if (si->loctab_used == 0)
779 return;
780
sewardjde4a1d02002-03-22 01:27:54 +0000781 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000782 VG_(ssort)(si->loctab, si->loctab_used, sizeof(*si->loctab), compare_RiLoc);
sewardjde4a1d02002-03-22 01:27:54 +0000783
784 /* If two adjacent entries overlap, truncate the first. */
sewardj05bcdcb2003-05-18 10:05:38 +0000785 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000786 vg_assert(si->loctab[i].size < 10000);
787 if (si->loctab[i].addr + si->loctab[i].size > si->loctab[i+1].addr) {
788 /* Do this in signed int32 because the actual .size fields
njna1685902005-03-16 04:09:21 +0000789 are only 12 bits. */
sewardjde4a1d02002-03-22 01:27:54 +0000790 Int new_size = si->loctab[i+1].addr - si->loctab[i].addr;
791 if (new_size < 0) {
792 si->loctab[i].size = 0;
793 } else
njna1685902005-03-16 04:09:21 +0000794 if (new_size > MAX_LOC_SIZE) {
795 si->loctab[i].size = MAX_LOC_SIZE;
sewardjde4a1d02002-03-22 01:27:54 +0000796 } else {
797 si->loctab[i].size = (UShort)new_size;
798 }
799 }
800 }
801
802 /* Zap any zero-sized entries resulting from the truncation
803 process. */
804 j = 0;
sewardj05bcdcb2003-05-18 10:05:38 +0000805 for (i = 0; i < (Int)si->loctab_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000806 if (si->loctab[i].size > 0) {
807 si->loctab[j] = si->loctab[i];
808 j++;
809 }
810 }
811 si->loctab_used = j;
812
813 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000814 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000815 /*
816 VG_(printf)("%d (%d) %d 0x%x\n",
817 i, si->loctab[i+1].confident,
818 si->loctab[i+1].size, si->loctab[i+1].addr );
819 */
820 /* No zero-sized symbols. */
821 vg_assert(si->loctab[i].size > 0);
822 /* In order. */
823 vg_assert(si->loctab[i].addr < si->loctab[i+1].addr);
824 /* No overlaps. */
825 vg_assert(si->loctab[i].addr + si->loctab[i].size - 1
826 < si->loctab[i+1].addr);
827 }
828# undef SWAP
829}
830
831
sewardj3a1c7db2005-05-02 09:43:44 +0000832/* Sort the call-frame-info table by starting address. Mash the table
833 around so as to establish the property that addresses are in order
834 and the ranges do not overlap. This facilitates using binary
835 search to map addresses to locations when we come to query the
836 table.
837
838 Also, set cfisi_minaddr and cfisi_maxaddr to be the min and max of
839 any of the address ranges contained in cfisi[0 .. cfisi_used-1], so
840 as to facilitate rapidly skipping this SegInfo when looking for an
841 address which falls outside that range.
842*/
843static Int compare_CfiSI(void *va, void *vb) {
844 CfiSI *a = (CfiSI*)va;
845 CfiSI *b = (CfiSI*)vb;
846
847 if (a->base < b->base) return -1;
848 if (a->base > b->base) return 1;
849 return 0;
850}
851
sewardjbf603752005-05-02 00:36:27 +0000852static
853void canonicaliseCfiSI ( SegInfo* si )
854{
855 Int i;
856 const Addr minAddr = 0;
857 const Addr maxAddr = ~minAddr;
858
859 /* Set cfisi_minaddr and cfisi_maxaddr to summarise the entire
860 address range contained in cfisi[0 .. cfisi_used-1]. */
861 si->cfisi_minaddr = maxAddr;
862 si->cfisi_maxaddr = minAddr;
863 for (i = 0; i < si->cfisi_used; i++) {
864 Addr here_min = si->cfisi[i].base;
865 Addr here_max = si->cfisi[i].base + si->cfisi[i].len - 1;
866 if (here_min < si->cfisi_minaddr)
867 si->cfisi_minaddr = here_min;
868 if (here_max > si->cfisi_maxaddr)
869 si->cfisi_maxaddr = here_max;
870 }
sewardj520e3492005-05-02 10:39:16 +0000871
872 if (VG_(clo_trace_cfi))
873 VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n",
874 si->cfisi_used,
875 si->cfisi_minaddr, si->cfisi_maxaddr);
sewardj3a1c7db2005-05-02 09:43:44 +0000876
877 /* Sort the cfisi array by base address. */
878 VG_(ssort)(si->cfisi, si->cfisi_used, sizeof(*si->cfisi), compare_CfiSI);
879
880 /* Ensure relevant postconditions hold. */
881 for (i = 0; i < si->cfisi_used; i++) {
882 /* No zero-length ranges. */
883 vg_assert(si->cfisi[i].len > 0);
884 /* Makes sense w.r.t. summary address range */
885 vg_assert(si->cfisi[i].base >= si->cfisi_minaddr);
886 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
887 <= si->cfisi_maxaddr);
888
889 if (i < si->cfisi_used - 1) {
sewardjc4f204f2005-05-03 15:23:00 +0000890 /*
891 if (!(si->cfisi[i].base < si->cfisi[i+1].base)) {
892 VG_(printf)("\nOOO cfisis:\n");
893 VG_(ppCfiSI)(&si->cfisi[i]);
894 VG_(ppCfiSI)(&si->cfisi[i+1]);
895 }
896 */
sewardj3a1c7db2005-05-02 09:43:44 +0000897 /* In order. */
898 vg_assert(si->cfisi[i].base < si->cfisi[i+1].base);
899 /* No overlaps. */
900 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
901 < si->cfisi[i+1].base);
902 }
903 }
904
sewardjbf603752005-05-02 00:36:27 +0000905}
906
907
sewardjde4a1d02002-03-22 01:27:54 +0000908/*------------------------------------------------------------*/
sewardjb51f2e62002-06-01 23:11:19 +0000909/*--- Read info from a .so/exe file. ---*/
910/*------------------------------------------------------------*/
911
fitzhardinge98abfc72003-12-16 02:05:15 +0000912Bool VG_(is_object_file)(const void *buf)
913{
914 {
sewardj7a21c612005-02-18 09:38:08 +0000915 ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf;
fitzhardinge98abfc72003-12-16 02:05:15 +0000916 Int ok = 1;
917
918 ok &= (ehdr->e_ident[EI_MAG0] == 0x7F
919 && ehdr->e_ident[EI_MAG1] == 'E'
920 && ehdr->e_ident[EI_MAG2] == 'L'
921 && ehdr->e_ident[EI_MAG3] == 'F');
njn35172bc2005-03-26 00:04:03 +0000922 ok &= (ehdr->e_ident[EI_CLASS] == VGA_ELF_CLASS
923 && ehdr->e_ident[EI_DATA] == VGA_ELF_ENDIANNESS
fitzhardinge98abfc72003-12-16 02:05:15 +0000924 && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
925 ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN);
njn35172bc2005-03-26 00:04:03 +0000926 ok &= (ehdr->e_machine == VGA_ELF_MACHINE);
fitzhardinge98abfc72003-12-16 02:05:15 +0000927 ok &= (ehdr->e_version == EV_CURRENT);
928 ok &= (ehdr->e_shstrndx != SHN_UNDEF);
929 ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0);
930 ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0);
931
932 if (ok)
933 return True;
934 }
935
936 /* other file formats here? */
937
938 return False;
939}
940
sewardj9ee81f52005-04-02 17:38:59 +0000941/* Demangle an intercept symbol into library:func form
942 eg "_vgi_libcZdsoZd6__ZdlPv" --> "libc.so.6:_ZdlPv"
943 Uses the Z-encoding scheme described in vg_replace_malloc.c.
944 Returns True if demangle OK, False otherwise.
rjwalshe4e779d2004-04-16 23:02:29 +0000945 */
946
947static Bool
nethercoteb1e1ad42004-08-03 23:44:12 +0000948intercept_demangle(const Char* symbol, Char* result, Int nbytes)
rjwalshe4e779d2004-04-16 23:02:29 +0000949{
sewardj9ee81f52005-04-02 17:38:59 +0000950# define EMIT(ch) \
951 do { \
952 if (j >= nbytes) \
953 result[j-1] = 0; \
954 else \
955 result[j++] = ch; \
956 } while (0)
rjwalshe4e779d2004-04-16 23:02:29 +0000957
sewardj9ee81f52005-04-02 17:38:59 +0000958 Bool error = False;
959 Int i, j = 0;
960 Int len = VG_(strlen)(symbol);
961 if (0) VG_(printf)("idm: %s\n", symbol);
962
963 i = VG_INTERCEPT_PREFIX_LEN;
964
965 /* Chew though the Z-encoded soname part. */
966 while (True) {
967
968 if (i >= len)
969 break;
970
971 if (symbol[i] == '_')
972 /* We found the underscore following the Z-encoded soname.
973 Just copy the rest literally. */
974 break;
975
976 if (symbol[i] != 'Z') {
977 EMIT(symbol[i]);
rjwalshe4e779d2004-04-16 23:02:29 +0000978 i++;
sewardj9ee81f52005-04-02 17:38:59 +0000979 continue;
rjwalshe4e779d2004-04-16 23:02:29 +0000980 }
sewardj9ee81f52005-04-02 17:38:59 +0000981
982 /* We've got a Z-escape. Act accordingly. */
983 i++;
984 if (i >= len) {
985 /* Hmm, Z right at the end. Something's wrong. */
986 error = True;
987 EMIT('Z');
988 break;
rjwalshe4e779d2004-04-16 23:02:29 +0000989 }
sewardj9ee81f52005-04-02 17:38:59 +0000990 switch (symbol[i]) {
991 case 'a': EMIT('*'); break;
992 case 'p': EMIT('+'); break;
993 case 'c': EMIT(':'); break;
994 case 'd': EMIT('.'); break;
995 case 'u': EMIT('_'); break;
996 case 's': EMIT(' '); break;
997 case 'Z': EMIT('Z'); break;
998 default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
999 }
1000 i++;
rjwalshe4e779d2004-04-16 23:02:29 +00001001 }
sewardj9ee81f52005-04-02 17:38:59 +00001002
1003 if (error || i >= len || symbol[i] != '_') {
1004 /* Something's wrong. Give up. */
1005 VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
1006 EMIT(0);
1007 return False;
1008 }
1009
1010 /* Copy the rest of the string verbatim. */
1011 i++;
1012 EMIT(':');
1013 while (True) {
1014 if (i >= len)
1015 break;
1016 EMIT(symbol[i]);
1017 i++;
1018 }
1019
1020 EMIT(0);
1021 if (0) VG_(printf)("%s\n", result);
rjwalshe4e779d2004-04-16 23:02:29 +00001022 return True;
sewardj9ee81f52005-04-02 17:38:59 +00001023
1024# undef EMIT
rjwalshe4e779d2004-04-16 23:02:29 +00001025}
1026
1027static
sewardj7a21c612005-02-18 09:38:08 +00001028void handle_intercept( SegInfo* si, Char* symbol, ElfXX_Sym* sym)
rjwalshe4e779d2004-04-16 23:02:29 +00001029{
sewardj9ee81f52005-04-02 17:38:59 +00001030 Bool ok;
1031 Int len = VG_(strlen)(symbol) + 1 - VG_INTERCEPT_PREFIX_LEN;
1032 Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
rjwalshe4e779d2004-04-16 23:02:29 +00001033 Char *func;
1034
sewardj9ee81f52005-04-02 17:38:59 +00001035 /* Put "soname:" at the start of lib. */
1036 lib[0] = 's';
1037 lib[1] = 'o';
1038 lib[2] = 'n';
1039 lib[3] = 'a';
1040 lib[4] = 'm';
1041 lib[5] = 'e';
1042 lib[6] = ':';
1043 lib[7] = 0;
rjwalshe4e779d2004-04-16 23:02:29 +00001044
sewardj9ee81f52005-04-02 17:38:59 +00001045 ok = intercept_demangle(symbol, lib+7, len);
1046 if (ok) {
1047 func = lib + VG_(strlen)(lib)-1;
rjwalshe4e779d2004-04-16 23:02:29 +00001048
sewardj9ee81f52005-04-02 17:38:59 +00001049 while(*func != ':') func--;
1050 *func = '\0';
1051
1052 if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func+1);
1053 VG_(add_redirect_sym_to_addr)(lib, func+1, si->offset + sym->st_value);
1054 }
1055
sewardjb5f6f512005-03-10 23:59:00 +00001056 VG_(arena_free)(VG_AR_SYMTAB, lib);
rjwalshe4e779d2004-04-16 23:02:29 +00001057}
1058
sewardjb5f6f512005-03-10 23:59:00 +00001059Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir)
rjwalshe4e779d2004-04-16 23:02:29 +00001060{
sewardjb5f6f512005-03-10 23:59:00 +00001061 SegInfo *si;
1062
1063 for(si = segInfo; si != NULL; si = si->next)
1064 if (VG_(resolve_redir)(redir, si))
1065 return True;
1066
1067 return False;
rjwalshe4e779d2004-04-16 23:02:29 +00001068}
1069
sewardjb5f6f512005-03-10 23:59:00 +00001070//static
1071//void handle_wrapper( SegInfo* si, Char* symbol, ElfXX_Sym* sym)
1072//{
1073// if (VG_(strcmp)(symbol, STR(VG_WRAPPER(freeres))) == 0)
1074// VGA_(intercept_libc_freeres_wrapper)((Addr)(si->offset + sym->st_value));
1075// else if (VG_(strcmp)(symbol, STR(VG_WRAPPER(pthread_startfunc_wrapper))) == 0)
1076// VG_(pthread_startfunc_wrapper)((Addr)(si->offset + sym->st_value));
1077//}
1078
nethercote80f76782003-11-13 22:34:00 +00001079/* Read a symbol table (normal or dynamic) */
1080static
rjwalshe4e779d2004-04-16 23:02:29 +00001081void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts,
sewardj7a21c612005-02-18 09:38:08 +00001082 ElfXX_Sym* o_symtab, UInt o_symtab_sz,
nethercote80f76782003-11-13 22:34:00 +00001083 UChar* o_strtab, UInt o_strtab_sz )
1084{
1085 Int i;
1086 Addr sym_addr;
1087 RiSym risym;
mueller82df83e2003-11-19 22:05:35 +00001088 Char* t0;
1089 Char* name;
1090
nethercote80f76782003-11-13 22:34:00 +00001091 if (o_strtab == NULL || o_symtab == NULL) {
jseward0edbfb52003-12-12 06:22:06 +00001092 Char buf[80];
1093 vg_assert(VG_(strlen)(tab_name) < 40);
1094 VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
1095 VG_(symerr)(buf);
nethercote80f76782003-11-13 22:34:00 +00001096 return;
1097 }
1098
1099 TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name,
sewardj7a21c612005-02-18 09:38:08 +00001100 o_symtab_sz/sizeof(ElfXX_Sym) );
nethercote80f76782003-11-13 22:34:00 +00001101
1102 /* Perhaps should start at i = 1; ELF docs suggest that entry
1103 0 always denotes `unknown symbol'. */
sewardj7a21c612005-02-18 09:38:08 +00001104 for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) {
1105 ElfXX_Sym* sym = & o_symtab[i];
nethercote80f76782003-11-13 22:34:00 +00001106# if 1
tomf26d0682005-04-02 14:57:43 +00001107 sym_addr = si->offset + sym->st_value;
nethercote80f76782003-11-13 22:34:00 +00001108
1109 if (VG_(clo_trace_symtab)) {
1110 VG_(printf)("raw symbol [%d]: ", i);
sewardj7a21c612005-02-18 09:38:08 +00001111 switch (ELFXX_ST_BIND(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001112 case STB_LOCAL: VG_(printf)("LOC "); break;
1113 case STB_GLOBAL: VG_(printf)("GLO "); break;
1114 case STB_WEAK: VG_(printf)("WEA "); break;
1115 case STB_LOPROC: VG_(printf)("lop "); break;
1116 case STB_HIPROC: VG_(printf)("hip "); break;
1117 default: VG_(printf)("??? "); break;
1118 }
sewardj7a21c612005-02-18 09:38:08 +00001119 switch (ELFXX_ST_TYPE(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001120 case STT_NOTYPE: VG_(printf)("NOT "); break;
1121 case STT_OBJECT: VG_(printf)("OBJ "); break;
1122 case STT_FUNC: VG_(printf)("FUN "); break;
1123 case STT_SECTION: VG_(printf)("SEC "); break;
1124 case STT_FILE: VG_(printf)("FIL "); break;
1125 case STT_LOPROC: VG_(printf)("lop "); break;
1126 case STT_HIPROC: VG_(printf)("hip "); break;
1127 default: VG_(printf)("??? "); break;
1128 }
1129 VG_(printf)(
1130 ": value %p, size %d, name %s\n",
1131 sym_addr, sym->st_size,
1132 ( sym->st_name
1133 ? ((Char*)o_strtab+sym->st_name)
1134 : (Char*)"NONAME" ) );
1135 }
1136# endif
1137
rjwalshe4e779d2004-04-16 23:02:29 +00001138 /*
1139 * Is this symbol a magic valgrind-intercept symbol? If so,
1140 * hand this off to the interceptinator.
1141 */
1142 if (do_intercepts) {
1143 if (VG_(strncmp)((Char*)o_strtab+sym->st_name,
1144 VG_INTERCEPT_PREFIX,
1145 VG_INTERCEPT_PREFIX_LEN) == 0) {
1146 handle_intercept(si, (Char*)o_strtab+sym->st_name, sym);
sewardjb5f6f512005-03-10 23:59:00 +00001147 }
1148 //else if (VG_(strncmp)((Char*)o_strtab+sym->st_name,
1149 // VG_WRAPPER_PREFIX,
1150 // VG_WRAPPER_PREFIX_LEN) == 0) {
1151 // handle_wrapper(si, (Char*)o_strtab+sym->st_name, sym);
1152 //}
rjwalshe4e779d2004-04-16 23:02:29 +00001153 }
1154
nethercote80f76782003-11-13 22:34:00 +00001155 /* Figure out if we're interested in the symbol.
1156 Firstly, is it of the right flavour? */
sewardj7a21c612005-02-18 09:38:08 +00001157 if ( ! ( (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL ||
1158 ELFXX_ST_BIND(sym->st_info) == STB_LOCAL ||
1159 ELFXX_ST_BIND(sym->st_info) == STB_WEAK)
nethercote80f76782003-11-13 22:34:00 +00001160 &&
sewardj7a21c612005-02-18 09:38:08 +00001161 (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC ||
nethercote80f76782003-11-13 22:34:00 +00001162 (VG_(needs).data_syms
sewardj7a21c612005-02-18 09:38:08 +00001163 && ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT))
nethercote80f76782003-11-13 22:34:00 +00001164 )
1165 )
1166 continue;
1167
1168 /* Secondly, if it's apparently in a GOT or PLT, it's really
1169 a reference to a symbol defined elsewhere, so ignore it. */
1170 if (si->got_start != 0
1171 && sym_addr >= si->got_start
1172 && sym_addr < si->got_start + si->got_size) {
1173 TRACE_SYMTAB("in GOT: %s\n", o_strtab+sym->st_name);
1174 continue;
1175 }
1176 if (si->plt_start != 0
1177 && sym_addr >= si->plt_start
1178 && sym_addr < si->plt_start + si->plt_size) {
1179 TRACE_SYMTAB("in PLT: %s\n", o_strtab+sym->st_name);
1180 continue;
1181 }
1182
1183 /* Don't bother if nameless, or zero-sized. */
sewardj7a21c612005-02-18 09:38:08 +00001184 if (sym->st_name == (ElfXX_Word)NULL
nethercote80f76782003-11-13 22:34:00 +00001185 || /* VG_(strlen)(o_strtab+sym->st_name) == 0 */
1186 /* equivalent but cheaper ... */
1187 * ((UChar*)(o_strtab+sym->st_name)) == 0
1188 || sym->st_size == 0) {
1189 TRACE_SYMTAB("size=0: %s\n", o_strtab+sym->st_name);
1190 continue;
1191 }
1192
1193# if 0
1194 /* Avoid _dl_ junk. (Why?) */
1195 /* 01-02-24: disabled until I find out if it really helps. */
1196 if (VG_(strncmp)("_dl_", o_strtab+sym->st_name, 4) == 0
1197 || VG_(strncmp)("_r_debug",
1198 o_strtab+sym->st_name, 8) == 0) {
1199 TRACE_SYMTAB("_dl_ junk: %s\n", o_strtab+sym->st_name);
1200 continue;
1201 }
1202# endif
1203
1204 /* This seems to significantly reduce the number of junk
1205 symbols, and particularly reduces the number of
1206 overlapping address ranges. Don't ask me why ... */
1207 if ((Int)sym->st_value == 0) {
1208 TRACE_SYMTAB( "valu=0: %s\n", o_strtab+sym->st_name);
1209 continue;
1210 }
1211
1212 /* If no part of the symbol falls within the mapped range,
1213 ignore it. */
1214 if (sym_addr+sym->st_size <= si->start
1215 || sym_addr >= si->start+si->size) {
1216 TRACE_SYMTAB( "outside mapped range" );
1217 continue;
1218 }
1219
1220 /* If we reach here, it's an interesting symbol; record it. */
mueller82df83e2003-11-19 22:05:35 +00001221 t0 = sym->st_name
nethercote80f76782003-11-13 22:34:00 +00001222 ? (Char*)(o_strtab+sym->st_name)
1223 : (Char*)"NONAME";
mueller82df83e2003-11-19 22:05:35 +00001224 name = VG_(addStr) ( si, t0, -1 );
nethercote80f76782003-11-13 22:34:00 +00001225 vg_assert(name != NULL
1226 /* && 0==VG_(strcmp)(t0,&vg_strtab[nmoff]) */ );
nethercote80f76782003-11-13 22:34:00 +00001227 /* VG_(printf)("%p + %d: %p %s\n", si->start,
1228 (Int)sym->st_value, sym_addr, t0 ); */
1229 risym.addr = sym_addr;
1230 risym.size = sym->st_size;
1231 risym.name = name;
1232 addSym ( si, &risym );
1233 }
1234}
1235
thughesc035bd92004-06-13 09:59:02 +00001236/*
1237 * This routine for calculating the CRC for a separate debug file
1238 * is GPLed code borrowed from binutils.
1239 */
1240static UInt
1241calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
1242{
1243 static const UInt crc32_table[256] =
1244 {
1245 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
1246 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
1247 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
1248 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1249 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
1250 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1251 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
1252 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1253 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1254 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
1255 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
1256 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1257 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
1258 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
1259 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
1260 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1261 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
1262 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1263 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
1264 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1265 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
1266 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
1267 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
1268 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1269 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
1270 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
1271 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1272 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1273 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1274 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1275 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1276 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1277 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1278 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1279 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1280 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1281 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1282 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1283 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1284 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1285 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1286 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1287 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1288 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1289 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1290 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1291 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1292 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1293 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1294 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1295 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1296 0x2d02ef8d
1297 };
1298 const UChar *end;
1299
1300 crc = ~crc & 0xffffffff;
1301 for (end = buf + len; buf < end; ++ buf)
1302 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
1303 return ~crc & 0xffffffff;;
1304}
1305
1306/*
1307 * Try and open a separate debug file, ignoring any where the CRC does
1308 * not match the value from the main object file.
1309 */
1310static
1311Addr open_debug_file( Char* name, UInt crc, UInt* size )
1312{
1313 Int fd;
1314 struct vki_stat stat_buf;
1315 Addr addr;
sewardjb5f6f512005-03-10 23:59:00 +00001316 UInt calccrc;
thughesc035bd92004-06-13 09:59:02 +00001317
1318 if ((fd = VG_(open)(name, VKI_O_RDONLY, 0)) < 0)
1319 return 0;
1320
1321 if (VG_(fstat)(fd, &stat_buf) != 0) {
1322 VG_(close)(fd);
1323 return 0;
1324 }
1325
sewardjb5f6f512005-03-10 23:59:00 +00001326 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001327 VG_(message)(Vg_DebugMsg, "Reading debug info from %s...", name);
sewardjb5f6f512005-03-10 23:59:00 +00001328
thughesc035bd92004-06-13 09:59:02 +00001329 *size = stat_buf.st_size;
1330
1331 if ((addr = (Addr)VG_(mmap)(NULL, *size, VKI_PROT_READ,
nethercoteb4250ae2004-07-10 16:50:09 +00001332 VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1333 0, fd, 0)) == (Addr)-1)
1334 {
thughesc035bd92004-06-13 09:59:02 +00001335 VG_(close)(fd);
1336 return 0;
1337 }
1338
1339 VG_(close)(fd);
1340
sewardjb5f6f512005-03-10 23:59:00 +00001341 calccrc = calc_gnu_debuglink_crc32(0, (UChar*)addr, *size);
1342 if (calccrc != crc) {
nethercotee567e702004-07-10 17:49:17 +00001343 int res = VG_(munmap)((void*)addr, *size);
1344 vg_assert(0 == res);
sewardjb5f6f512005-03-10 23:59:00 +00001345 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001346 VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc);
thughesc035bd92004-06-13 09:59:02 +00001347 return 0;
1348 }
1349
1350 return addr;
1351}
1352
1353/*
nethercoteb1e1ad42004-08-03 23:44:12 +00001354 * Try to find a separate debug file for a given object file.
thughesc035bd92004-06-13 09:59:02 +00001355 */
1356static
1357Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size )
1358{
sewardjb5f6f512005-03-10 23:59:00 +00001359 Char *objdir = VG_(arena_strdup)(VG_AR_SYMTAB, objpath);
thughesc035bd92004-06-13 09:59:02 +00001360 Char *objdirptr;
1361 Char *debugpath;
1362 Addr addr = 0;
1363
1364 if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
1365 *objdirptr = '\0';
1366
sewardjb5f6f512005-03-10 23:59:00 +00001367 debugpath = VG_(arena_malloc)(VG_AR_SYMTAB, VG_(strlen)(objdir) + VG_(strlen)(debugname) + 16);
thughesc035bd92004-06-13 09:59:02 +00001368
1369 VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
1370
1371 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1372 VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
1373 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1374 VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
1375 addr = open_debug_file(debugpath, crc, size);
1376 }
1377 }
1378
sewardjb5f6f512005-03-10 23:59:00 +00001379 VG_(arena_free)(VG_AR_SYMTAB, debugpath);
1380 VG_(arena_free)(VG_AR_SYMTAB, objdir);
thughesc035bd92004-06-13 09:59:02 +00001381
1382 return addr;
1383}
nethercote80f76782003-11-13 22:34:00 +00001384
sewardjde4a1d02002-03-22 01:27:54 +00001385/* Read the symbols from the object/exe specified by the SegInfo into
1386 the tables within the supplied SegInfo. */
1387static
njn695c16e2005-03-27 03:40:28 +00001388Bool read_lib_symbols ( SegInfo* si )
sewardjde4a1d02002-03-22 01:27:54 +00001389{
nethercote80f76782003-11-13 22:34:00 +00001390 Bool res;
sewardj7a21c612005-02-18 09:38:08 +00001391 ElfXX_Ehdr* ehdr; /* The ELF header */
1392 ElfXX_Shdr* shdr; /* The section table */
sewardjde4a1d02002-03-22 01:27:54 +00001393 UChar* sh_strtab; /* The section table's string table */
sewardjde4a1d02002-03-22 01:27:54 +00001394 Int fd;
1395 Int i;
1396 Bool ok;
1397 Addr oimage;
sewardj05bcdcb2003-05-18 10:05:38 +00001398 UInt n_oimage;
thughesc035bd92004-06-13 09:59:02 +00001399 Addr dimage = 0;
1400 UInt n_dimage = 0;
sewardjb3586202002-05-09 17:38:13 +00001401 struct vki_stat stat_buf;
sewardjde4a1d02002-03-22 01:27:54 +00001402
sewardjde4a1d02002-03-22 01:27:54 +00001403 oimage = (Addr)NULL;
1404 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001405 VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", si->filename, si->start );
sewardjde4a1d02002-03-22 01:27:54 +00001406
1407 /* mmap the object image aboard, so that we can read symbols and
1408 line number info out of it. It will be munmapped immediately
1409 thereafter; it is only aboard transiently. */
1410
sewardjb3586202002-05-09 17:38:13 +00001411 i = VG_(stat)(si->filename, &stat_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001412 if (i != 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001413 VG_(symerr)("Can't stat .so/.exe (to determine its size)?!");
sewardj8fe15a32002-10-20 19:29:21 +00001414 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001415 }
1416 n_oimage = stat_buf.st_size;
1417
njn25e49d8e72002-09-23 09:36:25 +00001418 fd = VG_(open)(si->filename, VKI_O_RDONLY, 0);
jsgff3c3f1a2003-10-14 22:13:28 +00001419 if (fd < 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001420 VG_(symerr)("Can't open .so/.exe to read symbols?!");
sewardj8fe15a32002-10-20 19:29:21 +00001421 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001422 }
1423
sewardjb3586202002-05-09 17:38:13 +00001424 oimage = (Addr)VG_(mmap)( NULL, n_oimage,
nethercoteb4250ae2004-07-10 16:50:09 +00001425 VKI_PROT_READ, VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1426 0, fd, 0 );
fitzhardinge98abfc72003-12-16 02:05:15 +00001427
nethercote80f76782003-11-13 22:34:00 +00001428 VG_(close)(fd);
1429
sewardjde4a1d02002-03-22 01:27:54 +00001430 if (oimage == ((Addr)(-1))) {
njn1fd5eb22005-03-13 05:43:23 +00001431 VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename );
1432 VG_(message)(Vg_UserMsg, " no symbols or debug info loaded" );
sewardj8fe15a32002-10-20 19:29:21 +00001433 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001434 }
1435
sewardjde4a1d02002-03-22 01:27:54 +00001436 /* Ok, the object image is safely in oimage[0 .. n_oimage-1].
1437 Now verify that it is a valid ELF .so or executable image.
1438 */
nethercote80f76782003-11-13 22:34:00 +00001439 res = False;
sewardj7a21c612005-02-18 09:38:08 +00001440 ok = (n_oimage >= sizeof(ElfXX_Ehdr));
1441 ehdr = (ElfXX_Ehdr*)oimage;
sewardjde4a1d02002-03-22 01:27:54 +00001442
fitzhardinge98abfc72003-12-16 02:05:15 +00001443 if (ok)
1444 ok &= VG_(is_object_file)(ehdr);
sewardjde4a1d02002-03-22 01:27:54 +00001445
1446 if (!ok) {
jsgfcb1d1c02003-10-14 21:55:10 +00001447 VG_(symerr)("Invalid ELF header, or missing stringtab/sectiontab.");
nethercote80f76782003-11-13 22:34:00 +00001448 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001449 }
1450
1451 /* Walk the LOAD headers in the phdr and update the SegInfo to
1452 include them all, so that this segment also contains data and
1453 bss memory. Also computes correct symbol offset value for this
1454 ELF file. */
sewardj7a21c612005-02-18 09:38:08 +00001455 if (ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001456 VG_(symerr)("ELF program header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001457 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001458 }
1459 {
1460 Bool offset_set = False;
sewardj7a21c612005-02-18 09:38:08 +00001461 ElfXX_Addr prev_addr = 0;
fitzhardinge98abfc72003-12-16 02:05:15 +00001462 Addr baseaddr = 0;
sewardj8fe15a32002-10-20 19:29:21 +00001463
1464 si->offset = 0;
1465
nethercote80f76782003-11-13 22:34:00 +00001466 for (i = 0; i < ehdr->e_phnum; i++) {
sewardj7a21c612005-02-18 09:38:08 +00001467 ElfXX_Phdr *o_phdr;
1468 ElfXX_Addr mapped, mapped_end;
sewardj8fe15a32002-10-20 19:29:21 +00001469
sewardj7a21c612005-02-18 09:38:08 +00001470 o_phdr = &((ElfXX_Phdr *)(oimage + ehdr->e_phoff))[i];
sewardj8fe15a32002-10-20 19:29:21 +00001471
fitzhardinge98abfc72003-12-16 02:05:15 +00001472 if (o_phdr->p_type == PT_DYNAMIC && si->soname == NULL) {
sewardj7a21c612005-02-18 09:38:08 +00001473 const ElfXX_Dyn *dyn = (const ElfXX_Dyn *)(oimage + o_phdr->p_offset);
fitzhardinge98abfc72003-12-16 02:05:15 +00001474 Int stroff = -1;
1475 Char *strtab = NULL;
1476 Int j;
1477
1478 for(j = 0; dyn[j].d_tag != DT_NULL; j++) {
1479 switch(dyn[j].d_tag) {
1480 case DT_SONAME:
1481 stroff = dyn[j].d_un.d_val;
1482 break;
1483
1484 case DT_STRTAB:
1485 strtab = (Char *)oimage + dyn[j].d_un.d_ptr - baseaddr;
1486 break;
1487 }
1488 }
1489
1490 if (stroff != -1 && strtab != 0) {
1491 TRACE_SYMTAB("soname=%s\n", strtab+stroff);
1492 si->soname = VG_(arena_strdup)(VG_AR_SYMTAB, strtab+stroff);
1493 }
1494 }
1495
sewardj8fe15a32002-10-20 19:29:21 +00001496 if (o_phdr->p_type != PT_LOAD)
1497 continue;
1498
1499 if (!offset_set) {
1500 offset_set = True;
1501 si->offset = si->start - o_phdr->p_vaddr;
fitzhardinge98abfc72003-12-16 02:05:15 +00001502 baseaddr = o_phdr->p_vaddr;
sewardj8fe15a32002-10-20 19:29:21 +00001503 }
1504
1505 if (o_phdr->p_vaddr < prev_addr) {
jsgfcb1d1c02003-10-14 21:55:10 +00001506 VG_(symerr)("ELF Phdrs are out of order!?");
nethercote80f76782003-11-13 22:34:00 +00001507 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001508 }
1509 prev_addr = o_phdr->p_vaddr;
1510
1511 mapped = o_phdr->p_vaddr + si->offset;
1512 mapped_end = mapped + o_phdr->p_memsz;
1513
1514 if (si->data_start == 0 &&
1515 (o_phdr->p_flags & (PF_R|PF_W|PF_X)) == (PF_R|PF_W)) {
1516 si->data_start = mapped;
1517 si->data_size = o_phdr->p_filesz;
1518 si->bss_start = mapped + o_phdr->p_filesz;
1519 if (o_phdr->p_memsz > o_phdr->p_filesz)
1520 si->bss_size = o_phdr->p_memsz - o_phdr->p_filesz;
1521 else
1522 si->bss_size = 0;
1523 }
1524
nethercote73b526f2004-10-31 18:48:21 +00001525 mapped = mapped & ~(VKI_PAGE_SIZE-1);
1526 mapped_end = (mapped_end + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE-1);
sewardj8fe15a32002-10-20 19:29:21 +00001527
sewardj1024cf72005-02-28 14:39:21 +00001528#if 0
1529 /* 20050228: disabled this until VG_(next_segment) can be
1530 reinstated in some clean incarnation of the low level
1531 memory manager. */
sewardj8fe15a32002-10-20 19:29:21 +00001532 if (VG_(needs).data_syms &&
1533 (mapped >= si->start && mapped <= (si->start+si->size)) &&
1534 (mapped_end > (si->start+si->size))) {
1535 UInt newsz = mapped_end - si->start;
1536 if (newsz > si->size) {
fitzhardinge98abfc72003-12-16 02:05:15 +00001537 Segment *seg;
1538
sewardj8fe15a32002-10-20 19:29:21 +00001539 if (0)
1540 VG_(printf)("extending mapping %p..%p %d -> ..%p %d\n",
1541 si->start, si->start+si->size, si->size,
1542 si->start+newsz, newsz);
fitzhardinge98abfc72003-12-16 02:05:15 +00001543
sewardjb5f6f512005-03-10 23:59:00 +00001544 for(seg = VG_(find_segment_containing)(si->start);
fitzhardinge98abfc72003-12-16 02:05:15 +00001545 seg != NULL && VG_(seg_overlaps)(seg, si->start, si->size);
1546 seg = VG_(next_segment)(seg)) {
1547 if (seg->symtab == si)
1548 continue;
1549
1550 if (seg->symtab != NULL)
nethercote8991d5a2004-11-03 17:07:46 +00001551 VG_(symtab_decref)(seg->symtab, seg->addr);
fitzhardinge98abfc72003-12-16 02:05:15 +00001552
1553 VG_(symtab_incref)(si);
1554 seg->symtab = si;
1555
1556 if (0)
1557 VG_(printf)("adding symtab %p (%p-%p) to segment %p (%p-%p)\n",
1558 si, si->start, si->start+newsz,
1559 seg, seg->addr, seg->addr+seg->len);
1560 }
1561
sewardj8fe15a32002-10-20 19:29:21 +00001562 si->size = newsz;
1563 }
1564 }
sewardj1024cf72005-02-28 14:39:21 +00001565#endif
1566
sewardj8fe15a32002-10-20 19:29:21 +00001567 }
sewardjde4a1d02002-03-22 01:27:54 +00001568 }
1569
nethercote80f76782003-11-13 22:34:00 +00001570 TRACE_SYMTAB("shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n",
sewardj7a21c612005-02-18 09:38:08 +00001571 ehdr->e_shoff, ehdr->e_shnum, sizeof(ElfXX_Shdr), n_oimage );
sewardjde4a1d02002-03-22 01:27:54 +00001572
sewardj7a21c612005-02-18 09:38:08 +00001573 if (ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001574 VG_(symerr)("ELF section header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001575 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001576 }
1577
sewardj7a21c612005-02-18 09:38:08 +00001578 shdr = (ElfXX_Shdr*)(oimage + ehdr->e_shoff);
sewardjde4a1d02002-03-22 01:27:54 +00001579 sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset);
1580
nethercote80f76782003-11-13 22:34:00 +00001581 /* Find interesting sections, read the symbol table(s), read any debug
1582 information */
sewardjde4a1d02002-03-22 01:27:54 +00001583 {
nethercote80f76782003-11-13 22:34:00 +00001584 /* Pointers to start of sections */
1585 UChar* o_strtab = NULL; /* .strtab */
sewardj7a21c612005-02-18 09:38:08 +00001586 ElfXX_Sym* o_symtab = NULL; /* .symtab */
nethercote80f76782003-11-13 22:34:00 +00001587 UChar* o_dynstr = NULL; /* .dynstr */
sewardj7a21c612005-02-18 09:38:08 +00001588 ElfXX_Sym* o_dynsym = NULL; /* .dynsym */
thughesc035bd92004-06-13 09:59:02 +00001589 Char* debuglink = NULL; /* .gnu_debuglink */
nethercote80f76782003-11-13 22:34:00 +00001590 UChar* stab = NULL; /* .stab (stabs) */
1591 UChar* stabstr = NULL; /* .stabstr (stabs) */
1592 UChar* debug_line = NULL; /* .debug_line (dwarf2) */
jseward8b3131a2003-12-13 23:16:26 +00001593 UChar* dwarf1d = NULL; /* .debug (dwarf1) */
1594 UChar* dwarf1l = NULL; /* .line (dwarf1) */
sewardj5c638c22005-04-30 07:55:58 +00001595 UChar* ehframe = NULL; /* .eh_frame (dwarf2) */
sewardjde4a1d02002-03-22 01:27:54 +00001596
nethercote80f76782003-11-13 22:34:00 +00001597 /* Section sizes, in bytes */
1598 UInt o_strtab_sz = 0;
1599 UInt o_symtab_sz = 0;
1600 UInt o_dynstr_sz = 0;
1601 UInt o_dynsym_sz = 0;
thughesc035bd92004-06-13 09:59:02 +00001602 UInt debuglink_sz = 0;
nethercote80f76782003-11-13 22:34:00 +00001603 UInt stab_sz = 0;
1604 UInt stabstr_sz = 0;
1605 UInt debug_line_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001606 UInt dwarf1d_sz = 0;
1607 UInt dwarf1l_sz = 0;
sewardj5c638c22005-04-30 07:55:58 +00001608 UInt ehframe_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001609
tom2fd38902005-05-01 15:14:01 +00001610 /* Section virtual addresses */
1611 Addr dummy_addr = 0;
1612 Addr ehframe_addr = 0;
1613
jseward8b3131a2003-12-13 23:16:26 +00001614 Bool has_debuginfo = False;
sewardjde4a1d02002-03-22 01:27:54 +00001615
nethercote80f76782003-11-13 22:34:00 +00001616 /* Find all interesting sections */
sewardjde4a1d02002-03-22 01:27:54 +00001617 for (i = 0; i < ehdr->e_shnum; i++) {
tom2fd38902005-05-01 15:14:01 +00001618# define FIND(sec_name, sec_data, sec_size, sec_addr, in_exec, type) \
nethercote80f76782003-11-13 22:34:00 +00001619 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1620 if (0 != sec_data) \
1621 VG_(core_panic)("repeated section!\n"); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001622 if (in_exec) \
nethercote80f76782003-11-13 22:34:00 +00001623 sec_data = (type)(si->offset + shdr[i].sh_addr); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001624 else \
nethercote80f76782003-11-13 22:34:00 +00001625 sec_data = (type)(oimage + shdr[i].sh_offset); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001626 sec_size = shdr[i].sh_size; \
tom2fd38902005-05-01 15:14:01 +00001627 sec_addr = si->offset + shdr[i].sh_addr; \
nethercote80f76782003-11-13 22:34:00 +00001628 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1629 sec_name, sec_data, sec_data + sec_size - 1); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001630 if ( shdr[i].sh_offset + sec_size > n_oimage ) { \
nethercote80f76782003-11-13 22:34:00 +00001631 VG_(symerr)(" section beyond image end?!"); \
1632 goto out; \
1633 } \
sewardjde4a1d02002-03-22 01:27:54 +00001634 }
1635
nethercote80f76782003-11-13 22:34:00 +00001636 /* Nb: must find where .got and .plt sections will be in the
1637 * executable image, not in the object image transiently loaded. */
tom2fd38902005-05-01 15:14:01 +00001638 FIND(".dynsym", o_dynsym, o_dynsym_sz, dummy_addr, 0, ElfXX_Sym*)
1639 else FIND(".dynstr", o_dynstr, o_dynstr_sz, dummy_addr, 0, UChar*)
1640 else FIND(".symtab", o_symtab, o_symtab_sz, dummy_addr, 0, ElfXX_Sym*)
1641 else FIND(".strtab", o_strtab, o_strtab_sz, dummy_addr, 0, UChar*)
sewardjde4a1d02002-03-22 01:27:54 +00001642
tom2fd38902005-05-01 15:14:01 +00001643 else FIND(".gnu_debuglink", debuglink, debuglink_sz, dummy_addr, 0, Char*)
thughesc035bd92004-06-13 09:59:02 +00001644
tom2fd38902005-05-01 15:14:01 +00001645 else FIND(".stab", stab, stab_sz, dummy_addr, 0, UChar*)
1646 else FIND(".stabstr", stabstr, stabstr_sz, dummy_addr, 0, UChar*)
1647 else FIND(".debug_line", debug_line, debug_line_sz, dummy_addr, 0, UChar*)
1648 else FIND(".debug", dwarf1d, dwarf1d_sz, dummy_addr, 0, UChar*)
1649 else FIND(".line", dwarf1l, dwarf1l_sz, dummy_addr, 0, UChar*)
1650 else FIND(".eh_frame", ehframe, ehframe_sz, ehframe_addr, 0, UChar*)
nethercote80f76782003-11-13 22:34:00 +00001651
tom2fd38902005-05-01 15:14:01 +00001652 else FIND(".got", si->got_start, si->got_size, dummy_addr, 1, Addr)
1653 else FIND(".plt", si->plt_start, si->plt_size, dummy_addr, 1, Addr)
nethercote80f76782003-11-13 22:34:00 +00001654
jseward8b3131a2003-12-13 23:16:26 +00001655# undef FIND
nethercote80f76782003-11-13 22:34:00 +00001656
1657 /* Check some sizes */
sewardj7a21c612005-02-18 09:38:08 +00001658 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1659 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
sewardjde4a1d02002-03-22 01:27:54 +00001660 }
1661
rjwalshe4e779d2004-04-16 23:02:29 +00001662 read_symtab(si, "symbol table", False,
nethercote80f76782003-11-13 22:34:00 +00001663 o_symtab, o_symtab_sz,
1664 o_strtab, o_strtab_sz);
sewardjde4a1d02002-03-22 01:27:54 +00001665
rjwalshe4e779d2004-04-16 23:02:29 +00001666 read_symtab(si, "dynamic symbol table", True,
nethercote80f76782003-11-13 22:34:00 +00001667 o_dynsym, o_dynsym_sz,
1668 o_dynstr, o_dynstr_sz);
sewardj9b81a422003-04-26 21:42:09 +00001669
thughesc035bd92004-06-13 09:59:02 +00001670 /* Did we find a debuglink section? */
1671 if (debuglink != NULL) {
sewardjb5f6f512005-03-10 23:59:00 +00001672 UInt crc_offset = ROUNDUP(VG_(strlen)(debuglink)+1, 4);
thughesc035bd92004-06-13 09:59:02 +00001673 UInt crc;
1674
1675 vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
1676
1677 /* Extract the CRC from the debuglink section */
1678 crc = *(UInt *)(debuglink + crc_offset);
1679
1680 /* See if we can find a matching debug file */
1681 if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) {
sewardj7a21c612005-02-18 09:38:08 +00001682 ehdr = (ElfXX_Ehdr*)dimage;
thughesc035bd92004-06-13 09:59:02 +00001683
sewardj7a21c612005-02-18 09:38:08 +00001684 if (n_dimage >= sizeof(ElfXX_Ehdr) && VG_(is_object_file)(ehdr))
thughesc035bd92004-06-13 09:59:02 +00001685 {
sewardj7a21c612005-02-18 09:38:08 +00001686 shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff);
thughesc035bd92004-06-13 09:59:02 +00001687 sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset);
1688
1689 /* Find all interesting sections */
1690 for (i = 0; i < ehdr->e_shnum; i++) {
1691# define FIND(sec_name, sec_data, sec_size, type) \
1692 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1693 if (0 != sec_data) \
1694 VG_(core_panic)("repeated section!\n"); \
1695 sec_data = (type)(dimage + shdr[i].sh_offset); \
1696 sec_size = shdr[i].sh_size; \
1697 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1698 sec_name, sec_data, sec_data + sec_size - 1); \
1699 if ( shdr[i].sh_offset + sec_size > n_dimage ) { \
1700 VG_(symerr)(" section beyond image end?!"); \
1701 goto out; \
1702 } \
1703 }
1704
1705 /* Nb: must find where .got and .plt sections will be in the
1706 * executable image, not in the object image transiently loaded. */
1707 FIND(".stab", stab, stab_sz, UChar*)
1708 else FIND(".stabstr", stabstr, stabstr_sz, UChar*)
1709 else FIND(".debug_line", debug_line, debug_line_sz, UChar*)
1710 else FIND(".debug", dwarf1d, dwarf1d_sz, UChar*)
1711 else FIND(".line", dwarf1l, dwarf1l_sz, UChar*)
1712
1713# undef FIND
1714
1715 /* Check some sizes */
sewardj7a21c612005-02-18 09:38:08 +00001716 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1717 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
thughesc035bd92004-06-13 09:59:02 +00001718 }
1719 }
1720 }
1721 }
1722
sewardj5c638c22005-04-30 07:55:58 +00001723 /* Read .eh_frame (call-frame-info) if any */
sewardj55022aa2005-05-03 16:05:00 +00001724 if (ehframe) {
tom2fd38902005-05-01 15:14:01 +00001725 VG_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_addr );
sewardj5c638c22005-04-30 07:55:58 +00001726 }
1727
nethercote80f76782003-11-13 22:34:00 +00001728 /* Read the stabs and/or dwarf2 debug information, if any. */
1729 if (stab != NULL && stabstr != NULL) {
jseward8b3131a2003-12-13 23:16:26 +00001730 has_debuginfo = True;
1731 VG_(read_debuginfo_stabs) ( si, stab, stab_sz,
1732 stabstr, stabstr_sz );
1733 }
tom6f917fd2005-03-30 15:05:46 +00001734 if (debug_line) {
jseward8b3131a2003-12-13 23:16:26 +00001735 has_debuginfo = True;
nethercote80f76782003-11-13 22:34:00 +00001736 VG_(read_debuginfo_dwarf2) ( si, debug_line, debug_line_sz );
jseward8b3131a2003-12-13 23:16:26 +00001737 }
1738 if (dwarf1d && dwarf1l) {
1739 has_debuginfo = True;
1740 VG_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz,
1741 dwarf1l, dwarf1l_sz );
1742 }
1743 if (!has_debuginfo) {
sewardj5c638c22005-04-30 07:55:58 +00001744 VG_(symerr)(" object doesn't have any line number info");
nethercote80f76782003-11-13 22:34:00 +00001745 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001746 }
sewardj5c638c22005-04-30 07:55:58 +00001747
sewardjde4a1d02002-03-22 01:27:54 +00001748 }
nethercote80f76782003-11-13 22:34:00 +00001749 res = True;
sewardjde4a1d02002-03-22 01:27:54 +00001750
nethercotee567e702004-07-10 17:49:17 +00001751 out: {
1752 Int m_res;
thughesc035bd92004-06-13 09:59:02 +00001753 /* Last, but not least, heave the image(s) back overboard. */
nethercotee567e702004-07-10 17:49:17 +00001754 if (dimage) {
1755 m_res = VG_(munmap) ( (void*)dimage, n_dimage );
1756 vg_assert(0 == m_res);
1757 }
1758 m_res = VG_(munmap) ( (void*)oimage, n_oimage );
1759 vg_assert(0 == m_res);
nethercote80f76782003-11-13 22:34:00 +00001760 return res;
nethercotee567e702004-07-10 17:49:17 +00001761 }
sewardjde4a1d02002-03-22 01:27:54 +00001762}
1763
sewardjde4a1d02002-03-22 01:27:54 +00001764/*------------------------------------------------------------*/
1765/*--- Main entry point for symbols table reading. ---*/
1766/*------------------------------------------------------------*/
1767
1768/* The root structure for the entire symbol table system. It is a
1769 linked list of SegInfos. Note that this entire mechanism assumes
1770 that what we read from /proc/self/maps doesn't contain overlapping
1771 address ranges, and as a result the SegInfos in this list describe
1772 disjoint address ranges.
1773*/
fitzhardinge98abfc72003-12-16 02:05:15 +00001774SegInfo *VG_(read_seg_symbols) ( Segment *seg )
sewardjde4a1d02002-03-22 01:27:54 +00001775{
1776 SegInfo* si;
1777
fitzhardinge98abfc72003-12-16 02:05:15 +00001778 vg_assert(seg->symtab == NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001779
njnfa1016e2003-09-25 17:54:11 +00001780 VGP_PUSHCC(VgpReadSyms);
1781
sewardjde4a1d02002-03-22 01:27:54 +00001782 /* Get the record initialised right. */
njn25e49d8e72002-09-23 09:36:25 +00001783 si = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(SegInfo));
sewardjde4a1d02002-03-22 01:27:54 +00001784
sewardj8fe15a32002-10-20 19:29:21 +00001785 VG_(memset)(si, 0, sizeof(*si));
fitzhardinge98abfc72003-12-16 02:05:15 +00001786 si->start = seg->addr;
1787 si->size = seg->len;
1788 si->foffset = seg->offset;
fitzhardinge1a4adf02003-12-22 10:42:59 +00001789 si->filename = VG_(arena_strdup)(VG_AR_SYMTAB, seg->filename);
fitzhardinge98abfc72003-12-16 02:05:15 +00001790
1791 si->ref = 1;
sewardjde4a1d02002-03-22 01:27:54 +00001792
1793 si->symtab = NULL;
1794 si->symtab_size = si->symtab_used = 0;
1795 si->loctab = NULL;
1796 si->loctab_size = si->loctab_used = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001797 si->strchunks = NULL;
1798 si->scopetab = NULL;
1799 si->scopetab_size = si->scopetab_used = 0;
sewardj5c638c22005-04-30 07:55:58 +00001800 si->cfisi = NULL;
1801 si->cfisi_size = si->cfisi_used = 0;
sewardjbf603752005-05-02 00:36:27 +00001802 si->cfisi_minaddr = si->cfisi_maxaddr = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001803
fitzhardinge98abfc72003-12-16 02:05:15 +00001804 si->seg = seg;
1805
jsgfcb1d1c02003-10-14 21:55:10 +00001806 si->stab_typetab = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001807
nethercote80f76782003-11-13 22:34:00 +00001808 si->plt_start = si->plt_size = 0;
1809 si->got_start = si->got_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001810 si->data_start = si->data_size = 0;
nethercote80f76782003-11-13 22:34:00 +00001811 si->bss_start = si->bss_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001812
sewardjde4a1d02002-03-22 01:27:54 +00001813 /* And actually fill it up. */
njn695c16e2005-03-27 03:40:28 +00001814 if (!read_lib_symbols ( si ) && 0) {
sewardj8fe15a32002-10-20 19:29:21 +00001815 /* XXX this interacts badly with the prevN optimization in
1816 addStr(). Since this frees the si, the si pointer value can
1817 be recycled, which confuses the curr_si == si test. For now,
1818 this code is disabled, and everything is included in the
1819 segment list, even if it is a bad ELF file. Ironically,
1820 running this under valgrind itself hides the problem, because
1821 it doesn't recycle pointers... */
1822 freeSegInfo( si );
1823 } else {
1824 si->next = segInfo;
1825 segInfo = si;
1826
1827 canonicaliseSymtab ( si );
1828 canonicaliseLoctab ( si );
jsgfcb1d1c02003-10-14 21:55:10 +00001829 canonicaliseScopetab ( si );
sewardjbf603752005-05-02 00:36:27 +00001830 canonicaliseCfiSI ( si );
fitzhardinge98abfc72003-12-16 02:05:15 +00001831
1832 /* do redirects */
sewardjb5f6f512005-03-10 23:59:00 +00001833 VG_(resolve_seg_redirs)( si );
sewardj8fe15a32002-10-20 19:29:21 +00001834 }
njnfa1016e2003-09-25 17:54:11 +00001835 VGP_POPCC(VgpReadSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001836
1837 return si;
sewardjde4a1d02002-03-22 01:27:54 +00001838}
1839
1840
sewardjde4a1d02002-03-22 01:27:54 +00001841/* When an munmap() call happens, check to see whether it corresponds
1842 to a segment for a .so, and if so discard the relevant SegInfo.
1843 This might not be a very clever idea from the point of view of
1844 accuracy of error messages, but we need to do it in order to
sewardj18d75132002-05-16 11:06:21 +00001845 maintain the no-overlapping invariant.
sewardjde4a1d02002-03-22 01:27:54 +00001846*/
nethercote928a5f72004-11-03 18:10:37 +00001847static void unload_symbols ( Addr start, SizeT length )
sewardjde4a1d02002-03-22 01:27:54 +00001848{
1849 SegInfo *prev, *curr;
1850
sewardjde4a1d02002-03-22 01:27:54 +00001851 prev = NULL;
1852 curr = segInfo;
1853 while (True) {
1854 if (curr == NULL) break;
1855 if (start == curr->start) break;
1856 prev = curr;
1857 curr = curr->next;
1858 }
njnfa1016e2003-09-25 17:54:11 +00001859 if (curr == NULL) {
1860 VGP_POPCC(VgpReadSyms);
njn25e49d8e72002-09-23 09:36:25 +00001861 return;
njnfa1016e2003-09-25 17:54:11 +00001862 }
sewardjde4a1d02002-03-22 01:27:54 +00001863
mueller75c0ed62003-11-19 00:47:00 +00001864 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001865 VG_(message)(Vg_DebugMsg,
fitzhardinge98abfc72003-12-16 02:05:15 +00001866 "discard syms at %p-%p in %s due to munmap()",
1867 start, start+length, curr->filename ? curr->filename : (Char *)"???");
sewardjde4a1d02002-03-22 01:27:54 +00001868
1869 vg_assert(prev == NULL || prev->next == curr);
1870
1871 if (prev == NULL) {
1872 segInfo = curr->next;
1873 } else {
1874 prev->next = curr->next;
1875 }
1876
1877 freeSegInfo(curr);
njn25e49d8e72002-09-23 09:36:25 +00001878 return;
sewardjde4a1d02002-03-22 01:27:54 +00001879}
1880
nethercote8991d5a2004-11-03 17:07:46 +00001881void VG_(symtab_decref)(SegInfo *si, Addr start)
fitzhardinge98abfc72003-12-16 02:05:15 +00001882{
1883 vg_assert(si->ref >= 1);
1884 if (--si->ref == 0)
nethercote85cdd342004-08-01 22:36:40 +00001885 unload_symbols(si->start, si->size);
fitzhardinge98abfc72003-12-16 02:05:15 +00001886}
1887
1888void VG_(symtab_incref)(SegInfo *si)
1889{
1890 vg_assert(si->ref > 0);
1891 si->ref++;
1892}
sewardjde4a1d02002-03-22 01:27:54 +00001893
1894/*------------------------------------------------------------*/
1895/*--- Use of symbol table & location info to create ---*/
1896/*--- plausible-looking stack dumps. ---*/
1897/*------------------------------------------------------------*/
1898
1899/* Find a symbol-table index containing the specified pointer, or -1
1900 if not found. Binary search. */
1901
njn25e49d8e72002-09-23 09:36:25 +00001902static Int search_one_symtab ( SegInfo* si, Addr ptr,
1903 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001904{
1905 Addr a_mid_lo, a_mid_hi;
njn25e49d8e72002-09-23 09:36:25 +00001906 Int mid, size,
sewardjde4a1d02002-03-22 01:27:54 +00001907 lo = 0,
1908 hi = si->symtab_used-1;
1909 while (True) {
1910 /* current unsearched space is from lo to hi, inclusive. */
1911 if (lo > hi) return -1; /* not found */
1912 mid = (lo + hi) / 2;
1913 a_mid_lo = si->symtab[mid].addr;
njn25e49d8e72002-09-23 09:36:25 +00001914 size = ( match_anywhere_in_fun
1915 ? si->symtab[mid].size
1916 : 1);
1917 a_mid_hi = ((Addr)si->symtab[mid].addr) + size - 1;
sewardjde4a1d02002-03-22 01:27:54 +00001918
1919 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1920 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1921 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1922 return mid;
1923 }
1924}
1925
1926
sewardj25c7c3a2003-07-10 00:17:58 +00001927/* SLOW (Linear search). Try and map a symbol name to an address.
1928 Since this is searching in the direction opposite to which the
1929 table is designed we have no option but to do a complete linear
1930 scan of the table. Returns NULL if not found. */
1931
sewardjb5f6f512005-03-10 23:59:00 +00001932Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name )
sewardj25c7c3a2003-07-10 00:17:58 +00001933{
1934 UInt i;
1935 for (i = 0; i < si->symtab_used; i++) {
sewardjc8bf5fe2003-07-13 00:53:22 +00001936 if (0)
jsgfcb1d1c02003-10-14 21:55:10 +00001937 VG_(printf)("%p %s\n", si->symtab[i].addr, si->symtab[i].name);
1938 if (0 == VG_(strcmp)(name, si->symtab[i].name))
sewardj25c7c3a2003-07-10 00:17:58 +00001939 return si->symtab[i].addr;
1940 }
1941 return (Addr)NULL;
1942}
1943
1944
sewardjde4a1d02002-03-22 01:27:54 +00001945/* Search all symtabs that we know about to locate ptr. If found, set
1946 *psi to the relevant SegInfo, and *symno to the symtab entry number
1947 within that. If not found, *psi is set to NULL. */
1948
njn25e49d8e72002-09-23 09:36:25 +00001949static void search_all_symtabs ( Addr ptr, /*OUT*/SegInfo** psi,
1950 /*OUT*/Int* symno,
1951 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001952{
1953 Int sno;
1954 SegInfo* si;
fitzhardinge98abfc72003-12-16 02:05:15 +00001955 Segment *s;
njn25e49d8e72002-09-23 09:36:25 +00001956
njn25e49d8e72002-09-23 09:36:25 +00001957 VGP_PUSHCC(VgpSearchSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001958
1959 s = VG_(find_segment)(ptr);
1960
sewardjb5f6f512005-03-10 23:59:00 +00001961 if (s == NULL || s->symtab == NULL)
fitzhardinge98abfc72003-12-16 02:05:15 +00001962 goto not_found;
njn25e49d8e72002-09-23 09:36:25 +00001963
fitzhardinge98abfc72003-12-16 02:05:15 +00001964 si = s->symtab;
1965
1966 sno = search_one_symtab ( si, ptr, match_anywhere_in_fun );
1967 if (sno == -1) goto not_found;
1968
1969 *symno = sno;
1970 *psi = si;
1971 VGP_POPCC(VgpSearchSyms);
1972 return;
1973
sewardjde4a1d02002-03-22 01:27:54 +00001974 not_found:
1975 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00001976 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001977}
1978
1979
1980/* Find a location-table index containing the specified pointer, or -1
1981 if not found. Binary search. */
1982
1983static Int search_one_loctab ( SegInfo* si, Addr ptr )
1984{
1985 Addr a_mid_lo, a_mid_hi;
1986 Int mid,
1987 lo = 0,
1988 hi = si->loctab_used-1;
1989 while (True) {
1990 /* current unsearched space is from lo to hi, inclusive. */
1991 if (lo > hi) return -1; /* not found */
1992 mid = (lo + hi) / 2;
1993 a_mid_lo = si->loctab[mid].addr;
1994 a_mid_hi = ((Addr)si->loctab[mid].addr) + si->loctab[mid].size - 1;
1995
1996 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1997 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1998 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1999 return mid;
2000 }
2001}
2002
2003
2004/* Search all loctabs that we know about to locate ptr. If found, set
2005 *psi to the relevant SegInfo, and *locno to the loctab entry number
2006 within that. If not found, *psi is set to NULL.
2007*/
njn25e49d8e72002-09-23 09:36:25 +00002008static void search_all_loctabs ( Addr ptr, /*OUT*/SegInfo** psi,
2009 /*OUT*/Int* locno )
sewardjde4a1d02002-03-22 01:27:54 +00002010{
2011 Int lno;
2012 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00002013
2014 VGP_PUSHCC(VgpSearchSyms);
2015
sewardjde4a1d02002-03-22 01:27:54 +00002016 for (si = segInfo; si != NULL; si = si->next) {
2017 if (si->start <= ptr && ptr < si->start+si->size) {
2018 lno = search_one_loctab ( si, ptr );
2019 if (lno == -1) goto not_found;
2020 *locno = lno;
2021 *psi = si;
njn25e49d8e72002-09-23 09:36:25 +00002022 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00002023 return;
2024 }
2025 }
2026 not_found:
2027 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002028 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00002029}
2030
2031
jsgfcb1d1c02003-10-14 21:55:10 +00002032/* Find a scope-table index containing the specified pointer, or -1
2033 if not found. Binary search. */
2034
2035static Int search_one_scopetab ( SegInfo* si, Addr ptr )
2036{
2037 Addr a_mid_lo, a_mid_hi;
2038 Int mid,
2039 lo = 0,
2040 hi = si->scopetab_used-1;
2041 while (True) {
2042 /* current unsearched space is from lo to hi, inclusive. */
2043 if (lo > hi) return -1; /* not found */
2044 mid = (lo + hi) / 2;
2045 a_mid_lo = si->scopetab[mid].addr;
2046 a_mid_hi = ((Addr)si->scopetab[mid].addr) + si->scopetab[mid].size - 1;
2047
2048 if (ptr < a_mid_lo) { hi = mid-1; continue; }
2049 if (ptr > a_mid_hi) { lo = mid+1; continue; }
2050 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2051 return mid;
2052 }
2053}
2054
2055
2056/* Search all scopetabs that we know about to locate ptr. If found, set
2057 *psi to the relevant SegInfo, and *locno to the scopetab entry number
2058 within that. If not found, *psi is set to NULL.
2059*/
2060static void search_all_scopetabs ( Addr ptr,
2061 /*OUT*/SegInfo** psi,
2062 /*OUT*/Int* scopeno )
2063{
2064 Int scno;
2065 SegInfo* si;
2066
2067 VGP_PUSHCC(VgpSearchSyms);
2068
2069 for (si = segInfo; si != NULL; si = si->next) {
2070 if (si->start <= ptr && ptr < si->start+si->size) {
2071 scno = search_one_scopetab ( si, ptr );
2072 if (scno == -1) goto not_found;
2073 *scopeno = scno;
2074 *psi = si;
2075 VGP_POPCC(VgpSearchSyms);
2076 return;
2077 }
2078 }
2079 not_found:
2080 *psi = NULL;
2081 VGP_POPCC(VgpSearchSyms);
2082}
2083
sewardj3a1c7db2005-05-02 09:43:44 +00002084
2085/* Find a CFI-table index containing the specified pointer, or -1
2086 if not found. Binary search. */
2087
2088static Int search_one_cfitab ( SegInfo* si, Addr ptr )
2089{
2090 Addr a_mid_lo, a_mid_hi;
2091 Int mid, size,
2092 lo = 0,
2093 hi = si->cfisi_used-1;
2094 while (True) {
2095 /* current unsearched space is from lo to hi, inclusive. */
2096 if (lo > hi) return -1; /* not found */
2097 mid = (lo + hi) / 2;
2098 a_mid_lo = si->cfisi[mid].base;
2099 size = si->cfisi[mid].len;
2100 a_mid_hi = a_mid_lo + size - 1;
2101 vg_assert(a_mid_hi >= a_mid_lo);
2102 if (ptr < a_mid_lo) { hi = mid-1; continue; }
2103 if (ptr > a_mid_hi) { lo = mid+1; continue; }
2104 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2105 return mid;
2106 }
2107}
2108
2109
sewardjde4a1d02002-03-22 01:27:54 +00002110/* The whole point of this whole big deal: map a code address to a
2111 plausible symbol name. Returns False if no idea; otherwise True.
njn25e49d8e72002-09-23 09:36:25 +00002112 Caller supplies buf and nbuf. If demangle is False, don't do
njn695c16e2005-03-27 03:40:28 +00002113 demangling, regardless of VG_(clo_demangle) -- probably because the
2114 call has come from VG_(get_fnname_nodemangle)(). */
njn25e49d8e72002-09-23 09:36:25 +00002115static
2116Bool get_fnname ( Bool demangle, Addr a, Char* buf, Int nbuf,
sewardj1771e172002-11-13 22:06:35 +00002117 Bool match_anywhere_in_fun, Bool show_offset)
sewardjde4a1d02002-03-22 01:27:54 +00002118{
2119 SegInfo* si;
2120 Int sno;
sewardj1771e172002-11-13 22:06:35 +00002121 Int offset;
2122
njn25e49d8e72002-09-23 09:36:25 +00002123 search_all_symtabs ( a, &si, &sno, match_anywhere_in_fun );
sewardjde4a1d02002-03-22 01:27:54 +00002124 if (si == NULL)
2125 return False;
njn25e49d8e72002-09-23 09:36:25 +00002126 if (demangle) {
jsgfcb1d1c02003-10-14 21:55:10 +00002127 VG_(demangle) ( si->symtab[sno].name, buf, nbuf );
njn25e49d8e72002-09-23 09:36:25 +00002128 } else {
njnbe73f432005-03-26 21:34:45 +00002129 VG_(strncpy_safely) ( buf, si->symtab[sno].name, nbuf );
sewardjde4a1d02002-03-22 01:27:54 +00002130 }
sewardj1771e172002-11-13 22:06:35 +00002131
2132 offset = a - si->symtab[sno].addr;
2133 if (show_offset && offset != 0) {
2134 Char buf2[12];
2135 Char* symend = buf + VG_(strlen)(buf);
2136 Char* end = buf + nbuf;
2137 Int len;
2138
2139 len = VG_(sprintf)(buf2, "%c%d",
2140 offset < 0 ? '-' : '+',
2141 offset < 0 ? -offset : offset);
sewardj05bcdcb2003-05-18 10:05:38 +00002142 vg_assert(len < (Int)sizeof(buf2));
sewardj1771e172002-11-13 22:06:35 +00002143
2144 if (len < (end - symend)) {
2145 Char *cp = buf2;
2146 VG_(memcpy)(symend, cp, len+1);
2147 }
2148 }
2149
sewardjde4a1d02002-03-22 01:27:54 +00002150 return True;
2151}
2152
nethercote7cc9c232004-01-21 15:08:04 +00002153/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002154 match anywhere in function, but don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002155Bool VG_(get_fnname) ( Addr a, Char* buf, Int nbuf )
2156{
2157 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002158 /*match_anywhere_in_fun*/True,
2159 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002160}
sewardjde4a1d02002-03-22 01:27:54 +00002161
nethercote7cc9c232004-01-21 15:08:04 +00002162/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002163 match anywhere in function, and show offset if nonzero. */
2164Bool VG_(get_fnname_w_offset) ( Addr a, Char* buf, Int nbuf )
2165{
2166 return get_fnname ( /*demangle*/True, a, buf, nbuf,
2167 /*match_anywhere_in_fun*/True,
2168 /*show offset?*/True );
2169}
2170
nethercote7cc9c232004-01-21 15:08:04 +00002171/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002172 only succeed if 'a' matches first instruction of function,
2173 and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002174Bool VG_(get_fnname_if_entry) ( Addr a, Char* buf, Int nbuf )
2175{
2176 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002177 /*match_anywhere_in_fun*/False,
2178 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002179}
2180
sewardj6e008cb2002-12-15 13:11:39 +00002181/* This is only available to core... don't demangle C++ names,
2182 match anywhere in function, and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002183Bool VG_(get_fnname_nodemangle) ( Addr a, Char* buf, Int nbuf )
2184{
2185 return get_fnname ( /*demangle*/False, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002186 /*match_anywhere_in_fun*/True,
2187 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002188}
2189
2190/* Map a code address to the name of a shared object file or the executable.
2191 Returns False if no idea; otherwise True. Doesn't require debug info.
2192 Caller supplies buf and nbuf. */
2193Bool VG_(get_objname) ( Addr a, Char* buf, Int nbuf )
sewardjde4a1d02002-03-22 01:27:54 +00002194{
2195 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00002196
sewardjde4a1d02002-03-22 01:27:54 +00002197 for (si = segInfo; si != NULL; si = si->next) {
2198 if (si->start <= a && a < si->start+si->size) {
2199 VG_(strncpy_safely)(buf, si->filename, nbuf);
2200 return True;
2201 }
2202 }
2203 return False;
2204}
2205
njnb877d492003-01-28 20:40:57 +00002206/* Map a code address to its SegInfo. Returns NULL if not found. Doesn't
2207 require debug info. */
2208SegInfo* VG_(get_obj) ( Addr a )
2209{
2210 SegInfo* si;
2211
njnb877d492003-01-28 20:40:57 +00002212 for (si = segInfo; si != NULL; si = si->next) {
2213 if (si->start <= a && a < si->start+si->size) {
2214 return si;
2215 }
2216 }
nethercote80f76782003-11-13 22:34:00 +00002217 return NULL;
njnb877d492003-01-28 20:40:57 +00002218}
2219
njn25e49d8e72002-09-23 09:36:25 +00002220
2221/* Map a code address to a filename. Returns True if successful. */
2222Bool VG_(get_filename)( Addr a, Char* filename, Int n_filename )
sewardjde4a1d02002-03-22 01:27:54 +00002223{
njn25e49d8e72002-09-23 09:36:25 +00002224 SegInfo* si;
2225 Int locno;
2226 search_all_loctabs ( a, &si, &locno );
2227 if (si == NULL)
2228 return False;
njnbe73f432005-03-26 21:34:45 +00002229 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
njn25e49d8e72002-09-23 09:36:25 +00002230 return True;
sewardjde4a1d02002-03-22 01:27:54 +00002231}
2232
njn25e49d8e72002-09-23 09:36:25 +00002233/* Map a code address to a line number. Returns True if successful. */
2234Bool VG_(get_linenum)( Addr a, UInt* lineno )
2235{
2236 SegInfo* si;
2237 Int locno;
2238 search_all_loctabs ( a, &si, &locno );
2239 if (si == NULL)
2240 return False;
2241 *lineno = si->loctab[locno].lineno;
2242
2243 return True;
2244}
sewardjde4a1d02002-03-22 01:27:54 +00002245
2246/* Map a code address to a (filename, line number) pair.
2247 Returns True if successful.
2248*/
njn25e49d8e72002-09-23 09:36:25 +00002249Bool VG_(get_filename_linenum)( Addr a,
2250 Char* filename, Int n_filename,
2251 UInt* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00002252{
2253 SegInfo* si;
2254 Int locno;
2255 search_all_loctabs ( a, &si, &locno );
2256 if (si == NULL)
2257 return False;
njnbe73f432005-03-26 21:34:45 +00002258 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
sewardjde4a1d02002-03-22 01:27:54 +00002259 *lineno = si->loctab[locno].lineno;
njn4f9c9342002-04-29 16:03:24 +00002260
sewardjde4a1d02002-03-22 01:27:54 +00002261 return True;
2262}
2263
jsgfcb1d1c02003-10-14 21:55:10 +00002264#ifndef TEST
2265
2266/* return a pointer to a register (now for 5 other impossible things
2267 before breakfast) */
2268static UInt *regaddr(ThreadId tid, Int regno)
2269{
2270 UInt *ret = 0;
2271
sewardj2a99cf62004-11-24 10:44:19 +00002272 ret = VGA_(reg_addr_from_tst)(regno, &VG_(threads)[tid].arch);
jsgfcb1d1c02003-10-14 21:55:10 +00002273
2274 if (ret == 0) {
2275 Char file[100];
2276 Int line;
njn67516132005-03-22 04:02:43 +00002277 Addr eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002278
2279 if (!VG_(get_filename_linenum)(eip, file, sizeof(file), &line))
2280 file[0] = 0;
2281 VG_(printf)("mysterious register %d used at %p %s:%d\n",
2282 regno, eip, file, line);
2283 }
2284
2285 return ret;
2286}
2287
2288/* Get a list of all variables in scope, working out from the directly
2289 current one */
2290Variable *VG_(get_scope_variables)(ThreadId tid)
2291{
2292 static const Bool debug = False;
2293 Variable *list, *end;
2294 Addr eip;
2295 SegInfo *si;
2296 Int scopeidx;
2297 Scope *scope;
2298 Int distance;
2299 static const Int maxsyms = 1000;
2300 Int nsyms = maxsyms;
2301
2302 list = end = NULL;
2303
njn67516132005-03-22 04:02:43 +00002304 eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002305
2306 search_all_scopetabs(eip, &si, &scopeidx);
2307
2308 if (debug)
2309 VG_(printf)("eip=%p si=%p (%s; offset=%p) scopeidx=%d\n",
2310 eip, si, si ? si->filename : (Char *)"???",
2311 si ? si->offset : 0x99999, scopeidx);
2312
2313 if (si == NULL)
2314 return NULL; /* nothing in scope (should use global scope at least) */
2315
2316 if (debug) {
2317 ScopeRange *sr = &si->scopetab[scopeidx];
2318 Char file[100];
2319 Int line;
2320
2321 if (!VG_(get_filename_linenum)(sr->addr, file, sizeof(file), &line))
2322 file[0] = 0;
2323
2324 VG_(printf)("found scope range %p: eip=%p (%s:%d) size=%d scope=%p\n",
2325 sr, sr->addr, file, line, sr->size, sr->scope);
2326 }
2327
2328 distance = 0;
2329 for(scope = si->scopetab[scopeidx].scope; scope != NULL; scope = scope->outer, distance++) {
2330 UInt i;
2331
2332 for(i = 0; i < scope->nsyms; i++) {
2333 Sym *sym = &scope->syms[i];
2334 Variable *v;
2335
2336 if (nsyms-- == 0) {
2337 VG_(printf)("max %d syms reached\n", maxsyms);
2338 return list;
2339 }
2340
2341 v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
2342
2343 v->next = NULL;
2344 v->distance = distance;
2345 v->type = VG_(st_basetype)(sym->type, False);
2346 v->name = VG_(arena_strdup)(VG_AR_SYMTAB, sym->name);
2347 v->container = NULL;
2348 v->size = VG_(st_sizeof)(sym->type);
2349
2350 if (debug && 0)
mueller5ed88f22004-01-06 16:02:29 +00002351 VG_(printf)("sym->name=%s sym->kind=%d offset=%d\n", sym->name, sym->kind, sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002352 switch(sym->kind) {
2353 UInt reg;
2354
2355 case SyGlobal:
2356 case SyStatic:
mueller5ed88f22004-01-06 16:02:29 +00002357 if (sym->u.addr == 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00002358 /* XXX lookup value */
2359 }
mueller5ed88f22004-01-06 16:02:29 +00002360 v->valuep = sym->u.addr;
jsgfcb1d1c02003-10-14 21:55:10 +00002361 break;
2362
2363 case SyReg:
mueller5ed88f22004-01-06 16:02:29 +00002364 v->valuep = (Addr)regaddr(tid, sym->u.regno);
jsgfcb1d1c02003-10-14 21:55:10 +00002365 break;
2366
2367 case SyEBPrel:
2368 case SyESPrel:
nethercotecd656042004-09-11 23:48:22 +00002369 reg = *regaddr(tid, sym->kind == SyESPrel ?
njndb9b7732005-03-26 00:32:29 +00002370 VGA_R_STACK_PTR : VGA_R_FRAME_PTR);
jsgfcb1d1c02003-10-14 21:55:10 +00002371 if (debug)
mueller5ed88f22004-01-06 16:02:29 +00002372 VG_(printf)("reg=%p+%d=%p\n", reg, sym->u.offset, reg+sym->u.offset);
2373 v->valuep = (Addr)(reg + sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002374 break;
2375
2376 case SyType:
2377 VG_(core_panic)("unexpected typedef in scope");
2378 }
2379
2380 if (v->valuep == 0) {
2381 /* not interesting or useful */
2382 VG_(arena_free)(VG_AR_SYMTAB, v);
2383 continue;
2384 }
2385
2386 /* append to end of list */
2387 if (list == NULL)
2388 list = end = v;
2389 else {
2390 end->next = v;
2391 end = v;
2392 }
2393 }
2394 }
2395
2396 return list;
2397}
2398#endif /* TEST */
2399
njn6c846552003-09-16 07:41:43 +00002400/* Print into buf info on code address, function name and filename */
njnd01fef72005-03-25 23:35:48 +00002401Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf)
sewardjde4a1d02002-03-22 01:27:54 +00002402{
njn6c846552003-09-16 07:41:43 +00002403#define APPEND(str) \
2404 { UChar* sss; \
2405 for (sss = str; n < n_buf-1 && *sss != 0; n++,sss++) \
2406 buf[n] = *sss; \
2407 buf[n] = '\0'; \
sewardjde4a1d02002-03-22 01:27:54 +00002408 }
nethercote80f76782003-11-13 22:34:00 +00002409 UInt lineno;
2410 UChar ibuf[20];
2411 UInt n = 0;
njn47b209a2005-03-25 23:47:16 +00002412 static UChar buf_fn[VG_ERRTXT_LEN];
2413 static UChar buf_obj[VG_ERRTXT_LEN];
2414 static UChar buf_srcloc[VG_ERRTXT_LEN];
2415 Bool know_fnname = VG_(get_fnname) (eip, buf_fn, VG_ERRTXT_LEN);
2416 Bool know_objname = VG_(get_objname)(eip, buf_obj, VG_ERRTXT_LEN);
2417 Bool know_srcloc = VG_(get_filename_linenum)(eip, buf_srcloc,
2418 VG_ERRTXT_LEN, &lineno);
sewardja4da2f32005-03-02 14:06:08 +00002419 VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip);
njn6c846552003-09-16 07:41:43 +00002420 APPEND(ibuf);
2421 if (know_fnname) {
2422 APPEND(buf_fn);
2423 if (!know_srcloc && know_objname) {
2424 APPEND(" (in ");
2425 APPEND(buf_obj);
2426 APPEND(")");
2427 }
2428 } else if (know_objname && !know_srcloc) {
2429 APPEND("(within ");
2430 APPEND(buf_obj);
2431 APPEND(")");
2432 } else {
2433 APPEND("???");
2434 }
2435 if (know_srcloc) {
2436 APPEND(" (");
2437 APPEND(buf_srcloc);
2438 APPEND(":");
2439 VG_(sprintf)(ibuf,"%d",lineno);
2440 APPEND(ibuf);
2441 APPEND(")");
2442 }
2443 return buf;
2444
2445#undef APPEND
2446}
2447
sewardj35165532005-04-30 18:47:48 +00002448/* Returns True if OK. If not OK, *{ip,sp,fp}P are not changed. */
2449
2450Bool VG_(use_CFI_info) ( /*MOD*/Addr* ipP,
2451 /*MOD*/Addr* spP,
2452 /*MOD*/Addr* fpP,
2453 Addr min_accessible,
2454 Addr max_accessible )
2455{
2456 Int i;
2457 SegInfo* si;
2458 CfiSI* cfisi = NULL;
2459 Addr cfa, ipHere, spHere, fpHere, ipPrev, spPrev, fpPrev;
2460
sewardjbf603752005-05-02 00:36:27 +00002461
sewardj35165532005-04-30 18:47:48 +00002462 if (0) VG_(printf)("search for %p\n", *ipP);
2463
2464 for (si = segInfo; si != NULL; si = si->next) {
sewardjbf603752005-05-02 00:36:27 +00002465 /* Use the per-SegInfo summary address ranges to skip
2466 inapplicable SegInfos quickly. */
2467 if (si->cfisi_used == 0)
2468 continue;
2469 if (*ipP < si->cfisi_minaddr || *ipP > si->cfisi_maxaddr)
2470 continue;
2471
sewardj3a1c7db2005-05-02 09:43:44 +00002472 i = search_one_cfitab( si, *ipP );
2473 if (i != -1) {
2474 vg_assert(i >= 0 && i < si->cfisi_used);
2475 cfisi = &si->cfisi[i];
2476 break;
sewardj35165532005-04-30 18:47:48 +00002477 }
2478 }
2479
sewardj35165532005-04-30 18:47:48 +00002480 if (cfisi == NULL)
2481 return False;
2482
2483 if (0) {
2484 VG_(printf)("found cfisi: ");
2485 VG_(ppCfiSI)(cfisi);
2486 }
2487
2488 ipPrev = spPrev = fpPrev = 0;
2489
2490 ipHere = *ipP;
2491 spHere = *spP;
2492 fpHere = *fpP;
2493
2494 cfa = cfisi->cfa_off + (cfisi->cfa_sprel ? spHere : fpHere);
2495
2496# define COMPUTE(_prev, _here, _how, _off) \
2497 do { \
2498 switch (_how) { \
2499 case CFIR_UNKNOWN: \
2500 return False; \
2501 case CFIR_SAME: \
2502 _prev = _here; break; \
2503 case CFIR_MEMCFAREL: { \
2504 Addr a = cfa + (Word)_off; \
2505 if (a < min_accessible \
2506 || a+sizeof(Addr) > max_accessible) \
2507 return False; \
2508 _prev = *(Addr*)a; \
2509 break; \
2510 } \
2511 case CFIR_CFAREL: \
2512 _prev = cfa + (Word)_off; \
2513 break; \
2514 } \
2515 } while (0)
2516
2517 COMPUTE(ipPrev, ipHere, cfisi->ra_how, cfisi->ra_off);
2518 COMPUTE(spPrev, spHere, cfisi->sp_how, cfisi->sp_off);
2519 COMPUTE(fpPrev, fpHere, cfisi->fp_how, cfisi->fp_off);
2520
2521# undef COMPUTE
2522
2523 *ipP = ipPrev;
2524 *spP = spPrev;
2525 *fpP = fpPrev;
2526 return True;
2527}
2528
2529
sewardj25c7c3a2003-07-10 00:17:58 +00002530/*------------------------------------------------------------*/
sewardj47104382002-10-20 18:35:48 +00002531/*--- SegInfo accessor functions ---*/
2532/*------------------------------------------------------------*/
2533
2534const SegInfo* VG_(next_seginfo)(const SegInfo* seg)
2535{
sewardj47104382002-10-20 18:35:48 +00002536 if (seg == NULL)
2537 return segInfo;
2538 return seg->next;
2539}
2540
2541Addr VG_(seg_start)(const SegInfo* seg)
2542{
2543 return seg->start;
2544}
2545
nethercote928a5f72004-11-03 18:10:37 +00002546SizeT VG_(seg_size)(const SegInfo* seg)
sewardj47104382002-10-20 18:35:48 +00002547{
2548 return seg->size;
2549}
2550
2551const UChar* VG_(seg_filename)(const SegInfo* seg)
2552{
2553 return seg->filename;
2554}
2555
nethercote928a5f72004-11-03 18:10:37 +00002556ULong VG_(seg_sym_offset)(const SegInfo* seg)
sewardj47104382002-10-20 18:35:48 +00002557{
2558 return seg->offset;
2559}
2560
2561VgSectKind VG_(seg_sect_kind)(Addr a)
2562{
2563 SegInfo* seg;
2564 VgSectKind ret = Vg_SectUnknown;
2565
sewardj47104382002-10-20 18:35:48 +00002566 for(seg = segInfo; seg != NULL; seg = seg->next) {
2567 if (a >= seg->start && a < (seg->start + seg->size)) {
2568 if (0)
sewardj8fe15a32002-10-20 19:29:21 +00002569 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 +00002570 a, seg, seg->filename,
2571 seg->got_start, seg->got_size,
sewardj8fe15a32002-10-20 19:29:21 +00002572 seg->plt_start, seg->plt_size,
2573 seg->data_start, seg->data_size,
2574 seg->bss_start, seg->bss_size);
sewardj47104382002-10-20 18:35:48 +00002575 ret = Vg_SectText;
2576
sewardj8fe15a32002-10-20 19:29:21 +00002577 if (a >= seg->data_start && a < (seg->data_start + seg->data_size))
2578 ret = Vg_SectData;
2579 else if (a >= seg->bss_start && a < (seg->bss_start + seg->bss_size))
2580 ret = Vg_SectBSS;
2581 else if (a >= seg->plt_start && a < (seg->plt_start + seg->plt_size))
sewardj47104382002-10-20 18:35:48 +00002582 ret = Vg_SectPLT;
2583 else if (a >= seg->got_start && a < (seg->got_start + seg->got_size))
2584 ret = Vg_SectGOT;
2585 }
2586 }
2587
2588 return ret;
2589}
2590
sewardjde4a1d02002-03-22 01:27:54 +00002591/*--------------------------------------------------------------------*/
2592/*--- end vg_symtab2.c ---*/
2593/*--------------------------------------------------------------------*/