blob: bf7a2ec07df90e64cf4d07dc79c883c0abdfb648 [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_debuginfo.h"
njn94b1e2e2005-05-10 05:00:55 +000035#include "pub_core_demangle.h"
njn97405b22005-06-02 03:39:33 +000036#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_core_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000038#include "pub_core_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000039#include "pub_core_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_core_machine.h"
njnaf1d7df2005-06-11 01:31:52 +000041#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_core_options.h"
njnd1af0032005-05-29 17:01:48 +000043#include "pub_core_redir.h"
njnf4c50162005-06-20 14:18:12 +000044#include "pub_core_tooliface.h" // For VG_(needs).data_syms
njndab4e4b2005-06-26 14:48:23 +000045
sewardj45f4e7c2005-09-27 19:20:21 +000046#include "pub_core_aspacemgr.h"
47
njndab4e4b2005-06-26 14:48:23 +000048#include "priv_symtypes.h"
njnea27e462005-05-31 02:38:09 +000049#include "priv_symtab.h"
sewardj55f9d1a2005-04-25 11:11:44 +000050
njn43b9a8a2005-05-10 04:37:01 +000051#include <elf.h> /* ELF defns */
sewardjde4a1d02002-03-22 01:27:54 +000052
njn0787fc02005-06-26 02:19:17 +000053/* The root structure for the entire symbol table system. It is a
54 linked list of SegInfos. Note that this entire mechanism assumes
55 that what we read from /proc/self/maps doesn't contain overlapping
56 address ranges, and as a result the SegInfos in this list describe
57 disjoint address ranges.
58*/
njn16eeb4e2005-06-16 03:56:58 +000059static SegInfo* segInfo_list = NULL;
sewardjb5f6f512005-03-10 23:59:00 +000060
sewardj7a21c612005-02-18 09:38:08 +000061/*------------------------------------------------------------*/
62/*--- 32/64-bit parameterisation ---*/
63/*------------------------------------------------------------*/
64
65/* For all the ELF macros and types which specify '32' or '64',
66 select the correct variant for this platform and give it
67 an 'XX' name. Then use the 'XX' variant consistently in
68 the rest of this file.
69*/
njna37029a2005-05-15 03:56:26 +000070#if VG_WORDSIZE == 4
sewardj7a21c612005-02-18 09:38:08 +000071# define ElfXX_Ehdr Elf32_Ehdr
72# define ElfXX_Shdr Elf32_Shdr
73# define ElfXX_Phdr Elf32_Phdr
74# define ElfXX_Sym Elf32_Sym
75# define ElfXX_Word Elf32_Word
76# define ElfXX_Addr Elf32_Addr
77# define ElfXX_Dyn Elf32_Dyn
78# define ELFXX_ST_BIND ELF32_ST_BIND
79# define ELFXX_ST_TYPE ELF32_ST_TYPE
80
njna37029a2005-05-15 03:56:26 +000081#elif VG_WORDSIZE == 8
sewardj7a21c612005-02-18 09:38:08 +000082# define ElfXX_Ehdr Elf64_Ehdr
83# define ElfXX_Shdr Elf64_Shdr
84# define ElfXX_Phdr Elf64_Phdr
85# define ElfXX_Sym Elf64_Sym
86# define ElfXX_Word Elf64_Word
87# define ElfXX_Addr Elf64_Addr
88# define ElfXX_Dyn Elf64_Dyn
89# define ELFXX_ST_BIND ELF64_ST_BIND
90# define ELFXX_ST_TYPE ELF64_ST_TYPE
91
92#else
njna37029a2005-05-15 03:56:26 +000093# error "VG_WORDSIZE should be 4 or 8"
sewardj7a21c612005-02-18 09:38:08 +000094#endif
95
96
97/*------------------------------------------------------------*/
sewardj0d1a8962005-09-28 01:23:25 +000098/*--- Forwards decls ---*/
99/*------------------------------------------------------------*/
100
101static Bool is_elf_object_file ( const void *buf );
102static void unload_symbols ( Addr start, SizeT length );
103
104
105/*------------------------------------------------------------*/
sewardj45f4e7c2005-09-27 19:20:21 +0000106/*--- TOP LEVEL ---*/
107/*------------------------------------------------------------*/
108
109/* If this mapping is at the beginning of a file, isn't part of
110 Valgrind, is at least readable and seems to contain an object
111 file, then try reading symbols from it.
112
113 Getting this heuristic right is critical. On x86-linux,
114 objects are typically mapped twice:
115
116 1b8fb000-1b8ff000 r-xp 00000000 08:02 4471477 vgpreload_memcheck.so
117 1b8ff000-1b900000 rw-p 00004000 08:02 4471477 vgpreload_memcheck.so
118
119 whereas ppc32-linux mysteriously does this:
120
121 118a6000-118ad000 r-xp 00000000 08:05 14209428 vgpreload_memcheck.so
122 118ad000-118b6000 ---p 00007000 08:05 14209428 vgpreload_memcheck.so
123 118b6000-118bd000 rwxp 00000000 08:05 14209428 vgpreload_memcheck.so
124
125 The third mapping should not be considered to have executable code in.
126 Therefore a test which works for both is: r and x and NOT w. Reading
127 symbols from the rwx segment -- which overlaps the r-x segment in the
128 file -- causes the redirection mechanism to redirect to addresses in
129 that third segment, which is wrong and causes crashes.
sewardj018895d2005-12-28 15:19:39 +0000130
131 ------
132 JRS 28 Dec 05: unfortunately icc 8.1 on x86 has been seen to
133 produce executables with a single rwx segment rather than a
134 (r-x,rw-) pair. That means the rules have to be modified thusly:
135
136 x86-linux: consider if r and x
137 all others: consider if r and x and NOT w
138
sewardj45f4e7c2005-09-27 19:20:21 +0000139*/
140
sewardj45f4e7c2005-09-27 19:20:21 +0000141static void nuke_syms_in_range ( Addr start, SizeT length )
142{
143 /* Repeatedly scan the segInfo list, looking for segInfos in this
144 range, and call unload_symbols on the segInfo's stated start
145 point. This modifies the list, hence the multiple
146 iterations. */
147 Bool found;
148 SegInfo* curr;
149
150 while (True) {
151 found = False;
152
153 curr = segInfo_list;
154 while (True) {
155 if (curr == NULL) break;
sewardj018895d2005-12-28 15:19:39 +0000156 if (start+length-1 < curr->start
157 || curr->start+curr->size-1 < start) {
sewardj45f4e7c2005-09-27 19:20:21 +0000158 /* no overlap */
159 } else {
160 found = True;
161 break;
162 }
163 curr = curr->next;
164 }
165
166 if (!found) break;
167 unload_symbols( curr->start, curr->size );
sewardj45f4e7c2005-09-27 19:20:21 +0000168 }
169}
170
sewardjf72cced2005-11-08 00:45:47 +0000171/* Notify the debuginfo system about a new mapping. This is the way
172 new debug information gets loaded. If allow_SkFileV is True, it
173 will try load debug info if the mapping at 'a' belongs to Valgrind;
174 whereas normally (False) it will not do that. This allows us to
175 carefully control when the thing will read symbols from the
176 Valgrind executable itself. */
177
178void VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
sewardj45f4e7c2005-09-27 19:20:21 +0000179{
180 NSegment* seg;
181 HChar* filename;
182 Bool ok;
183
sewardj018895d2005-12-28 15:19:39 +0000184 /* See comment at start of section for explanation of this do/don't
185 logic. */
186# if defined(VGP_x86_linux)
187 Bool require_no_W = False;
188# else
189 Bool require_no_W = True;
190# endif
191
sewardj45f4e7c2005-09-27 19:20:21 +0000192 seg = VG_(am_find_nsegment)(a);
193 vg_assert(seg);
194
195 filename = VG_(am_get_filename)( seg );
196 if (!filename)
197 return;
198
199 filename = VG_(arena_strdup)( VG_AR_SYMTAB, filename );
200
sewardjf72cced2005-11-08 00:45:47 +0000201 ok = (seg->kind == SkFileC || (seg->kind == SkFileV && allow_SkFileV))
202 && seg->offset == 0
203 && seg->fnIdx != -1
204 && seg->hasR
205 && seg->hasX
sewardj018895d2005-12-28 15:19:39 +0000206 && (require_no_W ? (!seg->hasW) : True)
sewardjf72cced2005-11-08 00:45:47 +0000207 && is_elf_object_file( (const void*)seg->start );
sewardj45f4e7c2005-09-27 19:20:21 +0000208
209 if (!ok) {
210 VG_(arena_free)(VG_AR_SYMTAB, filename);
211 return;
212 }
213
214 nuke_syms_in_range( seg->start, seg->end + 1 - seg->start );
215 VG_(read_seg_symbols)( seg->start, seg->end + 1 - seg->start,
216 seg->offset, filename );
217
218 /* VG_(read_seg_symbols) makes its own copy of filename, so is safe
219 to free it. */
220 VG_(arena_free)(VG_AR_SYMTAB, filename);
221}
222
223void VG_(di_notify_munmap)( Addr a, SizeT len )
224{
225 nuke_syms_in_range(a, len);
226}
227
228void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
229{
230 Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
231# if defined(VGP_x86_linux)
232 exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
233# endif
234 if (0 && !exe_ok)
235 nuke_syms_in_range(a, len);
236}
237
238
239/*------------------------------------------------------------*/
sewardj7a21c612005-02-18 09:38:08 +0000240/*--- ---*/
241/*------------------------------------------------------------*/
242
sewardjde4a1d02002-03-22 01:27:54 +0000243/* Majorly rewritten Sun 3 Feb 02 to enable loading symbols from
244 dlopen()ed libraries, which is something that KDE3 does a lot.
sewardjde4a1d02002-03-22 01:27:54 +0000245
njn25e49d8e72002-09-23 09:36:25 +0000246 Stabs reader greatly improved by Nick Nethercote, Apr 02.
sewardjde4a1d02002-03-22 01:27:54 +0000247*/
248
sewardjde4a1d02002-03-22 01:27:54 +0000249static void freeSegInfo ( SegInfo* si )
250{
jsgfcb1d1c02003-10-14 21:55:10 +0000251 struct strchunk *chunk, *next;
sewardjde4a1d02002-03-22 01:27:54 +0000252 vg_assert(si != NULL);
njn25e49d8e72002-09-23 09:36:25 +0000253 if (si->filename) VG_(arena_free)(VG_AR_SYMTAB, si->filename);
254 if (si->symtab) VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
255 if (si->loctab) VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
jsgfcb1d1c02003-10-14 21:55:10 +0000256 if (si->scopetab) VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
sewardj5c638c22005-04-30 07:55:58 +0000257 if (si->cfisi) VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
jsgfcb1d1c02003-10-14 21:55:10 +0000258
259 for(chunk = si->strchunks; chunk != NULL; chunk = next) {
260 next = chunk->next;
261 VG_(arena_free)(VG_AR_SYMTAB, chunk);
262 }
njn25e49d8e72002-09-23 09:36:25 +0000263 VG_(arena_free)(VG_AR_SYMTAB, si);
sewardjde4a1d02002-03-22 01:27:54 +0000264}
265
266
267/*------------------------------------------------------------*/
268/*--- Adding stuff ---*/
269/*------------------------------------------------------------*/
270
271/* Add a str to the string table, including terminating zero, and
jsgfcb1d1c02003-10-14 21:55:10 +0000272 return pointer to the string in vg_strtab. Unless it's been seen
273 recently, in which case we find the old pointer and return that.
274 This avoids the most egregious duplications.
sewardjde4a1d02002-03-22 01:27:54 +0000275
jsgfcb1d1c02003-10-14 21:55:10 +0000276 JSGF: changed from returning an index to a pointer, and changed to
277 a chunking memory allocator rather than reallocating, so the
278 pointers are stable.
279*/
280
sewardj7eb7c582005-06-23 01:02:53 +0000281Char* ML_(addStr) ( SegInfo* si, Char* str, Int len )
sewardjde4a1d02002-03-22 01:27:54 +0000282{
jsgfcb1d1c02003-10-14 21:55:10 +0000283 struct strchunk *chunk;
njn16eeb4e2005-06-16 03:56:58 +0000284 Int space_needed;
285 Char* p;
njn25e49d8e72002-09-23 09:36:25 +0000286
jsgfcb1d1c02003-10-14 21:55:10 +0000287 if (len == -1)
288 len = VG_(strlen)(str);
njn25e49d8e72002-09-23 09:36:25 +0000289
jsgfcb1d1c02003-10-14 21:55:10 +0000290 space_needed = 1 + len;
njn25e49d8e72002-09-23 09:36:25 +0000291
njn16eeb4e2005-06-16 03:56:58 +0000292 // Allocate a new strtab chunk if necessary
jsgfcb1d1c02003-10-14 21:55:10 +0000293 if (si->strchunks == NULL ||
294 (si->strchunks->strtab_used + space_needed) > STRCHUNKSIZE) {
295 chunk = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*chunk));
296 chunk->strtab_used = 0;
297 chunk->next = si->strchunks;
298 si->strchunks = chunk;
sewardjde4a1d02002-03-22 01:27:54 +0000299 }
jsgfcb1d1c02003-10-14 21:55:10 +0000300 chunk = si->strchunks;
sewardjde4a1d02002-03-22 01:27:54 +0000301
njn16eeb4e2005-06-16 03:56:58 +0000302 p = &chunk->strtab[chunk->strtab_used];
303 VG_(memcpy)(p, str, len);
jsgfcb1d1c02003-10-14 21:55:10 +0000304 chunk->strtab[chunk->strtab_used+len] = '\0';
305 chunk->strtab_used += space_needed;
sewardjde4a1d02002-03-22 01:27:54 +0000306
njn16eeb4e2005-06-16 03:56:58 +0000307 return p;
sewardjde4a1d02002-03-22 01:27:54 +0000308}
309
310/* Add a symbol to the symbol table. */
sewardjde4a1d02002-03-22 01:27:54 +0000311static __inline__
312void addSym ( SegInfo* si, RiSym* sym )
313{
sewardj05bcdcb2003-05-18 10:05:38 +0000314 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000315 RiSym* new_tab;
316
317 /* Ignore zero-sized syms. */
318 if (sym->size == 0) return;
319
320 if (si->symtab_used == si->symtab_size) {
321 new_sz = 2 * si->symtab_size;
322 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000323 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiSym) );
sewardjde4a1d02002-03-22 01:27:54 +0000324 if (si->symtab != NULL) {
325 for (i = 0; i < si->symtab_used; i++)
326 new_tab[i] = si->symtab[i];
njn25e49d8e72002-09-23 09:36:25 +0000327 VG_(arena_free)(VG_AR_SYMTAB, si->symtab);
sewardjde4a1d02002-03-22 01:27:54 +0000328 }
329 si->symtab = new_tab;
330 si->symtab_size = new_sz;
331 }
332
333 si->symtab[si->symtab_used] = *sym;
334 si->symtab_used++;
335 vg_assert(si->symtab_used <= si->symtab_size);
336}
337
338/* Add a location to the location table. */
339
340static __inline__
341void addLoc ( SegInfo* si, RiLoc* loc )
342{
sewardj05bcdcb2003-05-18 10:05:38 +0000343 UInt new_sz, i;
sewardjde4a1d02002-03-22 01:27:54 +0000344 RiLoc* new_tab;
345
njne0ee0712002-05-03 16:41:05 +0000346 /* Zero-sized locs should have been ignored earlier */
347 vg_assert(loc->size > 0);
sewardjde4a1d02002-03-22 01:27:54 +0000348
349 if (si->loctab_used == si->loctab_size) {
350 new_sz = 2 * si->loctab_size;
351 if (new_sz == 0) new_sz = 500;
njn25e49d8e72002-09-23 09:36:25 +0000352 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(RiLoc) );
sewardjde4a1d02002-03-22 01:27:54 +0000353 if (si->loctab != NULL) {
354 for (i = 0; i < si->loctab_used; i++)
355 new_tab[i] = si->loctab[i];
njn25e49d8e72002-09-23 09:36:25 +0000356 VG_(arena_free)(VG_AR_SYMTAB, si->loctab);
sewardjde4a1d02002-03-22 01:27:54 +0000357 }
358 si->loctab = new_tab;
359 si->loctab_size = new_sz;
360 }
361
362 si->loctab[si->loctab_used] = *loc;
363 si->loctab_used++;
364 vg_assert(si->loctab_used <= si->loctab_size);
365}
366
367
sewardjb51f2e62002-06-01 23:11:19 +0000368/* Top-level place to call to add a source-location mapping entry. */
369
sewardj7eb7c582005-06-23 01:02:53 +0000370void ML_(addLineInfo) ( SegInfo* si,
jsgfcb1d1c02003-10-14 21:55:10 +0000371 Char* filename,
sewardj7cee6f92005-06-13 17:39:06 +0000372 Char* dirname, /* NULL == directory is unknown */
jsgfcb1d1c02003-10-14 21:55:10 +0000373 Addr this,
374 Addr next,
375 Int lineno,
376 Int entry /* only needed for debug printing */
sewardj7cee6f92005-06-13 17:39:06 +0000377 )
sewardjb51f2e62002-06-01 23:11:19 +0000378{
jsgfcb1d1c02003-10-14 21:55:10 +0000379 static const Bool debug = False;
sewardjb51f2e62002-06-01 23:11:19 +0000380 RiLoc loc;
381 Int size = next - this;
382
383 /* Ignore zero-sized locs */
384 if (this == next) return;
385
jsgfcb1d1c02003-10-14 21:55:10 +0000386 if (debug)
sewardj7cee6f92005-06-13 17:39:06 +0000387 VG_(printf)( " src %s %s line %d %p-%p\n",
388 dirname ? dirname : (Char*)"(unknown)",
389 filename, lineno, this, next );
jsgfcb1d1c02003-10-14 21:55:10 +0000390
sewardjb51f2e62002-06-01 23:11:19 +0000391 /* Maximum sanity checking. Some versions of GNU as do a shabby
392 * job with stabs entries; if anything looks suspicious, revert to
393 * a size of 1. This should catch the instruction of interest
394 * (since if using asm-level debug info, one instruction will
395 * correspond to one line, unlike with C-level debug info where
396 * multiple instructions can map to the one line), but avoid
397 * catching any other instructions bogusly. */
thughesc1c57952004-11-01 17:36:15 +0000398 if (this > next) {
399 if (VG_(clo_verbosity) > 2) {
400 VG_(message)(Vg_DebugMsg,
401 "warning: line info addresses out of order "
402 "at entry %d: 0x%x 0x%x", entry, this, next);
403 }
sewardjb51f2e62002-06-01 23:11:19 +0000404 size = 1;
405 }
406
407 if (size > MAX_LOC_SIZE) {
sewardjd84606d2002-06-18 01:04:57 +0000408 if (0)
sewardjb51f2e62002-06-01 23:11:19 +0000409 VG_(message)(Vg_DebugMsg,
sewardj08a50f62002-06-17 02:21:20 +0000410 "warning: line info address range too large "
sewardjb51f2e62002-06-01 23:11:19 +0000411 "at entry %d: %d", entry, size);
412 size = 1;
413 }
414
sewardj08a50f62002-06-17 02:21:20 +0000415 /* vg_assert(this < si->start + si->size && next-1 >= si->start); */
njne306ffe2002-06-08 13:34:17 +0000416 if (this >= si->start + si->size || next-1 < si->start) {
sewardjd84606d2002-06-18 01:04:57 +0000417 if (0)
njn7a740542005-08-25 00:20:56 +0000418 VG_(message)(Vg_DebugMsg,
419 "warning: ignoring line info entry falling "
420 "outside current SegInfo: %p %p %p %p",
421 si->start, si->start + si->size,
422 this, next-1);
njne306ffe2002-06-08 13:34:17 +0000423 return;
424 }
425
426 vg_assert(lineno >= 0);
427 if (lineno > MAX_LINENO) {
njn7a740542005-08-25 00:20:56 +0000428 static Bool complained = False;
429 if (!complained) {
430 complained = True;
431 VG_(message)(Vg_UserMsg,
432 "warning: ignoring line info entry with "
433 "huge line number (%d)", lineno);
434 VG_(message)(Vg_UserMsg,
435 " Can't handle line numbers "
436 "greater than %d, sorry", MAX_LINENO);
437 VG_(message)(Vg_UserMsg,
438 "(Nb: this message is only shown once)");
439 }
440 return;
njne306ffe2002-06-08 13:34:17 +0000441 }
sewardjb51f2e62002-06-01 23:11:19 +0000442
443 loc.addr = this;
444 loc.size = (UShort)size;
445 loc.lineno = lineno;
jsgfcb1d1c02003-10-14 21:55:10 +0000446 loc.filename = filename;
sewardj7cee6f92005-06-13 17:39:06 +0000447 loc.dirname = dirname;
sewardjb642dc22002-10-12 17:27:16 +0000448
449 if (0) VG_(message)(Vg_DebugMsg,
450 "addLoc: addr %p, size %d, line %d, file %s",
jsgfcb1d1c02003-10-14 21:55:10 +0000451 this,size,lineno,filename);
sewardjb642dc22002-10-12 17:27:16 +0000452
sewardjb51f2e62002-06-01 23:11:19 +0000453 addLoc ( si, &loc );
454}
455
jsgfcb1d1c02003-10-14 21:55:10 +0000456static __inline__
457void addScopeRange ( SegInfo* si, ScopeRange *range )
458{
459 Int new_sz, i;
460 ScopeRange* new_tab;
461
462 /* Zero-sized scopes should have been ignored earlier */
463 vg_assert(range->size > 0);
464
465 if (si->scopetab_used == si->scopetab_size) {
466 new_sz = 2 * si->scopetab_size;
467 if (new_sz == 0) new_sz = 500;
468 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(*new_tab) );
469 if (si->scopetab != NULL) {
470 for (i = 0; i < si->scopetab_used; i++)
471 new_tab[i] = si->scopetab[i];
472 VG_(arena_free)(VG_AR_SYMTAB, si->scopetab);
473 }
474 si->scopetab = new_tab;
475 si->scopetab_size = new_sz;
476 }
477
478 si->scopetab[si->scopetab_used] = *range;
479 si->scopetab_used++;
480 vg_assert(si->scopetab_used <= si->scopetab_size);
481}
482
483
484/* Top-level place to call to add a source-location mapping entry. */
485
sewardj7eb7c582005-06-23 01:02:53 +0000486void ML_(addScopeInfo) ( SegInfo* si,
jsgfcb1d1c02003-10-14 21:55:10 +0000487 Addr this,
488 Addr next,
489 Scope *scope)
490{
491 static const Bool debug = False;
492 Int size = next - this;
493 ScopeRange range;
494
fitzhardinge83d8a712004-02-05 22:58:37 +0000495 /* Ignore zero-sized or negative scopes */
496 if (size <= 0) {
jsgfcb1d1c02003-10-14 21:55:10 +0000497 if (debug)
498 VG_(printf)("ignoring zero-sized range, scope %p at %p\n", scope, this);
499 return;
500 }
501
502 if (debug)
503 VG_(printf)("adding scope range %p-%p (size=%d) scope %p (%d)\n",
504 this, next, next-this, scope, scope->depth);
505
506 range.addr = this;
507 range.size = size;
508 range.scope = scope;
509
510 addScopeRange ( si, &range );
511}
512
sewardj35165532005-04-30 18:47:48 +0000513
514/* Top-level place to call to add a CFI summary record. The supplied
515 CfiSI is copied. */
sewardj7eb7c582005-06-23 01:02:53 +0000516void ML_(addCfiSI) ( SegInfo* si, CfiSI* cfisi )
sewardj35165532005-04-30 18:47:48 +0000517{
518 static const Bool debug = False;
tom60a4b0b2005-10-12 10:45:27 +0000519 UInt new_sz, i;
520 CfiSI* new_tab;
sewardj35165532005-04-30 18:47:48 +0000521
522 if (debug) {
523 VG_(printf)("adding CfiSI: ");
sewardj7eb7c582005-06-23 01:02:53 +0000524 ML_(ppCfiSI)(cfisi);
sewardj35165532005-04-30 18:47:48 +0000525 }
526
sewardj6b2eefa2005-05-20 02:10:45 +0000527 vg_assert(cfisi->len > 0 && cfisi->len < 2000000);
sewardjbf603752005-05-02 00:36:27 +0000528
sewardjc4f204f2005-05-03 15:23:00 +0000529 /* Rule out ones which are completely outside the segment. These
530 probably indicate some kind of bug, but for the meantime ignore
531 them. */
532 if ( cfisi->base + cfisi->len - 1 < si->start
533 || si->start + si->size - 1 < cfisi->base ) {
sewardj55022aa2005-05-03 16:05:00 +0000534 static Int complaints = 3;
535 if (VG_(clo_trace_cfi) || complaints > 0) {
536 complaints--;
sewardjbe18a592005-05-06 17:01:21 +0000537 if (VG_(clo_verbosity) > 1) {
538 VG_(message)(
539 Vg_DebugMsg,
540 "warning: CfiSI %p .. %p outside segment %p .. %p",
541 cfisi->base,
542 cfisi->base + cfisi->len - 1,
543 si->start,
544 si->start + si->size - 1
545 );
546 }
sewardj55022aa2005-05-03 16:05:00 +0000547 if (VG_(clo_trace_cfi))
sewardj7eb7c582005-06-23 01:02:53 +0000548 ML_(ppCfiSI)(cfisi);
sewardjc4f204f2005-05-03 15:23:00 +0000549 }
550 return;
551 }
552
sewardj35165532005-04-30 18:47:48 +0000553 if (si->cfisi_used == si->cfisi_size) {
554 new_sz = 2 * si->cfisi_size;
555 if (new_sz == 0) new_sz = 20;
556 new_tab = VG_(arena_malloc)(VG_AR_SYMTAB, new_sz * sizeof(CfiSI) );
557 if (si->cfisi != NULL) {
558 for (i = 0; i < si->cfisi_used; i++)
559 new_tab[i] = si->cfisi[i];
560 VG_(arena_free)(VG_AR_SYMTAB, si->cfisi);
561 }
562 si->cfisi = new_tab;
563 si->cfisi_size = new_sz;
564 }
565
566 si->cfisi[si->cfisi_used] = *cfisi;
567 si->cfisi_used++;
568 vg_assert(si->cfisi_used <= si->cfisi_size);
569}
570
571
sewardjde4a1d02002-03-22 01:27:54 +0000572/*------------------------------------------------------------*/
573/*--- Helpers ---*/
574/*------------------------------------------------------------*/
575
576/* Non-fatal -- use vg_panic if terminal. */
sewardj7eb7c582005-06-23 01:02:53 +0000577void ML_(symerr) ( Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000578{
579 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +0000580 VG_(message)(Vg_DebugMsg,"%s", msg );
sewardjde4a1d02002-03-22 01:27:54 +0000581}
582
583
584/* Print a symbol. */
585static
586void printSym ( SegInfo* si, Int i )
587{
588 VG_(printf)( "%5d: %8p .. %8p (%d) %s\n",
589 i,
590 si->symtab[i].addr,
591 si->symtab[i].addr + si->symtab[i].size - 1, si->symtab[i].size,
jsgfcb1d1c02003-10-14 21:55:10 +0000592 si->symtab[i].name );
sewardjde4a1d02002-03-22 01:27:54 +0000593}
594
nethercote80f76782003-11-13 22:34:00 +0000595#define TRACE_SYMTAB(format, args...) \
596 if (VG_(clo_trace_symtab)) { VG_(printf)(format, ## args); }
597
sewardjde4a1d02002-03-22 01:27:54 +0000598
599#if 0
600/* Print the entire sym tab. */
601static __attribute__ ((unused))
602void printSymtab ( void )
603{
604 Int i;
605 VG_(printf)("\n------ BEGIN vg_symtab ------\n");
606 for (i = 0; i < vg_symtab_used; i++)
607 printSym(i);
608 VG_(printf)("------ BEGIN vg_symtab ------\n");
609}
610#endif
611
612#if 0
613/* Paranoid strcat. */
614static
615void safeCopy ( UChar* dst, UInt maxlen, UChar* src )
616{
617 UInt i = 0, j = 0;
618 while (True) {
619 if (i >= maxlen) return;
620 if (dst[i] == 0) break;
621 i++;
622 }
623 while (True) {
624 if (i >= maxlen) return;
625 dst[i] = src[j];
626 if (src[j] == 0) return;
627 i++; j++;
628 }
629}
630#endif
631
sewardjb51f2e62002-06-01 23:11:19 +0000632
sewardjde4a1d02002-03-22 01:27:54 +0000633/*------------------------------------------------------------*/
634/*--- Canonicalisers ---*/
635/*------------------------------------------------------------*/
636
637/* Sort the symtab by starting address, and emit warnings if any
nethercote80f76782003-11-13 22:34:00 +0000638 symbols have overlapping address ranges. We use that old chestnut,
639 shellsort. Mash the table around so as to establish the property
640 that addresses are in order and the ranges to not overlap. This
641 facilitates using binary search to map addresses to symbols when we
642 come to query the table.
sewardjde4a1d02002-03-22 01:27:54 +0000643*/
jsgfcb1d1c02003-10-14 21:55:10 +0000644static Int compare_RiSym(void *va, void *vb) {
645 RiSym *a = (RiSym *)va;
646 RiSym *b = (RiSym *)vb;
647
nethercote05fdfac2004-08-01 20:24:46 +0000648 if (a->addr < b->addr) return -1;
649 if (a->addr > b->addr) return 1;
650 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000651}
652
fitzhardinge1c76dc42003-12-15 09:00:21 +0000653/* Two symbols have the same address. Which name do we prefer?
654
sewardjb5f6f512005-03-10 23:59:00 +0000655 The general rule is to prefer the shorter symbol name. If the
656 symbol contains a '@', which means its versioned, then the length
657 up to the '@' is used for length comparison purposes (so
658 "foo@GLIBC_2.4.2" is considered shorter than "foobar"), but if two
659 symbols have the same length, the one with the version string is
660 preferred. If all else fails, use alphabetical ordering.
njn16eeb4e2005-06-16 03:56:58 +0000661
662 Very occasionally this goes wrong (eg. 'memcmp' and 'bcmp' are aliases
663 in glibc, we choose the 'bcmp' symbol because it's shorter, so we
664 can misdescribe memcmp() as bcmp()). This is hard to avoid. It's
665 mentioned in the FAQ file.
fitzhardinge1c76dc42003-12-15 09:00:21 +0000666 */
667static RiSym *prefersym(RiSym *a, RiSym *b)
668{
sewardjb5f6f512005-03-10 23:59:00 +0000669 Int lena, lenb; /* full length */
670 Int vlena, vlenb; /* length without version */
671 const Char *vpa, *vpb;
fitzhardingeefda47f2003-12-15 23:31:52 +0000672
sewardjb5f6f512005-03-10 23:59:00 +0000673 vlena = lena = VG_(strlen)(a->name);
674 vlenb = lenb = VG_(strlen)(b->name);
fitzhardinge1c76dc42003-12-15 09:00:21 +0000675
sewardjb5f6f512005-03-10 23:59:00 +0000676 vpa = VG_(strchr)(a->name, '@');
677 vpb = VG_(strchr)(b->name, '@');
fitzhardinge1c76dc42003-12-15 09:00:21 +0000678
sewardjb5f6f512005-03-10 23:59:00 +0000679 if (vpa)
680 vlena = vpa - a->name;
681 if (vpb)
682 vlenb = vpb - b->name;
fitzhardingeefda47f2003-12-15 23:31:52 +0000683
njn16eeb4e2005-06-16 03:56:58 +0000684 TRACE_SYMTAB("choosing between '%s' and '%s'\n", a->name, b->name);
685
sewardjb5f6f512005-03-10 23:59:00 +0000686 /* Select the shortest unversioned name */
687 if (vlena < vlenb)
688 return a;
689 else if (vlenb < vlena)
fitzhardinge1c76dc42003-12-15 09:00:21 +0000690 return b;
691
sewardjb5f6f512005-03-10 23:59:00 +0000692 /* Equal lengths; select the versioned name */
693 if (vpa && !vpb)
694 return a;
695 if (vpb && !vpa)
696 return b;
697
698 /* Either both versioned or neither is versioned; select them
699 alphabetically */
700 if (VG_(strcmp)(a->name, b->name) < 0)
701 return a;
702 else
703 return b;
fitzhardinge1c76dc42003-12-15 09:00:21 +0000704}
705
sewardjde4a1d02002-03-22 01:27:54 +0000706static
707void canonicaliseSymtab ( SegInfo* si )
708{
jsgfcb1d1c02003-10-14 21:55:10 +0000709 Int i, j, n_merged, n_truncated;
sewardjde4a1d02002-03-22 01:27:54 +0000710 Addr s1, s2, e1, e2;
711
712# define SWAP(ty,aa,bb) \
713 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
714
jsgfcb1d1c02003-10-14 21:55:10 +0000715 if (si->symtab_used == 0)
716 return;
sewardjde4a1d02002-03-22 01:27:54 +0000717
nethercote3acbb5d2003-11-13 21:50:45 +0000718 VG_(ssort)(si->symtab, si->symtab_used, sizeof(*si->symtab), compare_RiSym);
sewardjde4a1d02002-03-22 01:27:54 +0000719
720 cleanup_more:
721
njn16eeb4e2005-06-16 03:56:58 +0000722 /* If two symbols have identical address ranges, we pick one
723 using prefersym() (see it for details). */
sewardjde4a1d02002-03-22 01:27:54 +0000724 do {
725 n_merged = 0;
726 j = si->symtab_used;
727 si->symtab_used = 0;
728 for (i = 0; i < j; i++) {
729 if (i < j-1
730 && si->symtab[i].addr == si->symtab[i+1].addr
731 && si->symtab[i].size == si->symtab[i+1].size) {
732 n_merged++;
733 /* merge the two into one */
fitzhardinge1c76dc42003-12-15 09:00:21 +0000734 si->symtab[si->symtab_used++] = *prefersym(&si->symtab[i], &si->symtab[i+1]);
sewardjde4a1d02002-03-22 01:27:54 +0000735 i++;
736 } else {
737 si->symtab[si->symtab_used++] = si->symtab[i];
738 }
739 }
nethercote80f76782003-11-13 22:34:00 +0000740 TRACE_SYMTAB( "%d merged\n", n_merged);
sewardjde4a1d02002-03-22 01:27:54 +0000741 }
742 while (n_merged > 0);
743
744 /* Detect and "fix" overlapping address ranges. */
745 n_truncated = 0;
746
sewardj05bcdcb2003-05-18 10:05:38 +0000747 for (i = 0; i < ((Int)si->symtab_used) -1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000748
749 vg_assert(si->symtab[i].addr <= si->symtab[i+1].addr);
750
751 /* Check for common (no overlap) case. */
752 if (si->symtab[i].addr + si->symtab[i].size
753 <= si->symtab[i+1].addr)
754 continue;
755
756 /* There's an overlap. Truncate one or the other. */
757 if (VG_(clo_trace_symtab)) {
758 VG_(printf)("overlapping address ranges in symbol table\n\t");
759 printSym(si,i);
760 VG_(printf)("\t");
761 printSym(si,i+1);
762 VG_(printf)("\n");
763 }
764
765 /* Truncate one or the other. */
766 s1 = si->symtab[i].addr;
767 s2 = si->symtab[i+1].addr;
768 e1 = s1 + si->symtab[i].size - 1;
769 e2 = s2 + si->symtab[i+1].size - 1;
770 if (s1 < s2) {
771 e1 = s2-1;
772 } else {
773 vg_assert(s1 == s2);
774 if (e1 > e2) {
775 s1 = e2+1; SWAP(Addr,s1,s2); SWAP(Addr,e1,e2);
776 } else
777 if (e1 < e2) {
778 s2 = e1+1;
779 } else {
780 /* e1 == e2. Identical addr ranges. We'll eventually wind
781 up back at cleanup_more, which will take care of it. */
782 }
783 }
784 si->symtab[i].addr = s1;
785 si->symtab[i+1].addr = s2;
786 si->symtab[i].size = e1 - s1 + 1;
787 si->symtab[i+1].size = e2 - s2 + 1;
788 vg_assert(s1 <= s2);
789 vg_assert(si->symtab[i].size > 0);
790 vg_assert(si->symtab[i+1].size > 0);
791 /* It may be that the i+1 entry now needs to be moved further
792 along to maintain the address order requirement. */
793 j = i+1;
sewardj05bcdcb2003-05-18 10:05:38 +0000794 while (j < ((Int)si->symtab_used)-1
sewardjde4a1d02002-03-22 01:27:54 +0000795 && si->symtab[j].addr > si->symtab[j+1].addr) {
796 SWAP(RiSym,si->symtab[j],si->symtab[j+1]);
797 j++;
798 }
799 n_truncated++;
800 }
801
802 if (n_truncated > 0) goto cleanup_more;
803
804 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000805 for (i = 0; i < ((Int)si->symtab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000806 /* No zero-sized symbols. */
807 vg_assert(si->symtab[i].size > 0);
808 /* In order. */
809 vg_assert(si->symtab[i].addr < si->symtab[i+1].addr);
810 /* No overlaps. */
811 vg_assert(si->symtab[i].addr + si->symtab[i].size - 1
812 < si->symtab[i+1].addr);
813 }
814# undef SWAP
815}
816
jsgfcb1d1c02003-10-14 21:55:10 +0000817/* Sort the scope range table by starting address. Mash the table
818 around so as to establish the property that addresses are in order
819 and the ranges do not overlap. This facilitates using binary
820 search to map addresses to scopes when we come to query the
821 table.
822*/
823static Int compare_ScopeRange(void *va, void *vb) {
824 ScopeRange *a = (ScopeRange *)va;
825 ScopeRange *b = (ScopeRange *)vb;
826
nethercote05fdfac2004-08-01 20:24:46 +0000827 if (a->addr < b->addr) return -1;
828 if (a->addr > b->addr) return 1;
829 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000830}
831
832static
833void canonicaliseScopetab ( SegInfo* si )
834{
835 Int i,j;
836
837 if (si->scopetab_used == 0)
838 return;
839
840 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000841 VG_(ssort)(si->scopetab, si->scopetab_used, sizeof(*si->scopetab),
842 compare_ScopeRange);
jsgfcb1d1c02003-10-14 21:55:10 +0000843
844 /* If two adjacent entries overlap, truncate the first. */
845 for (i = 0; i < si->scopetab_used-1; i++) {
846 if (si->scopetab[i].addr + si->scopetab[i].size > si->scopetab[i+1].addr) {
847 Int new_size = si->scopetab[i+1].addr - si->scopetab[i].addr;
848
849 if (new_size < 0)
850 si->scopetab[i].size = 0;
851 else
852 si->scopetab[i].size = new_size;
853 }
854 }
855
856 /* Zap any zero-sized entries resulting from the truncation
857 process. */
858 j = 0;
859 for (i = 0; i < si->scopetab_used; i++) {
860 if (si->scopetab[i].size > 0) {
sewardj79069582005-07-23 17:45:15 +0000861 if (j != i)
862 si->scopetab[j] = si->scopetab[i];
jsgfcb1d1c02003-10-14 21:55:10 +0000863 j++;
864 }
865 }
866 si->scopetab_used = j;
867
868 /* Ensure relevant postconditions hold. */
869 for (i = 0; i < si->scopetab_used-1; i++) {
870 /*
871 VG_(printf)("%d (%d) %d 0x%x\n",
872 i, si->scopetab[i+1].confident,
873 si->scopetab[i+1].size, si->scopetab[i+1].addr );
874 */
875 /* No zero-sized symbols. */
876 vg_assert(si->scopetab[i].size > 0);
877 /* In order. */
878 if (si->scopetab[i].addr >= si->scopetab[i+1].addr)
879 VG_(printf)("si->scopetab[%d] = %p,size=%d [%d] = %p,size=%d\n",
880 i, si->scopetab[i].addr, si->scopetab[i].size,
881 i+1, si->scopetab[i+1].addr, si->scopetab[i+1].size);
882 vg_assert(si->scopetab[i].addr < si->scopetab[i+1].addr);
883 /* No overlaps. */
884 vg_assert(si->scopetab[i].addr + si->scopetab[i].size - 1
885 < si->scopetab[i+1].addr);
886 }
887}
sewardjde4a1d02002-03-22 01:27:54 +0000888
889
890/* Sort the location table by starting address. Mash the table around
891 so as to establish the property that addresses are in order and the
892 ranges do not overlap. This facilitates using binary search to map
sewardjb51f2e62002-06-01 23:11:19 +0000893 addresses to locations when we come to query the table.
894*/
jsgfcb1d1c02003-10-14 21:55:10 +0000895static Int compare_RiLoc(void *va, void *vb) {
896 RiLoc *a = (RiLoc *)va;
897 RiLoc *b = (RiLoc *)vb;
898
nethercote05fdfac2004-08-01 20:24:46 +0000899 if (a->addr < b->addr) return -1;
900 if (a->addr > b->addr) return 1;
901 return 0;
jsgfcb1d1c02003-10-14 21:55:10 +0000902}
903
sewardjde4a1d02002-03-22 01:27:54 +0000904static
905void canonicaliseLoctab ( SegInfo* si )
906{
njn16eeb4e2005-06-16 03:56:58 +0000907 Int i, j;
sewardjde4a1d02002-03-22 01:27:54 +0000908
909# define SWAP(ty,aa,bb) \
910 do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0);
911
jsgfcb1d1c02003-10-14 21:55:10 +0000912 if (si->loctab_used == 0)
913 return;
914
sewardjde4a1d02002-03-22 01:27:54 +0000915 /* Sort by start address. */
nethercote3acbb5d2003-11-13 21:50:45 +0000916 VG_(ssort)(si->loctab, si->loctab_used, sizeof(*si->loctab), compare_RiLoc);
sewardjde4a1d02002-03-22 01:27:54 +0000917
918 /* If two adjacent entries overlap, truncate the first. */
sewardj05bcdcb2003-05-18 10:05:38 +0000919 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000920 vg_assert(si->loctab[i].size < 10000);
921 if (si->loctab[i].addr + si->loctab[i].size > si->loctab[i+1].addr) {
922 /* Do this in signed int32 because the actual .size fields
njna1685902005-03-16 04:09:21 +0000923 are only 12 bits. */
sewardjde4a1d02002-03-22 01:27:54 +0000924 Int new_size = si->loctab[i+1].addr - si->loctab[i].addr;
925 if (new_size < 0) {
926 si->loctab[i].size = 0;
927 } else
njna1685902005-03-16 04:09:21 +0000928 if (new_size > MAX_LOC_SIZE) {
929 si->loctab[i].size = MAX_LOC_SIZE;
sewardjde4a1d02002-03-22 01:27:54 +0000930 } else {
931 si->loctab[i].size = (UShort)new_size;
932 }
933 }
934 }
935
936 /* Zap any zero-sized entries resulting from the truncation
937 process. */
938 j = 0;
sewardj05bcdcb2003-05-18 10:05:38 +0000939 for (i = 0; i < (Int)si->loctab_used; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000940 if (si->loctab[i].size > 0) {
sewardj79069582005-07-23 17:45:15 +0000941 if (j != i)
942 si->loctab[j] = si->loctab[i];
sewardjde4a1d02002-03-22 01:27:54 +0000943 j++;
944 }
945 }
946 si->loctab_used = j;
947
948 /* Ensure relevant postconditions hold. */
sewardj05bcdcb2003-05-18 10:05:38 +0000949 for (i = 0; i < ((Int)si->loctab_used)-1; i++) {
sewardjde4a1d02002-03-22 01:27:54 +0000950 /*
951 VG_(printf)("%d (%d) %d 0x%x\n",
952 i, si->loctab[i+1].confident,
953 si->loctab[i+1].size, si->loctab[i+1].addr );
954 */
955 /* No zero-sized symbols. */
956 vg_assert(si->loctab[i].size > 0);
957 /* In order. */
958 vg_assert(si->loctab[i].addr < si->loctab[i+1].addr);
959 /* No overlaps. */
960 vg_assert(si->loctab[i].addr + si->loctab[i].size - 1
961 < si->loctab[i+1].addr);
962 }
963# undef SWAP
964}
965
966
sewardj3a1c7db2005-05-02 09:43:44 +0000967/* Sort the call-frame-info table by starting address. Mash the table
968 around so as to establish the property that addresses are in order
969 and the ranges do not overlap. This facilitates using binary
970 search to map addresses to locations when we come to query the
971 table.
972
973 Also, set cfisi_minaddr and cfisi_maxaddr to be the min and max of
974 any of the address ranges contained in cfisi[0 .. cfisi_used-1], so
975 as to facilitate rapidly skipping this SegInfo when looking for an
976 address which falls outside that range.
977*/
978static Int compare_CfiSI(void *va, void *vb) {
979 CfiSI *a = (CfiSI*)va;
980 CfiSI *b = (CfiSI*)vb;
981
982 if (a->base < b->base) return -1;
983 if (a->base > b->base) return 1;
984 return 0;
985}
986
sewardjbf603752005-05-02 00:36:27 +0000987static
988void canonicaliseCfiSI ( SegInfo* si )
989{
sewardje75d1572005-07-23 17:14:03 +0000990 Int i, j;
sewardjbf603752005-05-02 00:36:27 +0000991 const Addr minAddr = 0;
992 const Addr maxAddr = ~minAddr;
993
sewardje75d1572005-07-23 17:14:03 +0000994 /* Note: take care in here. si->cfisi can be NULL, in which
995 case _used and _size fields will be zero. */
996 if (si->cfisi == NULL) {
997 vg_assert(si->cfisi_used == 0);
998 vg_assert(si->cfisi_size == 0);
999 }
1000
sewardjbf603752005-05-02 00:36:27 +00001001 /* Set cfisi_minaddr and cfisi_maxaddr to summarise the entire
1002 address range contained in cfisi[0 .. cfisi_used-1]. */
1003 si->cfisi_minaddr = maxAddr;
1004 si->cfisi_maxaddr = minAddr;
sewardje75d1572005-07-23 17:14:03 +00001005 for (i = 0; i < (Int)si->cfisi_used; i++) {
sewardjbf603752005-05-02 00:36:27 +00001006 Addr here_min = si->cfisi[i].base;
1007 Addr here_max = si->cfisi[i].base + si->cfisi[i].len - 1;
1008 if (here_min < si->cfisi_minaddr)
1009 si->cfisi_minaddr = here_min;
1010 if (here_max > si->cfisi_maxaddr)
1011 si->cfisi_maxaddr = here_max;
1012 }
sewardj520e3492005-05-02 10:39:16 +00001013
1014 if (VG_(clo_trace_cfi))
1015 VG_(printf)("canonicaliseCfiSI: %d entries, %p .. %p\n",
1016 si->cfisi_used,
1017 si->cfisi_minaddr, si->cfisi_maxaddr);
sewardj3a1c7db2005-05-02 09:43:44 +00001018
1019 /* Sort the cfisi array by base address. */
1020 VG_(ssort)(si->cfisi, si->cfisi_used, sizeof(*si->cfisi), compare_CfiSI);
1021
sewardje75d1572005-07-23 17:14:03 +00001022 /* If two adjacent entries overlap, truncate the first. */
1023 for (i = 0; i < (Int)si->cfisi_used-1; i++) {
1024 if (si->cfisi[i].base + si->cfisi[i].len > si->cfisi[i+1].base) {
1025 Int new_len = si->cfisi[i+1].base - si->cfisi[i].base;
1026 /* how could it be otherwise? The entries are sorted by the
1027 .base field. */
1028 vg_assert(new_len >= 0);
1029 vg_assert(new_len <= si->cfisi[i].len);
1030 si->cfisi[i].len = new_len;
1031 }
1032 }
1033
1034 /* Zap any zero-sized entries resulting from the truncation
1035 process. */
1036 j = 0;
1037 for (i = 0; i < (Int)si->cfisi_used; i++) {
1038 if (si->cfisi[i].len > 0) {
sewardj79069582005-07-23 17:45:15 +00001039 if (j != i)
1040 si->cfisi[j] = si->cfisi[i];
sewardje75d1572005-07-23 17:14:03 +00001041 j++;
1042 }
1043 }
1044 /* VG_(printf)("XXXXXXXXXXXXX %d %d\n", si->cfisi_used, j); */
1045 si->cfisi_used = j;
1046
sewardj3a1c7db2005-05-02 09:43:44 +00001047 /* Ensure relevant postconditions hold. */
sewardje75d1572005-07-23 17:14:03 +00001048 for (i = 0; i < (Int)si->cfisi_used; i++) {
sewardj3a1c7db2005-05-02 09:43:44 +00001049 /* No zero-length ranges. */
1050 vg_assert(si->cfisi[i].len > 0);
1051 /* Makes sense w.r.t. summary address range */
1052 vg_assert(si->cfisi[i].base >= si->cfisi_minaddr);
1053 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
1054 <= si->cfisi_maxaddr);
1055
1056 if (i < si->cfisi_used - 1) {
sewardjc4f204f2005-05-03 15:23:00 +00001057 /*
1058 if (!(si->cfisi[i].base < si->cfisi[i+1].base)) {
1059 VG_(printf)("\nOOO cfisis:\n");
cerion7b2c38c2005-06-23 07:52:54 +00001060 ML_(ppCfiSI)(&si->cfisi[i]);
1061 ML_(ppCfiSI)(&si->cfisi[i+1]);
sewardjc4f204f2005-05-03 15:23:00 +00001062 }
1063 */
sewardj3a1c7db2005-05-02 09:43:44 +00001064 /* In order. */
1065 vg_assert(si->cfisi[i].base < si->cfisi[i+1].base);
1066 /* No overlaps. */
1067 vg_assert(si->cfisi[i].base + si->cfisi[i].len - 1
1068 < si->cfisi[i+1].base);
1069 }
1070 }
1071
sewardjbf603752005-05-02 00:36:27 +00001072}
1073
1074
sewardjde4a1d02002-03-22 01:27:54 +00001075/*------------------------------------------------------------*/
sewardjb51f2e62002-06-01 23:11:19 +00001076/*--- Read info from a .so/exe file. ---*/
1077/*------------------------------------------------------------*/
1078
sewardj0d1a8962005-09-28 01:23:25 +00001079static Bool is_elf_object_file(const void *buf)
fitzhardinge98abfc72003-12-16 02:05:15 +00001080{
1081 {
sewardj7a21c612005-02-18 09:38:08 +00001082 ElfXX_Ehdr *ehdr = (ElfXX_Ehdr *)buf;
fitzhardinge98abfc72003-12-16 02:05:15 +00001083 Int ok = 1;
1084
1085 ok &= (ehdr->e_ident[EI_MAG0] == 0x7F
1086 && ehdr->e_ident[EI_MAG1] == 'E'
1087 && ehdr->e_ident[EI_MAG2] == 'L'
1088 && ehdr->e_ident[EI_MAG3] == 'F');
njnaf839f52005-06-23 03:27:57 +00001089 ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS
sewardj6e340c72005-07-10 00:53:42 +00001090 && ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX
fitzhardinge98abfc72003-12-16 02:05:15 +00001091 && ehdr->e_ident[EI_VERSION] == EV_CURRENT);
1092 ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN);
njnaf839f52005-06-23 03:27:57 +00001093 ok &= (ehdr->e_machine == VG_ELF_MACHINE);
fitzhardinge98abfc72003-12-16 02:05:15 +00001094 ok &= (ehdr->e_version == EV_CURRENT);
1095 ok &= (ehdr->e_shstrndx != SHN_UNDEF);
1096 ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0);
1097 ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0);
1098
1099 if (ok)
1100 return True;
1101 }
1102
1103 /* other file formats here? */
1104
1105 return False;
1106}
1107
njn16eeb4e2005-06-16 03:56:58 +00001108static Bool is_interesting_symbol(SegInfo* si, ElfXX_Sym* sym,
1109 Char* sym_name, Addr sym_addr)
rjwalshe4e779d2004-04-16 23:02:29 +00001110{
njn16eeb4e2005-06-16 03:56:58 +00001111 /* Figure out if we're interested in the symbol.
1112 Firstly, is it of the right flavour? */
1113 if ( ! ( (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL ||
1114 ELFXX_ST_BIND(sym->st_info) == STB_LOCAL ||
1115 ELFXX_ST_BIND(sym->st_info) == STB_WEAK)
1116 &&
1117 (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC ||
1118 (VG_(needs).data_syms
1119 && ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT))
1120 )
1121 )
1122 return False;
rjwalshe4e779d2004-04-16 23:02:29 +00001123
njn16eeb4e2005-06-16 03:56:58 +00001124 /* Secondly, if it's apparently in a GOT or PLT, it's really
1125 a reference to a symbol defined elsewhere, so ignore it. */
1126 if (si->got_start != 0
1127 && sym_addr >= si->got_start
1128 && sym_addr < si->got_start + si->got_size) {
1129 TRACE_SYMTAB("ignore -- in GOT: %s\n", sym_name);
1130 return False;
rjwalshe4e779d2004-04-16 23:02:29 +00001131 }
njn16eeb4e2005-06-16 03:56:58 +00001132 if (si->plt_start != 0
1133 && sym_addr >= si->plt_start
1134 && sym_addr < si->plt_start + si->plt_size) {
1135 TRACE_SYMTAB("ignore -- in PLT: %s\n", sym_name);
sewardj9ee81f52005-04-02 17:38:59 +00001136 return False;
1137 }
1138
njn16eeb4e2005-06-16 03:56:58 +00001139 /* Don't bother if nameless, or zero-sized. */
1140 if (sym->st_name == (ElfXX_Word)NULL
1141 || /* VG_(strlen)(sym_name) == 0 */
1142 /* equivalent but cheaper ... */
1143 sym_name[0] == 0
1144 || sym->st_size == 0) {
1145 TRACE_SYMTAB("ignore -- size=0: %s\n", sym_name);
1146 return False;
sewardj9ee81f52005-04-02 17:38:59 +00001147 }
1148
njn16eeb4e2005-06-16 03:56:58 +00001149 /* This seems to significantly reduce the number of junk
1150 symbols, and particularly reduces the number of
1151 overlapping address ranges. Don't ask me why ... */
1152 if ((Int)sym->st_value == 0) {
1153 TRACE_SYMTAB( "ignore -- valu=0: %s\n", sym_name);
1154 return False;
1155 }
1156
1157 /* If no part of the symbol falls within the mapped range,
1158 ignore it. */
1159 if (sym_addr+sym->st_size <= si->start
1160 || sym_addr >= si->start+si->size) {
1161 TRACE_SYMTAB( "ignore -- outside mapped range\n" );
1162 return False;
1163 }
1164
1165 // It is an interesting symbol!
rjwalshe4e779d2004-04-16 23:02:29 +00001166 return True;
1167}
1168
nethercote80f76782003-11-13 22:34:00 +00001169/* Read a symbol table (normal or dynamic) */
1170static
rjwalshe4e779d2004-04-16 23:02:29 +00001171void read_symtab( SegInfo* si, Char* tab_name, Bool do_intercepts,
sewardj7a21c612005-02-18 09:38:08 +00001172 ElfXX_Sym* o_symtab, UInt o_symtab_sz,
nethercote80f76782003-11-13 22:34:00 +00001173 UChar* o_strtab, UInt o_strtab_sz )
1174{
1175 Int i;
1176 Addr sym_addr;
njn16eeb4e2005-06-16 03:56:58 +00001177 Char* sym_name;
nethercote80f76782003-11-13 22:34:00 +00001178 RiSym risym;
mueller82df83e2003-11-19 22:05:35 +00001179 Char* name;
njn16eeb4e2005-06-16 03:56:58 +00001180 ElfXX_Sym* sym;
mueller82df83e2003-11-19 22:05:35 +00001181
nethercote80f76782003-11-13 22:34:00 +00001182 if (o_strtab == NULL || o_symtab == NULL) {
jseward0edbfb52003-12-12 06:22:06 +00001183 Char buf[80];
1184 vg_assert(VG_(strlen)(tab_name) < 40);
1185 VG_(sprintf)(buf, " object doesn't have a %s", tab_name);
sewardj7eb7c582005-06-23 01:02:53 +00001186 ML_(symerr)(buf);
nethercote80f76782003-11-13 22:34:00 +00001187 return;
1188 }
1189
1190 TRACE_SYMTAB("Reading %s (%d entries)\n", tab_name,
sewardj7a21c612005-02-18 09:38:08 +00001191 o_symtab_sz/sizeof(ElfXX_Sym) );
nethercote80f76782003-11-13 22:34:00 +00001192
1193 /* Perhaps should start at i = 1; ELF docs suggest that entry
njn02bc4b82005-05-15 17:28:26 +00001194 0 always denotes 'unknown symbol'. */
sewardj7a21c612005-02-18 09:38:08 +00001195 for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) {
njn16eeb4e2005-06-16 03:56:58 +00001196 sym = & o_symtab[i];
1197 sym_name = (Char*)(o_strtab + sym->st_name);
tomf26d0682005-04-02 14:57:43 +00001198 sym_addr = si->offset + sym->st_value;
nethercote80f76782003-11-13 22:34:00 +00001199
1200 if (VG_(clo_trace_symtab)) {
1201 VG_(printf)("raw symbol [%d]: ", i);
sewardj7a21c612005-02-18 09:38:08 +00001202 switch (ELFXX_ST_BIND(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001203 case STB_LOCAL: VG_(printf)("LOC "); break;
1204 case STB_GLOBAL: VG_(printf)("GLO "); break;
1205 case STB_WEAK: VG_(printf)("WEA "); break;
1206 case STB_LOPROC: VG_(printf)("lop "); break;
1207 case STB_HIPROC: VG_(printf)("hip "); break;
1208 default: VG_(printf)("??? "); break;
1209 }
sewardj7a21c612005-02-18 09:38:08 +00001210 switch (ELFXX_ST_TYPE(sym->st_info)) {
nethercote80f76782003-11-13 22:34:00 +00001211 case STT_NOTYPE: VG_(printf)("NOT "); break;
1212 case STT_OBJECT: VG_(printf)("OBJ "); break;
1213 case STT_FUNC: VG_(printf)("FUN "); break;
1214 case STT_SECTION: VG_(printf)("SEC "); break;
1215 case STT_FILE: VG_(printf)("FIL "); break;
1216 case STT_LOPROC: VG_(printf)("lop "); break;
1217 case STT_HIPROC: VG_(printf)("hip "); break;
1218 default: VG_(printf)("??? "); break;
1219 }
1220 VG_(printf)(
1221 ": value %p, size %d, name %s\n",
1222 sym_addr, sym->st_size,
njn16eeb4e2005-06-16 03:56:58 +00001223 ( sym->st_name ? sym_name : (Char*)"NONAME" ) );
nethercote80f76782003-11-13 22:34:00 +00001224 }
nethercote80f76782003-11-13 22:34:00 +00001225
njn16eeb4e2005-06-16 03:56:58 +00001226 // Record interesting symbols in our symtab.
1227 if ( is_interesting_symbol(si, sym, sym_name, sym_addr) ) {
1228 vg_assert(sym->st_name != 0);
1229 vg_assert(sym_name[0] != 0);
sewardj7eb7c582005-06-23 01:02:53 +00001230 name = ML_(addStr) ( si, sym_name, -1 );
njn16eeb4e2005-06-16 03:56:58 +00001231 vg_assert(name != NULL);
1232
1233 /*
1234 * Is this symbol a magic valgrind-intercept symbol? If so,
1235 * hand this off to the redir module.
1236 *
1237 * Note: this function can change the symbol name just added to
1238 * the string table. Importantly, it never makes it bigger.
1239 */
1240 if (do_intercepts) {
1241 VG_(maybe_redir_or_notify)( name, sym_addr );
1242 }
1243
1244 risym.addr = sym_addr;
1245 risym.size = sym->st_size;
1246 risym.name = name;
1247 addSym ( si, &risym );
rjwalshe4e779d2004-04-16 23:02:29 +00001248 }
nethercote80f76782003-11-13 22:34:00 +00001249 }
1250}
1251
thughesc035bd92004-06-13 09:59:02 +00001252/*
1253 * This routine for calculating the CRC for a separate debug file
1254 * is GPLed code borrowed from binutils.
1255 */
1256static UInt
1257calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
1258{
1259 static const UInt crc32_table[256] =
1260 {
1261 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
1262 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
1263 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
1264 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1265 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
1266 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
1267 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
1268 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1269 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
1270 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
1271 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
1272 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1273 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
1274 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
1275 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
1276 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1277 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
1278 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
1279 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
1280 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1281 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
1282 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
1283 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
1284 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1285 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
1286 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
1287 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1288 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1289 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1290 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1291 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1292 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1293 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1294 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1295 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1296 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1297 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1298 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1299 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1300 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1301 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1302 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1303 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1304 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1305 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1306 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1307 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1308 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1309 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1310 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1311 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1312 0x2d02ef8d
1313 };
1314 const UChar *end;
1315
1316 crc = ~crc & 0xffffffff;
1317 for (end = buf + len; buf < end; ++ buf)
1318 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
1319 return ~crc & 0xffffffff;;
1320}
1321
1322/*
1323 * Try and open a separate debug file, ignoring any where the CRC does
1324 * not match the value from the main object file.
1325 */
1326static
1327Addr open_debug_file( Char* name, UInt crc, UInt* size )
1328{
sewardj45f4e7c2005-09-27 19:20:21 +00001329 SysRes fd, sres;
thughesc035bd92004-06-13 09:59:02 +00001330 struct vki_stat stat_buf;
sewardjb5f6f512005-03-10 23:59:00 +00001331 UInt calccrc;
thughesc035bd92004-06-13 09:59:02 +00001332
sewardj92645592005-07-23 09:18:34 +00001333 fd = VG_(open)(name, VKI_O_RDONLY, 0);
1334 if (fd.isError)
thughesc035bd92004-06-13 09:59:02 +00001335 return 0;
1336
sewardj92645592005-07-23 09:18:34 +00001337 if (VG_(fstat)(fd.val, &stat_buf) != 0) {
1338 VG_(close)(fd.val);
thughesc035bd92004-06-13 09:59:02 +00001339 return 0;
1340 }
1341
sewardjb5f6f512005-03-10 23:59:00 +00001342 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001343 VG_(message)(Vg_DebugMsg, "Reading debug info from %s...", name);
sewardjb5f6f512005-03-10 23:59:00 +00001344
thughesc035bd92004-06-13 09:59:02 +00001345 *size = stat_buf.st_size;
1346
sewardj45f4e7c2005-09-27 19:20:21 +00001347 sres = VG_(am_mmap_file_float_valgrind)
1348 ( *size, VKI_PROT_READ, fd.val, 0 );
thughesc035bd92004-06-13 09:59:02 +00001349
sewardj92645592005-07-23 09:18:34 +00001350 VG_(close)(fd.val);
thughesc035bd92004-06-13 09:59:02 +00001351
sewardj45f4e7c2005-09-27 19:20:21 +00001352 if (sres.isError)
1353 return 0;
1354
1355 calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sres.val, *size);
sewardjb5f6f512005-03-10 23:59:00 +00001356 if (calccrc != crc) {
sewardj45f4e7c2005-09-27 19:20:21 +00001357 SysRes res = VG_(am_munmap_valgrind)(sres.val, *size);
1358 vg_assert(!res.isError);
sewardjb5f6f512005-03-10 23:59:00 +00001359 if (VG_(clo_verbosity) > 1)
njn1fd5eb22005-03-13 05:43:23 +00001360 VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc);
thughesc035bd92004-06-13 09:59:02 +00001361 return 0;
1362 }
1363
sewardj45f4e7c2005-09-27 19:20:21 +00001364 return sres.val;
thughesc035bd92004-06-13 09:59:02 +00001365}
1366
1367/*
nethercoteb1e1ad42004-08-03 23:44:12 +00001368 * Try to find a separate debug file for a given object file.
thughesc035bd92004-06-13 09:59:02 +00001369 */
1370static
1371Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size )
1372{
sewardjb5f6f512005-03-10 23:59:00 +00001373 Char *objdir = VG_(arena_strdup)(VG_AR_SYMTAB, objpath);
thughesc035bd92004-06-13 09:59:02 +00001374 Char *objdirptr;
1375 Char *debugpath;
1376 Addr addr = 0;
1377
1378 if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
1379 *objdirptr = '\0';
1380
sewardjb5f6f512005-03-10 23:59:00 +00001381 debugpath = VG_(arena_malloc)(VG_AR_SYMTAB, VG_(strlen)(objdir) + VG_(strlen)(debugname) + 16);
thughesc035bd92004-06-13 09:59:02 +00001382
1383 VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
1384
1385 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1386 VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
1387 if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
1388 VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
1389 addr = open_debug_file(debugpath, crc, size);
1390 }
1391 }
1392
sewardjb5f6f512005-03-10 23:59:00 +00001393 VG_(arena_free)(VG_AR_SYMTAB, debugpath);
1394 VG_(arena_free)(VG_AR_SYMTAB, objdir);
thughesc035bd92004-06-13 09:59:02 +00001395
1396 return addr;
1397}
nethercote80f76782003-11-13 22:34:00 +00001398
sewardjde4a1d02002-03-22 01:27:54 +00001399/* Read the symbols from the object/exe specified by the SegInfo into
1400 the tables within the supplied SegInfo. */
1401static
njn695c16e2005-03-27 03:40:28 +00001402Bool read_lib_symbols ( SegInfo* si )
sewardjde4a1d02002-03-22 01:27:54 +00001403{
nethercote80f76782003-11-13 22:34:00 +00001404 Bool res;
sewardj7a21c612005-02-18 09:38:08 +00001405 ElfXX_Ehdr* ehdr; /* The ELF header */
1406 ElfXX_Shdr* shdr; /* The section table */
sewardjde4a1d02002-03-22 01:27:54 +00001407 UChar* sh_strtab; /* The section table's string table */
sewardj45f4e7c2005-09-27 19:20:21 +00001408 SysRes fd, sres;
sewardjde4a1d02002-03-22 01:27:54 +00001409 Int i;
1410 Bool ok;
1411 Addr oimage;
sewardj05bcdcb2003-05-18 10:05:38 +00001412 UInt n_oimage;
thughesc035bd92004-06-13 09:59:02 +00001413 Addr dimage = 0;
1414 UInt n_dimage = 0;
sewardjb3586202002-05-09 17:38:13 +00001415 struct vki_stat stat_buf;
sewardjde4a1d02002-03-22 01:27:54 +00001416
sewardjde4a1d02002-03-22 01:27:54 +00001417 oimage = (Addr)NULL;
1418 if (VG_(clo_verbosity) > 1)
sewardj45f4e7c2005-09-27 19:20:21 +00001419 VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)",
1420 si->filename, si->start );
sewardjde4a1d02002-03-22 01:27:54 +00001421
1422 /* mmap the object image aboard, so that we can read symbols and
1423 line number info out of it. It will be munmapped immediately
1424 thereafter; it is only aboard transiently. */
1425
tom6c93c4f2005-08-05 07:46:32 +00001426 fd = VG_(stat)(si->filename, &stat_buf);
1427 if (fd.isError) {
sewardj7eb7c582005-06-23 01:02:53 +00001428 ML_(symerr)("Can't stat .so/.exe (to determine its size)?!");
sewardj8fe15a32002-10-20 19:29:21 +00001429 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001430 }
1431 n_oimage = stat_buf.st_size;
1432
njn25e49d8e72002-09-23 09:36:25 +00001433 fd = VG_(open)(si->filename, VKI_O_RDONLY, 0);
sewardj92645592005-07-23 09:18:34 +00001434 if (fd.isError) {
sewardj7eb7c582005-06-23 01:02:53 +00001435 ML_(symerr)("Can't open .so/.exe to read symbols?!");
sewardj8fe15a32002-10-20 19:29:21 +00001436 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001437 }
1438
sewardj45f4e7c2005-09-27 19:20:21 +00001439 sres = VG_(am_mmap_file_float_valgrind)
1440 ( n_oimage, VKI_PROT_READ, fd.val, 0 );
fitzhardinge98abfc72003-12-16 02:05:15 +00001441
sewardj92645592005-07-23 09:18:34 +00001442 VG_(close)(fd.val);
nethercote80f76782003-11-13 22:34:00 +00001443
sewardj45f4e7c2005-09-27 19:20:21 +00001444 if (sres.isError) {
njn1fd5eb22005-03-13 05:43:23 +00001445 VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename );
1446 VG_(message)(Vg_UserMsg, " no symbols or debug info loaded" );
sewardj8fe15a32002-10-20 19:29:21 +00001447 return False;
sewardjde4a1d02002-03-22 01:27:54 +00001448 }
1449
sewardj45f4e7c2005-09-27 19:20:21 +00001450 oimage = sres.val;
1451
sewardjde4a1d02002-03-22 01:27:54 +00001452 /* Ok, the object image is safely in oimage[0 .. n_oimage-1].
1453 Now verify that it is a valid ELF .so or executable image.
1454 */
nethercote80f76782003-11-13 22:34:00 +00001455 res = False;
sewardj7a21c612005-02-18 09:38:08 +00001456 ok = (n_oimage >= sizeof(ElfXX_Ehdr));
1457 ehdr = (ElfXX_Ehdr*)oimage;
sewardjde4a1d02002-03-22 01:27:54 +00001458
fitzhardinge98abfc72003-12-16 02:05:15 +00001459 if (ok)
sewardj0d1a8962005-09-28 01:23:25 +00001460 ok &= is_elf_object_file(ehdr);
sewardjde4a1d02002-03-22 01:27:54 +00001461
1462 if (!ok) {
sewardj7eb7c582005-06-23 01:02:53 +00001463 ML_(symerr)("Invalid ELF header, or missing stringtab/sectiontab.");
nethercote80f76782003-11-13 22:34:00 +00001464 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001465 }
1466
1467 /* Walk the LOAD headers in the phdr and update the SegInfo to
1468 include them all, so that this segment also contains data and
1469 bss memory. Also computes correct symbol offset value for this
1470 ELF file. */
sewardj7a21c612005-02-18 09:38:08 +00001471 if (ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) > n_oimage) {
sewardj7eb7c582005-06-23 01:02:53 +00001472 ML_(symerr)("ELF program header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001473 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001474 }
1475 {
1476 Bool offset_set = False;
sewardj7a21c612005-02-18 09:38:08 +00001477 ElfXX_Addr prev_addr = 0;
fitzhardinge98abfc72003-12-16 02:05:15 +00001478 Addr baseaddr = 0;
sewardj8fe15a32002-10-20 19:29:21 +00001479
1480 si->offset = 0;
1481
njn0787fc02005-06-26 02:19:17 +00001482 vg_assert(si->soname == NULL);
1483
nethercote80f76782003-11-13 22:34:00 +00001484 for (i = 0; i < ehdr->e_phnum; i++) {
sewardj7a21c612005-02-18 09:38:08 +00001485 ElfXX_Phdr *o_phdr;
1486 ElfXX_Addr mapped, mapped_end;
sewardj8fe15a32002-10-20 19:29:21 +00001487
sewardj7a21c612005-02-18 09:38:08 +00001488 o_phdr = &((ElfXX_Phdr *)(oimage + ehdr->e_phoff))[i];
sewardj8fe15a32002-10-20 19:29:21 +00001489
njn0787fc02005-06-26 02:19:17 +00001490 // Try to get the soname.
fitzhardinge98abfc72003-12-16 02:05:15 +00001491 if (o_phdr->p_type == PT_DYNAMIC && si->soname == NULL) {
sewardj7a21c612005-02-18 09:38:08 +00001492 const ElfXX_Dyn *dyn = (const ElfXX_Dyn *)(oimage + o_phdr->p_offset);
fitzhardinge98abfc72003-12-16 02:05:15 +00001493 Int stroff = -1;
1494 Char *strtab = NULL;
1495 Int j;
1496
1497 for(j = 0; dyn[j].d_tag != DT_NULL; j++) {
1498 switch(dyn[j].d_tag) {
1499 case DT_SONAME:
1500 stroff = dyn[j].d_un.d_val;
1501 break;
1502
1503 case DT_STRTAB:
1504 strtab = (Char *)oimage + dyn[j].d_un.d_ptr - baseaddr;
1505 break;
1506 }
1507 }
1508
1509 if (stroff != -1 && strtab != 0) {
1510 TRACE_SYMTAB("soname=%s\n", strtab+stroff);
1511 si->soname = VG_(arena_strdup)(VG_AR_SYMTAB, strtab+stroff);
1512 }
1513 }
1514
sewardj8fe15a32002-10-20 19:29:21 +00001515 if (o_phdr->p_type != PT_LOAD)
1516 continue;
1517
1518 if (!offset_set) {
1519 offset_set = True;
1520 si->offset = si->start - o_phdr->p_vaddr;
fitzhardinge98abfc72003-12-16 02:05:15 +00001521 baseaddr = o_phdr->p_vaddr;
sewardj8fe15a32002-10-20 19:29:21 +00001522 }
1523
njn0787fc02005-06-26 02:19:17 +00001524 // Make sure the Phdrs are in order
sewardj8fe15a32002-10-20 19:29:21 +00001525 if (o_phdr->p_vaddr < prev_addr) {
sewardj7eb7c582005-06-23 01:02:53 +00001526 ML_(symerr)("ELF Phdrs are out of order!?");
nethercote80f76782003-11-13 22:34:00 +00001527 goto out;
sewardj8fe15a32002-10-20 19:29:21 +00001528 }
1529 prev_addr = o_phdr->p_vaddr;
1530
njn0787fc02005-06-26 02:19:17 +00001531 // Get the data and bss start/size if appropriate
sewardj8fe15a32002-10-20 19:29:21 +00001532 mapped = o_phdr->p_vaddr + si->offset;
1533 mapped_end = mapped + o_phdr->p_memsz;
sewardj8fe15a32002-10-20 19:29:21 +00001534 if (si->data_start == 0 &&
1535 (o_phdr->p_flags & (PF_R|PF_W|PF_X)) == (PF_R|PF_W)) {
1536 si->data_start = mapped;
1537 si->data_size = o_phdr->p_filesz;
1538 si->bss_start = mapped + o_phdr->p_filesz;
1539 if (o_phdr->p_memsz > o_phdr->p_filesz)
1540 si->bss_size = o_phdr->p_memsz - o_phdr->p_filesz;
1541 else
1542 si->bss_size = 0;
1543 }
tom7e8c7ca2005-11-16 00:09:15 +00001544
1545 mapped = mapped & ~(VKI_PAGE_SIZE-1);
njn0787fc02005-06-26 02:19:17 +00001546 mapped_end = (mapped_end + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE-1);
1547
sewardj8fe15a32002-10-20 19:29:21 +00001548 if (VG_(needs).data_syms &&
1549 (mapped >= si->start && mapped <= (si->start+si->size)) &&
1550 (mapped_end > (si->start+si->size))) {
1551 UInt newsz = mapped_end - si->start;
1552 if (newsz > si->size) {
1553 if (0)
1554 VG_(printf)("extending mapping %p..%p %d -> ..%p %d\n",
1555 si->start, si->start+si->size, si->size,
1556 si->start+newsz, newsz);
fitzhardinge98abfc72003-12-16 02:05:15 +00001557
sewardj8fe15a32002-10-20 19:29:21 +00001558 si->size = newsz;
1559 }
1560 }
1561 }
sewardjde4a1d02002-03-22 01:27:54 +00001562 }
1563
nethercote80f76782003-11-13 22:34:00 +00001564 TRACE_SYMTAB("shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n",
sewardj7a21c612005-02-18 09:38:08 +00001565 ehdr->e_shoff, ehdr->e_shnum, sizeof(ElfXX_Shdr), n_oimage );
sewardjde4a1d02002-03-22 01:27:54 +00001566
sewardj7a21c612005-02-18 09:38:08 +00001567 if (ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) > n_oimage) {
sewardj7eb7c582005-06-23 01:02:53 +00001568 ML_(symerr)("ELF section header is beyond image end?!");
nethercote80f76782003-11-13 22:34:00 +00001569 goto out;
sewardjde4a1d02002-03-22 01:27:54 +00001570 }
1571
sewardj7a21c612005-02-18 09:38:08 +00001572 shdr = (ElfXX_Shdr*)(oimage + ehdr->e_shoff);
sewardjde4a1d02002-03-22 01:27:54 +00001573 sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset);
1574
nethercote80f76782003-11-13 22:34:00 +00001575 /* Find interesting sections, read the symbol table(s), read any debug
1576 information */
sewardjde4a1d02002-03-22 01:27:54 +00001577 {
nethercote80f76782003-11-13 22:34:00 +00001578 /* Pointers to start of sections */
1579 UChar* o_strtab = NULL; /* .strtab */
sewardj7a21c612005-02-18 09:38:08 +00001580 ElfXX_Sym* o_symtab = NULL; /* .symtab */
nethercote80f76782003-11-13 22:34:00 +00001581 UChar* o_dynstr = NULL; /* .dynstr */
sewardj7a21c612005-02-18 09:38:08 +00001582 ElfXX_Sym* o_dynsym = NULL; /* .dynsym */
thughesc035bd92004-06-13 09:59:02 +00001583 Char* debuglink = NULL; /* .gnu_debuglink */
nethercote80f76782003-11-13 22:34:00 +00001584 UChar* stab = NULL; /* .stab (stabs) */
1585 UChar* stabstr = NULL; /* .stabstr (stabs) */
1586 UChar* debug_line = NULL; /* .debug_line (dwarf2) */
sewardj022bf2f2005-06-14 21:51:14 +00001587 UChar* debug_info = NULL; /* .debug_info (dwarf2) */
1588 UChar* debug_abbv = NULL; /* .debug_abbrev (dwarf2) */
1589 UChar* debug_str = NULL; /* .debug_str (dwarf2) */
jseward8b3131a2003-12-13 23:16:26 +00001590 UChar* dwarf1d = NULL; /* .debug (dwarf1) */
1591 UChar* dwarf1l = NULL; /* .line (dwarf1) */
sewardj5c638c22005-04-30 07:55:58 +00001592 UChar* ehframe = NULL; /* .eh_frame (dwarf2) */
sewardjde4a1d02002-03-22 01:27:54 +00001593
nethercote80f76782003-11-13 22:34:00 +00001594 /* Section sizes, in bytes */
1595 UInt o_strtab_sz = 0;
1596 UInt o_symtab_sz = 0;
1597 UInt o_dynstr_sz = 0;
1598 UInt o_dynsym_sz = 0;
thughesc035bd92004-06-13 09:59:02 +00001599 UInt debuglink_sz = 0;
nethercote80f76782003-11-13 22:34:00 +00001600 UInt stab_sz = 0;
1601 UInt stabstr_sz = 0;
1602 UInt debug_line_sz = 0;
sewardj022bf2f2005-06-14 21:51:14 +00001603 UInt debug_info_sz = 0;
1604 UInt debug_abbv_sz = 0;
1605 UInt debug_str_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001606 UInt dwarf1d_sz = 0;
1607 UInt dwarf1l_sz = 0;
sewardj5c638c22005-04-30 07:55:58 +00001608 UInt ehframe_sz = 0;
jseward8b3131a2003-12-13 23:16:26 +00001609
tom2fd38902005-05-01 15:14:01 +00001610 /* Section virtual addresses */
1611 Addr dummy_addr = 0;
1612 Addr ehframe_addr = 0;
1613
nethercote80f76782003-11-13 22:34:00 +00001614 /* Find all interesting sections */
sewardjde4a1d02002-03-22 01:27:54 +00001615 for (i = 0; i < ehdr->e_shnum; i++) {
tom2fd38902005-05-01 15:14:01 +00001616# define FIND(sec_name, sec_data, sec_size, sec_addr, in_exec, type) \
nethercote80f76782003-11-13 22:34:00 +00001617 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
sewardj88b7add2005-10-21 02:37:40 +00001618 Bool nobits; \
nethercote80f76782003-11-13 22:34:00 +00001619 if (0 != sec_data) \
1620 VG_(core_panic)("repeated section!\n"); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001621 if (in_exec) \
nethercote80f76782003-11-13 22:34:00 +00001622 sec_data = (type)(si->offset + shdr[i].sh_addr); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001623 else \
nethercote80f76782003-11-13 22:34:00 +00001624 sec_data = (type)(oimage + shdr[i].sh_offset); \
nethercotefd1ea4c2003-12-01 11:54:09 +00001625 sec_size = shdr[i].sh_size; \
sewardj88b7add2005-10-21 02:37:40 +00001626 nobits = shdr[i].sh_type == SHT_NOBITS; \
tom2fd38902005-05-01 15:14:01 +00001627 sec_addr = si->offset + shdr[i].sh_addr; \
nethercote80f76782003-11-13 22:34:00 +00001628 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1629 sec_name, sec_data, sec_data + sec_size - 1); \
sewardj88b7add2005-10-21 02:37:40 +00001630 /* SHT_NOBITS sections have zero size in the file. */ \
1631 if ( shdr[i].sh_offset + (nobits ? 0 : sec_size) > n_oimage ) { \
sewardj7eb7c582005-06-23 01:02:53 +00001632 ML_(symerr)(" section beyond image end?!"); \
nethercote80f76782003-11-13 22:34:00 +00001633 goto out; \
1634 } \
sewardjde4a1d02002-03-22 01:27:54 +00001635 }
1636
nethercote80f76782003-11-13 22:34:00 +00001637 /* Nb: must find where .got and .plt sections will be in the
1638 * executable image, not in the object image transiently loaded. */
tom2fd38902005-05-01 15:14:01 +00001639 FIND(".dynsym", o_dynsym, o_dynsym_sz, dummy_addr, 0, ElfXX_Sym*)
1640 else FIND(".dynstr", o_dynstr, o_dynstr_sz, dummy_addr, 0, UChar*)
1641 else FIND(".symtab", o_symtab, o_symtab_sz, dummy_addr, 0, ElfXX_Sym*)
1642 else FIND(".strtab", o_strtab, o_strtab_sz, dummy_addr, 0, UChar*)
sewardjde4a1d02002-03-22 01:27:54 +00001643
tom2fd38902005-05-01 15:14:01 +00001644 else FIND(".gnu_debuglink", debuglink, debuglink_sz, dummy_addr, 0, Char*)
thughesc035bd92004-06-13 09:59:02 +00001645
tom2fd38902005-05-01 15:14:01 +00001646 else FIND(".stab", stab, stab_sz, dummy_addr, 0, UChar*)
1647 else FIND(".stabstr", stabstr, stabstr_sz, dummy_addr, 0, UChar*)
sewardj022bf2f2005-06-14 21:51:14 +00001648
tom2fd38902005-05-01 15:14:01 +00001649 else FIND(".debug_line", debug_line, debug_line_sz, dummy_addr, 0, UChar*)
sewardj022bf2f2005-06-14 21:51:14 +00001650 else FIND(".debug_info", debug_info, debug_info_sz, dummy_addr, 0, UChar*)
1651 else FIND(".debug_abbrev", debug_abbv, debug_abbv_sz, dummy_addr, 0, UChar*)
1652 else FIND(".debug_str", debug_str, debug_str_sz, dummy_addr, 0, UChar*)
1653
tom2fd38902005-05-01 15:14:01 +00001654 else FIND(".debug", dwarf1d, dwarf1d_sz, dummy_addr, 0, UChar*)
1655 else FIND(".line", dwarf1l, dwarf1l_sz, dummy_addr, 0, UChar*)
1656 else FIND(".eh_frame", ehframe, ehframe_sz, ehframe_addr, 0, UChar*)
nethercote80f76782003-11-13 22:34:00 +00001657
tom2fd38902005-05-01 15:14:01 +00001658 else FIND(".got", si->got_start, si->got_size, dummy_addr, 1, Addr)
1659 else FIND(".plt", si->plt_start, si->plt_size, dummy_addr, 1, Addr)
nethercote80f76782003-11-13 22:34:00 +00001660
jseward8b3131a2003-12-13 23:16:26 +00001661# undef FIND
sewardjde4a1d02002-03-22 01:27:54 +00001662 }
njn36ef6ba2005-05-14 18:42:26 +00001663
1664 /* Check some sizes */
1665 vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0);
1666 vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0);
sewardjde4a1d02002-03-22 01:27:54 +00001667
thughesc035bd92004-06-13 09:59:02 +00001668 /* Did we find a debuglink section? */
1669 if (debuglink != NULL) {
njn13bfd852005-06-02 03:52:53 +00001670 UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink)+1, 4);
thughesc035bd92004-06-13 09:59:02 +00001671 UInt crc;
1672
1673 vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
1674
1675 /* Extract the CRC from the debuglink section */
1676 crc = *(UInt *)(debuglink + crc_offset);
1677
1678 /* See if we can find a matching debug file */
1679 if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) {
sewardj7a21c612005-02-18 09:38:08 +00001680 ehdr = (ElfXX_Ehdr*)dimage;
thughesc035bd92004-06-13 09:59:02 +00001681
sewardj0d1a8962005-09-28 01:23:25 +00001682 if (n_dimage >= sizeof(ElfXX_Ehdr) && is_elf_object_file(ehdr))
thughesc035bd92004-06-13 09:59:02 +00001683 {
sewardj7a21c612005-02-18 09:38:08 +00001684 shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff);
thughesc035bd92004-06-13 09:59:02 +00001685 sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset);
1686
1687 /* Find all interesting sections */
1688 for (i = 0; i < ehdr->e_shnum; i++) {
1689# define FIND(sec_name, sec_data, sec_size, type) \
1690 if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \
sewardj88b7add2005-10-21 02:37:40 +00001691 Bool nobits; \
thughesc035bd92004-06-13 09:59:02 +00001692 if (0 != sec_data) \
1693 VG_(core_panic)("repeated section!\n"); \
1694 sec_data = (type)(dimage + shdr[i].sh_offset); \
1695 sec_size = shdr[i].sh_size; \
sewardj88b7add2005-10-21 02:37:40 +00001696 nobits = shdr[i].sh_type == SHT_NOBITS; \
thughesc035bd92004-06-13 09:59:02 +00001697 TRACE_SYMTAB( "%18s: %p .. %p\n", \
1698 sec_name, sec_data, sec_data + sec_size - 1); \
sewardj88b7add2005-10-21 02:37:40 +00001699 /* SHT_NOBITS sections have zero size in the file. */ \
1700 if ( shdr[i].sh_offset + (nobits ? 0 : sec_size) > n_dimage ) { \
sewardj7eb7c582005-06-23 01:02:53 +00001701 ML_(symerr)(" section beyond image end?!"); \
thughesc035bd92004-06-13 09:59:02 +00001702 goto out; \
1703 } \
1704 }
1705
1706 /* Nb: must find where .got and .plt sections will be in the
1707 * executable image, not in the object image transiently loaded. */
1708 FIND(".stab", stab, stab_sz, UChar*)
1709 else FIND(".stabstr", stabstr, stabstr_sz, UChar*)
1710 else FIND(".debug_line", debug_line, debug_line_sz, UChar*)
tome36cb5a2005-06-15 10:19:43 +00001711 else FIND(".debug_info", debug_info, debug_info_sz, UChar*)
1712 else FIND(".debug_abbrev", debug_abbv, debug_abbv_sz, UChar*)
1713 else FIND(".debug_str", debug_str, debug_str_sz, UChar*)
thughesc035bd92004-06-13 09:59:02 +00001714 else FIND(".debug", dwarf1d, dwarf1d_sz, UChar*)
1715 else FIND(".line", dwarf1l, dwarf1l_sz, UChar*)
1716
1717# undef FIND
thughesc035bd92004-06-13 09:59:02 +00001718 }
1719 }
1720 }
1721 }
1722
njnd54e4ec2005-05-15 03:38:53 +00001723 /* Read symbols */
1724 read_symtab(si, "symbol table", False,
1725 o_symtab, o_symtab_sz,
1726 o_strtab, o_strtab_sz);
1727
1728 read_symtab(si, "dynamic symbol table", True,
1729 o_dynsym, o_dynsym_sz,
1730 o_dynstr, o_dynstr_sz);
1731
sewardj5c638c22005-04-30 07:55:58 +00001732 /* Read .eh_frame (call-frame-info) if any */
sewardj55022aa2005-05-03 16:05:00 +00001733 if (ehframe) {
sewardj7eb7c582005-06-23 01:02:53 +00001734 ML_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_addr );
sewardj5c638c22005-04-30 07:55:58 +00001735 }
1736
sewardje7aa4ae2005-06-09 12:43:42 +00001737 /* Read the stabs and/or dwarf2 debug information, if any. It
1738 appears reading stabs stuff on amd64-linux doesn't work, so
1739 we ignore it. */
1740# if !defined(VGP_amd64_linux)
njn0787fc02005-06-26 02:19:17 +00001741 if (stab && stabstr) {
sewardj7eb7c582005-06-23 01:02:53 +00001742 ML_(read_debuginfo_stabs) ( si, stab, stab_sz,
jseward8b3131a2003-12-13 23:16:26 +00001743 stabstr, stabstr_sz );
1744 }
sewardje7aa4ae2005-06-09 12:43:42 +00001745# endif
sewardj1a0e39f2006-01-01 23:00:49 +00001746 /* jrs 2006-01-01: icc-8.1 has been observed to generate
1747 binaries without debug_str sections. Don't preclude
1748 debuginfo reading for that reason, but, in
1749 read_unitinfo_dwarf2, do check that debugstr is non-NULL
1750 before using it. */
1751 if (debug_info && debug_abbv && debug_line /* && debug_str */) {
sewardj7eb7c582005-06-23 01:02:53 +00001752 ML_(read_debuginfo_dwarf2) ( si,
sewardj022bf2f2005-06-14 21:51:14 +00001753 debug_info, debug_info_sz,
1754 debug_abbv,
1755 debug_line, debug_line_sz,
1756 debug_str );
jseward8b3131a2003-12-13 23:16:26 +00001757 }
1758 if (dwarf1d && dwarf1l) {
sewardj7eb7c582005-06-23 01:02:53 +00001759 ML_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz,
jseward8b3131a2003-12-13 23:16:26 +00001760 dwarf1l, dwarf1l_sz );
sewardjde4a1d02002-03-22 01:27:54 +00001761 }
1762 }
nethercote80f76782003-11-13 22:34:00 +00001763 res = True;
sewardjde4a1d02002-03-22 01:27:54 +00001764
nethercotee567e702004-07-10 17:49:17 +00001765 out: {
sewardj45f4e7c2005-09-27 19:20:21 +00001766 SysRes m_res;
thughesc035bd92004-06-13 09:59:02 +00001767 /* Last, but not least, heave the image(s) back overboard. */
nethercotee567e702004-07-10 17:49:17 +00001768 if (dimage) {
sewardj45f4e7c2005-09-27 19:20:21 +00001769 m_res = VG_(am_munmap_valgrind) ( dimage, n_dimage );
1770 vg_assert(!m_res.isError);
nethercotee567e702004-07-10 17:49:17 +00001771 }
sewardj45f4e7c2005-09-27 19:20:21 +00001772 m_res = VG_(am_munmap_valgrind) ( oimage, n_oimage );
1773 vg_assert(!m_res.isError);
nethercote80f76782003-11-13 22:34:00 +00001774 return res;
nethercotee567e702004-07-10 17:49:17 +00001775 }
sewardjde4a1d02002-03-22 01:27:54 +00001776}
1777
sewardjde4a1d02002-03-22 01:27:54 +00001778/*------------------------------------------------------------*/
1779/*--- Main entry point for symbols table reading. ---*/
1780/*------------------------------------------------------------*/
1781
njn0787fc02005-06-26 02:19:17 +00001782static SegInfo*
1783alloc_SegInfo(Addr start, SizeT size, OffT foffset, const Char* filename)
sewardjde4a1d02002-03-22 01:27:54 +00001784{
njn0787fc02005-06-26 02:19:17 +00001785 SegInfo* si = VG_(arena_calloc)(VG_AR_SYMTAB, 1, sizeof(SegInfo));
sewardjde4a1d02002-03-22 01:27:54 +00001786
njn0787fc02005-06-26 02:19:17 +00001787 si->start = start;
1788 si->size = size;
1789 si->foffset = foffset;
1790 si->filename = VG_(arena_strdup)(VG_AR_SYMTAB, filename);
fitzhardinge98abfc72003-12-16 02:05:15 +00001791
1792 si->ref = 1;
sewardjde4a1d02002-03-22 01:27:54 +00001793
njn0787fc02005-06-26 02:19:17 +00001794 // Everything else -- pointers, sizes, arrays -- is zeroed by calloc.
jsgfcb1d1c02003-10-14 21:55:10 +00001795
njn0787fc02005-06-26 02:19:17 +00001796 return si;
1797}
sewardjde4a1d02002-03-22 01:27:54 +00001798
njn0787fc02005-06-26 02:19:17 +00001799SegInfo *VG_(read_seg_symbols) ( Addr seg_addr, SizeT seg_len,
1800 OffT seg_offset, const Char* seg_filename)
1801{
1802 SegInfo* si = alloc_SegInfo(seg_addr, seg_len, seg_offset, seg_filename);
sewardj8a77ffb2003-07-10 23:31:27 +00001803
njn0787fc02005-06-26 02:19:17 +00001804 if (!read_lib_symbols ( si )) {
1805 // Something went wrong (eg. bad ELF file).
sewardj8fe15a32002-10-20 19:29:21 +00001806 freeSegInfo( si );
njn0787fc02005-06-26 02:19:17 +00001807 si = NULL;
1808
sewardj8fe15a32002-10-20 19:29:21 +00001809 } else {
njn16eeb4e2005-06-16 03:56:58 +00001810 // Prepend si to segInfo_list
1811 si->next = segInfo_list;
1812 segInfo_list = si;
sewardj8fe15a32002-10-20 19:29:21 +00001813
njn16eeb4e2005-06-16 03:56:58 +00001814 canonicaliseSymtab ( si );
1815 canonicaliseLoctab ( si );
jsgfcb1d1c02003-10-14 21:55:10 +00001816 canonicaliseScopetab ( si );
njn16eeb4e2005-06-16 03:56:58 +00001817 canonicaliseCfiSI ( si );
fitzhardinge98abfc72003-12-16 02:05:15 +00001818
1819 /* do redirects */
njnd9109c62005-06-26 04:49:25 +00001820 VG_(resolve_existing_redirs_with_seginfo)( si );
sewardj8fe15a32002-10-20 19:29:21 +00001821 }
fitzhardinge98abfc72003-12-16 02:05:15 +00001822
1823 return si;
sewardjde4a1d02002-03-22 01:27:54 +00001824}
1825
1826
sewardjde4a1d02002-03-22 01:27:54 +00001827/* When an munmap() call happens, check to see whether it corresponds
1828 to a segment for a .so, and if so discard the relevant SegInfo.
1829 This might not be a very clever idea from the point of view of
1830 accuracy of error messages, but we need to do it in order to
sewardj18d75132002-05-16 11:06:21 +00001831 maintain the no-overlapping invariant.
sewardjde4a1d02002-03-22 01:27:54 +00001832*/
nethercote928a5f72004-11-03 18:10:37 +00001833static void unload_symbols ( Addr start, SizeT length )
sewardjde4a1d02002-03-22 01:27:54 +00001834{
njnb3edb1f2005-08-14 04:29:12 +00001835 SegInfo** prev_next_ptr = &segInfo_list;
1836 SegInfo* curr = segInfo_list;
sewardjde4a1d02002-03-22 01:27:54 +00001837
njnb3edb1f2005-08-14 04:29:12 +00001838 while (curr) {
1839 if (start == curr->start) {
1840 // Found it; remove from list and free it.
1841 if (VG_(clo_verbosity) > 1)
1842 VG_(message)(Vg_DebugMsg,
1843 "discard syms at %p-%p in %s due to munmap()",
1844 start, start+length,
1845 curr->filename ? curr->filename : (Char *)"???");
1846 vg_assert(*prev_next_ptr == curr);
1847 *prev_next_ptr = curr->next;
1848 freeSegInfo(curr);
1849 return;
1850 }
1851 prev_next_ptr = &curr->next;
1852 curr = curr->next;
njnfa1016e2003-09-25 17:54:11 +00001853 }
sewardjde4a1d02002-03-22 01:27:54 +00001854
njnb3edb1f2005-08-14 04:29:12 +00001855 // Not found.
sewardjde4a1d02002-03-22 01:27:54 +00001856}
1857
sewardjde4a1d02002-03-22 01:27:54 +00001858/*------------------------------------------------------------*/
1859/*--- Use of symbol table & location info to create ---*/
1860/*--- plausible-looking stack dumps. ---*/
1861/*------------------------------------------------------------*/
1862
1863/* Find a symbol-table index containing the specified pointer, or -1
1864 if not found. Binary search. */
1865
njn25e49d8e72002-09-23 09:36:25 +00001866static Int search_one_symtab ( SegInfo* si, Addr ptr,
1867 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001868{
1869 Addr a_mid_lo, a_mid_hi;
njn25e49d8e72002-09-23 09:36:25 +00001870 Int mid, size,
sewardjde4a1d02002-03-22 01:27:54 +00001871 lo = 0,
1872 hi = si->symtab_used-1;
1873 while (True) {
1874 /* current unsearched space is from lo to hi, inclusive. */
1875 if (lo > hi) return -1; /* not found */
1876 mid = (lo + hi) / 2;
1877 a_mid_lo = si->symtab[mid].addr;
njn25e49d8e72002-09-23 09:36:25 +00001878 size = ( match_anywhere_in_fun
1879 ? si->symtab[mid].size
1880 : 1);
1881 a_mid_hi = ((Addr)si->symtab[mid].addr) + size - 1;
sewardjde4a1d02002-03-22 01:27:54 +00001882
1883 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1884 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1885 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1886 return mid;
1887 }
1888}
1889
1890
sewardj25c7c3a2003-07-10 00:17:58 +00001891/* SLOW (Linear search). Try and map a symbol name to an address.
1892 Since this is searching in the direction opposite to which the
1893 table is designed we have no option but to do a complete linear
1894 scan of the table. Returns NULL if not found. */
1895
sewardjb5f6f512005-03-10 23:59:00 +00001896Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name )
sewardj25c7c3a2003-07-10 00:17:58 +00001897{
1898 UInt i;
1899 for (i = 0; i < si->symtab_used; i++) {
sewardjc8bf5fe2003-07-13 00:53:22 +00001900 if (0)
jsgfcb1d1c02003-10-14 21:55:10 +00001901 VG_(printf)("%p %s\n", si->symtab[i].addr, si->symtab[i].name);
1902 if (0 == VG_(strcmp)(name, si->symtab[i].name))
sewardj25c7c3a2003-07-10 00:17:58 +00001903 return si->symtab[i].addr;
1904 }
1905 return (Addr)NULL;
1906}
1907
1908
sewardjde4a1d02002-03-22 01:27:54 +00001909/* Search all symtabs that we know about to locate ptr. If found, set
1910 *psi to the relevant SegInfo, and *symno to the symtab entry number
1911 within that. If not found, *psi is set to NULL. */
njn25e49d8e72002-09-23 09:36:25 +00001912static void search_all_symtabs ( Addr ptr, /*OUT*/SegInfo** psi,
1913 /*OUT*/Int* symno,
1914 Bool match_anywhere_in_fun )
sewardjde4a1d02002-03-22 01:27:54 +00001915{
1916 Int sno;
1917 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00001918
njn1727cc82005-06-21 23:09:45 +00001919 for (si = segInfo_list; si != NULL; si = si->next) {
1920 if (si->start <= ptr && ptr < si->start+si->size) {
1921 sno = search_one_symtab ( si, ptr, match_anywhere_in_fun );
1922 if (sno == -1) goto not_found;
1923 *symno = sno;
1924 *psi = si;
njn1727cc82005-06-21 23:09:45 +00001925 return;
1926 }
1927 }
sewardjde4a1d02002-03-22 01:27:54 +00001928 not_found:
1929 *psi = NULL;
1930}
1931
1932
1933/* Find a location-table index containing the specified pointer, or -1
1934 if not found. Binary search. */
1935
1936static Int search_one_loctab ( SegInfo* si, Addr ptr )
1937{
1938 Addr a_mid_lo, a_mid_hi;
1939 Int mid,
1940 lo = 0,
1941 hi = si->loctab_used-1;
1942 while (True) {
1943 /* current unsearched space is from lo to hi, inclusive. */
1944 if (lo > hi) return -1; /* not found */
1945 mid = (lo + hi) / 2;
1946 a_mid_lo = si->loctab[mid].addr;
1947 a_mid_hi = ((Addr)si->loctab[mid].addr) + si->loctab[mid].size - 1;
1948
1949 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1950 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1951 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
1952 return mid;
1953 }
1954}
1955
1956
1957/* Search all loctabs that we know about to locate ptr. If found, set
1958 *psi to the relevant SegInfo, and *locno to the loctab entry number
1959 within that. If not found, *psi is set to NULL.
1960*/
njn25e49d8e72002-09-23 09:36:25 +00001961static void search_all_loctabs ( Addr ptr, /*OUT*/SegInfo** psi,
1962 /*OUT*/Int* locno )
sewardjde4a1d02002-03-22 01:27:54 +00001963{
1964 Int lno;
1965 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00001966
njn16eeb4e2005-06-16 03:56:58 +00001967 for (si = segInfo_list; si != NULL; si = si->next) {
sewardjde4a1d02002-03-22 01:27:54 +00001968 if (si->start <= ptr && ptr < si->start+si->size) {
1969 lno = search_one_loctab ( si, ptr );
1970 if (lno == -1) goto not_found;
1971 *locno = lno;
1972 *psi = si;
1973 return;
1974 }
1975 }
1976 not_found:
1977 *psi = NULL;
1978}
1979
1980
jsgfcb1d1c02003-10-14 21:55:10 +00001981/* Find a scope-table index containing the specified pointer, or -1
1982 if not found. Binary search. */
1983
1984static Int search_one_scopetab ( SegInfo* si, Addr ptr )
1985{
1986 Addr a_mid_lo, a_mid_hi;
1987 Int mid,
1988 lo = 0,
1989 hi = si->scopetab_used-1;
1990 while (True) {
1991 /* current unsearched space is from lo to hi, inclusive. */
1992 if (lo > hi) return -1; /* not found */
1993 mid = (lo + hi) / 2;
1994 a_mid_lo = si->scopetab[mid].addr;
1995 a_mid_hi = ((Addr)si->scopetab[mid].addr) + si->scopetab[mid].size - 1;
1996
1997 if (ptr < a_mid_lo) { hi = mid-1; continue; }
1998 if (ptr > a_mid_hi) { lo = mid+1; continue; }
1999 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2000 return mid;
2001 }
2002}
2003
2004
2005/* Search all scopetabs that we know about to locate ptr. If found, set
2006 *psi to the relevant SegInfo, and *locno to the scopetab entry number
2007 within that. If not found, *psi is set to NULL.
2008*/
2009static void search_all_scopetabs ( Addr ptr,
2010 /*OUT*/SegInfo** psi,
2011 /*OUT*/Int* scopeno )
2012{
2013 Int scno;
2014 SegInfo* si;
2015
njn16eeb4e2005-06-16 03:56:58 +00002016 for (si = segInfo_list; si != NULL; si = si->next) {
jsgfcb1d1c02003-10-14 21:55:10 +00002017 if (si->start <= ptr && ptr < si->start+si->size) {
2018 scno = search_one_scopetab ( si, ptr );
2019 if (scno == -1) goto not_found;
2020 *scopeno = scno;
2021 *psi = si;
jsgfcb1d1c02003-10-14 21:55:10 +00002022 return;
2023 }
2024 }
2025 not_found:
2026 *psi = NULL;
jsgfcb1d1c02003-10-14 21:55:10 +00002027}
2028
sewardj3a1c7db2005-05-02 09:43:44 +00002029
2030/* Find a CFI-table index containing the specified pointer, or -1
2031 if not found. Binary search. */
2032
2033static Int search_one_cfitab ( SegInfo* si, Addr ptr )
2034{
2035 Addr a_mid_lo, a_mid_hi;
2036 Int mid, size,
2037 lo = 0,
2038 hi = si->cfisi_used-1;
2039 while (True) {
2040 /* current unsearched space is from lo to hi, inclusive. */
2041 if (lo > hi) return -1; /* not found */
2042 mid = (lo + hi) / 2;
2043 a_mid_lo = si->cfisi[mid].base;
2044 size = si->cfisi[mid].len;
2045 a_mid_hi = a_mid_lo + size - 1;
2046 vg_assert(a_mid_hi >= a_mid_lo);
2047 if (ptr < a_mid_lo) { hi = mid-1; continue; }
2048 if (ptr > a_mid_hi) { lo = mid+1; continue; }
2049 vg_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
2050 return mid;
2051 }
2052}
2053
2054
sewardjde4a1d02002-03-22 01:27:54 +00002055/* The whole point of this whole big deal: map a code address to a
2056 plausible symbol name. Returns False if no idea; otherwise True.
njn25e49d8e72002-09-23 09:36:25 +00002057 Caller supplies buf and nbuf. If demangle is False, don't do
njn695c16e2005-03-27 03:40:28 +00002058 demangling, regardless of VG_(clo_demangle) -- probably because the
2059 call has come from VG_(get_fnname_nodemangle)(). */
njn25e49d8e72002-09-23 09:36:25 +00002060static
2061Bool get_fnname ( Bool demangle, Addr a, Char* buf, Int nbuf,
sewardj1771e172002-11-13 22:06:35 +00002062 Bool match_anywhere_in_fun, Bool show_offset)
sewardjde4a1d02002-03-22 01:27:54 +00002063{
2064 SegInfo* si;
2065 Int sno;
sewardj1771e172002-11-13 22:06:35 +00002066 Int offset;
2067
njn25e49d8e72002-09-23 09:36:25 +00002068 search_all_symtabs ( a, &si, &sno, match_anywhere_in_fun );
sewardjde4a1d02002-03-22 01:27:54 +00002069 if (si == NULL)
2070 return False;
njn25e49d8e72002-09-23 09:36:25 +00002071 if (demangle) {
jsgfcb1d1c02003-10-14 21:55:10 +00002072 VG_(demangle) ( si->symtab[sno].name, buf, nbuf );
njn25e49d8e72002-09-23 09:36:25 +00002073 } else {
njnbe73f432005-03-26 21:34:45 +00002074 VG_(strncpy_safely) ( buf, si->symtab[sno].name, nbuf );
sewardjde4a1d02002-03-22 01:27:54 +00002075 }
sewardj1771e172002-11-13 22:06:35 +00002076
2077 offset = a - si->symtab[sno].addr;
2078 if (show_offset && offset != 0) {
2079 Char buf2[12];
2080 Char* symend = buf + VG_(strlen)(buf);
2081 Char* end = buf + nbuf;
2082 Int len;
2083
2084 len = VG_(sprintf)(buf2, "%c%d",
2085 offset < 0 ? '-' : '+',
2086 offset < 0 ? -offset : offset);
sewardj05bcdcb2003-05-18 10:05:38 +00002087 vg_assert(len < (Int)sizeof(buf2));
sewardj1771e172002-11-13 22:06:35 +00002088
2089 if (len < (end - symend)) {
2090 Char *cp = buf2;
2091 VG_(memcpy)(symend, cp, len+1);
2092 }
2093 }
2094
sewardjde4a1d02002-03-22 01:27:54 +00002095 return True;
2096}
2097
nethercote7cc9c232004-01-21 15:08:04 +00002098/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002099 match anywhere in function, but don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002100Bool VG_(get_fnname) ( Addr a, Char* buf, Int nbuf )
2101{
2102 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002103 /*match_anywhere_in_fun*/True,
2104 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002105}
sewardjde4a1d02002-03-22 01:27:54 +00002106
nethercote7cc9c232004-01-21 15:08:04 +00002107/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002108 match anywhere in function, and show offset if nonzero. */
2109Bool VG_(get_fnname_w_offset) ( Addr a, Char* buf, Int nbuf )
2110{
2111 return get_fnname ( /*demangle*/True, a, buf, nbuf,
2112 /*match_anywhere_in_fun*/True,
2113 /*show offset?*/True );
2114}
2115
nethercote7cc9c232004-01-21 15:08:04 +00002116/* This is available to tools... always demangle C++ names,
sewardj6e008cb2002-12-15 13:11:39 +00002117 only succeed if 'a' matches first instruction of function,
2118 and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002119Bool VG_(get_fnname_if_entry) ( Addr a, Char* buf, Int nbuf )
2120{
2121 return get_fnname ( /*demangle*/True, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002122 /*match_anywhere_in_fun*/False,
2123 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002124}
2125
sewardj6e008cb2002-12-15 13:11:39 +00002126/* This is only available to core... don't demangle C++ names,
2127 match anywhere in function, and don't show offsets. */
njn25e49d8e72002-09-23 09:36:25 +00002128Bool VG_(get_fnname_nodemangle) ( Addr a, Char* buf, Int nbuf )
2129{
2130 return get_fnname ( /*demangle*/False, a, buf, nbuf,
sewardj6e008cb2002-12-15 13:11:39 +00002131 /*match_anywhere_in_fun*/True,
2132 /*show offset?*/False );
njn25e49d8e72002-09-23 09:36:25 +00002133}
2134
2135/* Map a code address to the name of a shared object file or the executable.
2136 Returns False if no idea; otherwise True. Doesn't require debug info.
2137 Caller supplies buf and nbuf. */
2138Bool VG_(get_objname) ( Addr a, Char* buf, Int nbuf )
sewardjde4a1d02002-03-22 01:27:54 +00002139{
2140 SegInfo* si;
njn25e49d8e72002-09-23 09:36:25 +00002141
njn16eeb4e2005-06-16 03:56:58 +00002142 for (si = segInfo_list; si != NULL; si = si->next) {
sewardjde4a1d02002-03-22 01:27:54 +00002143 if (si->start <= a && a < si->start+si->size) {
2144 VG_(strncpy_safely)(buf, si->filename, nbuf);
2145 return True;
2146 }
2147 }
2148 return False;
2149}
2150
njnb877d492003-01-28 20:40:57 +00002151/* Map a code address to its SegInfo. Returns NULL if not found. Doesn't
2152 require debug info. */
njn3c45f5b2005-07-06 13:19:11 +00002153SegInfo* VG_(find_seginfo) ( Addr a )
njnb877d492003-01-28 20:40:57 +00002154{
2155 SegInfo* si;
2156
njn16eeb4e2005-06-16 03:56:58 +00002157 for (si = segInfo_list; si != NULL; si = si->next) {
njnb877d492003-01-28 20:40:57 +00002158 if (si->start <= a && a < si->start+si->size) {
2159 return si;
2160 }
2161 }
nethercote80f76782003-11-13 22:34:00 +00002162 return NULL;
njnb877d492003-01-28 20:40:57 +00002163}
2164
njn25e49d8e72002-09-23 09:36:25 +00002165
2166/* Map a code address to a filename. Returns True if successful. */
2167Bool VG_(get_filename)( Addr a, Char* filename, Int n_filename )
sewardjde4a1d02002-03-22 01:27:54 +00002168{
njn25e49d8e72002-09-23 09:36:25 +00002169 SegInfo* si;
2170 Int locno;
2171 search_all_loctabs ( a, &si, &locno );
2172 if (si == NULL)
2173 return False;
njnbe73f432005-03-26 21:34:45 +00002174 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
njn25e49d8e72002-09-23 09:36:25 +00002175 return True;
sewardjde4a1d02002-03-22 01:27:54 +00002176}
2177
njn25e49d8e72002-09-23 09:36:25 +00002178/* Map a code address to a line number. Returns True if successful. */
2179Bool VG_(get_linenum)( Addr a, UInt* lineno )
2180{
2181 SegInfo* si;
2182 Int locno;
2183 search_all_loctabs ( a, &si, &locno );
2184 if (si == NULL)
2185 return False;
2186 *lineno = si->loctab[locno].lineno;
2187
2188 return True;
2189}
sewardjde4a1d02002-03-22 01:27:54 +00002190
sewardj7cee6f92005-06-13 17:39:06 +00002191/* Map a code address to a filename/line number/dir name info.
2192 See prototype for detailed description of behaviour.
sewardjde4a1d02002-03-22 01:27:54 +00002193*/
sewardj7cee6f92005-06-13 17:39:06 +00002194Bool VG_(get_filename_linenum) ( Addr a,
2195 /*OUT*/Char* filename, Int n_filename,
2196 /*OUT*/Char* dirname, Int n_dirname,
2197 /*OUT*/Bool* dirname_available,
2198 /*OUT*/UInt* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00002199{
2200 SegInfo* si;
2201 Int locno;
sewardj7cee6f92005-06-13 17:39:06 +00002202
2203 vg_assert( (dirname == NULL && dirname_available == NULL)
2204 ||
2205 (dirname != NULL && dirname_available != NULL) );
2206
sewardjde4a1d02002-03-22 01:27:54 +00002207 search_all_loctabs ( a, &si, &locno );
2208 if (si == NULL)
2209 return False;
njnbe73f432005-03-26 21:34:45 +00002210 VG_(strncpy_safely)(filename, si->loctab[locno].filename, n_filename);
sewardjde4a1d02002-03-22 01:27:54 +00002211 *lineno = si->loctab[locno].lineno;
njn4f9c9342002-04-29 16:03:24 +00002212
sewardj7cee6f92005-06-13 17:39:06 +00002213 if (dirname) {
2214 /* caller wants directory info too .. */
2215 vg_assert(n_dirname > 0);
2216 if (si->loctab[locno].dirname) {
2217 /* .. and we have some */
2218 *dirname_available = True;
2219 VG_(strncpy_safely)(dirname, si->loctab[locno].dirname,
2220 n_dirname);
2221 } else {
2222 /* .. but we don't have any */
2223 *dirname_available = False;
2224 *dirname = 0;
2225 }
2226 }
2227
sewardjde4a1d02002-03-22 01:27:54 +00002228 return True;
2229}
2230
jsgfcb1d1c02003-10-14 21:55:10 +00002231#ifndef TEST
2232
njn6b2b96a2005-05-16 00:01:04 +00002233// Note that R_STACK_PTR and R_FRAME_PTR are used again further below,
2234// which is why they get a named constant.
2235static Addr regaddr_from_tst(Int regno, ThreadArchState *arch)
2236{
2237#if defined(VGA_x86)
sewardj7cee6f92005-06-13 17:39:06 +00002238 /* This is the Intel register encoding -- integer regs. */
njn6b2b96a2005-05-16 00:01:04 +00002239# define R_STACK_PTR 4
2240# define R_FRAME_PTR 5
2241 switch (regno) {
2242 case 0: return (Addr) & arch->vex.guest_EAX;
2243 case 1: return (Addr) & arch->vex.guest_ECX;
2244 case 2: return (Addr) & arch->vex.guest_EDX;
2245 case 3: return (Addr) & arch->vex.guest_EBX;
2246 case R_STACK_PTR: return (Addr) & arch->vex.guest_ESP;
2247 case R_FRAME_PTR: return (Addr) & arch->vex.guest_EBP;
2248 case 6: return (Addr) & arch->vex.guest_ESI;
2249 case 7: return (Addr) & arch->vex.guest_EDI;
2250 default: return 0;
2251 }
2252#elif defined(VGA_amd64)
sewardj7cee6f92005-06-13 17:39:06 +00002253 /* This is the AMD64 register encoding -- integer regs. */
tom7b998562005-05-16 07:31:57 +00002254# define R_STACK_PTR 7
2255# define R_FRAME_PTR 6
2256 switch (regno) {
2257 case 0: return (Addr) & arch->vex.guest_RAX;
2258 case 1: return (Addr) & arch->vex.guest_RDX;
2259 case 2: return (Addr) & arch->vex.guest_RCX;
2260 case 3: return (Addr) & arch->vex.guest_RBX;
2261 case 4: return (Addr) & arch->vex.guest_RSI;
2262 case 5: return (Addr) & arch->vex.guest_RDI;
2263 case R_FRAME_PTR: return (Addr) & arch->vex.guest_RBP;
2264 case R_STACK_PTR: return (Addr) & arch->vex.guest_RSP;
2265 case 8: return (Addr) & arch->vex.guest_R8;
2266 case 9: return (Addr) & arch->vex.guest_R9;
2267 case 10: return (Addr) & arch->vex.guest_R10;
2268 case 11: return (Addr) & arch->vex.guest_R11;
2269 case 12: return (Addr) & arch->vex.guest_R12;
2270 case 13: return (Addr) & arch->vex.guest_R13;
2271 case 14: return (Addr) & arch->vex.guest_R14;
2272 case 15: return (Addr) & arch->vex.guest_R15;
2273 default: return 0;
2274 }
sewardj2c48c7b2005-11-29 13:05:56 +00002275#elif defined(VGA_ppc32) || defined(VGA_ppc64)
2276 /* This is the PPC register encoding -- integer regs. */
cerion85665ca2005-06-20 15:51:07 +00002277# define R_STACK_PTR 1
2278# define R_FRAME_PTR 1
2279 switch (regno) {
2280 case 0: return (Addr) & arch->vex.guest_GPR0;
2281 case R_STACK_PTR: return (Addr) & arch->vex.guest_GPR1;
2282 case 2: return (Addr) & arch->vex.guest_GPR2;
2283 case 3: return (Addr) & arch->vex.guest_GPR3;
2284 case 4: return (Addr) & arch->vex.guest_GPR4;
2285 case 5: return (Addr) & arch->vex.guest_GPR5;
2286 case 6: return (Addr) & arch->vex.guest_GPR6;
2287 case 7: return (Addr) & arch->vex.guest_GPR7;
2288 case 8: return (Addr) & arch->vex.guest_GPR8;
2289 case 9: return (Addr) & arch->vex.guest_GPR9;
2290 case 10: return (Addr) & arch->vex.guest_GPR10;
2291 case 11: return (Addr) & arch->vex.guest_GPR11;
2292 case 12: return (Addr) & arch->vex.guest_GPR12;
2293 case 13: return (Addr) & arch->vex.guest_GPR13;
2294 case 14: return (Addr) & arch->vex.guest_GPR14;
2295 case 15: return (Addr) & arch->vex.guest_GPR15;
2296 case 16: return (Addr) & arch->vex.guest_GPR16;
2297 case 17: return (Addr) & arch->vex.guest_GPR17;
2298 case 18: return (Addr) & arch->vex.guest_GPR18;
2299 case 19: return (Addr) & arch->vex.guest_GPR19;
2300 case 20: return (Addr) & arch->vex.guest_GPR20;
2301 case 21: return (Addr) & arch->vex.guest_GPR21;
2302 case 22: return (Addr) & arch->vex.guest_GPR22;
2303 case 23: return (Addr) & arch->vex.guest_GPR23;
2304 case 24: return (Addr) & arch->vex.guest_GPR24;
2305 case 25: return (Addr) & arch->vex.guest_GPR25;
2306 case 26: return (Addr) & arch->vex.guest_GPR26;
2307 case 27: return (Addr) & arch->vex.guest_GPR27;
2308 case 28: return (Addr) & arch->vex.guest_GPR28;
2309 case 29: return (Addr) & arch->vex.guest_GPR29;
2310 case 30: return (Addr) & arch->vex.guest_GPR30;
2311 case 31: return (Addr) & arch->vex.guest_GPR31;
2312 default: return 0;
2313 }
njn6b2b96a2005-05-16 00:01:04 +00002314#else
2315# error Unknown platform
2316#endif
2317}
2318
2319
jsgfcb1d1c02003-10-14 21:55:10 +00002320/* return a pointer to a register (now for 5 other impossible things
2321 before breakfast) */
njn6b2b96a2005-05-16 00:01:04 +00002322static Addr regaddr(ThreadId tid, Int regno)
jsgfcb1d1c02003-10-14 21:55:10 +00002323{
njn6b2b96a2005-05-16 00:01:04 +00002324 Addr ret = regaddr_from_tst(regno, &VG_(threads)[tid].arch);
jsgfcb1d1c02003-10-14 21:55:10 +00002325
2326 if (ret == 0) {
njn252ed912005-05-15 03:30:56 +00002327 Char buf[100];
2328 VG_(describe_IP)( VG_(get_IP)(tid), buf, 100 );
2329 VG_(printf)("mysterious register %d used at %s\n", regno, buf);
jsgfcb1d1c02003-10-14 21:55:10 +00002330 }
2331
2332 return ret;
2333}
2334
2335/* Get a list of all variables in scope, working out from the directly
2336 current one */
sewardj7eb7c582005-06-23 01:02:53 +00002337Variable* ML_(get_scope_variables)(ThreadId tid)
jsgfcb1d1c02003-10-14 21:55:10 +00002338{
2339 static const Bool debug = False;
2340 Variable *list, *end;
2341 Addr eip;
2342 SegInfo *si;
2343 Int scopeidx;
2344 Scope *scope;
2345 Int distance;
2346 static const Int maxsyms = 1000;
2347 Int nsyms = maxsyms;
2348
2349 list = end = NULL;
2350
njn67516132005-03-22 04:02:43 +00002351 eip = VG_(get_IP)(tid);
jsgfcb1d1c02003-10-14 21:55:10 +00002352
2353 search_all_scopetabs(eip, &si, &scopeidx);
2354
2355 if (debug)
2356 VG_(printf)("eip=%p si=%p (%s; offset=%p) scopeidx=%d\n",
2357 eip, si, si ? si->filename : (Char *)"???",
2358 si ? si->offset : 0x99999, scopeidx);
2359
2360 if (si == NULL)
2361 return NULL; /* nothing in scope (should use global scope at least) */
2362
2363 if (debug) {
2364 ScopeRange *sr = &si->scopetab[scopeidx];
2365 Char file[100];
2366 Int line;
2367
sewardj7cee6f92005-06-13 17:39:06 +00002368 if (!VG_(get_filename_linenum)(sr->addr, file, sizeof(file),
2369 NULL, 0, NULL, &line))
jsgfcb1d1c02003-10-14 21:55:10 +00002370 file[0] = 0;
2371
2372 VG_(printf)("found scope range %p: eip=%p (%s:%d) size=%d scope=%p\n",
2373 sr, sr->addr, file, line, sr->size, sr->scope);
2374 }
2375
2376 distance = 0;
sewardj7cee6f92005-06-13 17:39:06 +00002377 for (scope = si->scopetab[scopeidx].scope;
2378 scope != NULL;
2379 scope = scope->outer, distance++) {
jsgfcb1d1c02003-10-14 21:55:10 +00002380 UInt i;
2381
2382 for(i = 0; i < scope->nsyms; i++) {
2383 Sym *sym = &scope->syms[i];
2384 Variable *v;
2385
2386 if (nsyms-- == 0) {
2387 VG_(printf)("max %d syms reached\n", maxsyms);
2388 return list;
2389 }
2390
2391 v = VG_(arena_malloc)(VG_AR_SYMTAB, sizeof(*v));
2392
2393 v->next = NULL;
2394 v->distance = distance;
sewardj7eb7c582005-06-23 01:02:53 +00002395 v->type = ML_(st_basetype)(sym->type, False);
jsgfcb1d1c02003-10-14 21:55:10 +00002396 v->name = VG_(arena_strdup)(VG_AR_SYMTAB, sym->name);
2397 v->container = NULL;
sewardj7eb7c582005-06-23 01:02:53 +00002398 v->size = ML_(st_sizeof)(sym->type);
jsgfcb1d1c02003-10-14 21:55:10 +00002399
2400 if (debug && 0)
mueller5ed88f22004-01-06 16:02:29 +00002401 VG_(printf)("sym->name=%s sym->kind=%d offset=%d\n", sym->name, sym->kind, sym->u.offset);
jsgfcb1d1c02003-10-14 21:55:10 +00002402 switch(sym->kind) {
jsgfcb1d1c02003-10-14 21:55:10 +00002403
2404 case SyGlobal:
2405 case SyStatic:
mueller5ed88f22004-01-06 16:02:29 +00002406 if (sym->u.addr == 0) {
jsgfcb1d1c02003-10-14 21:55:10 +00002407 /* XXX lookup value */
2408 }
mueller5ed88f22004-01-06 16:02:29 +00002409 v->valuep = sym->u.addr;
jsgfcb1d1c02003-10-14 21:55:10 +00002410 break;
2411
2412 case SyReg:
njn6b2b96a2005-05-16 00:01:04 +00002413 v->valuep = regaddr(tid, sym->u.regno);
jsgfcb1d1c02003-10-14 21:55:10 +00002414 break;
2415
2416 case SyEBPrel:
njn6b2b96a2005-05-16 00:01:04 +00002417 case SyESPrel: {
2418 Addr reg = *(Addr*)regaddr(tid, sym->kind == SyESPrel
2419 ? R_STACK_PTR : R_FRAME_PTR);
jsgfcb1d1c02003-10-14 21:55:10 +00002420 if (debug)
mueller5ed88f22004-01-06 16:02:29 +00002421 VG_(printf)("reg=%p+%d=%p\n", reg, sym->u.offset, reg+sym->u.offset);
njn6b2b96a2005-05-16 00:01:04 +00002422 v->valuep = reg + sym->u.offset;
jsgfcb1d1c02003-10-14 21:55:10 +00002423 break;
njn6b2b96a2005-05-16 00:01:04 +00002424 }
jsgfcb1d1c02003-10-14 21:55:10 +00002425
2426 case SyType:
2427 VG_(core_panic)("unexpected typedef in scope");
2428 }
2429
2430 if (v->valuep == 0) {
2431 /* not interesting or useful */
2432 VG_(arena_free)(VG_AR_SYMTAB, v);
2433 continue;
2434 }
2435
2436 /* append to end of list */
2437 if (list == NULL)
2438 list = end = v;
2439 else {
2440 end->next = v;
2441 end = v;
2442 }
2443 }
2444 }
2445
2446 return list;
2447}
sewardj7cee6f92005-06-13 17:39:06 +00002448
2449# undef R_STACK_PTR
2450# undef R_FRAME_PTR
2451
jsgfcb1d1c02003-10-14 21:55:10 +00002452#endif /* TEST */
2453
njn6c846552003-09-16 07:41:43 +00002454/* Print into buf info on code address, function name and filename */
sewardj948d7612005-06-09 23:58:36 +00002455
2456static Int putStr ( Int n, Int n_buf, Char* buf, Char* str )
2457{
2458 for (; n < n_buf-1 && *str != 0; n++,str++)
2459 buf[n] = *str;
2460 buf[n] = '\0';
2461 return n;
2462}
2463static Int putStrEsc ( Int n, Int n_buf, Char* buf, Char* str )
2464{
2465 Char alt[2];
2466 for (; *str != 0; str++) {
2467 switch (*str) {
2468 case '&': n = putStr( n, n_buf, buf, "&amp;"); break;
2469 case '<': n = putStr( n, n_buf, buf, "&lt;"); break;
2470 case '>': n = putStr( n, n_buf, buf, "&gt;"); break;
2471 default: alt[0] = *str;
2472 alt[1] = 0;
2473 n = putStr( n, n_buf, buf, alt );
2474 break;
2475 }
2476 }
2477 return n;
2478}
2479
njnd01fef72005-03-25 23:35:48 +00002480Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf)
sewardjde4a1d02002-03-22 01:27:54 +00002481{
sewardj948d7612005-06-09 23:58:36 +00002482# define APPEND(_str) \
2483 n = putStr(n, n_buf, buf, _str);
2484# define APPEND_ESC(_str) \
2485 n = putStrEsc(n, n_buf, buf, _str);
njn83f9e792005-06-11 05:04:09 +00002486# define BUF_LEN 4096
sewardj948d7612005-06-09 23:58:36 +00002487
nethercote80f76782003-11-13 22:34:00 +00002488 UInt lineno;
sewardj71bc3cb2005-05-19 00:25:45 +00002489 UChar ibuf[50];
sewardj948d7612005-06-09 23:58:36 +00002490 Int n = 0;
njn83f9e792005-06-11 05:04:09 +00002491 static UChar buf_fn[BUF_LEN];
2492 static UChar buf_obj[BUF_LEN];
2493 static UChar buf_srcloc[BUF_LEN];
sewardj7cee6f92005-06-13 17:39:06 +00002494 static UChar buf_dirname[BUF_LEN];
2495 Bool know_dirinfo = False;
njn83f9e792005-06-11 05:04:09 +00002496 Bool know_fnname = VG_(get_fnname) (eip, buf_fn, BUF_LEN);
2497 Bool know_objname = VG_(get_objname)(eip, buf_obj, BUF_LEN);
sewardj7cee6f92005-06-13 17:39:06 +00002498 Bool know_srcloc = VG_(get_filename_linenum)(
2499 eip,
2500 buf_srcloc, BUF_LEN,
2501 buf_dirname, BUF_LEN, &know_dirinfo,
2502 &lineno
2503 );
sewardj71bc3cb2005-05-19 00:25:45 +00002504 if (VG_(clo_xml)) {
2505
sewardj8665d8e2005-06-01 17:35:23 +00002506 Bool human_readable = True;
2507 HChar* maybe_newline = human_readable ? "\n " : "";
2508 HChar* maybe_newline2 = human_readable ? "\n " : "";
2509
sewardj71bc3cb2005-05-19 00:25:45 +00002510 /* Print in XML format, dumping in as much info as we know. */
2511 APPEND("<frame>");
2512 VG_(sprintf)(ibuf,"<ip>0x%llx</ip>", (ULong)eip);
sewardj8665d8e2005-06-01 17:35:23 +00002513 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002514 APPEND(ibuf);
2515 if (know_objname) {
sewardj8665d8e2005-06-01 17:35:23 +00002516 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002517 APPEND("<obj>");
sewardj948d7612005-06-09 23:58:36 +00002518 APPEND_ESC(buf_obj);
sewardj71bc3cb2005-05-19 00:25:45 +00002519 APPEND("</obj>");
2520 }
2521 if (know_fnname) {
sewardj8665d8e2005-06-01 17:35:23 +00002522 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002523 APPEND("<fn>");
sewardj948d7612005-06-09 23:58:36 +00002524 APPEND_ESC(buf_fn);
sewardj71bc3cb2005-05-19 00:25:45 +00002525 APPEND("</fn>");
2526 }
2527 if (know_srcloc) {
sewardj7cee6f92005-06-13 17:39:06 +00002528 if (know_dirinfo) {
2529 APPEND(maybe_newline);
2530 APPEND("<dir>");
2531 APPEND(buf_dirname);
2532 APPEND("</dir>");
2533 }
sewardj8665d8e2005-06-01 17:35:23 +00002534 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002535 APPEND("<file>");
sewardj948d7612005-06-09 23:58:36 +00002536 APPEND_ESC(buf_srcloc);
sewardj71bc3cb2005-05-19 00:25:45 +00002537 APPEND("</file>");
sewardj8665d8e2005-06-01 17:35:23 +00002538 APPEND(maybe_newline);
sewardj71bc3cb2005-05-19 00:25:45 +00002539 APPEND("<line>");
2540 VG_(sprintf)(ibuf,"%d",lineno);
2541 APPEND(ibuf);
2542 APPEND("</line>");
2543 }
sewardj8665d8e2005-06-01 17:35:23 +00002544 APPEND(maybe_newline2);
sewardj71bc3cb2005-05-19 00:25:45 +00002545 APPEND("</frame>");
2546
2547 } else {
2548
2549 /* Print for humans to read */
2550 VG_(sprintf)(ibuf,"0x%llx: ", (ULong)eip);
2551 APPEND(ibuf);
2552 if (know_fnname) {
2553 APPEND(buf_fn);
2554 if (!know_srcloc && know_objname) {
2555 APPEND(" (in ");
2556 APPEND(buf_obj);
2557 APPEND(")");
2558 }
2559 } else if (know_objname && !know_srcloc) {
2560 APPEND("(within ");
njn6c846552003-09-16 07:41:43 +00002561 APPEND(buf_obj);
2562 APPEND(")");
sewardj71bc3cb2005-05-19 00:25:45 +00002563 } else {
2564 APPEND("???");
njn6c846552003-09-16 07:41:43 +00002565 }
sewardj71bc3cb2005-05-19 00:25:45 +00002566 if (know_srcloc) {
2567 APPEND(" (");
2568 APPEND(buf_srcloc);
2569 APPEND(":");
2570 VG_(sprintf)(ibuf,"%d",lineno);
2571 APPEND(ibuf);
2572 APPEND(")");
2573 }
2574
njn6c846552003-09-16 07:41:43 +00002575 }
2576 return buf;
2577
sewardj948d7612005-06-09 23:58:36 +00002578# undef APPEND
2579# undef APPEND_ESC
sewardj7cee6f92005-06-13 17:39:06 +00002580# undef BUF_LEN
njn6c846552003-09-16 07:41:43 +00002581}
2582
sewardj35165532005-04-30 18:47:48 +00002583/* Returns True if OK. If not OK, *{ip,sp,fp}P are not changed. */
sewardj1d3cee22005-11-14 15:10:12 +00002584/* NOTE: this function may rearrange the order of entries in the
2585 SegInfo list. */
sewardj35165532005-04-30 18:47:48 +00002586Bool VG_(use_CFI_info) ( /*MOD*/Addr* ipP,
2587 /*MOD*/Addr* spP,
2588 /*MOD*/Addr* fpP,
2589 Addr min_accessible,
2590 Addr max_accessible )
2591{
2592 Int i;
2593 SegInfo* si;
2594 CfiSI* cfisi = NULL;
2595 Addr cfa, ipHere, spHere, fpHere, ipPrev, spPrev, fpPrev;
2596
sewardj1d3cee22005-11-14 15:10:12 +00002597 static UInt n_search = 0;
2598 static UInt n_steps = 0;
2599 n_search++;
sewardjbf603752005-05-02 00:36:27 +00002600
sewardj35165532005-04-30 18:47:48 +00002601 if (0) VG_(printf)("search for %p\n", *ipP);
2602
njn16eeb4e2005-06-16 03:56:58 +00002603 for (si = segInfo_list; si != NULL; si = si->next) {
sewardj1d3cee22005-11-14 15:10:12 +00002604 n_steps++;
2605
sewardjbf603752005-05-02 00:36:27 +00002606 /* Use the per-SegInfo summary address ranges to skip
2607 inapplicable SegInfos quickly. */
2608 if (si->cfisi_used == 0)
2609 continue;
2610 if (*ipP < si->cfisi_minaddr || *ipP > si->cfisi_maxaddr)
2611 continue;
2612
sewardj3a1c7db2005-05-02 09:43:44 +00002613 i = search_one_cfitab( si, *ipP );
2614 if (i != -1) {
2615 vg_assert(i >= 0 && i < si->cfisi_used);
2616 cfisi = &si->cfisi[i];
2617 break;
sewardj35165532005-04-30 18:47:48 +00002618 }
2619 }
2620
sewardj35165532005-04-30 18:47:48 +00002621 if (cfisi == NULL)
2622 return False;
2623
sewardj1d3cee22005-11-14 15:10:12 +00002624 if (0 && ((n_search & 0xFFFFF) == 0))
2625 VG_(printf)("%u %u\n", n_search, n_steps);
2626
2627 /* Start of performance-enhancing hack: once every 16 (chosen
2628 hackily after profiling) successful searchs, move the found
2629 SegInfo one step closer to the start of the list. This makes
2630 future searches cheaper. For starting konqueror on amd64, this
2631 in fact reduces the total amount of searching done by the above
2632 find-the-right-SegInfo loop by more than a factor of 20. */
2633 if ((n_search & 0xF) == 0) {
2634 /* Move si one step closer to the start of the list. */
2635 SegInfo* si0 = segInfo_list;
2636 SegInfo* si1 = NULL;
2637 SegInfo* si2 = NULL;
2638 SegInfo* tmp;
2639 while (True) {
2640 if (si0 == NULL) break;
2641 if (si0 == si) break;
2642 si2 = si1;
2643 si1 = si0;
2644 si0 = si0->next;
2645 }
2646 if (si0 == si && si0 != NULL && si1 != NULL && si2 != NULL) {
2647 /* si0 points to si, si1 to its predecessor, and si2 to si1's
2648 predecessor. Swap si0 and si1, that is, move si0 one step
2649 closer to the start of the list. */
2650 tmp = si0->next;
2651 si2->next = si0;
2652 si0->next = si1;
2653 si1->next = tmp;
2654 }
2655 }
2656 /* End of performance-enhancing hack. */
2657
sewardj35165532005-04-30 18:47:48 +00002658 if (0) {
2659 VG_(printf)("found cfisi: ");
sewardj7eb7c582005-06-23 01:02:53 +00002660 ML_(ppCfiSI)(cfisi);
sewardj35165532005-04-30 18:47:48 +00002661 }
2662
2663 ipPrev = spPrev = fpPrev = 0;
2664
2665 ipHere = *ipP;
2666 spHere = *spP;
2667 fpHere = *fpP;
2668
2669 cfa = cfisi->cfa_off + (cfisi->cfa_sprel ? spHere : fpHere);
2670
2671# define COMPUTE(_prev, _here, _how, _off) \
2672 do { \
2673 switch (_how) { \
2674 case CFIR_UNKNOWN: \
2675 return False; \
2676 case CFIR_SAME: \
2677 _prev = _here; break; \
2678 case CFIR_MEMCFAREL: { \
2679 Addr a = cfa + (Word)_off; \
2680 if (a < min_accessible \
2681 || a+sizeof(Addr) > max_accessible) \
2682 return False; \
2683 _prev = *(Addr*)a; \
2684 break; \
2685 } \
2686 case CFIR_CFAREL: \
2687 _prev = cfa + (Word)_off; \
2688 break; \
2689 } \
2690 } while (0)
2691
2692 COMPUTE(ipPrev, ipHere, cfisi->ra_how, cfisi->ra_off);
2693 COMPUTE(spPrev, spHere, cfisi->sp_how, cfisi->sp_off);
2694 COMPUTE(fpPrev, fpHere, cfisi->fp_how, cfisi->fp_off);
2695
2696# undef COMPUTE
2697
2698 *ipP = ipPrev;
2699 *spP = spPrev;
2700 *fpP = fpPrev;
2701 return True;
2702}
2703
2704
sewardj25c7c3a2003-07-10 00:17:58 +00002705/*------------------------------------------------------------*/
sewardj47104382002-10-20 18:35:48 +00002706/*--- SegInfo accessor functions ---*/
2707/*------------------------------------------------------------*/
2708
njn36ef6ba2005-05-14 18:42:26 +00002709const SegInfo* VG_(next_seginfo)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002710{
njn36ef6ba2005-05-14 18:42:26 +00002711 if (si == NULL)
njn16eeb4e2005-06-16 03:56:58 +00002712 return segInfo_list;
njn36ef6ba2005-05-14 18:42:26 +00002713 return si->next;
sewardj47104382002-10-20 18:35:48 +00002714}
2715
njnd9e5fd72005-06-25 19:51:33 +00002716Addr VG_(seginfo_start)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002717{
njn36ef6ba2005-05-14 18:42:26 +00002718 return si->start;
sewardj47104382002-10-20 18:35:48 +00002719}
2720
njnd9e5fd72005-06-25 19:51:33 +00002721SizeT VG_(seginfo_size)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002722{
njn36ef6ba2005-05-14 18:42:26 +00002723 return si->size;
sewardj47104382002-10-20 18:35:48 +00002724}
2725
njn4f612c22005-06-25 20:22:43 +00002726const UChar* VG_(seginfo_soname)(const SegInfo* si)
2727{
2728 return si->soname;
2729}
2730
njnd9e5fd72005-06-25 19:51:33 +00002731const UChar* VG_(seginfo_filename)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002732{
njn36ef6ba2005-05-14 18:42:26 +00002733 return si->filename;
sewardj47104382002-10-20 18:35:48 +00002734}
2735
njnd9e5fd72005-06-25 19:51:33 +00002736ULong VG_(seginfo_sym_offset)(const SegInfo* si)
sewardj47104382002-10-20 18:35:48 +00002737{
njn36ef6ba2005-05-14 18:42:26 +00002738 return si->offset;
sewardj47104382002-10-20 18:35:48 +00002739}
2740
njnd9e5fd72005-06-25 19:51:33 +00002741VgSectKind VG_(seginfo_sect_kind)(Addr a)
sewardj47104382002-10-20 18:35:48 +00002742{
njn36ef6ba2005-05-14 18:42:26 +00002743 SegInfo* si;
sewardj47104382002-10-20 18:35:48 +00002744 VgSectKind ret = Vg_SectUnknown;
2745
njn16eeb4e2005-06-16 03:56:58 +00002746 for(si = segInfo_list; si != NULL; si = si->next) {
njn36ef6ba2005-05-14 18:42:26 +00002747 if (a >= si->start && a < (si->start + si->size)) {
sewardj47104382002-10-20 18:35:48 +00002748 if (0)
njn36ef6ba2005-05-14 18:42:26 +00002749 VG_(printf)("addr=%p si=%p %s got=%p %d plt=%p %d data=%p %d bss=%p %d\n",
2750 a, si, si->filename,
2751 si->got_start, si->got_size,
2752 si->plt_start, si->plt_size,
2753 si->data_start, si->data_size,
2754 si->bss_start, si->bss_size);
sewardj47104382002-10-20 18:35:48 +00002755 ret = Vg_SectText;
2756
njn36ef6ba2005-05-14 18:42:26 +00002757 if (a >= si->data_start && a < (si->data_start + si->data_size))
sewardj8fe15a32002-10-20 19:29:21 +00002758 ret = Vg_SectData;
njn36ef6ba2005-05-14 18:42:26 +00002759 else if (a >= si->bss_start && a < (si->bss_start + si->bss_size))
sewardj8fe15a32002-10-20 19:29:21 +00002760 ret = Vg_SectBSS;
njn36ef6ba2005-05-14 18:42:26 +00002761 else if (a >= si->plt_start && a < (si->plt_start + si->plt_size))
sewardj47104382002-10-20 18:35:48 +00002762 ret = Vg_SectPLT;
njn36ef6ba2005-05-14 18:42:26 +00002763 else if (a >= si->got_start && a < (si->got_start + si->got_size))
sewardj47104382002-10-20 18:35:48 +00002764 ret = Vg_SectGOT;
2765 }
2766 }
2767
2768 return ret;
2769}
2770
sewardjde4a1d02002-03-22 01:27:54 +00002771/*--------------------------------------------------------------------*/
njnea27e462005-05-31 02:38:09 +00002772/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00002773/*--------------------------------------------------------------------*/