blob: a55e289a1b28c9390172bb07f5990f78dcf9ff07 [file] [log] [blame]
sewardjb5f6f512005-03-10 23:59:00 +00001
sewardjde4a1d02002-03-22 01:27:54 +00002/*--------------------------------------------------------------------*/
3/*--- Management of symbols and debugging information. ---*/
njnea27e462005-05-31 02:38:09 +00004/*--- symtab.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00005/*--------------------------------------------------------------------*/
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
njnc7561b92005-06-19 01:24:32 +000032#include "pub_core_basics.h"
33#include "pub_core_threadstate.h"
njnf4c50162005-06-20 14:18:12 +000034#include "pub_core_aspacemgr.h" // For Segment type
35#include "pub_core_debuginfo.h"
njn94b1e2e2005-05-10 05:00:55 +000036#include "pub_core_demangle.h"
njn97405b22005-06-02 03:39:33 +000037#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_core_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000039#include "pub_core_libcfile.h"
njne9befc62005-06-11 15:51:30 +000040#include "pub_core_libcmman.h"
njn36a20fa2005-06-03 03:08:39 +000041#include "pub_core_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000042#include "pub_core_machine.h"
njnaf1d7df2005-06-11 01:31:52 +000043#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000044#include "pub_core_options.h"
njn31513b42005-06-01 03:09:59 +000045#include "pub_core_profile.h"
njnd1af0032005-05-29 17:01:48 +000046#include "pub_core_redir.h"
njnf4c50162005-06-20 14:18:12 +000047#include "pub_core_tooliface.h" // For VG_(needs).data_syms
njnea27e462005-05-31 02:38:09 +000048#include "priv_symtab.h"
sewardj55f9d1a2005-04-25 11:11:44 +000049
njn43b9a8a2005-05-10 04:37:01 +000050#include <elf.h> /* ELF defns */
sewardjde4a1d02002-03-22 01:27:54 +000051
njn16eeb4e2005-06-16 03:56:58 +000052static SegInfo* segInfo_list = NULL;
sewardjb5f6f512005-03-10 23:59:00 +000053
sewardj7a21c612005-02-18 09:38:08 +000054/*------------------------------------------------------------*/
55/*--- 32/64-bit parameterisation ---*/
56/*------------------------------------------------------------*/
57
58/* For all the ELF macros and types which specify '32' or '64',
59 select the correct variant for this platform and give it
60 an 'XX' name. Then use the 'XX' variant consistently in
61 the rest of this file.
62*/
njna37029a2005-05-15 03:56:26 +000063#if VG_WORDSIZE == 4
sewardj7a21c612005-02-18 09:38:08 +000064# define ElfXX_Ehdr Elf32_Ehdr
65# define ElfXX_Shdr Elf32_Shdr
66# define ElfXX_Phdr Elf32_Phdr
67# define ElfXX_Sym Elf32_Sym
68# define ElfXX_Word Elf32_Word
69# define ElfXX_Addr Elf32_Addr
70# define ElfXX_Dyn Elf32_Dyn
71# define ELFXX_ST_BIND ELF32_ST_BIND
72# define ELFXX_ST_TYPE ELF32_ST_TYPE
73
njna37029a2005-05-15 03:56:26 +000074#elif VG_WORDSIZE == 8
sewardj7a21c612005-02-18 09:38:08 +000075# define ElfXX_Ehdr Elf64_Ehdr
76# define ElfXX_Shdr Elf64_Shdr
77# define ElfXX_Phdr Elf64_Phdr
78# define ElfXX_Sym Elf64_Sym
79# define ElfXX_Word Elf64_Word
80# define ElfXX_Addr Elf64_Addr
81# define ElfXX_Dyn Elf64_Dyn
82# define ELFXX_ST_BIND ELF64_ST_BIND
83# define ELFXX_ST_TYPE ELF64_ST_TYPE
84
85#else
njna37029a2005-05-15 03:56:26 +000086# error "VG_WORDSIZE should be 4 or 8"
sewardj7a21c612005-02-18 09:38:08 +000087#endif
88
89
90/*------------------------------------------------------------*/
91/*--- ---*/
92/*------------------------------------------------------------*/
93
sewardjde4a1d02002-03-22 01:27:54 +000094/* Majorly rewritten Sun 3 Feb 02 to enable loading symbols from
95 dlopen()ed libraries, which is something that KDE3 does a lot.
sewardjde4a1d02002-03-22 01:27:54 +000096
njn25e49d8e72002-09-23 09:36:25 +000097 Stabs reader greatly improved by Nick Nethercote, Apr 02.
sewardjde4a1d02002-03-22 01:27:54 +000098*/
99
sewardjde4a1d02002-03-22 01:27:54 +0000100static void freeSegInfo ( SegInfo* si )
101{
jsgfcb1d1c02003-10-14 21:55:10 +0000102 struct strchunk *chunk, *next;
sewardjde4a1d02002-03-22 01:27:54 +0000103 vg_assert(si != NULL);
njn25e49d8e72002-09-23 09:36:25 +0000104 if (si->filename) VG_(arena_free)(VG_AR_SYMTAB, si->filename);
105 if (si->symtab) VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
106 if (si->loctab) VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
jsgfcb1d1c02003-10-14 21:55:10 +0000107 if (si->scopetab) VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
sewardj5c638c22005-04-30 07:55:58 +0000108 if (si->cfisi) VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
jsgfcb1d1c02003-10-14 21:55:10 +0000109
110 for(chunk = si->strchunks; chunk != NULL; chunk = next) {
111 next = chunk->next;
112 VG_(arena_free)(VG_AR_SYMTAB, chunk);
113 }
njn25e49d8e72002-09-23 09:36:25 +0000114 VG_(arena_free)(VG_AR_SYMTAB, si);
sewardjde4a1d02002-03-22 01:27:54 +0000115}
116
117
118/*------------------------------------------------------------*/
119/*--- Adding stuff ---*/
120/*------------------------------------------------------------*/
121
122/* Add a str to the string table, including terminating zero, and
jsgfcb1d1c02003-10-14 21:55:10 +0000123 return pointer to the string in vg_strtab. Unless it's been seen
124 recently, in which case we find the old pointer and return that.
125 This avoids the most egregious duplications.
sewardjde4a1d02002-03-22 01:27:54 +0000126
jsgfcb1d1c02003-10-14 21:55:10 +0000127 JSGF: changed from returning an index to a pointer, and changed to
128 a chunking memory allocator rather than reallocating, so the
129 pointers are stable.
130*/
131
132Char *VG_(addStr) ( SegInfo* si, Char* str, Int len )
sewardjde4a1d02002-03-22 01:27:54 +0000133{
jsgfcb1d1c02003-10-14 21:55:10 +0000134 struct strchunk *chunk;
njn16eeb4e2005-06-16 03:56:58 +0000135 Int space_needed;
136 Char* p;
njn25e49d8e72002-09-23 09:36:25 +0000137
jsgfcb1d1c02003-10-14 21:55:10 +0000138 if (len == -1)
139 len = VG_(strlen)(str);
njn25e49d8e72002-09-23 09:36:25 +0000140
jsgfcb1d1c02003-10-14 21:55:10 +0000141 space_needed = 1 + len;
njn25e49d8e72002-09-23 09:36:25 +0000142
njn16eeb4e2005-06-16 03:56:58 +0000143 // Allocate a new strtab chunk if necessary
jsgfcb1d1c02003-10-14 21:55:10 +0000144 if (si->strchunks == NULL ||
145 (si->strchunks->strtab_used + space_needed) > STRCHUNKSIZE) {
146 chunk = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*chunk));
147 chunk->strtab_used = 0;
148 chunk->next = si->strchunks;
149 si->strchunks = chunk;
sewardjde4a1d02002-03-22 01:27:54 +0000150 }
jsgfcb1d1c02003-10-14 21:55:10 +0000151 chunk = si->strchunks;
sewardjde4a1d02002-03-22 01:27:54 +0000152
njn16eeb4e2005-06-16 03:56:58 +0000153 p = &chunk->strtab[chunk->strtab_used];
154 VG_(memcpy)(p, str, len);
jsgfcb1d1c02003-10-14 21:55:10 +0000155 chunk->strtab[chunk->strtab_used+len] = '\0';
156 chunk->strtab_used += space_needed;
sewardjde4a1d02002-03-22 01:27:54 +0000157
njn16eeb4e2005-06-16 03:56:58 +0000158 return p;
sewardjde4a1d02002-03-22 01:27:54 +0000159}
160
161/* Add a symbol to the symbol table. */
sewardjde4a1d02002-03-22 01:27:54 +0000162static __inline__
163void addSym ( SegInfo* si, RiSym* sym )
164{
sewardj05bcdcb2003-05-18 10:05:38 +0000165 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000166 RiSym* new_tab;
167
168 /* Ignore zero-sized syms. */
169 if (sym->size == 0) return;
170
171 if (si->symtab_used == si->symtab_size) {
172 new_sz = 2 * si->symtab_size;
173 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000174 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiSym) );
sewardjde4a1d02002-03-22 01:27:54 +0000175 if (si->symtab != NULL) {
176 for (i = 0; i < si->symtab_used; i++)
177 new_tab[i] = si->symtab[i];
njn25e49d8e72002-09-23 09:36:25 +0000178 VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
sewardjde4a1d02002-03-22 01:27:54 +0000179 }
180 si->symtab = new_tab;
181 si->symtab_size = new_sz;
182 }
183
184 si->symtab[si->symtab_used] = *sym;
185 si->symtab_used++;
186 vg_assert(si->symtab_used <= si->symtab_size);
187}
188
189/* Add a location to the location table. */
190
191static __inline__
192void addLoc ( SegInfo* si, RiLoc* loc )
193{
sewardj05bcdcb2003-05-18 10:05:38 +0000194 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000195 RiLoc* new_tab;
196
njne0ee0712002-05-03 16:41:05 +0000197 /* Zero-sized locs should have been ignored earlier */
198 vg_assert(loc->size > 0);
sewardjde4a1d02002-03-22 01:27:54 +0000199
200 if (si->loctab_used == si->loctab_size) {
201 new_sz = 2 * si->loctab_size;
202 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000203 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiLoc) );
sewardjde4a1d02002-03-22 01:27:54 +0000204 if (si->loctab != NULL) {
205 for (i = 0; i < si->loctab_used; i++)
206 new_tab[i] = si->loctab[i];
njn25e49d8e72002-09-23 09:36:25 +0000207 VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
sewardjde4a1d02002-03-22 01:27:54 +0000208 }
209 si->loctab = new_tab;
210 si->loctab_size = new_sz;
211 }
212
213 si->loctab[si->loctab_used] = *loc;
214 si->loctab_used++;
215 vg_assert(si->loctab_used <= si->loctab_size);
216}
217
218
sewardjb51f2e62002-06-01 23:11:19 +0000219/* Top-level place to call to add a source-location mapping entry. */
220
jsgfcb1d1c02003-10-14 21:55:10 +0000221void VG_(addLineInfo) ( SegInfo* si,
222 Char* filename,
sewardj7cee6f92005-06-13 17:39:06 +0000223 Char* dirname, /* NULL == directory is unknown */
jsgfcb1d1c02003-10-14 21:55:10 +0000224 Addr this,
225 Addr next,
226 Int lineno,
227 Int entry /* only needed for debug printing */
sewardj7cee6f92005-06-13 17:39:06 +0000228 )
sewardjb51f2e62002-06-01 23:11:19 +0000229{
jsgfcb1d1c02003-10-14 21:55:10 +0000230 static const Bool debug = False;
sewardjb51f2e62002-06-01 23:11:19 +0000231 RiLoc loc;
232 Int size = next - this;
233
234 /* Ignore zero-sized locs */
235 if (this == next) return;
236
jsgfcb1d1c02003-10-14 21:55:10 +0000237 if (debug)
sewardj7cee6f92005-06-13 17:39:06 +0000238 VG_(printf)( " src %s %s line %d %p-%p\n",
239 dirname ? dirname : (Char*)"(unknown)",
240 filename, lineno, this, next );
jsgfcb1d1c02003-10-14 21:55:10 +0000241
sewardjb51f2e62002-06-01 23:11:19 +0000242 /* Maximum sanity checking. Some versions of GNU as do a shabby
243 * job with stabs entries; if anything looks suspicious, revert to
244 * a size of 1. This should catch the instruction of interest
245 * (since if using asm-level debug info, one instruction will
246 * correspond to one line, unlike with C-level debug info where
247 * multiple instructions can map to the one line), but avoid
248 * catching any other instructions bogusly. */
thughesc1c57952004-11-01 17:36:15 +0000249 if (this > next) {
250 if (VG_(clo_verbosity) > 2) {
251 VG_(message)(Vg_DebugMsg,
252 "warning: line info addresses out of order "
253 "at entry %d: 0x%x 0x%x", entry, this, next);
254 }
sewardjb51f2e62002-06-01 23:11:19 +0000255 size = 1;
256 }
257
258 if (size > MAX_LOC_SIZE) {
sewardjd84606d2002-06-18 01:04:57 +0000259 if (0)
sewardjb51f2e62002-06-01 23:11:19 +0000260 VG_(message)(Vg_DebugMsg,
sewardj08a50f62002-06-17 02:21:20 +0000261 "warning: line info address range too large "
sewardjb51f2e62002-06-01 23:11:19 +0000262 "at entry %d: %d", entry, size);
263 size = 1;
264 }
265
sewardj08a50f62002-06-17 02:21:20 +0000266 /* vg_assert(this < si->start + si->size && next-1 >= si->start); */
njne306ffe2002-06-08 13:34:17 +0000267 if (this >= si->start + si->size || next-1 < si->start) {
sewardjd84606d2002-06-18 01:04:57 +0000268 if (0)
sewardj08a50f62002-06-17 02:21:20 +0000269 VG_(message)(Vg_DebugMsg,
270 "warning: ignoring line info entry falling "
271 "outside current SegInfo: %p %p %p %p",
272 si->start, si->start + si->size,
273 this, next-1);
njne306ffe2002-06-08 13:34:17 +0000274 return;
275 }
276
277 vg_assert(lineno >= 0);
278 if (lineno > MAX_LINENO) {
279 VG_(message)(Vg_UserMsg,
sewardj08a50f62002-06-17 02:21:20 +0000280 "warning: ignoring line info entry with "
281 "huge line number (%d)", lineno);
njne306ffe2002-06-08 13:34:17 +0000282 VG_(message)(Vg_UserMsg,
283 " Can't handle line numbers "
sewardj08a50f62002-06-17 02:21:20 +0000284 "greater than %d, sorry", MAX_LINENO);
njne306ffe2002-06-08 13:34:17 +0000285 return;
286 }
sewardjb51f2e62002-06-01 23:11:19 +0000287
288 loc.addr = this;
289 loc.size = (UShort)size;
290 loc.lineno = lineno;
jsgfcb1d1c02003-10-14 21:55:10 +0000291 loc.filename = filename;
sewardj7cee6f92005-06-13 17:39:06 +0000292 loc.dirname = dirname;
sewardjb642dc22002-10-12 17:27:16 +0000293
294 if (0) VG_(message)(Vg_DebugMsg,
295 "addLoc: addr %p, size %d, line %d, file %s",
jsgfcb1d1c02003-10-14 21:55:10 +0000296 this,size,lineno,filename);
sewardjb642dc22002-10-12 17:27:16 +0000297
sewardjb51f2e62002-06-01 23:11:19 +0000298 addLoc ( si, &loc );
299}
300
jsgfcb1d1c02003-10-14 21:55:10 +0000301static __inline__
302void addScopeRange ( SegInfo* si, ScopeRange *range )
303{
304 Int new_sz, i;
305 ScopeRange* new_tab;
306
307 /* Zero-sized scopes should have been ignored earlier */
308 vg_assert(range->size > 0);
309
310 if (si->scopetab_used == si->scopetab_size) {
311 new_sz = 2 * si->scopetab_size;
312 if (new_sz == 0) new_sz = 500;
313 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(*new_tab) );
314 if (si->scopetab != NULL) {
315 for (i = 0; i < si->scopetab_used; i++)
316 new_tab[i] = si->scopetab[i];
317 VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
318 }
319 si->scopetab = new_tab;
320 si->scopetab_size = new_sz;
321 }
322
323 si->scopetab[si->scopetab_used] = *range;
324 si->scopetab_used++;
325 vg_assert(si->scopetab_used <= si->scopetab_size);
326}
327
328
329/* Top-level place to call to add a source-location mapping entry. */
330
331void VG_(addScopeInfo) ( SegInfo* si,
332 Addr this,
333 Addr next,
334 Scope *scope)
335{
336 static const Bool debug = False;
337 Int size = next - this;
338 ScopeRange range;
339
fitzhardinge83d8a712004-02-05 22:58:37 +0000340 /* Ignore zero-sized or negative scopes */
341 if (size <= 0) {
jsgfcb1d1c02003-10-14 21:55:10 +0000342 if (debug)
343 VG_(printf)("ignoring zero-sized range, scope %p at %p\n", scope, this);
344 return;
345 }
346
347 if (debug)
348 VG_(printf)("adding scope range %p-%p (size=%d) scope %p (%d)\n",
349 this, next, next-this, scope, scope->depth);
350
351 range.addr = this;
352 range.size = size;
353 range.scope = scope;
354
355 addScopeRange ( si, &range );
356}
357
sewardj35165532005-04-30 18:47:48 +0000358
359/* Top-level place to call to add a CFI summary record. The supplied
360 CfiSI is copied. */
361void VG_(addCfiSI) ( SegInfo* si, CfiSI* cfisi )
362{
363 static const Bool debug = False;
364
365 if (debug) {
366 VG_(printf)("adding CfiSI: ");
367 VG_(ppCfiSI)(cfisi);
368 }
369
sewardj6b2eefa2005-05-20 02:10:45 +0000370 vg_assert(cfisi->len > 0 && cfisi->len < 2000000);
sewardjbf603752005-05-02 00:36:27 +0000371
sewardj35165532005-04-30 18:47:48 +0000372 UInt new_sz, i;
373 CfiSI* new_tab;
374
sewardjc4f204f2005-05-03 15:23:00 +0000375 /* Rule out ones which are completely outside the segment. These
376 probably indicate some kind of bug, but for the meantime ignore
377 them. */
378 if ( cfisi->base + cfisi->len - 1 < si->start
379 || si->start + si->size - 1 < cfisi->base ) {
sewardj55022aa2005-05-03 16:05:00 +0000380 static Int complaints = 3;
381 if (VG_(clo_trace_cfi) || complaints > 0) {
382 complaints--;
sewardjbe18a592005-05-06 17:01:21 +0000383 if (VG_(clo_verbosity) > 1) {
384 VG_(message)(
385 Vg_DebugMsg,
386 "warning: CfiSI %p .. %p outside segment %p .. %p",
387 cfisi->base,
388 cfisi->base + cfisi->len - 1,
389 si->start,
390 si->start + si->size - 1
391 );
392 }
sewardj55022aa2005-05-03 16:05:00 +0000393 if (VG_(clo_trace_cfi))
394 VG_(ppCfiSI)(cfisi);
sewardjc4f204f2005-05-03 15:23:00 +0000395 }
396 return;
397 }
398
sewardj35165532005-04-30 18:47:48 +0000399 if (si->cfisi_used == si->cfisi_size) {
400 new_sz = 2 * si->cfisi_size;
401 if (new_sz == 0) new_sz = 20;
402 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(CfiSI) );
403 if (si->cfisi != NULL) {
404 for (i = 0; i < si->cfisi_used; i++)
405 new_tab[i] = si->cfisi[i];
406 VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
407 }
408 si->cfisi = new_tab;
409 si->cfisi_size = new_sz;
410 }
411
412 si->cfisi[si->cfisi_used] = *cfisi;
413 si->cfisi_used++;
414 vg_assert(si->cfisi_used <= si->cfisi_size);
415}
416
417
sewardjde4a1d02002-03-22 01:27:54 +0000418/*------------------------------------------------------------*/
419/*--- Helpers ---*/
420/*------------------------------------------------------------*/
421
422/* Non-fatal -- use vg_panic if terminal. */
jsgfcb1d1c02003-10-14 21:55:10 +0000423void VG_(symerr) ( Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000424{
425 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +0000426 VG_(message)(Vg_DebugMsg,"%s", msg );
sewardjde4a1d02002-03-22 01:27:54 +0000427}
428
429
430/* Print a symbol. */
431static
432void printSym ( SegInfo* si, Int i )
433{
434 VG_(printf)( "%5d: %8p .. %8p (%d) %s\n",
435 i,
436 si->symtab[i].addr,
437 si->symtab[i].addr + si->symtab[i].size - 1, si->symtab[i].size,
jsgfcb1d1c02003-10-14 21:55:10 +0000438 si->symtab[i].name );
sewardjde4a1d02002-03-22 01:27:54 +0000439}
440
nethercote80f76782003-11-13 22:34:00 +0000441#define TRACE_SYMTAB(format, args...) \
442 if (VG_(clo_trace_symtab)) { VG_(printf)(format, ## args); }
443
sewardjde4a1d02002-03-22 01:27:54 +0000444
445#if 0
446/* Print the entire sym tab. */
447static __attribute__ ((unused))
448void printSymtab ( void )
449{
450 Int i;
451 VG_(printf)("\n------ BEGIN vg_symtab ------\n");
452 for (i = 0; i < vg_symtab_used; i++)
453 printSym(i);
454 VG_(printf)("------ BEGIN vg_symtab ------\n");
455}
456#endif
457
458#if 0
459/* Paranoid strcat. */
460static
461void safeCopy ( UChar* dst, UInt maxlen, UChar* src )
462{
463 UInt i = 0, j = 0;
464 while (True) {
465 if (i >= maxlen) return;
466 if (dst[i] == 0) break;
467 i++;
468 }
469 while (True) {
470 if (i >= maxlen) return;
471 dst[i] = src[j];
472 if (src[j] == 0) return;
473 i++; j++;
474 }
475}
476#endif
477
sewardjb51f2e62002-06-01 23:11:19 +0000478
sewardjde4a1d02002-03-22 01:27:54 +0000479/*------------------------------------------------------------*/
480/*--- Canonicalisers ---*/
481/*------------------------------------------------------------*/
482
483/* Sort the symtab by starting address, and emit warnings if any
nethercote80f76782003-11-13 22:34:00 +0000484 symbols have overlapping address ranges. We use that old chestnut,
485 shellsort. Mash the table around so as to establish the property
486 that addresses are in order and the ranges to not overlap. This
487 facilitates using binary search to map addresses to symbols when we
488 come to query the table.
sewardjde4a1d02002-03-22 01:27:54 +0000489*/
jsgfcb1d1c02003-10-14 21:55:10 +0000490static Int compare_RiSym(void *va, void *vb) {
491 RiSym *a = (RiSym *)va;
492 RiSym *b = (RiSym *)vb;
493
nethercote05fdfac2004-08-01 20:24:46 +0000494 if (a->addr < b->addr) return -1;
495 if (a->addr > b->addr) return 1;
496 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000497}
498
fitzhardinge1c76dc42003-12-15 09:00:21 +0000499/* Two symbols have the same address. Which name do we prefer?
500
sewardjb5f6f512005-03-10 23:59:00 +0000501 The general rule is to prefer the shorter symbol name. If the
502 symbol contains a '@', which means its versioned, then the length
503 up to the '@' is used for length comparison purposes (so
504 "foo@GLIBC_2.4.2" is considered shorter than "foobar"), but if two
505 symbols have the same length, the one with the version string is
506 preferred. If all else fails, use alphabetical ordering.
njn16eeb4e2005-06-16 03:56:58 +0000507
508 Very occasionally this goes wrong (eg. 'memcmp' and 'bcmp' are aliases
509 in glibc, we choose the 'bcmp' symbol because it's shorter, so we
510 can misdescribe memcmp() as bcmp()). This is hard to avoid. It's
511 mentioned in the FAQ file.
fitzhardinge1c76dc42003-12-15 09:00:21 +0000512 */
513static RiSym *prefersym(RiSym *a, RiSym *b)
514{
sewardjb5f6f512005-03-10 23:59:00 +0000515 Int lena, lenb; /* full length */
516 Int vlena, vlenb; /* length without version */
517 const Char *vpa, *vpb;
fitzhardingeefda47f2003-12-15 23:31:52 +0000518
sewardjb5f6f512005-03-10 23:59:00 +0000519 vlena = lena = VG_(strlen)(a->name);
520 vlenb = lenb = VG_(strlen)(b->name);
fitzhardinge1c76dc42003-12-15 09:00:21 +0000521
sewardjb5f6f512005-03-10 23:59:00 +0000522 vpa = VG_(strchr)(a->name, '@');
523 vpb = VG_(strchr)(b->name, '@');
fitzhardinge1c76dc42003-12-15 09:00:21 +0000524
sewardjb5f6f512005-03-10 23:59:00 +0000525 if (vpa)
526 vlena = vpa - a->name;
527 if (vpb)
528 vlenb = vpb - b->name;
fitzhardingeefda47f2003-12-15 23:31:52 +0000529
njn16eeb4e2005-06-16 03:56:58 +0000530 TRACE_SYMTAB("choosing between '%s' and '%s'\n", a->name, b->name);
531
sewardjb5f6f512005-03-10 23:59:00 +0000532 /* Select the shortest unversioned name */
533 if (vlena < vlenb)
534 return a;
535 else if (vlenb < vlena)
fitzhardinge1c76dc42003-12-15 09:00:21 +0000536 return b;
537
sewardjb5f6f512005-03-10 23:59:00 +0000538 /* Equal lengths; select the versioned name */
539 if (vpa && !vpb)
540 return a;
541 if (vpb && !vpa)
542 return b;
543
544 /* Either both versioned or neither is versioned; select them
545 alphabetically */
546 if (VG_(strcmp)(a->name, b->name) < 0)
547 return a;
548 else
549 return b;
fitzhardinge1c76dc42003-12-15 09:00:21 +0000550}
551
sewardjde4a1d02002-03-22 01:27:54 +0000552static
553void canonicaliseSymtab ( SegInfo* si )
554{
jsgfcb1d1c02003-10-14 21:55:10 +0000555 Int i, j, n_merged, n_truncated;
sewardjde4a1d02002-03-22 01:27:54 +0000556 Addr s1, s2, e1, e2;
557
558# define SWAP(ty,aa,bb) \
559 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
560
jsgfcb1d1c02003-10-14 21:55:10 +0000561 if (si->symtab_used == 0)
562 return;
sewardjde4a1d02002-03-22 01:27:54 +0000563
nethercote3acbb5d2003-11-13 21:50:45 +0000564 VG_(ssort)(si->symtab, si->symtab_used, sizeof(*si->symtab), compare_RiSym);
sewardjde4a1d02002-03-22 01:27:54 +0000565
566 cleanup_more:
567
njn16eeb4e2005-06-16 03:56:58 +0000568 /* If two symbols have identical address ranges, we pick one
569 using prefersym() (see it for details). */
sewardjde4a1d02002-03-22 01:27:54 +0000570 do {
571 n_merged = 0;
572 j = si->symtab_used;
573 si->symtab_used = 0;
574 for (i = 0; i < j; i++) {
575 if (i < j-1
576 && si->symtab[i].addr == si->symtab[i+1].addr
577 && si->symtab[i].size == si->symtab[i+1].size) {
578 n_merged++;
579 /* merge the two into one */
fitzhardinge1c76dc42003-12-15 09:00:21 +0000580 si->symtab[si->symtab_used++] = *prefersym(&si->symtab[i], &si->symtab[i+1]);
sewardjde4a1d02002-03-22 01:27:54 +0000581 i++;
582 } else {
583 si->symtab[si->symtab_used++] = si->symtab[i];
584 }
585 }
nethercote80f76782003-11-13 22:34:00 +0000586 TRACE_SYMTAB( "%d merged\n", n_merged);
sewardjde4a1d02002-03-22 01:27:54 +0000587 }
588 while (n_merged > 0);
589
590 /* Detect and "fix" overlapping address ranges. */
591 n_truncated = 0;
592
sewardj05bcdcb2003-05-18 10:05:38 +0000593 for (i = 0; i < ((Int)si->symtab_used) -1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000594
595 vg_assert(si->symtab[i].addr <= si->symtab[i+1].addr);
596
597 /* Check for common (no overlap) case. */
598 if (si->symtab[i].addr + si->symtab[i].size
599 <= si->symtab[i+1].addr)
600 continue;
601
602 /* There's an overlap. Truncate one or the other. */
603 if (VG_(clo_trace_symtab)) {
604 VG_(printf)("overlapping address ranges in symbol table\n\t");
605 printSym(si,i);
606 VG_(printf)("\t");
607 printSym(si,i+1);
608 VG_(printf)("\n");
609 }
610
611 /* Truncate one or the other. */
612 s1 = si->symtab[i].addr;
613 s2 = si->symtab[i+1].addr;
614 e1 = s1 + si->symtab[i].size - 1;
615 e2 = s2 + si->symtab[i+1].size - 1;
616 if (s1 < s2) {
617 e1 = s2-1;
618 } else {
619 vg_assert(s1 == s2);
620 if (e1 > e2) {
621 s1 = e2+1; SWAP(Addr,s1,s2); SWAP(Addr,e1,e2);
622 } else
623 if (e1 < e2) {
624 s2 = e1+1;
625 } else {
626 /* e1 == e2. Identical addr ranges. We'll eventually wind
627 up back at cleanup_more, which will take care of it. */
628 }
629 }
630 si->symtab[i].addr = s1;
631 si->symtab[i+1].addr = s2;
632 si->symtab[i].size = e1 - s1 + 1;
633 si->symtab[i+1].size = e2 - s2 + 1;
634 vg_assert(s1 <= s2);
635 vg_assert(si->symtab[i].size > 0);
636 vg_assert(si->symtab[i+1].size > 0);
637 /* It may be that the i+1 entry now needs to be moved further
638 along to maintain the address order requirement. */
639 j = i+1;
sewardj05bcdcb2003-05-18 10:05:38 +0000640 while (j < ((Int)si->symtab_used)-1
sewardjde4a1d02002-03-22 01:27:54 +0000641 && si->symtab[j].addr > si->symtab[j+1].addr) {
642 SWAP(RiSym,si->symtab[j],si->symtab[j+1]);
643 j++;
644 }
645 n_truncated++;
646 }
647
648 if (n_truncated > 0) goto cleanup_more;
649
650 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000651 for (i = 0; i < ((Int)si->symtab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000652 /* No zero-sized symbols. */
653 vg_assert(si->symtab[i].size > 0);
654 /* In order. */
655 vg_assert(si->symtab[i].addr < si->symtab[i+1].addr);
656 /* No overlaps. */
657 vg_assert(si->symtab[i].addr + si->symtab[i].size - 1
658 < si->symtab[i+1].addr);
659 }
660# undef SWAP
661}
662
jsgfcb1d1c02003-10-14 21:55:10 +0000663/* Sort the scope range table by starting address. Mash the table
664 around so as to establish the property that addresses are in order
665 and the ranges do not overlap. This facilitates using binary
666 search to map addresses to scopes when we come to query the
667 table.
668*/
669static Int compare_ScopeRange(void *va, void *vb) {
670 ScopeRange *a = (ScopeRange *)va;
671 ScopeRange *b = (ScopeRange *)vb;
672
nethercote05fdfac2004-08-01 20:24:46 +0000673 if (a->addr < b->addr) return -1;
674 if (a->addr > b->addr) return 1;
675 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000676}
677
678static
679void canonicaliseScopetab ( SegInfo* si )
680{
681 Int i,j;
682
683 if (si->scopetab_used == 0)
684 return;
685
686 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000687 VG_(ssort)(si->scopetab, si->scopetab_used, sizeof(*si->scopetab),
688 compare_ScopeRange);
jsgfcb1d1c02003-10-14 21:55:10 +0000689
690 /* If two adjacent entries overlap, truncate the first. */
691 for (i = 0; i < si->scopetab_used-1; i++) {
692 if (si->scopetab[i].addr + si->scopetab[i].size > si->scopetab[i+1].addr) {
693 Int new_size = si->scopetab[i+1].addr - si->scopetab[i].addr;
694
695 if (new_size < 0)
696 si->scopetab[i].size = 0;
697 else
698 si->scopetab[i].size = new_size;
699 }
700 }
701
702 /* Zap any zero-sized entries resulting from the truncation
703 process. */
704 j = 0;
705 for (i = 0; i < si->scopetab_used; i++) {
706 if (si->scopetab[i].size > 0) {
707 si->scopetab[j] = si->scopetab[i];
708 j++;
709 }
710 }
711 si->scopetab_used = j;
712
713 /* Ensure relevant postconditions hold. */
714 for (i = 0; i < si->scopetab_used-1; i++) {
715 /*
716 VG_(printf)("%d (%d) %d 0x%x\n",
717 i, si->scopetab[i+1].confident,
718 si->scopetab[i+1].size, si->scopetab[i+1].addr );
719 */
720 /* No zero-sized symbols. */
721 vg_assert(si->scopetab[i].size > 0);
722 /* In order. */
723 if (si->scopetab[i].addr >= si->scopetab[i+1].addr)
724 VG_(printf)("si->scopetab[%d] = %p,size=%d [%d] = %p,size=%d\n",
725 i, si->scopetab[i].addr, si->scopetab[i].size,
726 i+1, si->scopetab[i+1].addr, si->scopetab[i+1].size);
727 vg_assert(si->scopetab[i].addr < si->scopetab[i+1].addr);
728 /* No overlaps. */
729 vg_assert(si->scopetab[i].addr + si->scopetab[i].size - 1
730 < si->scopetab[i+1].addr);
731 }
732}
sewardjde4a1d02002-03-22 01:27:54 +0000733
734
735/* Sort the location table by starting address. Mash the table around
736 so as to establish the property that addresses are in order and the
737 ranges do not overlap. This facilitates using binary search to map
sewardjb51f2e62002-06-01 23:11:19 +0000738 addresses to locations when we come to query the table.
739*/
jsgfcb1d1c02003-10-14 21:55:10 +0000740static Int compare_RiLoc(void *va, void *vb) {
741 RiLoc *a = (RiLoc *)va;
742 RiLoc *b = (RiLoc *)vb;
743
nethercote05fdfac2004-08-01 20:24:46 +0000744 if (a->addr < b->addr) return -1;
745 if (a->addr > b->addr) return 1;
746 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000747}
748
sewardjde4a1d02002-03-22 01:27:54 +0000749static
750void canonicaliseLoctab ( SegInfo* si )
751{
njn16eeb4e2005-06-16 03:56:58 +0000752 Int i, j;
sewardjde4a1d02002-03-22 01:27:54 +0000753
754# define SWAP(ty,aa,bb) \
755 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
756
jsgfcb1d1c02003-10-14 21:55:10 +0000757 if (si->loctab_used == 0)
758 return;
759
sewardjde4a1d02002-03-22 01:27:54 +0000760 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000761 VG_(ssort)(si->loctab, si->loctab_used, sizeof(*si->loctab), compare_RiLoc);
sewardjde4a1d02002-03-22 01:27:54 +0000762
763 /* If two adjacent entries overlap, truncate the first. */
sewardj05bcdcb2003-05-18 10:05:38 +0000764 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000765 vg_assert(si->loctab[i].size < 10000);
766 if (si->loctab[i].addr + si->loctab[i].size > si->loctab[i+1].addr) {
767 /* Do this in signed int32 because the actual .size fields
njna1685902005-03-16 04:09:21 +0000768 are only 12 bits. */
sewardjde4a1d02002-03-22 01:27:54 +0000769 Int new_size = si->loctab[i+1].addr - si->loctab[i].addr;
770 if (new_size < 0) {
771 si->loctab[i].size = 0;
772 } else
njna1685902005-03-16 04:09:21 +0000773 if (new_size > MAX_LOC_SIZE) {
774 si->loctab[i].size = MAX_LOC_SIZE;
sewardjde4a1d02002-03-22 01:27:54 +0000775 } else {
776 si->loctab[i].size = (UShort)new_size;
777 }
778 }
779 }
780
781 /* Zap any zero-sized entries resulting from the truncation
782 process. */
783 j = 0;
sewardj05bcdcb2003-05-18 10:05:38 +0000784 for (i = 0; i < (Int)si->loctab_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000785 if (si->loctab[i].size > 0) {
786 si->loctab[j] = si->loctab[i];
787 j++;
788 }
789 }
790 si->loctab_used = j;
791
792 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000793 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000794 /*
795 VG_(printf)("%d (%d) %d 0x%x\n",
796 i, si->loctab[i+1].confident,
797 si->loctab[i+1].size, si->loctab[i+1].addr );
798 */
799 /* No zero-sized symbols. */
800 vg_assert(si->loctab[i].size > 0);
801 /* In order. */
802 vg_assert(si->loctab[i].addr < si->loctab[i+1].addr);
803 /* No overlaps. */
804 vg_assert(si->loctab[i].addr + si->loctab[i].size - 1
805 < si->loctab[i+1].addr);
806 }
807# undef SWAP
808}
809
810
sewardj3a1c7db2005-05-02 09:43:44 +0000811/* Sort the call-frame-info table by starting address. Mash the table
812 around so as to establish the property that addresses are in order
813 and the ranges do not overlap. This facilitates using binary
814 search to map addresses to locations when we come to query the
815 table.
816
817 Also, set cfisi_minaddr and cfisi_maxaddr to be the min and max of
818 any of the address ranges contained in cfisi[0 .. cfisi_used-1], so
819 as to facilitate rapidly skipping this SegInfo when looking for an
820 address which falls outside that range.
821*/
822static Int compare_CfiSI(void *va, void *vb) {
823 CfiSI *a = (CfiSI*)va;
824 CfiSI *b = (CfiSI*)vb;
825
826 if (a->base < b->base) return -1;
827 if (a->base > b->base) return 1;
828 return 0;
829}
830
sewardjbf603752005-05-02 00:36:27 +0000831static
832void canonicaliseCfiSI ( SegInfo* si )
833{
834 Int i;
835 const Addr minAddr = 0;
836 const Addr maxAddr = ~minAddr;
837
838 /* Set cfisi_minaddr and cfisi_maxaddr to summarise the entire
839 address range contained in cfisi[0 .. cfisi_used-1]. */
840 si->cfisi_minaddr = maxAddr;
841 si->cfisi_maxaddr = minAddr;
842 for (i = 0; i < si->cfisi_used; i++) {
843 Addr here_min = si->cfisi[i].base;
844 Addr here_max = si->cfisi[i].base + si->cfisi[i].len - 1;
845 if (here_min < si->cfisi_minaddr)
846 si->cfisi_minaddr = here_min;
847 if (here_max > si->cfisi_maxaddr)
848 si->cfisi_maxaddr = here_max;
849 }
sewardj520e3492005-05-02 10:39:16 +0000850
851 if (VG_(clo_trace_cfi))
852 VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n",
853 si->cfisi_used,
854 si->cfisi_minaddr, si->cfisi_maxaddr);
sewardj3a1c7db2005-05-02 09:43:44 +0000855
856 /* Sort the cfisi array by base address. */
857 VG_(ssort)(si->cfisi, si->cfisi_used, sizeof(*si->cfisi), compare_CfiSI);
858
859 /* Ensure relevant postconditions hold. */
860 for (i = 0; i < si->cfisi_used; i++) {
861 /* No zero-length ranges. */
862 vg_assert(si->cfisi[i].len > 0);
863 /* Makes sense w.r.t. summary address range */
864 vg_assert(si->cfisi[i].base >= si->cfisi_minaddr);
865 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
866 <= si->cfisi_maxaddr);
867
868 if (i < si->cfisi_used - 1) {
sewardjc4f204f2005-05-03 15:23:00 +0000869 /*
870 if (!(si->cfisi[i].base < si->cfisi[i+1].base)) {
871 VG_(printf)("\nOOO cfisis:\n");
872 VG_(ppCfiSI)(&si->cfisi[i]);
873 VG_(ppCfiSI)(&si->cfisi[i+1]);
874 }
875 */
sewardj3a1c7db2005-05-02 09:43:44 +0000876 /* In order. */
877 vg_assert(si->cfisi[i].base < si->cfisi[i+1].base);
878 /* No overlaps. */
879 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
880 < si->cfisi[i+1].base);
881 }
882 }
883
sewardjbf603752005-05-02 00:36:27 +0000884}
885
886
sewardjde4a1d02002-03-22 01:27:54 +0000887/*------------------------------------------------------------*/
sewardjb51f2e62002-06-01 23:11:19 +0000888/*--- Read info from a .so/exe file. ---*/
889/*------------------------------------------------------------*/
890
fitzhardinge98abfc72003-12-16 02:05:15 +0000891Bool VG_(is_object_file)(const void *buf)
892{
893 {
sewardj7a21c612005-02-18 09:38:08 +0000894 ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf;
fitzhardinge98abfc72003-12-16 02:05:15 +0000895 Int ok = 1;
896
897 ok &= (ehdr->e_ident[EI_MAG0] == 0x7F
898 && ehdr->e_ident[EI_MAG1] == 'E'
899 && ehdr->e_ident[EI_MAG2] == 'L'
900 && ehdr->e_ident[EI_MAG3] == 'F');
njn35172bc2005-03-26 00:04:03 +0000901 ok &= (ehdr->e_ident[EI_CLASS] == VGA_ELF_CLASS
902 && ehdr->e_ident[EI_DATA] == VGA_ELF_ENDIANNESS
fitzhardinge98abfc72003-12-16 02:05:15 +0000903 && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
904 ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN);
njn35172bc2005-03-26 00:04:03 +0000905 ok &= (ehdr->e_machine == VGA_ELF_MACHINE);
fitzhardinge98abfc72003-12-16 02:05:15 +0000906 ok &= (ehdr->e_version == EV_CURRENT);
907 ok &= (ehdr->e_shstrndx != SHN_UNDEF);
908 ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0);
909 ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0);
910
911 if (ok)
912 return True;
913 }
914
915 /* other file formats here? */
916
917 return False;
918}
919
njn16eeb4e2005-06-16 03:56:58 +0000920static Bool is_interesting_symbol(SegInfo* si, ElfXX_Sym* sym,
921 Char* sym_name, Addr sym_addr)
rjwalshe4e779d2004-04-16 23:02:29 +0000922{
njn16eeb4e2005-06-16 03:56:58 +0000923 /* Figure out if we're interested in the symbol.
924 Firstly, is it of the right flavour? */
925 if ( ! ( (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL ||
926 ELFXX_ST_BIND(sym->st_info) == STB_LOCAL ||
927 ELFXX_ST_BIND(sym->st_info) == STB_WEAK)
928 &&
929 (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC ||
930 (VG_(needs).data_syms
931 && ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT))
932 )
933 )
934 return False;
rjwalshe4e779d2004-04-16 23:02:29 +0000935
njn16eeb4e2005-06-16 03:56:58 +0000936 /* Secondly, if it's apparently in a GOT or PLT, it's really
937 a reference to a symbol defined elsewhere, so ignore it. */
938 if (si->got_start != 0
939 && sym_addr >= si->got_start
940 && sym_addr < si->got_start + si->got_size) {
941 TRACE_SYMTAB("ignore -- in GOT: %s\n", sym_name);
942 return False;
rjwalshe4e779d2004-04-16 23:02:29 +0000943 }
njn16eeb4e2005-06-16 03:56:58 +0000944 if (si->plt_start != 0
945 && sym_addr >= si->plt_start
946 && sym_addr < si->plt_start + si->plt_size) {
947 TRACE_SYMTAB("ignore -- in PLT: %s\n", sym_name);
sewardj9ee81f52005-04-02 17:38:59 +0000948 return False;
949 }
950
njn16eeb4e2005-06-16 03:56:58 +0000951 /* Don't bother if nameless, or zero-sized. */
952 if (sym->st_name == (ElfXX_Word)NULL
953 || /* VG_(strlen)(sym_name) == 0 */
954 /* equivalent but cheaper ... */
955 sym_name[0] == 0
956 || sym->st_size == 0) {
957 TRACE_SYMTAB("ignore -- size=0: %s\n", sym_name);
958 return False;
sewardj9ee81f52005-04-02 17:38:59 +0000959 }
960
njn16eeb4e2005-06-16 03:56:58 +0000961 /* This seems to significantly reduce the number of junk
962 symbols, and particularly reduces the number of
963 overlapping address ranges. Don't ask me why ... */
964 if ((Int)sym->st_value == 0) {
965 TRACE_SYMTAB( "ignore -- valu=0: %s\n", sym_name);
966 return False;
967 }
968
969 /* If no part of the symbol falls within the mapped range,
970 ignore it. */
971 if (sym_addr+sym->st_size <= si->start
972 || sym_addr >= si->start+si->size) {
973 TRACE_SYMTAB( "ignore -- outside mapped range\n" );
974 return False;
975 }
976
977 // It is an interesting symbol!
rjwalshe4e779d2004-04-16 23:02:29 +0000978 return True;
979}
980
nethercote80f76782003-11-13 22:34:00 +0000981/* Read a symbol table (normal or dynamic) */
982static
rjwalshe4e779d2004-04-16 23:02:29 +0000983void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts,
sewardj7a21c612005-02-18 09:38:08 +0000984 ElfXX_Sym* o_symtab, UInt o_symtab_sz,
nethercote80f76782003-11-13 22:34:00 +0000985 UChar* o_strtab, UInt o_strtab_sz )
986{
987 Int i;
988 Addr sym_addr;
njn16eeb4e2005-06-16 03:56:58 +0000989 Char* sym_name;
nethercote80f76782003-11-13 22:34:00 +0000990 RiSym risym;
mueller82df83e2003-11-19 22:05:35 +0000991 Char* name;
njn16eeb4e2005-06-16 03:56:58 +0000992 ElfXX_Sym* sym;
mueller82df83e2003-11-19 22:05:35 +0000993
nethercote80f76782003-11-13 22:34:00 +0000994 if (o_strtab == NULL || o_symtab == NULL) {
jseward0edbfb52003-12-12 06:22:06 +0000995 Char buf[80];
996 vg_assert(VG_(strlen)(tab_name) < 40);
997 VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
998 VG_(symerr)(buf);
nethercote80f76782003-11-13 22:34:00 +0000999 return;
1000 }
1001
1002 TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name,
sewardj7a21c612005-02-18 09:38:08 +00001003 o_symtab_sz/sizeof(ElfXX_Sym) );
nethercote80f76782003-11-13 22:34:00 +00001004
1005 /* Perhaps should start at i = 1; ELF docs suggest that entry
njn02bc4b82005-05-15 17:28:26 +00001006 0 always denotes 'unknown symbol'. */
sewardj7a21c612005-02-18 09:38:08 +00001007 for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) {
njn16eeb4e2005-06-16 03:56:58 +00001008 sym = & o_symtab[i];
1009 sym_name = (Char*)(o_strtab + sym->st_name);
tomf26d0682005-04-02 14:57:43 +00001010 sym_addr = si->offset + sym->st_value;
nethercote80f76782003-11-13 22:34:00 +00001011
1012 if (VG_(clo_trace_symtab)) {
1013 VG_(printf)("raw symbol [%d]: ", i);
sewardj7a21c612005-02-18 09:38:08 +00001014 switch (ELFXX_ST_BIND(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001015 case STB_LOCAL: VG_(printf)("LOC "); break;
1016 case STB_GLOBAL: VG_(printf)("GLO "); break;
1017 case STB_WEAK: VG_(printf)("WEA "); break;
1018 case STB_LOPROC: VG_(printf)("lop "); break;
1019 case STB_HIPROC: VG_(printf)("hip "); break;
1020 default: VG_(printf)("??? "); break;
1021 }
sewardj7a21c612005-02-18 09:38:08 +00001022 switch (ELFXX_ST_TYPE(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001023 case STT_NOTYPE: VG_(printf)("NOT "); break;
1024 case STT_OBJECT: VG_(printf)("OBJ "); break;
1025 case STT_FUNC: VG_(printf)("FUN "); break;
1026 case STT_SECTION: VG_(printf)("SEC "); break;
1027 case STT_FILE: VG_(printf)("FIL "); break;
1028 case STT_LOPROC: VG_(printf)("lop "); break;
1029 case STT_HIPROC: VG_(printf)("hip "); break;
1030 default: VG_(printf)("??? "); break;
1031 }
1032 VG_(printf)(
1033 ": value %p, size %d, name %s\n",
1034 sym_addr, sym->st_size,
njn16eeb4e2005-06-16 03:56:58 +00001035 ( sym->st_name ? sym_name : (Char*)"NONAME" ) );
nethercote80f76782003-11-13 22:34:00 +00001036 }
nethercote80f76782003-11-13 22:34:00 +00001037
njn16eeb4e2005-06-16 03:56:58 +00001038 // Record interesting symbols in our symtab.
1039 if ( is_interesting_symbol(si, sym, sym_name, sym_addr) ) {
1040 vg_assert(sym->st_name != 0);
1041 vg_assert(sym_name[0] != 0);
1042 name = VG_(addStr) ( si, sym_name, -1 );
1043 vg_assert(name != NULL);
1044
1045 /*
1046 * Is this symbol a magic valgrind-intercept symbol? If so,
1047 * hand this off to the redir module.
1048 *
1049 * Note: this function can change the symbol name just added to
1050 * the string table. Importantly, it never makes it bigger.
1051 */
1052 if (do_intercepts) {
1053 VG_(maybe_redir_or_notify)( name, sym_addr );
1054 }
1055
1056 risym.addr = sym_addr;
1057 risym.size = sym->st_size;
1058 risym.name = name;
1059 addSym ( si, &risym );
rjwalshe4e779d2004-04-16 23:02:29 +00001060 }
nethercote80f76782003-11-13 22:34:00 +00001061 }
1062}
1063
thughesc035bd92004-06-13 09:59:02 +00001064/*
1065 * This routine for calculating the CRC for a separate debug file
1066 * is GPLed code borrowed from binutils.
1067 */
1068static UInt
1069calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
1070{
1071 static const UInt crc32_table[256] =
1072 {
1073 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
1074 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
1075 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
1076 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1077 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
1078 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1079 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
1080 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1081 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1082 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
1083 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
1084 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1085 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
1086 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
1087 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
1088 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1089 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
1090 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1091 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
1092 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1093 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
1094 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
1095 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
1096 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1097 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
1098 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
1099 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1100 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1101 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1102 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1103 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1104 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1105 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1106 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1107 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1108 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1109 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1110 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1111 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1112 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1113 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1114 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1115 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1116 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1117 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1118 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1119 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1120 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1121 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1122 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1123 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1124 0x2d02ef8d
1125 };
1126 const UChar *end;
1127
1128 crc = ~crc & 0xffffffff;
1129 for (end = buf + len; buf < end; ++ buf)
1130 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
1131 return ~crc & 0xffffffff;;
1132}
1133
1134/*
1135 * Try and open a separate debug file, ignoring any where the CRC does
1136 * not match the value from the main object file.
1137 */
1138static
1139Addr open_debug_file( Char* name, UInt crc, UInt* size )
1140{
1141 Int fd;
1142 struct vki_stat stat_buf;
1143 Addr addr;
sewardjb5f6f512005-03-10 23:59:00 +00001144 UInt calccrc;
thughesc035bd92004-06-13 09:59:02 +00001145
1146 if ((fd = VG_(open)(name, VKI_O_RDONLY, 0)) < 0)
1147 return 0;
1148
1149 if (VG_(fstat)(fd, &stat_buf) != 0) {
1150 VG_(close)(fd);
1151 return 0;
1152 }
1153
sewardjb5f6f512005-03-10 23:59:00 +00001154 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001155 VG_(message)(Vg_DebugMsg, "Reading debug info from %s...", name);
sewardjb5f6f512005-03-10 23:59:00 +00001156
thughesc035bd92004-06-13 09:59:02 +00001157 *size = stat_buf.st_size;
1158
1159 if ((addr = (Addr)VG_(mmap)(NULL, *size, VKI_PROT_READ,
nethercoteb4250ae2004-07-10 16:50:09 +00001160 VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1161 0, fd, 0)) == (Addr)-1)
1162 {
thughesc035bd92004-06-13 09:59:02 +00001163 VG_(close)(fd);
1164 return 0;
1165 }
1166
1167 VG_(close)(fd);
1168
sewardjb5f6f512005-03-10 23:59:00 +00001169 calccrc = calc_gnu_debuglink_crc32(0, (UChar*)addr, *size);
1170 if (calccrc != crc) {
nethercotee567e702004-07-10 17:49:17 +00001171 int res = VG_(munmap)((void*)addr, *size);
1172 vg_assert(0 == res);
sewardjb5f6f512005-03-10 23:59:00 +00001173 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001174 VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc);
thughesc035bd92004-06-13 09:59:02 +00001175 return 0;
1176 }
1177
1178 return addr;
1179}
1180
1181/*
nethercoteb1e1ad42004-08-03 23:44:12 +00001182 * Try to find a separate debug file for a given object file.
thughesc035bd92004-06-13 09:59:02 +00001183 */
1184static
1185Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size )
1186{
sewardjb5f6f512005-03-10 23:59:00 +00001187 Char *objdir = VG_(arena_strdup)(VG_AR_SYMTAB, objpath);
thughesc035bd92004-06-13 09:59:02 +00001188 Char *objdirptr;
1189 Char *debugpath;
1190 Addr addr = 0;
1191
1192 if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
1193 *objdirptr = '\0';
1194
sewardjb5f6f512005-03-10 23:59:00 +00001195 debugpath = VG_(arena_malloc)(VG_AR_SYMTAB, VG_(strlen)(objdir) + VG_(strlen)(debugname) + 16);
thughesc035bd92004-06-13 09:59:02 +00001196
1197 VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
1198
1199 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1200 VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
1201 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1202 VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
1203 addr = open_debug_file(debugpath, crc, size);
1204 }
1205 }
1206
sewardjb5f6f512005-03-10 23:59:00 +00001207 VG_(arena_free)(VG_AR_SYMTAB, debugpath);
1208 VG_(arena_free)(VG_AR_SYMTAB, objdir);
thughesc035bd92004-06-13 09:59:02 +00001209
1210 return addr;
1211}
nethercote80f76782003-11-13 22:34:00 +00001212
sewardjde4a1d02002-03-22 01:27:54 +00001213/* Read the symbols from the object/exe specified by the SegInfo into
1214 the tables within the supplied SegInfo. */
1215static
njn695c16e2005-03-27 03:40:28 +00001216Bool read_lib_symbols ( SegInfo* si )
sewardjde4a1d02002-03-22 01:27:54 +00001217{
nethercote80f76782003-11-13 22:34:00 +00001218 Bool res;
sewardj7a21c612005-02-18 09:38:08 +00001219 ElfXX_Ehdr* ehdr; /* The ELF header */
1220 ElfXX_Shdr* shdr; /* The section table */
sewardjde4a1d02002-03-22 01:27:54 +00001221 UChar* sh_strtab; /* The section table's string table */
sewardjde4a1d02002-03-22 01:27:54 +00001222 Int fd;
1223 Int i;
1224 Bool ok;
1225 Addr oimage;
sewardj05bcdcb2003-05-18 10:05:38 +00001226 UInt n_oimage;
thughesc035bd92004-06-13 09:59:02 +00001227 Addr dimage = 0;
1228 UInt n_dimage = 0;
sewardjb3586202002-05-09 17:38:13 +00001229 struct vki_stat stat_buf;
sewardjde4a1d02002-03-22 01:27:54 +00001230
sewardjde4a1d02002-03-22 01:27:54 +00001231 oimage = (Addr)NULL;
1232 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001233 VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", si->filename, si->start );
sewardjde4a1d02002-03-22 01:27:54 +00001234
1235 /* mmap the object image aboard, so that we can read symbols and
1236 line number info out of it. It will be munmapped immediately
1237 thereafter; it is only aboard transiently. */
1238
sewardjb3586202002-05-09 17:38:13 +00001239 i = VG_(stat)(si->filename, &stat_buf);
sewardjde4a1d02002-03-22 01:27:54 +00001240 if (i != 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001241 VG_(symerr)("Can't stat .so/.exe (to determine its size)?!");
sewardj8fe15a32002-10-20 19:29:21 +00001242 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001243 }
1244 n_oimage = stat_buf.st_size;
1245
njn25e49d8e72002-09-23 09:36:25 +00001246 fd = VG_(open)(si->filename, VKI_O_RDONLY, 0);
jsgff3c3f1a2003-10-14 22:13:28 +00001247 if (fd < 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00001248 VG_(symerr)("Can't open .so/.exe to read symbols?!");
sewardj8fe15a32002-10-20 19:29:21 +00001249 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001250 }
1251
sewardjb3586202002-05-09 17:38:13 +00001252 oimage = (Addr)VG_(mmap)( NULL, n_oimage,
nethercoteb4250ae2004-07-10 16:50:09 +00001253 VKI_PROT_READ, VKI_MAP_PRIVATE|VKI_MAP_NOSYMS,
1254 0, fd, 0 );
fitzhardinge98abfc72003-12-16 02:05:15 +00001255
nethercote80f76782003-11-13 22:34:00 +00001256 VG_(close)(fd);
1257
sewardjde4a1d02002-03-22 01:27:54 +00001258 if (oimage == ((Addr)(-1))) {
njn1fd5eb22005-03-13 05:43:23 +00001259 VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename );
1260 VG_(message)(Vg_UserMsg, " no symbols or debug info loaded" );
sewardj8fe15a32002-10-20 19:29:21 +00001261 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001262 }
1263
sewardjde4a1d02002-03-22 01:27:54 +00001264 /* Ok, the object image is safely in oimage[0 .. n_oimage-1].
1265 Now verify that it is a valid ELF .so or executable image.
1266 */
nethercote80f76782003-11-13 22:34:00 +00001267 res = False;
sewardj7a21c612005-02-18 09:38:08 +00001268 ok = (n_oimage >= sizeof(ElfXX_Ehdr));
1269 ehdr = (ElfXX_Ehdr*)oimage;
sewardjde4a1d02002-03-22 01:27:54 +00001270
fitzhardinge98abfc72003-12-16 02:05:15 +00001271 if (ok)
1272 ok &= VG_(is_object_file)(ehdr);
sewardjde4a1d02002-03-22 01:27:54 +00001273
1274 if (!ok) {
jsgfcb1d1c02003-10-14 21:55:10 +00001275 VG_(symerr)("Invalid ELF header, or missing stringtab/sectiontab.");
nethercote80f76782003-11-13 22:34:00 +00001276 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001277 }
1278
1279 /* Walk the LOAD headers in the phdr and update the SegInfo to
1280 include them all, so that this segment also contains data and
1281 bss memory. Also computes correct symbol offset value for this
1282 ELF file. */
sewardj7a21c612005-02-18 09:38:08 +00001283 if (ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001284 VG_(symerr)("ELF program header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001285 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001286 }
1287 {
1288 Bool offset_set = False;
sewardj7a21c612005-02-18 09:38:08 +00001289 ElfXX_Addr prev_addr = 0;
fitzhardinge98abfc72003-12-16 02:05:15 +00001290 Addr baseaddr = 0;
sewardj8fe15a32002-10-20 19:29:21 +00001291
1292 si->offset = 0;
1293
nethercote80f76782003-11-13 22:34:00 +00001294 for (i = 0; i < ehdr->e_phnum; i++) {
sewardj7a21c612005-02-18 09:38:08 +00001295 ElfXX_Phdr *o_phdr;
1296 ElfXX_Addr mapped, mapped_end;
sewardj8fe15a32002-10-20 19:29:21 +00001297
sewardj7a21c612005-02-18 09:38:08 +00001298 o_phdr = &((ElfXX_Phdr *)(oimage + ehdr->e_phoff))[i];
sewardj8fe15a32002-10-20 19:29:21 +00001299
fitzhardinge98abfc72003-12-16 02:05:15 +00001300 if (o_phdr->p_type == PT_DYNAMIC && si->soname == NULL) {
sewardj7a21c612005-02-18 09:38:08 +00001301 const ElfXX_Dyn *dyn = (const ElfXX_Dyn *)(oimage + o_phdr->p_offset);
fitzhardinge98abfc72003-12-16 02:05:15 +00001302 Int stroff = -1;
1303 Char *strtab = NULL;
1304 Int j;
1305
1306 for(j = 0; dyn[j].d_tag != DT_NULL; j++) {
1307 switch(dyn[j].d_tag) {
1308 case DT_SONAME:
1309 stroff = dyn[j].d_un.d_val;
1310 break;
1311
1312 case DT_STRTAB:
1313 strtab = (Char *)oimage + dyn[j].d_un.d_ptr - baseaddr;
1314 break;
1315 }
1316 }
1317
1318 if (stroff != -1 && strtab != 0) {
1319 TRACE_SYMTAB("soname=%s\n", strtab+stroff);
1320 si->soname = VG_(arena_strdup)(VG_AR_SYMTAB, strtab+stroff);
1321 }
1322 }
1323
sewardj8fe15a32002-10-20 19:29:21 +00001324 if (o_phdr->p_type != PT_LOAD)
1325 continue;
1326
1327 if (!offset_set) {
1328 offset_set = True;
1329 si->offset = si->start - o_phdr->p_vaddr;
fitzhardinge98abfc72003-12-16 02:05:15 +00001330 baseaddr = o_phdr->p_vaddr;
sewardj8fe15a32002-10-20 19:29:21 +00001331 }
1332
1333 if (o_phdr->p_vaddr < prev_addr) {
jsgfcb1d1c02003-10-14 21:55:10 +00001334 VG_(symerr)("ELF Phdrs are out of order!?");
nethercote80f76782003-11-13 22:34:00 +00001335 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001336 }
1337 prev_addr = o_phdr->p_vaddr;
1338
1339 mapped = o_phdr->p_vaddr + si->offset;
1340 mapped_end = mapped + o_phdr->p_memsz;
1341
1342 if (si->data_start == 0 &&
1343 (o_phdr->p_flags & (PF_R|PF_W|PF_X)) == (PF_R|PF_W)) {
1344 si->data_start = mapped;
1345 si->data_size = o_phdr->p_filesz;
1346 si->bss_start = mapped + o_phdr->p_filesz;
1347 if (o_phdr->p_memsz > o_phdr->p_filesz)
1348 si->bss_size = o_phdr->p_memsz - o_phdr->p_filesz;
1349 else
1350 si->bss_size = 0;
1351 }
1352
nethercote73b526f2004-10-31 18:48:21 +00001353 mapped = mapped & ~(VKI_PAGE_SIZE-1);
1354 mapped_end = (mapped_end + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE-1);
sewardj8fe15a32002-10-20 19:29:21 +00001355
sewardj1024cf72005-02-28 14:39:21 +00001356#if 0
1357 /* 20050228: disabled this until VG_(next_segment) can be
1358 reinstated in some clean incarnation of the low level
1359 memory manager. */
sewardj8fe15a32002-10-20 19:29:21 +00001360 if (VG_(needs).data_syms &&
1361 (mapped >= si->start && mapped <= (si->start+si->size)) &&
1362 (mapped_end > (si->start+si->size))) {
1363 UInt newsz = mapped_end - si->start;
1364 if (newsz > si->size) {
fitzhardinge98abfc72003-12-16 02:05:15 +00001365 Segment *seg;
1366
sewardj8fe15a32002-10-20 19:29:21 +00001367 if (0)
1368 VG_(printf)("extending mapping %p..%p %d -> ..%p %d\n",
1369 si->start, si->start+si->size, si->size,
1370 si->start+newsz, newsz);
fitzhardinge98abfc72003-12-16 02:05:15 +00001371
sewardjb5f6f512005-03-10 23:59:00 +00001372 for(seg = VG_(find_segment_containing)(si->start);
fitzhardinge98abfc72003-12-16 02:05:15 +00001373 seg != NULL && VG_(seg_overlaps)(seg, si->start, si->size);
1374 seg = VG_(next_segment)(seg)) {
1375 if (seg->symtab == si)
1376 continue;
1377
1378 if (seg->symtab != NULL)
njn36ef6ba2005-05-14 18:42:26 +00001379 VG_(seginfo_decref)(seg->symtab, seg->addr);
fitzhardinge98abfc72003-12-16 02:05:15 +00001380
1381 VG_(symtab_incref)(si);
1382 seg->symtab = si;
1383
1384 if (0)
1385 VG_(printf)("adding symtab %p (%p-%p) to segment %p (%p-%p)\n",
1386 si, si->start, si->start+newsz,
1387 seg, seg->addr, seg->addr+seg->len);
1388 }
1389
sewardj8fe15a32002-10-20 19:29:21 +00001390 si->size = newsz;
1391 }
1392 }
sewardj1024cf72005-02-28 14:39:21 +00001393#endif
1394
sewardj8fe15a32002-10-20 19:29:21 +00001395 }
sewardjde4a1d02002-03-22 01:27:54 +00001396 }
1397
nethercote80f76782003-11-13 22:34:00 +00001398 TRACE_SYMTAB("shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n",
sewardj7a21c612005-02-18 09:38:08 +00001399 ehdr->e_shoff, ehdr->e_shnum, sizeof(ElfXX_Shdr), n_oimage );
sewardjde4a1d02002-03-22 01:27:54 +00001400
sewardj7a21c612005-02-18 09:38:08 +00001401 if (ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) > n_oimage) {
jsgfcb1d1c02003-10-14 21:55:10 +00001402 VG_(symerr)("ELF section header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001403 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001404 }
1405
sewardj7a21c612005-02-18 09:38:08 +00001406 shdr = (ElfXX_Shdr*)(oimage + ehdr->e_shoff);
sewardjde4a1d02002-03-22 01:27:54 +00001407 sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset);
1408
nethercote80f76782003-11-13 22:34:00 +00001409 /* Find interesting sections, read the symbol table(s), read any debug
1410 information */
sewardjde4a1d02002-03-22 01:27:54 +00001411 {
nethercote80f76782003-11-13 22:34:00 +00001412 /* Pointers to start of sections */
1413 UChar* o_strtab = NULL; /* .strtab */
sewardj7a21c612005-02-18 09:38:08 +00001414 ElfXX_Sym* o_symtab = NULL; /* .symtab */
nethercote80f76782003-11-13 22:34:00 +00001415 UChar* o_dynstr = NULL; /* .dynstr */
sewardj7a21c612005-02-18 09:38:08 +00001416 ElfXX_Sym* o_dynsym = NULL; /* .dynsym */
thughesc035bd92004-06-13 09:59:02 +00001417 Char* debuglink = NULL; /* .gnu_debuglink */
nethercote80f76782003-11-13 22:34:00 +00001418 UChar* stab = NULL; /* .stab (stabs) */
1419 UChar* stabstr = NULL; /* .stabstr (stabs) */
1420 UChar* debug_line = NULL; /* .debug_line (dwarf2) */
sewardj022bf2f2005-06-14 21:51:14 +00001421 UChar* debug_info = NULL; /* .debug_info (dwarf2) */
1422 UChar* debug_abbv = NULL; /* .debug_abbrev (dwarf2) */
1423 UChar* debug_str = NULL; /* .debug_str (dwarf2) */
jseward8b3131a2003-12-13 23:16:26 +00001424 UChar* dwarf1d = NULL; /* .debug (dwarf1) */
1425 UChar* dwarf1l = NULL; /* .line (dwarf1) */
sewardj5c638c22005-04-30 07:55:58 +00001426 UChar* ehframe = NULL; /* .eh_frame (dwarf2) */
sewardjde4a1d02002-03-22 01:27:54 +00001427
nethercote80f76782003-11-13 22:34:00 +00001428 /* Section sizes, in bytes */
1429 UInt o_strtab_sz = 0;
1430 UInt o_symtab_sz = 0;
1431 UInt o_dynstr_sz = 0;
1432 UInt o_dynsym_sz = 0;
thughesc035bd92004-06-13 09:59:02 +00001433 UInt debuglink_sz = 0;
nethercote80f76782003-11-13 22:34:00 +00001434 UInt stab_sz = 0;
1435 UInt stabstr_sz = 0;
1436 UInt debug_line_sz = 0;
sewardj022bf2f2005-06-14 21:51:14 +00001437 UInt debug_info_sz = 0;
1438 UInt debug_abbv_sz = 0;
1439 UInt debug_str_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001440 UInt dwarf1d_sz = 0;
1441 UInt dwarf1l_sz = 0;
sewardj5c638c22005-04-30 07:55:58 +00001442 UInt ehframe_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001443
tom2fd38902005-05-01 15:14:01 +00001444 /* Section virtual addresses */
1445 Addr dummy_addr = 0;
1446 Addr ehframe_addr = 0;
1447
jseward8b3131a2003-12-13 23:16:26 +00001448 Bool has_debuginfo = False;
sewardjde4a1d02002-03-22 01:27:54 +00001449
nethercote80f76782003-11-13 22:34:00 +00001450 /* Find all interesting sections */
sewardjde4a1d02002-03-22 01:27:54 +00001451 for (i = 0; i < ehdr->e_shnum; i++) {
tom2fd38902005-05-01 15:14:01 +00001452# define FIND(sec_name, sec_data, sec_size, sec_addr, in_exec, type) \
nethercote80f76782003-11-13 22:34:00 +00001453 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1454 if (0 != sec_data) \
1455 VG_(core_panic)("repeated section!\n"); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001456 if (in_exec) \
nethercote80f76782003-11-13 22:34:00 +00001457 sec_data = (type)(si->offset + shdr[i].sh_addr); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001458 else \
nethercote80f76782003-11-13 22:34:00 +00001459 sec_data = (type)(oimage + shdr[i].sh_offset); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001460 sec_size = shdr[i].sh_size; \
tom2fd38902005-05-01 15:14:01 +00001461 sec_addr = si->offset + shdr[i].sh_addr; \
nethercote80f76782003-11-13 22:34:00 +00001462 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1463 sec_name, sec_data, sec_data + sec_size - 1); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001464 if ( shdr[i].sh_offset + sec_size > n_oimage ) { \
nethercote80f76782003-11-13 22:34:00 +00001465 VG_(symerr)(" section beyond image end?!"); \
1466 goto out; \
1467 } \
sewardjde4a1d02002-03-22 01:27:54 +00001468 }
1469
nethercote80f76782003-11-13 22:34:00 +00001470 /* Nb: must find where .got and .plt sections will be in the
1471 * executable image, not in the object image transiently loaded. */
tom2fd38902005-05-01 15:14:01 +00001472 FIND(".dynsym", o_dynsym, o_dynsym_sz, dummy_addr, 0, ElfXX_Sym*)
1473 else FIND(".dynstr", o_dynstr, o_dynstr_sz, dummy_addr, 0, UChar*)
1474 else FIND(".symtab", o_symtab, o_symtab_sz, dummy_addr, 0, ElfXX_Sym*)
1475 else FIND(".strtab", o_strtab, o_strtab_sz, dummy_addr, 0, UChar*)
sewardjde4a1d02002-03-22 01:27:54 +00001476
tom2fd38902005-05-01 15:14:01 +00001477 else FIND(".gnu_debuglink", debuglink, debuglink_sz, dummy_addr, 0, Char*)
thughesc035bd92004-06-13 09:59:02 +00001478
tom2fd38902005-05-01 15:14:01 +00001479 else FIND(".stab", stab, stab_sz, dummy_addr, 0, UChar*)
1480 else FIND(".stabstr", stabstr, stabstr_sz, dummy_addr, 0, UChar*)
sewardj022bf2f2005-06-14 21:51:14 +00001481
tom2fd38902005-05-01 15:14:01 +00001482 else FIND(".debug_line", debug_line, debug_line_sz, dummy_addr, 0, UChar*)
sewardj022bf2f2005-06-14 21:51:14 +00001483 else FIND(".debug_info", debug_info, debug_info_sz, dummy_addr, 0, UChar*)
1484 else FIND(".debug_abbrev", debug_abbv, debug_abbv_sz, dummy_addr, 0, UChar*)
1485 else FIND(".debug_str", debug_str, debug_str_sz, dummy_addr, 0, UChar*)
1486
tom2fd38902005-05-01 15:14:01 +00001487 else FIND(".debug", dwarf1d, dwarf1d_sz, dummy_addr, 0, UChar*)
1488 else FIND(".line", dwarf1l, dwarf1l_sz, dummy_addr, 0, UChar*)
1489 else FIND(".eh_frame", ehframe, ehframe_sz, ehframe_addr, 0, UChar*)
nethercote80f76782003-11-13 22:34:00 +00001490
tom2fd38902005-05-01 15:14:01 +00001491 else FIND(".got", si->got_start, si->got_size, dummy_addr, 1, Addr)
1492 else FIND(".plt", si->plt_start, si->plt_size, dummy_addr, 1, Addr)
nethercote80f76782003-11-13 22:34:00 +00001493
jseward8b3131a2003-12-13 23:16:26 +00001494# undef FIND
sewardjde4a1d02002-03-22 01:27:54 +00001495 }
njn36ef6ba2005-05-14 18:42:26 +00001496
1497 /* Check some sizes */
1498 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1499 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
sewardjde4a1d02002-03-22 01:27:54 +00001500
thughesc035bd92004-06-13 09:59:02 +00001501 /* Did we find a debuglink section? */
1502 if (debuglink != NULL) {
njn13bfd852005-06-02 03:52:53 +00001503 UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink)+1, 4);
thughesc035bd92004-06-13 09:59:02 +00001504 UInt crc;
1505
1506 vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
1507
1508 /* Extract the CRC from the debuglink section */
1509 crc = *(UInt *)(debuglink + crc_offset);
1510
1511 /* See if we can find a matching debug file */
1512 if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) {
sewardj7a21c612005-02-18 09:38:08 +00001513 ehdr = (ElfXX_Ehdr*)dimage;
thughesc035bd92004-06-13 09:59:02 +00001514
sewardj7a21c612005-02-18 09:38:08 +00001515 if (n_dimage >= sizeof(ElfXX_Ehdr) && VG_(is_object_file)(ehdr))
thughesc035bd92004-06-13 09:59:02 +00001516 {
sewardj7a21c612005-02-18 09:38:08 +00001517 shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff);
thughesc035bd92004-06-13 09:59:02 +00001518 sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset);
1519
1520 /* Find all interesting sections */
1521 for (i = 0; i < ehdr->e_shnum; i++) {
1522# define FIND(sec_name, sec_data, sec_size, type) \
1523 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
1524 if (0 != sec_data) \
1525 VG_(core_panic)("repeated section!\n"); \
1526 sec_data = (type)(dimage + shdr[i].sh_offset); \
1527 sec_size = shdr[i].sh_size; \
1528 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1529 sec_name, sec_data, sec_data + sec_size - 1); \
1530 if ( shdr[i].sh_offset + sec_size > n_dimage ) { \
1531 VG_(symerr)(" section beyond image end?!"); \
1532 goto out; \
1533 } \
1534 }
1535
1536 /* Nb: must find where .got and .plt sections will be in the
1537 * executable image, not in the object image transiently loaded. */
1538 FIND(".stab", stab, stab_sz, UChar*)
1539 else FIND(".stabstr", stabstr, stabstr_sz, UChar*)
1540 else FIND(".debug_line", debug_line, debug_line_sz, UChar*)
tome36cb5a2005-06-15 10:19:43 +00001541 else FIND(".debug_info", debug_info, debug_info_sz, UChar*)
1542 else FIND(".debug_abbrev", debug_abbv, debug_abbv_sz, UChar*)
1543 else FIND(".debug_str", debug_str, debug_str_sz, UChar*)
thughesc035bd92004-06-13 09:59:02 +00001544 else FIND(".debug", dwarf1d, dwarf1d_sz, UChar*)
1545 else FIND(".line", dwarf1l, dwarf1l_sz, UChar*)
1546
1547# undef FIND
thughesc035bd92004-06-13 09:59:02 +00001548 }
1549 }
1550 }
1551 }
1552
njnd54e4ec2005-05-15 03:38:53 +00001553 /* Read symbols */
1554 read_symtab(si, "symbol table", False,
1555 o_symtab, o_symtab_sz,
1556 o_strtab, o_strtab_sz);
1557
1558 read_symtab(si, "dynamic symbol table", True,
1559 o_dynsym, o_dynsym_sz,
1560 o_dynstr, o_dynstr_sz);
1561
sewardj5c638c22005-04-30 07:55:58 +00001562 /* Read .eh_frame (call-frame-info) if any */
sewardj55022aa2005-05-03 16:05:00 +00001563 if (ehframe) {
tom2fd38902005-05-01 15:14:01 +00001564 VG_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_addr );
sewardj5c638c22005-04-30 07:55:58 +00001565 }
1566
sewardje7aa4ae2005-06-09 12:43:42 +00001567 /* Read the stabs and/or dwarf2 debug information, if any. It
1568 appears reading stabs stuff on amd64-linux doesn't work, so
1569 we ignore it. */
1570# if !defined(VGP_amd64_linux)
nethercote80f76782003-11-13 22:34:00 +00001571 if (stab != NULL && stabstr != NULL) {
jseward8b3131a2003-12-13 23:16:26 +00001572 has_debuginfo = True;
1573 VG_(read_debuginfo_stabs) ( si, stab, stab_sz,
1574 stabstr, stabstr_sz );
1575 }
sewardje7aa4ae2005-06-09 12:43:42 +00001576# endif
tom6f917fd2005-03-30 15:05:46 +00001577 if (debug_line) {
jseward8b3131a2003-12-13 23:16:26 +00001578 has_debuginfo = True;
sewardj022bf2f2005-06-14 21:51:14 +00001579 VG_(read_debuginfo_dwarf2) ( si,
1580 debug_info, debug_info_sz,
1581 debug_abbv,
1582 debug_line, debug_line_sz,
1583 debug_str );
jseward8b3131a2003-12-13 23:16:26 +00001584 }
1585 if (dwarf1d && dwarf1l) {
1586 has_debuginfo = True;
1587 VG_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz,
1588 dwarf1l, dwarf1l_sz );
1589 }
1590 if (!has_debuginfo) {
sewardj5c638c22005-04-30 07:55:58 +00001591 VG_(symerr)(" object doesn't have any line number info");
nethercote80f76782003-11-13 22:34:00 +00001592 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001593 }
1594 }
nethercote80f76782003-11-13 22:34:00 +00001595 res = True;
sewardjde4a1d02002-03-22 01:27:54 +00001596
nethercotee567e702004-07-10 17:49:17 +00001597 out: {
1598 Int m_res;
thughesc035bd92004-06-13 09:59:02 +00001599 /* Last, but not least, heave the image(s) back overboard. */
nethercotee567e702004-07-10 17:49:17 +00001600 if (dimage) {
1601 m_res = VG_(munmap) ( (void*)dimage, n_dimage );
1602 vg_assert(0 == m_res);
1603 }
1604 m_res = VG_(munmap) ( (void*)oimage, n_oimage );
1605 vg_assert(0 == m_res);
nethercote80f76782003-11-13 22:34:00 +00001606 return res;
nethercotee567e702004-07-10 17:49:17 +00001607 }
sewardjde4a1d02002-03-22 01:27:54 +00001608}
1609
sewardjde4a1d02002-03-22 01:27:54 +00001610/*------------------------------------------------------------*/
1611/*--- Main entry point for symbols table reading. ---*/
1612/*------------------------------------------------------------*/
1613
1614/* The root structure for the entire symbol table system. It is a
1615 linked list of SegInfos. Note that this entire mechanism assumes
1616 that what we read from /proc/self/maps doesn't contain overlapping
1617 address ranges, and as a result the SegInfos in this list describe
1618 disjoint address ranges.
1619*/
fitzhardinge98abfc72003-12-16 02:05:15 +00001620SegInfo *VG_(read_seg_symbols) ( Segment *seg )
sewardjde4a1d02002-03-22 01:27:54 +00001621{
1622 SegInfo* si;
1623
njn36ef6ba2005-05-14 18:42:26 +00001624 vg_assert(seg->seginfo == NULL);
sewardjde4a1d02002-03-22 01:27:54 +00001625
njnfa1016e2003-09-25 17:54:11 +00001626 VGP_PUSHCC(VgpReadSyms);
1627
sewardjde4a1d02002-03-22 01:27:54 +00001628 /* Get the record initialised right. */
njn25e49d8e72002-09-23 09:36:25 +00001629 si = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(SegInfo));
sewardjde4a1d02002-03-22 01:27:54 +00001630
sewardj8fe15a32002-10-20 19:29:21 +00001631 VG_(memset)(si, 0, sizeof(*si));
fitzhardinge98abfc72003-12-16 02:05:15 +00001632 si->start = seg->addr;
1633 si->size = seg->len;
1634 si->foffset = seg->offset;
fitzhardinge1a4adf02003-12-22 10:42:59 +00001635 si->filename = VG_(arena_strdup)(VG_AR_SYMTAB, seg->filename);
fitzhardinge98abfc72003-12-16 02:05:15 +00001636
1637 si->ref = 1;
sewardjde4a1d02002-03-22 01:27:54 +00001638
1639 si->symtab = NULL;
1640 si->symtab_size = si->symtab_used = 0;
1641 si->loctab = NULL;
1642 si->loctab_size = si->loctab_used = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001643 si->strchunks = NULL;
1644 si->scopetab = NULL;
1645 si->scopetab_size = si->scopetab_used = 0;
sewardj5c638c22005-04-30 07:55:58 +00001646 si->cfisi = NULL;
1647 si->cfisi_size = si->cfisi_used = 0;
sewardjbf603752005-05-02 00:36:27 +00001648 si->cfisi_minaddr = si->cfisi_maxaddr = 0;
jsgfcb1d1c02003-10-14 21:55:10 +00001649
fitzhardinge98abfc72003-12-16 02:05:15 +00001650 si->seg = seg;
1651
jsgfcb1d1c02003-10-14 21:55:10 +00001652 si->stab_typetab = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001653
nethercote80f76782003-11-13 22:34:00 +00001654 si->plt_start = si->plt_size = 0;
1655 si->got_start = si->got_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001656 si->data_start = si->data_size = 0;
nethercote80f76782003-11-13 22:34:00 +00001657 si->bss_start = si->bss_size = 0;
sewardj8a77ffb2003-07-10 23:31:27 +00001658
sewardjde4a1d02002-03-22 01:27:54 +00001659 /* And actually fill it up. */
njn695c16e2005-03-27 03:40:28 +00001660 if (!read_lib_symbols ( si ) && 0) {
sewardj8fe15a32002-10-20 19:29:21 +00001661 /* XXX this interacts badly with the prevN optimization in
1662 addStr(). Since this frees the si, the si pointer value can
1663 be recycled, which confuses the curr_si == si test. For now,
1664 this code is disabled, and everything is included in the
1665 segment list, even if it is a bad ELF file. Ironically,
1666 running this under valgrind itself hides the problem, because
1667 it doesn't recycle pointers... */
njn16eeb4e2005-06-16 03:56:58 +00001668 // [Nb: the prevN optimization has now been removed from addStr().
1669 // However, when I try reactivating this path of the branch I get
1670 // seg faults... --njn 13-Jun-2005]
sewardj8fe15a32002-10-20 19:29:21 +00001671 freeSegInfo( si );
1672 } else {
njn16eeb4e2005-06-16 03:56:58 +00001673 // Prepend si to segInfo_list
1674 si->next = segInfo_list;
1675 segInfo_list = si;
sewardj8fe15a32002-10-20 19:29:21 +00001676
njn16eeb4e2005-06-16 03:56:58 +00001677 canonicaliseSymtab ( si );
1678 canonicaliseLoctab ( si );
jsgfcb1d1c02003-10-14 21:55:10 +00001679 canonicaliseScopetab ( si );
njn16eeb4e2005-06-16 03:56:58 +00001680 canonicaliseCfiSI ( si );
fitzhardinge98abfc72003-12-16 02:05:15 +00001681
1682 /* do redirects */
sewardjb5f6f512005-03-10 23:59:00 +00001683 VG_(resolve_seg_redirs)( si );
sewardj8fe15a32002-10-20 19:29:21 +00001684 }
njnfa1016e2003-09-25 17:54:11 +00001685 VGP_POPCC(VgpReadSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001686
1687 return si;
sewardjde4a1d02002-03-22 01:27:54 +00001688}
1689
1690
sewardjde4a1d02002-03-22 01:27:54 +00001691/* When an munmap() call happens, check to see whether it corresponds
1692 to a segment for a .so, and if so discard the relevant SegInfo.
1693 This might not be a very clever idea from the point of view of
1694 accuracy of error messages, but we need to do it in order to
sewardj18d75132002-05-16 11:06:21 +00001695 maintain the no-overlapping invariant.
sewardjde4a1d02002-03-22 01:27:54 +00001696*/
nethercote928a5f72004-11-03 18:10:37 +00001697static void unload_symbols ( Addr start, SizeT length )
sewardjde4a1d02002-03-22 01:27:54 +00001698{
1699 SegInfo *prev, *curr;
1700
sewardjde4a1d02002-03-22 01:27:54 +00001701 prev = NULL;
njn16eeb4e2005-06-16 03:56:58 +00001702 curr = segInfo_list;
sewardjde4a1d02002-03-22 01:27:54 +00001703 while (True) {
1704 if (curr == NULL) break;
1705 if (start == curr->start) break;
1706 prev = curr;
1707 curr = curr->next;
1708 }
njnfa1016e2003-09-25 17:54:11 +00001709 if (curr == NULL) {
1710 VGP_POPCC(VgpReadSyms);
njn25e49d8e72002-09-23 09:36:25 +00001711 return;
njnfa1016e2003-09-25 17:54:11 +00001712 }
sewardjde4a1d02002-03-22 01:27:54 +00001713
mueller75c0ed62003-11-19 00:47:00 +00001714 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001715 VG_(message)(Vg_DebugMsg,
fitzhardinge98abfc72003-12-16 02:05:15 +00001716 "discard syms at %p-%p in %s due to munmap()",
1717 start, start+length, curr->filename ? curr->filename : (Char *)"???");
sewardjde4a1d02002-03-22 01:27:54 +00001718
1719 vg_assert(prev == NULL || prev->next == curr);
1720
1721 if (prev == NULL) {
njn16eeb4e2005-06-16 03:56:58 +00001722 segInfo_list = curr->next;
sewardjde4a1d02002-03-22 01:27:54 +00001723 } else {
1724 prev->next = curr->next;
1725 }
1726
1727 freeSegInfo(curr);
njn25e49d8e72002-09-23 09:36:25 +00001728 return;
sewardjde4a1d02002-03-22 01:27:54 +00001729}
1730
njn36ef6ba2005-05-14 18:42:26 +00001731void VG_(seginfo_decref)(SegInfo *si, Addr start)
fitzhardinge98abfc72003-12-16 02:05:15 +00001732{
1733 vg_assert(si->ref >= 1);
1734 if (--si->ref == 0)
nethercote85cdd342004-08-01 22:36:40 +00001735 unload_symbols(si->start, si->size);
fitzhardinge98abfc72003-12-16 02:05:15 +00001736}
1737
njn36ef6ba2005-05-14 18:42:26 +00001738void VG_(seginfo_incref)(SegInfo *si)
fitzhardinge98abfc72003-12-16 02:05:15 +00001739{
1740 vg_assert(si->ref > 0);
1741 si->ref++;
1742}
sewardjde4a1d02002-03-22 01:27:54 +00001743
1744/*------------------------------------------------------------*/
1745/*--- Use of symbol table & location info to create ---*/
1746/*--- plausible-looking stack dumps. ---*/
1747/*------------------------------------------------------------*/
1748
1749/* Find a symbol-table index containing the specified pointer, or -1
1750 if not found. Binary search. */
1751
njn25e49d8e72002-09-23 09:36:25 +00001752static Int search_one_symtab ( SegInfo* si, Addr ptr,
1753 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001754{
1755 Addr a_mid_lo, a_mid_hi;
njn25e49d8e72002-09-23 09:36:25 +00001756 Int mid, size,
sewardjde4a1d02002-03-22 01:27:54 +00001757 lo = 0,
1758 hi = si->symtab_used-1;
1759 while (True) {
1760 /* current unsearched space is from lo to hi, inclusive. */
1761 if (lo > hi) return -1; /* not found */
1762 mid = (lo + hi) / 2;
1763 a_mid_lo = si->symtab[mid].addr;
njn25e49d8e72002-09-23 09:36:25 +00001764 size = ( match_anywhere_in_fun
1765 ? si->symtab[mid].size
1766 : 1);
1767 a_mid_hi = ((Addr)si->symtab[mid].addr) + size - 1;
sewardjde4a1d02002-03-22 01:27:54 +00001768
1769 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1770 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1771 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1772 return mid;
1773 }
1774}
1775
1776
sewardj25c7c3a2003-07-10 00:17:58 +00001777/* SLOW (Linear search). Try and map a symbol name to an address.
1778 Since this is searching in the direction opposite to which the
1779 table is designed we have no option but to do a complete linear
1780 scan of the table. Returns NULL if not found. */
1781
sewardjb5f6f512005-03-10 23:59:00 +00001782Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name )
sewardj25c7c3a2003-07-10 00:17:58 +00001783{
1784 UInt i;
1785 for (i = 0; i < si->symtab_used; i++) {
sewardjc8bf5fe2003-07-13 00:53:22 +00001786 if (0)
jsgfcb1d1c02003-10-14 21:55:10 +00001787 VG_(printf)("%p %s\n", si->symtab[i].addr, si->symtab[i].name);
1788 if (0 == VG_(strcmp)(name, si->symtab[i].name))
sewardj25c7c3a2003-07-10 00:17:58 +00001789 return si->symtab[i].addr;
1790 }
1791 return (Addr)NULL;
1792}
1793
1794
sewardjde4a1d02002-03-22 01:27:54 +00001795/* Search all symtabs that we know about to locate ptr. If found, set
1796 *psi to the relevant SegInfo, and *symno to the symtab entry number
1797 within that. If not found, *psi is set to NULL. */
1798
njn25e49d8e72002-09-23 09:36:25 +00001799static void search_all_symtabs ( Addr ptr, /*OUT*/SegInfo** psi,
1800 /*OUT*/Int* symno,
1801 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001802{
1803 Int sno;
1804 SegInfo* si;
fitzhardinge98abfc72003-12-16 02:05:15 +00001805 Segment *s;
njn25e49d8e72002-09-23 09:36:25 +00001806
njn25e49d8e72002-09-23 09:36:25 +00001807 VGP_PUSHCC(VgpSearchSyms);
fitzhardinge98abfc72003-12-16 02:05:15 +00001808
1809 s = VG_(find_segment)(ptr);
1810
njn36ef6ba2005-05-14 18:42:26 +00001811 if (s == NULL || s->seginfo == NULL)
fitzhardinge98abfc72003-12-16 02:05:15 +00001812 goto not_found;
njn25e49d8e72002-09-23 09:36:25 +00001813
njn36ef6ba2005-05-14 18:42:26 +00001814 si = s->seginfo;
fitzhardinge98abfc72003-12-16 02:05:15 +00001815
1816 sno = search_one_symtab ( si, ptr, match_anywhere_in_fun );
1817 if (sno == -1) goto not_found;
1818
1819 *symno = sno;
1820 *psi = si;
1821 VGP_POPCC(VgpSearchSyms);
1822 return;
1823
sewardjde4a1d02002-03-22 01:27:54 +00001824 not_found:
1825 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00001826 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001827}
1828
1829
1830/* Find a location-table index containing the specified pointer, or -1
1831 if not found. Binary search. */
1832
1833static Int search_one_loctab ( SegInfo* si, Addr ptr )
1834{
1835 Addr a_mid_lo, a_mid_hi;
1836 Int mid,
1837 lo = 0,
1838 hi = si->loctab_used-1;
1839 while (True) {
1840 /* current unsearched space is from lo to hi, inclusive. */
1841 if (lo > hi) return -1; /* not found */
1842 mid = (lo + hi) / 2;
1843 a_mid_lo = si->loctab[mid].addr;
1844 a_mid_hi = ((Addr)si->loctab[mid].addr) + si->loctab[mid].size - 1;
1845
1846 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1847 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1848 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1849 return mid;
1850 }
1851}
1852
1853
1854/* Search all loctabs that we know about to locate ptr. If found, set
1855 *psi to the relevant SegInfo, and *locno to the loctab entry number
1856 within that. If not found, *psi is set to NULL.
1857*/
njn25e49d8e72002-09-23 09:36:25 +00001858static void search_all_loctabs ( Addr ptr, /*OUT*/SegInfo** psi,
1859 /*OUT*/Int* locno )
sewardjde4a1d02002-03-22 01:27:54 +00001860{
1861 Int lno;
1862 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00001863
1864 VGP_PUSHCC(VgpSearchSyms);
1865
njn16eeb4e2005-06-16 03:56:58 +00001866 for (si = segInfo_list; si != NULL; si = si->next) {
sewardjde4a1d02002-03-22 01:27:54 +00001867 if (si->start <= ptr && ptr < si->start+si->size) {
1868 lno = search_one_loctab ( si, ptr );
1869 if (lno == -1) goto not_found;
1870 *locno = lno;
1871 *psi = si;
njn25e49d8e72002-09-23 09:36:25 +00001872 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001873 return;
1874 }
1875 }
1876 not_found:
1877 *psi = NULL;
njn25e49d8e72002-09-23 09:36:25 +00001878 VGP_POPCC(VgpSearchSyms);
sewardjde4a1d02002-03-22 01:27:54 +00001879}
1880
1881
jsgfcb1d1c02003-10-14 21:55:10 +00001882/* Find a scope-table index containing the specified pointer, or -1
1883 if not found. Binary search. */
1884
1885static Int search_one_scopetab ( SegInfo* si, Addr ptr )
1886{
1887 Addr a_mid_lo, a_mid_hi;
1888 Int mid,
1889 lo = 0,
1890 hi = si->scopetab_used-1;
1891 while (True) {
1892 /* current unsearched space is from lo to hi, inclusive. */
1893 if (lo > hi) return -1; /* not found */
1894 mid = (lo + hi) / 2;
1895 a_mid_lo = si->scopetab[mid].addr;
1896 a_mid_hi = ((Addr)si->scopetab[mid].addr) + si->scopetab[mid].size - 1;
1897
1898 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1899 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1900 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1901 return mid;
1902 }
1903}
1904
1905
1906/* Search all scopetabs that we know about to locate ptr. If found, set
1907 *psi to the relevant SegInfo, and *locno to the scopetab entry number
1908 within that. If not found, *psi is set to NULL.
1909*/
1910static void search_all_scopetabs ( Addr ptr,
1911 /*OUT*/SegInfo** psi,
1912 /*OUT*/Int* scopeno )
1913{
1914 Int scno;
1915 SegInfo* si;
1916
1917 VGP_PUSHCC(VgpSearchSyms);
1918
njn16eeb4e2005-06-16 03:56:58 +00001919 for (si = segInfo_list; si != NULL; si = si->next) {
jsgfcb1d1c02003-10-14 21:55:10 +00001920 if (si->start <= ptr && ptr < si->start+si->size) {
1921 scno = search_one_scopetab ( si, ptr );
1922 if (scno == -1) goto not_found;
1923 *scopeno = scno;
1924 *psi = si;
1925 VGP_POPCC(VgpSearchSyms);
1926 return;
1927 }
1928 }
1929 not_found:
1930 *psi = NULL;
1931 VGP_POPCC(VgpSearchSyms);
1932}
1933
sewardj3a1c7db2005-05-02 09:43:44 +00001934
1935/* Find a CFI-table index containing the specified pointer, or -1
1936 if not found. Binary search. */
1937
1938static Int search_one_cfitab ( SegInfo* si, Addr ptr )
1939{
1940 Addr a_mid_lo, a_mid_hi;
1941 Int mid, size,
1942 lo = 0,
1943 hi = si->cfisi_used-1;
1944 while (True) {
1945 /* current unsearched space is from lo to hi, inclusive. */
1946 if (lo > hi) return -1; /* not found */
1947 mid = (lo + hi) / 2;
1948 a_mid_lo = si->cfisi[mid].base;
1949 size = si->cfisi[mid].len;
1950 a_mid_hi = a_mid_lo + size - 1;
1951 vg_assert(a_mid_hi >= a_mid_lo);
1952 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1953 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1954 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1955 return mid;
1956 }
1957}
1958
1959
sewardjde4a1d02002-03-22 01:27:54 +00001960/* The whole point of this whole big deal: map a code address to a
1961 plausible symbol name. Returns False if no idea; otherwise True.
njn25e49d8e72002-09-23 09:36:25 +00001962 Caller supplies buf and nbuf. If demangle is False, don't do
njn695c16e2005-03-27 03:40:28 +00001963 demangling, regardless of VG_(clo_demangle) -- probably because the
1964 call has come from VG_(get_fnname_nodemangle)(). */
njn25e49d8e72002-09-23 09:36:25 +00001965static
1966Bool get_fnname ( Bool demangle, Addr a, Char* buf, Int nbuf,
sewardj1771e172002-11-13 22:06:35 +00001967 Bool match_anywhere_in_fun, Bool show_offset)
sewardjde4a1d02002-03-22 01:27:54 +00001968{
1969 SegInfo* si;
1970 Int sno;
sewardj1771e172002-11-13 22:06:35 +00001971 Int offset;
1972
njn25e49d8e72002-09-23 09:36:25 +00001973 search_all_symtabs ( a, &si, &sno, match_anywhere_in_fun );
sewardjde4a1d02002-03-22 01:27:54 +00001974 if (si == NULL)
1975 return False;
njn25e49d8e72002-09-23 09:36:25 +00001976 if (demangle) {
jsgfcb1d1c02003-10-14 21:55:10 +00001977 VG_(demangle) ( si->symtab[sno].name, buf, nbuf );
njn25e49d8e72002-09-23 09:36:25 +00001978 } else {
njnbe73f432005-03-26 21:34:45 +00001979 VG_(strncpy_safely) ( buf, si->symtab[sno].name, nbuf );
sewardjde4a1d02002-03-22 01:27:54 +00001980 }
sewardj1771e172002-11-13 22:06:35 +00001981
1982 offset = a - si->symtab[sno].addr;
1983 if (show_offset && offset != 0) {
1984 Char buf2[12];
1985 Char* symend = buf + VG_(strlen)(buf);
1986 Char* end = buf + nbuf;
1987 Int len;
1988
1989 len = VG_(sprintf)(buf2, "%c%d",
1990 offset < 0 ? '-' : '+',
1991 offset < 0 ? -offset : offset);
sewardj05bcdcb2003-05-18 10:05:38 +00001992 vg_assert(len < (Int)sizeof(buf2));
sewardj1771e172002-11-13 22:06:35 +00001993
1994 if (len < (end - symend)) {
1995 Char *cp = buf2;
1996 VG_(memcpy)(symend, cp, len+1);
1997 }
1998 }
1999
sewardjde4a1d02002-03-22 01:27:54 +00002000 return True;
2001}
2002
nethercote7cc9c232004-01-21 15:08:04 +00002003/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002004 match anywhere in function, but don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002005Bool VG_(get_fnname) ( Addr a, Char* buf, Int nbuf )
2006{
2007 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002008 /*match_anywhere_in_fun*/True,
2009 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002010}
sewardjde4a1d02002-03-22 01:27:54 +00002011
nethercote7cc9c232004-01-21 15:08:04 +00002012/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002013 match anywhere in function, and show offset if nonzero. */
2014Bool VG_(get_fnname_w_offset) ( Addr a, Char* buf, Int nbuf )
2015{
2016 return get_fnname ( /*demangle*/True, a, buf, nbuf,
2017 /*match_anywhere_in_fun*/True,
2018 /*show offset?*/True );
2019}
2020
nethercote7cc9c232004-01-21 15:08:04 +00002021/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002022 only succeed if 'a' matches first instruction of function,
2023 and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002024Bool VG_(get_fnname_if_entry) ( Addr a, Char* buf, Int nbuf )
2025{
2026 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002027 /*match_anywhere_in_fun*/False,
2028 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002029}
2030
sewardj6e008cb2002-12-15 13:11:39 +00002031/* This is only available to core... don't demangle C++ names,
2032 match anywhere in function, and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002033Bool VG_(get_fnname_nodemangle) ( Addr a, Char* buf, Int nbuf )
2034{
2035 return get_fnname ( /*demangle*/False, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002036 /*match_anywhere_in_fun*/True,
2037 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002038}
2039
2040/* Map a code address to the name of a shared object file or the executable.
2041 Returns False if no idea; otherwise True. Doesn't require debug info.
2042 Caller supplies buf and nbuf. */
2043Bool VG_(get_objname) ( Addr a, Char* buf, Int nbuf )
sewardjde4a1d02002-03-22 01:27:54 +00002044{
2045 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00002046
njn16eeb4e2005-06-16 03:56:58 +00002047 for (si = segInfo_list; si != NULL; si = si->next) {
sewardjde4a1d02002-03-22 01:27:54 +00002048 if (si->start <= a && a < si->start+si->size) {
2049 VG_(strncpy_safely)(buf, si->filename, nbuf);
2050 return True;
2051 }
2052 }
2053 return False;
2054}
2055
njnb877d492003-01-28 20:40:57 +00002056/* Map a code address to its SegInfo. Returns NULL if not found. Doesn't
2057 require debug info. */
2058SegInfo* VG_(get_obj) ( Addr a )
2059{
2060 SegInfo* si;
2061
njn16eeb4e2005-06-16 03:56:58 +00002062 for (si = segInfo_list; si != NULL; si = si->next) {
njnb877d492003-01-28 20:40:57 +00002063 if (si->start <= a && a < si->start+si->size) {
2064 return si;
2065 }
2066 }
nethercote80f76782003-11-13 22:34:00 +00002067 return NULL;
njnb877d492003-01-28 20:40:57 +00002068}
2069
njn25e49d8e72002-09-23 09:36:25 +00002070
2071/* Map a code address to a filename. Returns True if successful. */
2072Bool VG_(get_filename)( Addr a, Char* filename, Int n_filename )
sewardjde4a1d02002-03-22 01:27:54 +00002073{
njn25e49d8e72002-09-23 09:36:25 +00002074 SegInfo* si;
2075 Int locno;
2076 search_all_loctabs ( a, &si, &locno );
2077 if (si == NULL)
2078 return False;
njnbe73f432005-03-26 21:34:45 +00002079 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
njn25e49d8e72002-09-23 09:36:25 +00002080 return True;
sewardjde4a1d02002-03-22 01:27:54 +00002081}
2082
njn25e49d8e72002-09-23 09:36:25 +00002083/* Map a code address to a line number. Returns True if successful. */
2084Bool VG_(get_linenum)( Addr a, UInt* lineno )
2085{
2086 SegInfo* si;
2087 Int locno;
2088 search_all_loctabs ( a, &si, &locno );
2089 if (si == NULL)
2090 return False;
2091 *lineno = si->loctab[locno].lineno;
2092
2093 return True;
2094}
sewardjde4a1d02002-03-22 01:27:54 +00002095
sewardj7cee6f92005-06-13 17:39:06 +00002096/* Map a code address to a filename/line number/dir name info.
2097 See prototype for detailed description of behaviour.
sewardjde4a1d02002-03-22 01:27:54 +00002098*/
sewardj7cee6f92005-06-13 17:39:06 +00002099Bool VG_(get_filename_linenum) ( Addr a,
2100 /*OUT*/Char* filename, Int n_filename,
2101 /*OUT*/Char* dirname, Int n_dirname,
2102 /*OUT*/Bool* dirname_available,
2103 /*OUT*/UInt* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00002104{
2105 SegInfo* si;
2106 Int locno;
sewardj7cee6f92005-06-13 17:39:06 +00002107
2108 vg_assert( (dirname == NULL && dirname_available == NULL)
2109 ||
2110 (dirname != NULL && dirname_available != NULL) );
2111
sewardjde4a1d02002-03-22 01:27:54 +00002112 search_all_loctabs ( a, &si, &locno );
2113 if (si == NULL)
2114 return False;
njnbe73f432005-03-26 21:34:45 +00002115 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
sewardjde4a1d02002-03-22 01:27:54 +00002116 *lineno = si->loctab[locno].lineno;
njn4f9c9342002-04-29 16:03:24 +00002117
sewardj7cee6f92005-06-13 17:39:06 +00002118 if (dirname) {
2119 /* caller wants directory info too .. */
2120 vg_assert(n_dirname > 0);
2121 if (si->loctab[locno].dirname) {
2122 /* .. and we have some */
2123 *dirname_available = True;
2124 VG_(strncpy_safely)(dirname, si->loctab[locno].dirname,
2125 n_dirname);
2126 } else {
2127 /* .. but we don't have any */
2128 *dirname_available = False;
2129 *dirname = 0;
2130 }
2131 }
2132
sewardjde4a1d02002-03-22 01:27:54 +00002133 return True;
2134}
2135
jsgfcb1d1c02003-10-14 21:55:10 +00002136#ifndef TEST
2137
njn6b2b96a2005-05-16 00:01:04 +00002138// Note that R_STACK_PTR and R_FRAME_PTR are used again further below,
2139// which is why they get a named constant.
2140static Addr regaddr_from_tst(Int regno, ThreadArchState *arch)
2141{
2142#if defined(VGA_x86)
sewardj7cee6f92005-06-13 17:39:06 +00002143 /* This is the Intel register encoding -- integer regs. */
njn6b2b96a2005-05-16 00:01:04 +00002144# define R_STACK_PTR 4
2145# define R_FRAME_PTR 5
2146 switch (regno) {
2147 case 0: return (Addr) & arch->vex.guest_EAX;
2148 case 1: return (Addr) & arch->vex.guest_ECX;
2149 case 2: return (Addr) & arch->vex.guest_EDX;
2150 case 3: return (Addr) & arch->vex.guest_EBX;
2151 case R_STACK_PTR: return (Addr) & arch->vex.guest_ESP;
2152 case R_FRAME_PTR: return (Addr) & arch->vex.guest_EBP;
2153 case 6: return (Addr) & arch->vex.guest_ESI;
2154 case 7: return (Addr) & arch->vex.guest_EDI;
2155 default: return 0;
2156 }
2157#elif defined(VGA_amd64)
sewardj7cee6f92005-06-13 17:39:06 +00002158 /* This is the AMD64 register encoding -- integer regs. */
tom7b998562005-05-16 07:31:57 +00002159# define R_STACK_PTR 7
2160# define R_FRAME_PTR 6
2161 switch (regno) {
2162 case 0: return (Addr) & arch->vex.guest_RAX;
2163 case 1: return (Addr) & arch->vex.guest_RDX;
2164 case 2: return (Addr) & arch->vex.guest_RCX;
2165 case 3: return (Addr) & arch->vex.guest_RBX;
2166 case 4: return (Addr) & arch->vex.guest_RSI;
2167 case 5: return (Addr) & arch->vex.guest_RDI;
2168 case R_FRAME_PTR: return (Addr) & arch->vex.guest_RBP;
2169 case R_STACK_PTR: return (Addr) & arch->vex.guest_RSP;
2170 case 8: return (Addr) & arch->vex.guest_R8;
2171 case 9: return (Addr) & arch->vex.guest_R9;
2172 case 10: return (Addr) & arch->vex.guest_R10;
2173 case 11: return (Addr) & arch->vex.guest_R11;
2174 case 12: return (Addr) & arch->vex.guest_R12;
2175 case 13: return (Addr) & arch->vex.guest_R13;
2176 case 14: return (Addr) & arch->vex.guest_R14;
2177 case 15: return (Addr) & arch->vex.guest_R15;
2178 default: return 0;
2179 }
njn6b2b96a2005-05-16 00:01:04 +00002180#else
2181# error Unknown platform
2182#endif
2183}
2184
2185
jsgfcb1d1c02003-10-14 21:55:10 +00002186/* return a pointer to a register (now for 5 other impossible things
2187 before breakfast) */
njn6b2b96a2005-05-16 00:01:04 +00002188static Addr regaddr(ThreadId tid, Int regno)
jsgfcb1d1c02003-10-14 21:55:10 +00002189{
njn6b2b96a2005-05-16 00:01:04 +00002190 Addr ret = regaddr_from_tst(regno, &VG_(threads)[tid].arch);
jsgfcb1d1c02003-10-14 21:55:10 +00002191
2192 if (ret == 0) {
njn252ed912005-05-15 03:30:56 +00002193 Char buf[100];
2194 VG_(describe_IP)( VG_(get_IP)(tid), buf, 100 );
2195 VG_(printf)("mysterious register %d used at %s\n", regno, buf);
jsgfcb1d1c02003-10-14 21:55:10 +00002196 }
2197
2198 return ret;
2199}
2200
2201/* Get a list of all variables in scope, working out from the directly
2202 current one */
2203Variable *VG_(get_scope_variables)(ThreadId tid)
2204{
2205 static const Bool debug = False;
2206 Variable *list, *end;
2207 Addr eip;
2208 SegInfo *si;
2209 Int scopeidx;
2210 Scope *scope;
2211 Int distance;
2212 static const Int maxsyms = 1000;
2213 Int nsyms = maxsyms;
2214
2215 list = end = NULL;
2216
njn67516132005-03-22 04:02:43 +00002217 eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002218
2219 search_all_scopetabs(eip, &si, &scopeidx);
2220
2221 if (debug)
2222 VG_(printf)("eip=%p si=%p (%s; offset=%p) scopeidx=%d\n",
2223 eip, si, si ? si->filename : (Char *)"???",
2224 si ? si->offset : 0x99999, scopeidx);
2225
2226 if (si == NULL)
2227 return NULL; /* nothing in scope (should use global scope at least) */
2228
2229 if (debug) {
2230 ScopeRange *sr = &si->scopetab[scopeidx];
2231 Char file[100];
2232 Int line;
2233
sewardj7cee6f92005-06-13 17:39:06 +00002234 if (!VG_(get_filename_linenum)(sr->addr, file, sizeof(file),
2235 NULL, 0, NULL, &line))
jsgfcb1d1c02003-10-14 21:55:10 +00002236 file[0] = 0;
2237
2238 VG_(printf)("found scope range %p: eip=%p (%s:%d) size=%d scope=%p\n",
2239 sr, sr->addr, file, line, sr->size, sr->scope);
2240 }
2241
2242 distance = 0;
sewardj7cee6f92005-06-13 17:39:06 +00002243 for (scope = si->scopetab[scopeidx].scope;
2244 scope != NULL;
2245 scope = scope->outer, distance++) {
jsgfcb1d1c02003-10-14 21:55:10 +00002246 UInt i;
2247
2248 for(i = 0; i < scope->nsyms; i++) {
2249 Sym *sym = &scope->syms[i];
2250 Variable *v;
2251
2252 if (nsyms-- == 0) {
2253 VG_(printf)("max %d syms reached\n", maxsyms);
2254 return list;
2255 }
2256
2257 v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
2258
2259 v->next = NULL;
2260 v->distance = distance;
2261 v->type = VG_(st_basetype)(sym->type, False);
2262 v->name = VG_(arena_strdup)(VG_AR_SYMTAB, sym->name);
2263 v->container = NULL;
2264 v->size = VG_(st_sizeof)(sym->type);
2265
2266 if (debug && 0)
mueller5ed88f22004-01-06 16:02:29 +00002267 VG_(printf)("sym->name=%s sym->kind=%d offset=%d\n", sym->name, sym->kind, sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002268 switch(sym->kind) {
jsgfcb1d1c02003-10-14 21:55:10 +00002269
2270 case SyGlobal:
2271 case SyStatic:
mueller5ed88f22004-01-06 16:02:29 +00002272 if (sym->u.addr == 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00002273 /* XXX lookup value */
2274 }
mueller5ed88f22004-01-06 16:02:29 +00002275 v->valuep = sym->u.addr;
jsgfcb1d1c02003-10-14 21:55:10 +00002276 break;
2277
2278 case SyReg:
njn6b2b96a2005-05-16 00:01:04 +00002279 v->valuep = regaddr(tid, sym->u.regno);
jsgfcb1d1c02003-10-14 21:55:10 +00002280 break;
2281
2282 case SyEBPrel:
njn6b2b96a2005-05-16 00:01:04 +00002283 case SyESPrel: {
2284 Addr reg = *(Addr*)regaddr(tid, sym->kind == SyESPrel
2285 ? R_STACK_PTR : R_FRAME_PTR);
jsgfcb1d1c02003-10-14 21:55:10 +00002286 if (debug)
mueller5ed88f22004-01-06 16:02:29 +00002287 VG_(printf)("reg=%p+%d=%p\n", reg, sym->u.offset, reg+sym->u.offset);
njn6b2b96a2005-05-16 00:01:04 +00002288 v->valuep = reg + sym->u.offset;
jsgfcb1d1c02003-10-14 21:55:10 +00002289 break;
njn6b2b96a2005-05-16 00:01:04 +00002290 }
jsgfcb1d1c02003-10-14 21:55:10 +00002291
2292 case SyType:
2293 VG_(core_panic)("unexpected typedef in scope");
2294 }
2295
2296 if (v->valuep == 0) {
2297 /* not interesting or useful */
2298 VG_(arena_free)(VG_AR_SYMTAB, v);
2299 continue;
2300 }
2301
2302 /* append to end of list */
2303 if (list == NULL)
2304 list = end = v;
2305 else {
2306 end->next = v;
2307 end = v;
2308 }
2309 }
2310 }
2311
2312 return list;
2313}
sewardj7cee6f92005-06-13 17:39:06 +00002314
2315# undef R_STACK_PTR
2316# undef R_FRAME_PTR
2317
jsgfcb1d1c02003-10-14 21:55:10 +00002318#endif /* TEST */
2319
njn6c846552003-09-16 07:41:43 +00002320/* Print into buf info on code address, function name and filename */
sewardj948d7612005-06-09 23:58:36 +00002321
2322static Int putStr ( Int n, Int n_buf, Char* buf, Char* str )
2323{
2324 for (; n < n_buf-1 && *str != 0; n++,str++)
2325 buf[n] = *str;
2326 buf[n] = '\0';
2327 return n;
2328}
2329static Int putStrEsc ( Int n, Int n_buf, Char* buf, Char* str )
2330{
2331 Char alt[2];
2332 for (; *str != 0; str++) {
2333 switch (*str) {
2334 case '&': n = putStr( n, n_buf, buf, "&amp;"); break;
2335 case '<': n = putStr( n, n_buf, buf, "&lt;"); break;
2336 case '>': n = putStr( n, n_buf, buf, "&gt;"); break;
2337 default: alt[0] = *str;
2338 alt[1] = 0;
2339 n = putStr( n, n_buf, buf, alt );
2340 break;
2341 }
2342 }
2343 return n;
2344}
2345
njnd01fef72005-03-25 23:35:48 +00002346Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf)
sewardjde4a1d02002-03-22 01:27:54 +00002347{
sewardj948d7612005-06-09 23:58:36 +00002348# define APPEND(_str) \
2349 n = putStr(n, n_buf, buf, _str);
2350# define APPEND_ESC(_str) \
2351 n = putStrEsc(n, n_buf, buf, _str);
njn83f9e792005-06-11 05:04:09 +00002352# define BUF_LEN 4096
sewardj948d7612005-06-09 23:58:36 +00002353
nethercote80f76782003-11-13 22:34:00 +00002354 UInt lineno;
sewardj71bc3cb2005-05-19 00:25:45 +00002355 UChar ibuf[50];
sewardj948d7612005-06-09 23:58:36 +00002356 Int n = 0;
njn83f9e792005-06-11 05:04:09 +00002357 static UChar buf_fn[BUF_LEN];
2358 static UChar buf_obj[BUF_LEN];
2359 static UChar buf_srcloc[BUF_LEN];
sewardj7cee6f92005-06-13 17:39:06 +00002360 static UChar buf_dirname[BUF_LEN];
2361 Bool know_dirinfo = False;
njn83f9e792005-06-11 05:04:09 +00002362 Bool know_fnname = VG_(get_fnname) (eip, buf_fn, BUF_LEN);
2363 Bool know_objname = VG_(get_objname)(eip, buf_obj, BUF_LEN);
sewardj7cee6f92005-06-13 17:39:06 +00002364 Bool know_srcloc = VG_(get_filename_linenum)(
2365 eip,
2366 buf_srcloc, BUF_LEN,
2367 buf_dirname, BUF_LEN, &know_dirinfo,
2368 &lineno
2369 );
sewardj71bc3cb2005-05-19 00:25:45 +00002370 if (VG_(clo_xml)) {
2371
sewardj8665d8e2005-06-01 17:35:23 +00002372 Bool human_readable = True;
2373 HChar* maybe_newline = human_readable ? "\n " : "";
2374 HChar* maybe_newline2 = human_readable ? "\n " : "";
2375
sewardj71bc3cb2005-05-19 00:25:45 +00002376 /* Print in XML format, dumping in as much info as we know. */
2377 APPEND("<frame>");
2378 VG_(sprintf)(ibuf,"<ip>0x%llx</ip>", (ULong)eip);
sewardj8665d8e2005-06-01 17:35:23 +00002379 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002380 APPEND(ibuf);
2381 if (know_objname) {
sewardj8665d8e2005-06-01 17:35:23 +00002382 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002383 APPEND("<obj>");
sewardj948d7612005-06-09 23:58:36 +00002384 APPEND_ESC(buf_obj);
sewardj71bc3cb2005-05-19 00:25:45 +00002385 APPEND("</obj>");
2386 }
2387 if (know_fnname) {
sewardj8665d8e2005-06-01 17:35:23 +00002388 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002389 APPEND("<fn>");
sewardj948d7612005-06-09 23:58:36 +00002390 APPEND_ESC(buf_fn);
sewardj71bc3cb2005-05-19 00:25:45 +00002391 APPEND("</fn>");
2392 }
2393 if (know_srcloc) {
sewardj7cee6f92005-06-13 17:39:06 +00002394 if (know_dirinfo) {
2395 APPEND(maybe_newline);
2396 APPEND("<dir>");
2397 APPEND(buf_dirname);
2398 APPEND("</dir>");
2399 }
sewardj8665d8e2005-06-01 17:35:23 +00002400 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002401 APPEND("<file>");
sewardj948d7612005-06-09 23:58:36 +00002402 APPEND_ESC(buf_srcloc);
sewardj71bc3cb2005-05-19 00:25:45 +00002403 APPEND("</file>");
sewardj8665d8e2005-06-01 17:35:23 +00002404 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002405 APPEND("<line>");
2406 VG_(sprintf)(ibuf,"%d",lineno);
2407 APPEND(ibuf);
2408 APPEND("</line>");
2409 }
sewardj8665d8e2005-06-01 17:35:23 +00002410 APPEND(maybe_newline2);
sewardj71bc3cb2005-05-19 00:25:45 +00002411 APPEND("</frame>");
2412
2413 } else {
2414
2415 /* Print for humans to read */
2416 VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip);
2417 APPEND(ibuf);
2418 if (know_fnname) {
2419 APPEND(buf_fn);
2420 if (!know_srcloc && know_objname) {
2421 APPEND(" (in ");
2422 APPEND(buf_obj);
2423 APPEND(")");
2424 }
2425 } else if (know_objname && !know_srcloc) {
2426 APPEND("(within ");
njn6c846552003-09-16 07:41:43 +00002427 APPEND(buf_obj);
2428 APPEND(")");
sewardj71bc3cb2005-05-19 00:25:45 +00002429 } else {
2430 APPEND("???");
njn6c846552003-09-16 07:41:43 +00002431 }
sewardj71bc3cb2005-05-19 00:25:45 +00002432 if (know_srcloc) {
2433 APPEND(" (");
2434 APPEND(buf_srcloc);
2435 APPEND(":");
2436 VG_(sprintf)(ibuf,"%d",lineno);
2437 APPEND(ibuf);
2438 APPEND(")");
2439 }
2440
njn6c846552003-09-16 07:41:43 +00002441 }
2442 return buf;
2443
sewardj948d7612005-06-09 23:58:36 +00002444# undef APPEND
2445# undef APPEND_ESC
sewardj7cee6f92005-06-13 17:39:06 +00002446# undef BUF_LEN
njn6c846552003-09-16 07:41:43 +00002447}
2448
sewardj35165532005-04-30 18:47:48 +00002449/* Returns True if OK. If not OK, *{ip,sp,fp}P are not changed. */
2450
2451Bool VG_(use_CFI_info) ( /*MOD*/Addr* ipP,
2452 /*MOD*/Addr* spP,
2453 /*MOD*/Addr* fpP,
2454 Addr min_accessible,
2455 Addr max_accessible )
2456{
2457 Int i;
2458 SegInfo* si;
2459 CfiSI* cfisi = NULL;
2460 Addr cfa, ipHere, spHere, fpHere, ipPrev, spPrev, fpPrev;
2461
sewardjbf603752005-05-02 00:36:27 +00002462
sewardj35165532005-04-30 18:47:48 +00002463 if (0) VG_(printf)("search for %p\n", *ipP);
2464
njn16eeb4e2005-06-16 03:56:58 +00002465 for (si = segInfo_list; si != NULL; si = si->next) {
sewardjbf603752005-05-02 00:36:27 +00002466 /* Use the per-SegInfo summary address ranges to skip
2467 inapplicable SegInfos quickly. */
2468 if (si->cfisi_used == 0)
2469 continue;
2470 if (*ipP < si->cfisi_minaddr || *ipP > si->cfisi_maxaddr)
2471 continue;
2472
sewardj3a1c7db2005-05-02 09:43:44 +00002473 i = search_one_cfitab( si, *ipP );
2474 if (i != -1) {
2475 vg_assert(i >= 0 && i < si->cfisi_used);
2476 cfisi = &si->cfisi[i];
2477 break;
sewardj35165532005-04-30 18:47:48 +00002478 }
2479 }
2480
sewardj35165532005-04-30 18:47:48 +00002481 if (cfisi == NULL)
2482 return False;
2483
2484 if (0) {
2485 VG_(printf)("found cfisi: ");
2486 VG_(ppCfiSI)(cfisi);
2487 }
2488
2489 ipPrev = spPrev = fpPrev = 0;
2490
2491 ipHere = *ipP;
2492 spHere = *spP;
2493 fpHere = *fpP;
2494
2495 cfa = cfisi->cfa_off + (cfisi->cfa_sprel ? spHere : fpHere);
2496
2497# define COMPUTE(_prev, _here, _how, _off) \
2498 do { \
2499 switch (_how) { \
2500 case CFIR_UNKNOWN: \
2501 return False; \
2502 case CFIR_SAME: \
2503 _prev = _here; break; \
2504 case CFIR_MEMCFAREL: { \
2505 Addr a = cfa + (Word)_off; \
2506 if (a < min_accessible \
2507 || a+sizeof(Addr) > max_accessible) \
2508 return False; \
2509 _prev = *(Addr*)a; \
2510 break; \
2511 } \
2512 case CFIR_CFAREL: \
2513 _prev = cfa + (Word)_off; \
2514 break; \
2515 } \
2516 } while (0)
2517
2518 COMPUTE(ipPrev, ipHere, cfisi->ra_how, cfisi->ra_off);
2519 COMPUTE(spPrev, spHere, cfisi->sp_how, cfisi->sp_off);
2520 COMPUTE(fpPrev, fpHere, cfisi->fp_how, cfisi->fp_off);
2521
2522# undef COMPUTE
2523
2524 *ipP = ipPrev;
2525 *spP = spPrev;
2526 *fpP = fpPrev;
2527 return True;
2528}
2529
2530
sewardj25c7c3a2003-07-10 00:17:58 +00002531/*------------------------------------------------------------*/
sewardj47104382002-10-20 18:35:48 +00002532/*--- SegInfo accessor functions ---*/
2533/*------------------------------------------------------------*/
2534
njn36ef6ba2005-05-14 18:42:26 +00002535const SegInfo* VG_(next_seginfo)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002536{
njn36ef6ba2005-05-14 18:42:26 +00002537 if (si == NULL)
njn16eeb4e2005-06-16 03:56:58 +00002538 return segInfo_list;
njn36ef6ba2005-05-14 18:42:26 +00002539 return si->next;
sewardj47104382002-10-20 18:35:48 +00002540}
2541
njn36ef6ba2005-05-14 18:42:26 +00002542Addr VG_(seg_start)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002543{
njn36ef6ba2005-05-14 18:42:26 +00002544 return si->start;
sewardj47104382002-10-20 18:35:48 +00002545}
2546
njn36ef6ba2005-05-14 18:42:26 +00002547SizeT VG_(seg_size)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002548{
njn36ef6ba2005-05-14 18:42:26 +00002549 return si->size;
sewardj47104382002-10-20 18:35:48 +00002550}
2551
njn36ef6ba2005-05-14 18:42:26 +00002552const UChar* VG_(seg_filename)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002553{
njn36ef6ba2005-05-14 18:42:26 +00002554 return si->filename;
sewardj47104382002-10-20 18:35:48 +00002555}
2556
njn36ef6ba2005-05-14 18:42:26 +00002557ULong VG_(seg_sym_offset)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002558{
njn36ef6ba2005-05-14 18:42:26 +00002559 return si->offset;
sewardj47104382002-10-20 18:35:48 +00002560}
2561
2562VgSectKind VG_(seg_sect_kind)(Addr a)
2563{
njn36ef6ba2005-05-14 18:42:26 +00002564 SegInfo* si;
sewardj47104382002-10-20 18:35:48 +00002565 VgSectKind ret = Vg_SectUnknown;
2566
njn16eeb4e2005-06-16 03:56:58 +00002567 for(si = segInfo_list; si != NULL; si = si->next) {
njn36ef6ba2005-05-14 18:42:26 +00002568 if (a >= si->start && a < (si->start + si->size)) {
sewardj47104382002-10-20 18:35:48 +00002569 if (0)
njn36ef6ba2005-05-14 18:42:26 +00002570 VG_(printf)("addr=%p si=%p %s got=%p %d plt=%p %d data=%p %d bss=%p %d\n",
2571 a, si, si->filename,
2572 si->got_start, si->got_size,
2573 si->plt_start, si->plt_size,
2574 si->data_start, si->data_size,
2575 si->bss_start, si->bss_size);
sewardj47104382002-10-20 18:35:48 +00002576 ret = Vg_SectText;
2577
njn36ef6ba2005-05-14 18:42:26 +00002578 if (a >= si->data_start && a < (si->data_start + si->data_size))
sewardj8fe15a32002-10-20 19:29:21 +00002579 ret = Vg_SectData;
njn36ef6ba2005-05-14 18:42:26 +00002580 else if (a >= si->bss_start && a < (si->bss_start + si->bss_size))
sewardj8fe15a32002-10-20 19:29:21 +00002581 ret = Vg_SectBSS;
njn36ef6ba2005-05-14 18:42:26 +00002582 else if (a >= si->plt_start && a < (si->plt_start + si->plt_size))
sewardj47104382002-10-20 18:35:48 +00002583 ret = Vg_SectPLT;
njn36ef6ba2005-05-14 18:42:26 +00002584 else if (a >= si->got_start && a < (si->got_start + si->got_size))
sewardj47104382002-10-20 18:35:48 +00002585 ret = Vg_SectGOT;
2586 }
2587 }
2588
2589 return ret;
2590}
2591
sewardjde4a1d02002-03-22 01:27:54 +00002592/*--------------------------------------------------------------------*/
njnea27e462005-05-31 02:38:09 +00002593/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00002594/*--------------------------------------------------------------------*/