sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Reading of syms & debug info from ELF .so/executable files. ---*/ |
| 4 | /*--- readelf.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
| 11 | Copyright (C) 2000-2006 Julian Seward |
| 12 | jseward@acm.org |
| 13 | |
| 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 | |
| 29 | The GNU General Public License is contained in the file COPYING. |
| 30 | */ |
| 31 | /* |
| 32 | Stabs reader greatly improved by Nick Nethercote, Apr 02. |
| 33 | This module was also extensively hacked on by Jeremy Fitzhardinge |
| 34 | and Tom Hughes. |
| 35 | */ |
| 36 | |
| 37 | #include "pub_core_basics.h" |
| 38 | #include "pub_core_libcbase.h" |
| 39 | #include "pub_core_libcprint.h" |
| 40 | #include "pub_core_libcassert.h" |
| 41 | #include "pub_core_libcfile.h" |
| 42 | #include "pub_core_aspacemgr.h" /* for mmaping debuginfo files */ |
| 43 | #include "pub_core_machine.h" /* VG_ELF_CLASS */ |
| 44 | #include "pub_core_mallocfree.h" |
| 45 | #include "pub_core_options.h" |
| 46 | #include "pub_core_oset.h" |
| 47 | #include "pub_core_tooliface.h" /* VG_(needs) */ |
| 48 | #include "priv_storage.h" |
| 49 | #include "priv_readelf.h" /* self */ |
| 50 | #include "priv_readdwarf.h" /* 'cos ELF contains DWARF */ |
| 51 | #include "priv_readstabs.h" /* and stabs, if we're unlucky */ |
| 52 | |
| 53 | /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ |
| 54 | #include <elf.h> |
| 55 | /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ |
| 56 | |
| 57 | /*------------------------------------------------------------*/ |
| 58 | /*--- 32/64-bit parameterisation ---*/ |
| 59 | /*------------------------------------------------------------*/ |
| 60 | |
| 61 | /* For all the ELF macros and types which specify '32' or '64', |
| 62 | select the correct variant for this platform and give it |
| 63 | an 'XX' name. Then use the 'XX' variant consistently in |
| 64 | the rest of this file. |
| 65 | */ |
| 66 | #if VG_WORDSIZE == 4 |
| 67 | # define ElfXX_Ehdr Elf32_Ehdr |
| 68 | # define ElfXX_Shdr Elf32_Shdr |
| 69 | # define ElfXX_Phdr Elf32_Phdr |
| 70 | # define ElfXX_Sym Elf32_Sym |
| 71 | # define ElfXX_Word Elf32_Word |
| 72 | # define ElfXX_Addr Elf32_Addr |
| 73 | # define ElfXX_Dyn Elf32_Dyn |
| 74 | # define ELFXX_ST_BIND ELF32_ST_BIND |
| 75 | # define ELFXX_ST_TYPE ELF32_ST_TYPE |
| 76 | |
| 77 | #elif VG_WORDSIZE == 8 |
| 78 | # define ElfXX_Ehdr Elf64_Ehdr |
| 79 | # define ElfXX_Shdr Elf64_Shdr |
| 80 | # define ElfXX_Phdr Elf64_Phdr |
| 81 | # define ElfXX_Sym Elf64_Sym |
| 82 | # define ElfXX_Word Elf64_Word |
| 83 | # define ElfXX_Addr Elf64_Addr |
| 84 | # define ElfXX_Dyn Elf64_Dyn |
| 85 | # define ELFXX_ST_BIND ELF64_ST_BIND |
| 86 | # define ELFXX_ST_TYPE ELF64_ST_TYPE |
| 87 | |
| 88 | #else |
| 89 | # error "VG_WORDSIZE should be 4 or 8" |
| 90 | #endif |
| 91 | |
| 92 | |
| 93 | /*------------------------------------------------------------*/ |
| 94 | /*--- ---*/ |
| 95 | /*--- Read symbol table and line info from ELF files. ---*/ |
| 96 | /*--- ---*/ |
| 97 | /*------------------------------------------------------------*/ |
| 98 | |
| 99 | /* readelf.c parses ELF files and acquires symbol table info from |
| 100 | them. It calls onwards to readdwarf.c to read DWARF2/3 line number |
| 101 | and call frame info found. */ |
| 102 | |
| 103 | |
| 104 | /* Identify an ELF object file by peering at the first few bytes of |
| 105 | it. */ |
| 106 | |
| 107 | Bool ML_(is_elf_object_file)( const void* buf ) |
| 108 | { |
| 109 | ElfXX_Ehdr* ehdr = (ElfXX_Ehdr*)buf; |
| 110 | Int ok = 1; |
| 111 | |
| 112 | ok &= (ehdr->e_ident[EI_MAG0] == 0x7F |
| 113 | && ehdr->e_ident[EI_MAG1] == 'E' |
| 114 | && ehdr->e_ident[EI_MAG2] == 'L' |
| 115 | && ehdr->e_ident[EI_MAG3] == 'F'); |
| 116 | ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS |
| 117 | && ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX |
| 118 | && ehdr->e_ident[EI_VERSION] == EV_CURRENT); |
| 119 | ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN); |
| 120 | ok &= (ehdr->e_machine == VG_ELF_MACHINE); |
| 121 | ok &= (ehdr->e_version == EV_CURRENT); |
| 122 | ok &= (ehdr->e_shstrndx != SHN_UNDEF); |
| 123 | ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0); |
| 124 | ok &= (ehdr->e_phoff != 0 && ehdr->e_phnum != 0); |
| 125 | |
| 126 | if (ok) |
| 127 | return True; |
| 128 | else |
| 129 | return False; |
| 130 | } |
| 131 | |
| 132 | |
| 133 | /* Show a raw ELF symbol, given its in-image address and name. */ |
| 134 | |
| 135 | static |
| 136 | void show_raw_elf_symbol ( Int i, |
| 137 | ElfXX_Sym* sym, Char* sym_name, Addr sym_addr, |
| 138 | Bool ppc64_linux_format ) |
| 139 | { |
| 140 | HChar* space = ppc64_linux_format ? " " : ""; |
| 141 | VG_(printf)("raw symbol [%4d]: ", i); |
| 142 | switch (ELFXX_ST_BIND(sym->st_info)) { |
| 143 | case STB_LOCAL: VG_(printf)("LOC "); break; |
| 144 | case STB_GLOBAL: VG_(printf)("GLO "); break; |
| 145 | case STB_WEAK: VG_(printf)("WEA "); break; |
| 146 | case STB_LOPROC: VG_(printf)("lop "); break; |
| 147 | case STB_HIPROC: VG_(printf)("hip "); break; |
| 148 | default: VG_(printf)("??? "); break; |
| 149 | } |
| 150 | switch (ELFXX_ST_TYPE(sym->st_info)) { |
| 151 | case STT_NOTYPE: VG_(printf)("NOT "); break; |
| 152 | case STT_OBJECT: VG_(printf)("OBJ "); break; |
| 153 | case STT_FUNC: VG_(printf)("FUN "); break; |
| 154 | case STT_SECTION: VG_(printf)("SEC "); break; |
| 155 | case STT_FILE: VG_(printf)("FIL "); break; |
| 156 | case STT_LOPROC: VG_(printf)("lop "); break; |
| 157 | case STT_HIPROC: VG_(printf)("hip "); break; |
| 158 | default: VG_(printf)("??? "); break; |
| 159 | } |
| 160 | VG_(printf)(": val %010p, %ssz %4d %s\n", |
| 161 | sym_addr, space, sym->st_size, |
| 162 | ( sym->st_name ? sym_name : (Char*)"NONAME" ) ); |
| 163 | } |
| 164 | |
| 165 | |
| 166 | /* Decide whether SYM is something we should collect, and if so, copy |
| 167 | relevant info to the _OUT arguments. For {x86,amd64,ppc32}-linux |
| 168 | this is straightforward - the name, address, size are copied out |
| 169 | unchanged. |
| 170 | |
| 171 | For ppc64-linux it's more complex. If the symbol is seen to be in |
| 172 | the .opd section, it is taken to be a function descriptor, and so |
| 173 | a dereference is attempted, in order to get hold of the real entry |
| 174 | point address. Also as part of the dereference, there is an attempt |
| 175 | to calculate the TOC pointer (R2 value) associated with the symbol. |
| 176 | |
| 177 | To support the ppc64-linux pre-"dotless" ABI (prior to gcc 4.0.0), |
| 178 | if the symbol is seen to be outside the .opd section and its name |
| 179 | starts with a dot, an .opd deference is not attempted, and no TOC |
| 180 | pointer is calculated, but the the leading dot is removed from the |
| 181 | name. |
| 182 | |
| 183 | As a result, on ppc64-linux, the caller of this function may have |
| 184 | to piece together the real size, address, name of the symbol from |
| 185 | multiple calls to this function. Ugly and confusing. |
| 186 | */ |
| 187 | static |
| 188 | Bool get_elf_symbol_info ( |
| 189 | /* INPUTS */ |
| 190 | struct _SegInfo* si, /* containing SegInfo */ |
| 191 | ElfXX_Sym* sym, /* ELF symbol */ |
| 192 | Char* sym_name, /* name */ |
| 193 | Addr sym_addr, /* declared address */ |
| 194 | UChar* opd_filea, /* oimage of .opd sec (ppc64-linux only) */ |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 195 | OffT opd_offset, /* base address assumed in oimage */ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 196 | /* OUTPUTS */ |
| 197 | Char** sym_name_out, /* name we should record */ |
| 198 | Addr* sym_addr_out, /* addr we should record */ |
| 199 | Int* sym_size_out, /* symbol size */ |
| 200 | Addr* sym_tocptr_out, /* ppc64-linux only: R2 value to be |
| 201 | used on entry */ |
| 202 | Bool* from_opd_out /* ppc64-linux only: did we deref an |
| 203 | .opd entry? */ |
| 204 | ) |
| 205 | { |
| 206 | Bool plausible, is_in_opd; |
| 207 | |
| 208 | /* Set defaults */ |
| 209 | *sym_name_out = sym_name; |
| 210 | *sym_addr_out = sym_addr; |
| 211 | *sym_size_out = (Int)sym->st_size; |
| 212 | *sym_tocptr_out = 0; /* unknown/inapplicable */ |
| 213 | *from_opd_out = False; |
| 214 | |
| 215 | /* Figure out if we're interested in the symbol. Firstly, is it of |
| 216 | the right flavour? */ |
| 217 | plausible |
| 218 | = (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL |
| 219 | || ELFXX_ST_BIND(sym->st_info) == STB_LOCAL |
| 220 | || ELFXX_ST_BIND(sym->st_info) == STB_WEAK |
| 221 | ) |
| 222 | && |
| 223 | (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC |
| 224 | || (VG_(needs).data_syms |
| 225 | && ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT) |
| 226 | ); |
| 227 | |
| 228 | # if defined(VGP_ppc64_linux) |
| 229 | /* Allow STT_NOTYPE in the very special case where we're running on |
| 230 | ppc64-linux and the symbol is one which the .opd-chasing hack |
| 231 | below will chase. */ |
| 232 | if (!plausible |
| 233 | && ELFXX_ST_TYPE(sym->st_info) == STT_NOTYPE |
| 234 | && sym->st_size > 0 |
| 235 | && si->opd_start_vma != 0 |
| 236 | && sym_addr >= si->opd_start_vma |
| 237 | && sym_addr < si->opd_start_vma + si->opd_size) |
| 238 | plausible = True; |
| 239 | # endif |
| 240 | |
| 241 | if (!plausible) |
| 242 | return False; |
| 243 | |
| 244 | /* Ignore if nameless, or zero-sized. */ |
| 245 | if (sym->st_name == (ElfXX_Word)NULL |
| 246 | || /* VG_(strlen)(sym_name) == 0 */ |
| 247 | /* equivalent but cheaper ... */ |
| 248 | sym_name[0] == 0 |
| 249 | || sym->st_size == 0) { |
| 250 | TRACE_SYMTAB(" ignore -- size=0: %s\n", sym_name); |
| 251 | return False; |
| 252 | } |
| 253 | |
| 254 | /* This seems to significantly reduce the number of junk |
| 255 | symbols, and particularly reduces the number of |
| 256 | overlapping address ranges. Don't ask me why ... */ |
| 257 | if ((Int)sym->st_value == 0) { |
| 258 | TRACE_SYMTAB( " ignore -- valu=0: %s\n", sym_name); |
| 259 | return False; |
| 260 | } |
| 261 | |
| 262 | /* If it's apparently in a GOT or PLT, it's really a reference to a |
| 263 | symbol defined elsewhere, so ignore it. */ |
| 264 | if (si->got_start_vma != 0 |
| 265 | && sym_addr >= si->got_start_vma |
| 266 | && sym_addr < si->got_start_vma + si->got_size) { |
| 267 | TRACE_SYMTAB(" ignore -- in GOT: %s\n", sym_name); |
| 268 | return False; |
| 269 | } |
| 270 | if (si->plt_start_vma != 0 |
| 271 | && sym_addr >= si->plt_start_vma |
| 272 | && sym_addr < si->plt_start_vma + si->plt_size) { |
| 273 | TRACE_SYMTAB(" ignore -- in PLT: %s\n", sym_name); |
| 274 | return False; |
| 275 | } |
| 276 | |
| 277 | /* ppc64-linux nasty hack: if the symbol is in an .opd section, |
| 278 | then really what we have is the address of a function |
| 279 | descriptor. So use the first word of that as the function's |
| 280 | text. |
| 281 | |
| 282 | See thread starting at |
| 283 | http://gcc.gnu.org/ml/gcc-patches/2004-08/msg00557.html |
| 284 | */ |
| 285 | is_in_opd = False; |
| 286 | |
| 287 | if (si->opd_start_vma != 0 |
| 288 | && sym_addr >= si->opd_start_vma |
| 289 | && sym_addr < si->opd_start_vma + si->opd_size) { |
| 290 | # if !defined(VGP_ppc64_linux) |
| 291 | TRACE_SYMTAB(" ignore -- in OPD: %s\n", sym_name); |
| 292 | return False; |
| 293 | # else |
| 294 | Int offset_in_opd; |
| 295 | ULong* fn_descr; |
| 296 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 297 | if (0) VG_(printf)("opdXXX: opd_offset %p, sym_addr %p\n", |
| 298 | (void*)(opd_offset), (void*)sym_addr); |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 299 | |
| 300 | if (!VG_IS_8_ALIGNED(sym_addr)) { |
| 301 | TRACE_SYMTAB(" ignore -- not 8-aligned: %s\n", sym_name); |
| 302 | return False; |
| 303 | } |
| 304 | |
| 305 | /* sym_addr is a vma pointing into the .opd section. We know |
| 306 | the vma of the opd section start, so we can figure out how |
| 307 | far into the opd section this is. */ |
| 308 | |
| 309 | offset_in_opd = (Addr)sym_addr - (Addr)(si->opd_start_vma); |
| 310 | if (offset_in_opd < 0 || offset_in_opd >= si->opd_size) { |
| 311 | TRACE_SYMTAB(" ignore -- invalid OPD offset: %s\n", sym_name); |
| 312 | return False; |
| 313 | } |
| 314 | |
| 315 | /* Now we want to know what's at that offset in the .opd |
| 316 | section. We can't look in the running image since it won't |
| 317 | necessarily have been mapped. But we can consult the oimage. |
| 318 | opd_filea is the start address of the .opd in the oimage. |
| 319 | Hence: */ |
| 320 | |
| 321 | fn_descr = (ULong*)(opd_filea + offset_in_opd); |
| 322 | |
| 323 | if (0) VG_(printf)("opdXXY: offset %d, fn_descr %p\n", |
| 324 | offset_in_opd, fn_descr); |
| 325 | if (0) VG_(printf)("opdXXZ: *fn_descr %p\n", (void*)(fn_descr[0])); |
| 326 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 327 | /* opd_offset is the difference between si->start (where the |
| 328 | library got mapped) and the address space used for addresses |
| 329 | within the library file. */ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 330 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 331 | sym_addr = fn_descr[0] + opd_offset; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 332 | *sym_addr_out = sym_addr; |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 333 | *sym_tocptr_out = fn_descr[1] + opd_offset; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 334 | *from_opd_out = True; |
| 335 | is_in_opd = True; |
| 336 | |
| 337 | /* Do a final sanity check: if the symbol falls outside the |
| 338 | SegInfo's mapped range, ignore it. Since sym_addr has been |
| 339 | updated, that can be achieved simply by falling through to |
| 340 | the test below. */ |
| 341 | |
| 342 | # endif /* ppc64-linux nasty hack */ |
| 343 | } |
| 344 | |
| 345 | /* Here's yet another ppc64-linux hack. Get rid of leading dot if |
| 346 | the symbol is outside .opd. */ |
| 347 | # if defined(VGP_ppc64_linux) |
| 348 | if (si->opd_start_vma != 0 |
| 349 | && !is_in_opd |
| 350 | && sym_name[0] == '.') { |
| 351 | vg_assert(!(*from_opd_out)); |
| 352 | *sym_name_out = &sym_name[1]; |
| 353 | } |
| 354 | # endif |
| 355 | |
| 356 | /* If no part of the symbol falls within the mapped range, |
| 357 | ignore it. */ |
| 358 | if (*sym_addr_out + *sym_size_out <= si->start |
| 359 | || *sym_addr_out >= si->start+si->size) { |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 360 | TRACE_SYMTAB( "ignore -- %p .. %p outside mapped range %p .. %p\n", |
| 361 | *sym_addr_out, *sym_addr_out + *sym_size_out, |
| 362 | si->start, si->start+si->size); |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 363 | return False; |
| 364 | } |
| 365 | |
| 366 | # if defined(VGP_ppc64_linux) |
| 367 | /* It's crucial that we never add symbol addresses in the .opd |
| 368 | section. This would completely mess up function redirection and |
| 369 | intercepting. This assert ensures that any symbols that make it |
| 370 | into the symbol table on ppc64-linux don't point into .opd. */ |
| 371 | if (si->opd_start_vma != 0) { |
| 372 | vg_assert(*sym_addr_out + *sym_size_out <= si->opd_start_vma |
| 373 | || *sym_addr_out >= si->opd_start_vma + si->opd_size); |
| 374 | } |
| 375 | # endif |
| 376 | |
| 377 | /* Acquire! */ |
| 378 | return True; |
| 379 | } |
| 380 | |
| 381 | |
| 382 | /* Read an ELF symbol table (normal or dynamic). This one is for the |
| 383 | "normal" case ({x86,amd64,ppc32}-linux). */ |
| 384 | static |
| 385 | __attribute__((unused)) /* not referred to on all targets */ |
| 386 | void read_elf_symtab__normal( |
sewardj | 72c84c9 | 2006-04-06 13:31:17 +0000 | [diff] [blame] | 387 | struct _SegInfo* si, UChar* tab_name, |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 388 | ElfXX_Sym* o_symtab, UInt o_symtab_sz, OffT o_symtab_offset, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 389 | UChar* o_strtab, UInt o_strtab_sz, |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 390 | UChar* opd_filea, OffT opd_offset /* ppc64-linux only */ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 391 | ) |
| 392 | { |
| 393 | Int i; |
| 394 | Addr sym_addr, sym_addr_really; |
| 395 | Char *sym_name, *sym_name_really; |
| 396 | Int sym_size; |
| 397 | Addr sym_tocptr; |
| 398 | Bool from_opd; |
| 399 | DiSym risym; |
| 400 | ElfXX_Sym *sym; |
| 401 | |
| 402 | if (o_strtab == NULL || o_symtab == NULL) { |
| 403 | Char buf[80]; |
| 404 | vg_assert(VG_(strlen)(tab_name) < 40); |
| 405 | VG_(sprintf)(buf, " object doesn't have a %s", tab_name); |
| 406 | ML_(symerr)(buf); |
| 407 | return; |
| 408 | } |
| 409 | |
| 410 | TRACE_SYMTAB("\nReading (ELF, standard) %s (%d entries)\n", tab_name, |
| 411 | o_symtab_sz/sizeof(ElfXX_Sym) ); |
| 412 | |
| 413 | /* Perhaps should start at i = 1; ELF docs suggest that entry |
| 414 | 0 always denotes 'unknown symbol'. */ |
| 415 | for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) { |
| 416 | sym = & o_symtab[i]; |
| 417 | sym_name = (Char*)(o_strtab + sym->st_name); |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 418 | sym_addr = o_symtab_offset + sym->st_value; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 419 | |
| 420 | if (VG_(clo_trace_symtab)) |
| 421 | show_raw_elf_symbol(i, sym, sym_name, sym_addr, False); |
| 422 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 423 | if (get_elf_symbol_info(si, sym, sym_name, sym_addr, |
| 424 | opd_filea, opd_offset, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 425 | &sym_name_really, |
| 426 | &sym_addr_really, |
| 427 | &sym_size, |
| 428 | &sym_tocptr, |
| 429 | &from_opd)) { |
| 430 | |
| 431 | risym.addr = sym_addr_really; |
| 432 | risym.size = sym_size; |
| 433 | risym.name = ML_(addStr) ( si, sym_name_really, -1 ); |
| 434 | risym.tocptr = sym_tocptr; |
| 435 | vg_assert(risym.name != NULL); |
| 436 | vg_assert(risym.tocptr == 0); /* has no role except on ppc64-linux */ |
| 437 | ML_(addSym) ( si, &risym ); |
| 438 | |
| 439 | if (VG_(clo_trace_symtab)) { |
| 440 | VG_(printf)(" record [%4d]: " |
| 441 | " val %010p, sz %4d %s\n", |
| 442 | i, (void*)risym.addr, (Int)risym.size, |
| 443 | (HChar*)risym.name |
| 444 | ); |
| 445 | } |
| 446 | |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | |
| 452 | /* Read an ELF symbol table (normal or dynamic). This one is for |
| 453 | ppc64-linux, which requires special treatment. */ |
| 454 | |
| 455 | typedef |
| 456 | struct { |
| 457 | Addr addr; |
| 458 | UChar* name; |
| 459 | } |
| 460 | TempSymKey; |
| 461 | |
| 462 | typedef |
| 463 | struct { |
| 464 | TempSymKey key; |
| 465 | Addr tocptr; |
| 466 | Int size; |
| 467 | Bool from_opd; |
| 468 | } |
| 469 | TempSym; |
| 470 | |
| 471 | static Word cmp_TempSymKey ( TempSymKey* key1, TempSym* elem2 ) { |
| 472 | if (key1->addr < elem2->key.addr) return -1; |
| 473 | if (key1->addr > elem2->key.addr) return 1; |
| 474 | return (Word)VG_(strcmp)(key1->name, elem2->key.name); |
| 475 | } |
| 476 | static void* oset_malloc ( SizeT szB ) { |
| 477 | return VG_(arena_malloc)(VG_AR_SYMTAB, szB); |
| 478 | } |
| 479 | static void oset_free ( void* p ) { |
| 480 | VG_(arena_free)(VG_AR_SYMTAB, p); |
| 481 | } |
| 482 | |
| 483 | static |
| 484 | __attribute__((unused)) /* not referred to on all targets */ |
| 485 | void read_elf_symtab__ppc64_linux( |
| 486 | struct _SegInfo* si, UChar* tab_name, |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 487 | ElfXX_Sym* o_symtab, UInt o_symtab_sz, OffT o_symtab_offset, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 488 | UChar* o_strtab, UInt o_strtab_sz, |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 489 | UChar* opd_filea, OffT opd_offset /* ppc64-linux only */ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 490 | ) |
| 491 | { |
| 492 | Int i, old_size; |
| 493 | Addr sym_addr, sym_addr_really; |
| 494 | Char *sym_name, *sym_name_really; |
| 495 | Int sym_size; |
| 496 | Addr sym_tocptr, old_tocptr; |
| 497 | Bool from_opd, modify_size, modify_tocptr; |
| 498 | DiSym risym; |
| 499 | ElfXX_Sym *sym; |
| 500 | OSet *oset; |
| 501 | TempSymKey key; |
| 502 | TempSym *elem; |
| 503 | TempSym *prev; |
| 504 | |
| 505 | if (o_strtab == NULL || o_symtab == NULL) { |
| 506 | Char buf[80]; |
| 507 | vg_assert(VG_(strlen)(tab_name) < 40); |
| 508 | VG_(sprintf)(buf, " object doesn't have a %s", tab_name); |
| 509 | ML_(symerr)(buf); |
| 510 | return; |
| 511 | } |
| 512 | |
| 513 | TRACE_SYMTAB("\nReading (ELF, ppc64-linux) %s (%d entries)\n", tab_name, |
| 514 | o_symtab_sz/sizeof(ElfXX_Sym) ); |
| 515 | |
| 516 | oset = VG_(OSet_Create)( offsetof(TempSym,key), |
| 517 | (OSetCmp_t)cmp_TempSymKey, |
| 518 | oset_malloc, oset_free ); |
| 519 | vg_assert(oset); |
| 520 | |
| 521 | /* Perhaps should start at i = 1; ELF docs suggest that entry |
| 522 | 0 always denotes 'unknown symbol'. */ |
| 523 | for (i = 1; i < (Int)(o_symtab_sz/sizeof(ElfXX_Sym)); i++) { |
| 524 | sym = & o_symtab[i]; |
| 525 | sym_name = (Char*)(o_strtab + sym->st_name); |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 526 | sym_addr = o_symtab_offset + sym->st_value; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 527 | |
| 528 | if (VG_(clo_trace_symtab)) |
| 529 | show_raw_elf_symbol(i, sym, sym_name, sym_addr, True); |
| 530 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 531 | if (get_elf_symbol_info(si, sym, sym_name, sym_addr, |
| 532 | opd_filea, opd_offset, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 533 | &sym_name_really, |
| 534 | &sym_addr_really, |
| 535 | &sym_size, |
| 536 | &sym_tocptr, |
| 537 | &from_opd)) { |
| 538 | |
| 539 | /* Check if we've seen this (name,addr) key before. */ |
| 540 | key.addr = sym_addr_really; |
| 541 | key.name = sym_name_really; |
| 542 | prev = VG_(OSet_Lookup)( oset, &key ); |
| 543 | |
| 544 | if (prev) { |
| 545 | |
| 546 | /* Seen it before. Fold in whatever new info we can. */ |
| 547 | modify_size = False; |
| 548 | modify_tocptr = False; |
| 549 | old_size = 0; |
| 550 | old_tocptr = 0; |
| 551 | |
| 552 | if (prev->from_opd && !from_opd |
| 553 | && (prev->size == 24 || prev->size == 16) |
| 554 | && sym_size != prev->size) { |
| 555 | /* Existing one is an opd-redirect, with a bogus size, |
| 556 | so the only useful new fact we have is the real size |
| 557 | of the symbol. */ |
| 558 | modify_size = True; |
| 559 | old_size = prev->size; |
| 560 | prev->size = sym_size; |
| 561 | } |
| 562 | else |
| 563 | if (!prev->from_opd && from_opd |
| 564 | && (sym_size == 24 || sym_size == 16)) { |
| 565 | /* Existing one is non-opd, new one is opd. What we |
| 566 | can acquire from the new one is the TOC ptr to be |
| 567 | used. Since the existing sym is non-toc, it |
| 568 | shouldn't currently have an known TOC ptr. */ |
| 569 | vg_assert(prev->tocptr == 0); |
| 570 | modify_tocptr = True; |
| 571 | old_tocptr = prev->tocptr; |
| 572 | prev->tocptr = sym_tocptr; |
| 573 | } |
| 574 | else { |
| 575 | /* ignore. can we do better here? */ |
| 576 | } |
| 577 | |
| 578 | /* Only one or the other is possible (I think) */ |
| 579 | vg_assert(!(modify_size && modify_tocptr)); |
| 580 | |
| 581 | if (modify_size && VG_(clo_trace_symtab)) { |
| 582 | VG_(printf)(" modify (old sz %4d) " |
| 583 | " val %010p, toc %010p, sz %4d %s\n", |
| 584 | old_size, |
| 585 | (void*) prev->key.addr, |
| 586 | (void*) prev->tocptr, |
| 587 | (Int) prev->size, |
| 588 | (HChar*)prev->key.name |
| 589 | ); |
| 590 | } |
| 591 | if (modify_tocptr && VG_(clo_trace_symtab)) { |
| 592 | VG_(printf)(" modify (upd tocptr) " |
| 593 | " val %010p, toc %010p, sz %4d %s\n", |
| 594 | (void*) prev->key.addr, |
| 595 | (void*) prev->tocptr, |
| 596 | (Int) prev->size, |
| 597 | (HChar*)prev->key.name |
| 598 | ); |
| 599 | } |
| 600 | |
| 601 | } else { |
| 602 | |
| 603 | /* A new (name,addr) key. Add and continue. */ |
| 604 | elem = VG_(OSet_AllocNode)(oset, sizeof(TempSym)); |
| 605 | vg_assert(elem); |
| 606 | elem->key = key; |
| 607 | elem->tocptr = sym_tocptr; |
| 608 | elem->size = sym_size; |
| 609 | elem->from_opd = from_opd; |
| 610 | VG_(OSet_Insert)(oset, elem); |
| 611 | if (VG_(clo_trace_symtab)) { |
| 612 | VG_(printf)(" to-oset [%4d]: " |
| 613 | " val %010p, toc %010p, sz %4d %s\n", |
| 614 | i, (void*) elem->key.addr, |
| 615 | (void*) elem->tocptr, |
| 616 | (Int) elem->size, |
| 617 | (HChar*)elem->key.name |
| 618 | ); |
| 619 | } |
| 620 | |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | /* All the syms that matter are in the oset. Now pull them out, |
| 626 | build a "standard" symbol table, and nuke the oset. */ |
| 627 | |
| 628 | i = 0; |
| 629 | VG_(OSet_ResetIter)( oset ); |
| 630 | |
| 631 | while ( (elem = VG_(OSet_Next)(oset)) ) { |
| 632 | risym.addr = elem->key.addr; |
| 633 | risym.size = elem->size; |
| 634 | risym.name = ML_(addStr) ( si, elem->key.name, -1 ); |
| 635 | risym.tocptr = elem->tocptr; |
| 636 | vg_assert(risym.name != NULL); |
| 637 | |
| 638 | ML_(addSym) ( si, &risym ); |
| 639 | if (VG_(clo_trace_symtab)) { |
| 640 | VG_(printf)(" record [%4d]: " |
| 641 | " val %010p, toc %010p, sz %4d %s\n", |
| 642 | i, (void*) risym.addr, |
| 643 | (void*) risym.tocptr, |
| 644 | (Int) risym.size, |
| 645 | (HChar*)risym.name |
| 646 | ); |
| 647 | } |
| 648 | i++; |
| 649 | } |
| 650 | |
| 651 | VG_(OSet_Destroy)( oset, NULL ); |
| 652 | } |
| 653 | |
| 654 | |
| 655 | /* |
| 656 | * This routine for calculating the CRC for a separate debug file |
| 657 | * is GPLed code borrowed from GNU binutils. |
| 658 | */ |
| 659 | static UInt |
| 660 | calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len) |
| 661 | { |
| 662 | static const UInt crc32_table[256] = |
| 663 | { |
| 664 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, |
| 665 | 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, |
| 666 | 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, |
| 667 | 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, |
| 668 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, |
| 669 | 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, |
| 670 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, |
| 671 | 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, |
| 672 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, |
| 673 | 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, |
| 674 | 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, |
| 675 | 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
| 676 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, |
| 677 | 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, |
| 678 | 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, |
| 679 | 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, |
| 680 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, |
| 681 | 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, |
| 682 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, |
| 683 | 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, |
| 684 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, |
| 685 | 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, |
| 686 | 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, |
| 687 | 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
| 688 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, |
| 689 | 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, |
| 690 | 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, |
| 691 | 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, |
| 692 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, |
| 693 | 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, |
| 694 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, |
| 695 | 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, |
| 696 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, |
| 697 | 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, |
| 698 | 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, |
| 699 | 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
| 700 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, |
| 701 | 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, |
| 702 | 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, |
| 703 | 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, |
| 704 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, |
| 705 | 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, |
| 706 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, |
| 707 | 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, |
| 708 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, |
| 709 | 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, |
| 710 | 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, |
| 711 | 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
| 712 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, |
| 713 | 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, |
| 714 | 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, |
| 715 | 0x2d02ef8d |
| 716 | }; |
| 717 | const UChar *end; |
| 718 | |
| 719 | crc = ~crc & 0xffffffff; |
| 720 | for (end = buf + len; buf < end; ++ buf) |
| 721 | crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); |
| 722 | return ~crc & 0xffffffff;; |
| 723 | } |
| 724 | |
| 725 | /* |
| 726 | * Try and open a separate debug file, ignoring any where the CRC does |
| 727 | * not match the value from the main object file. |
| 728 | */ |
| 729 | static |
| 730 | Addr open_debug_file( Char* name, UInt crc, UInt* size ) |
| 731 | { |
| 732 | SysRes fd, sres; |
| 733 | struct vki_stat stat_buf; |
| 734 | UInt calccrc; |
| 735 | |
| 736 | fd = VG_(open)(name, VKI_O_RDONLY, 0); |
| 737 | if (fd.isError) |
| 738 | return 0; |
| 739 | |
| 740 | if (VG_(fstat)(fd.val, &stat_buf) != 0) { |
| 741 | VG_(close)(fd.val); |
| 742 | return 0; |
| 743 | } |
| 744 | |
| 745 | if (VG_(clo_verbosity) > 1) |
| 746 | VG_(message)(Vg_DebugMsg, "Reading debug info from %s...", name); |
| 747 | |
| 748 | *size = stat_buf.st_size; |
| 749 | |
| 750 | sres = VG_(am_mmap_file_float_valgrind) |
| 751 | ( *size, VKI_PROT_READ, fd.val, 0 ); |
| 752 | |
| 753 | VG_(close)(fd.val); |
| 754 | |
| 755 | if (sres.isError) |
| 756 | return 0; |
| 757 | |
| 758 | calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sres.val, *size); |
| 759 | if (calccrc != crc) { |
| 760 | SysRes res = VG_(am_munmap_valgrind)(sres.val, *size); |
| 761 | vg_assert(!res.isError); |
| 762 | if (VG_(clo_verbosity) > 1) |
| 763 | VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc); |
| 764 | return 0; |
| 765 | } |
| 766 | |
| 767 | return sres.val; |
| 768 | } |
| 769 | |
| 770 | /* |
| 771 | * Try to find a separate debug file for a given object file. |
| 772 | */ |
| 773 | static |
| 774 | Addr find_debug_file( Char* objpath, Char* debugname, UInt crc, UInt* size ) |
| 775 | { |
| 776 | Char *objdir = VG_(arena_strdup)(VG_AR_SYMTAB, objpath); |
| 777 | Char *objdirptr; |
| 778 | Char *debugpath; |
| 779 | Addr addr = 0; |
| 780 | |
| 781 | if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL) |
| 782 | *objdirptr = '\0'; |
| 783 | |
| 784 | debugpath = VG_(arena_malloc)(VG_AR_SYMTAB, VG_(strlen)(objdir) + VG_(strlen)(debugname) + 16); |
| 785 | |
| 786 | VG_(sprintf)(debugpath, "%s/%s", objdir, debugname); |
| 787 | |
| 788 | if ((addr = open_debug_file(debugpath, crc, size)) == 0) { |
| 789 | VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname); |
| 790 | if ((addr = open_debug_file(debugpath, crc, size)) == 0) { |
| 791 | VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname); |
| 792 | addr = open_debug_file(debugpath, crc, size); |
| 793 | } |
| 794 | } |
| 795 | |
| 796 | VG_(arena_free)(VG_AR_SYMTAB, debugpath); |
| 797 | VG_(arena_free)(VG_AR_SYMTAB, objdir); |
| 798 | |
| 799 | return addr; |
| 800 | } |
| 801 | |
| 802 | |
| 803 | /* The central function for reading ELF debug info. For the |
| 804 | object/exe specified by the SegInfo, find ELF sections, then read |
| 805 | the symbols, line number info, file name info, CFA (stack-unwind |
| 806 | info) and anything else we want, into the tables within the |
| 807 | supplied SegInfo. |
| 808 | */ |
| 809 | Bool ML_(read_elf_debug_info) ( struct _SegInfo* si ) |
| 810 | { |
| 811 | Bool res; |
| 812 | ElfXX_Ehdr* ehdr; /* The ELF header */ |
| 813 | ElfXX_Shdr* shdr; /* The section table */ |
| 814 | UChar* sh_strtab; /* The section table's string table */ |
| 815 | SysRes fd, sres; |
| 816 | Int i; |
| 817 | Bool ok; |
| 818 | Addr oimage; |
| 819 | UInt n_oimage; |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 820 | OffT offset_oimage = 0; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 821 | Addr dimage = 0; |
| 822 | UInt n_dimage = 0; |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 823 | OffT offset_dimage = 0; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 824 | |
| 825 | oimage = (Addr)NULL; |
| 826 | if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir)) |
| 827 | VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", |
| 828 | si->filename, si->start ); |
| 829 | |
| 830 | /* mmap the object image aboard, so that we can read symbols and |
| 831 | line number info out of it. It will be munmapped immediately |
| 832 | thereafter; it is only aboard transiently. */ |
| 833 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 834 | fd = VG_(open)(si->filename, VKI_O_RDONLY, 0); |
| 835 | if (fd.isError) { |
| 836 | ML_(symerr)("Can't open .so/.exe to read symbols?!"); |
| 837 | return False; |
| 838 | } |
| 839 | |
tom | 574b893 | 2006-07-05 17:47:46 +0000 | [diff] [blame^] | 840 | n_oimage = VG_(fsize)(fd.val); |
| 841 | if (n_oimage < 0) { |
| 842 | ML_(symerr)("Can't stat .so/.exe (to determine its size)?!"); |
| 843 | VG_(close)(fd.val); |
| 844 | return False; |
| 845 | } |
| 846 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 847 | sres = VG_(am_mmap_file_float_valgrind) |
| 848 | ( n_oimage, VKI_PROT_READ, fd.val, 0 ); |
| 849 | |
| 850 | VG_(close)(fd.val); |
| 851 | |
| 852 | if (sres.isError) { |
| 853 | VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename ); |
| 854 | VG_(message)(Vg_UserMsg, " no symbols or debug info loaded" ); |
| 855 | return False; |
| 856 | } |
| 857 | |
| 858 | oimage = sres.val; |
| 859 | |
| 860 | /* Ok, the object image is safely in oimage[0 .. n_oimage-1]. |
| 861 | Now verify that it is a valid ELF .so or executable image. |
| 862 | */ |
| 863 | res = False; |
| 864 | ok = (n_oimage >= sizeof(ElfXX_Ehdr)); |
| 865 | ehdr = (ElfXX_Ehdr*)oimage; |
| 866 | |
| 867 | if (ok) |
| 868 | ok &= ML_(is_elf_object_file)(ehdr); |
| 869 | |
| 870 | if (!ok) { |
| 871 | ML_(symerr)("Invalid ELF header, or missing stringtab/sectiontab."); |
| 872 | goto out; |
| 873 | } |
| 874 | |
| 875 | /* Walk the LOAD headers in the phdr and update the SegInfo to |
| 876 | include them all, so that this segment also contains data and |
| 877 | bss memory. Also computes correct symbol offset value for this |
| 878 | ELF file. */ |
| 879 | if (ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) > n_oimage) { |
| 880 | ML_(symerr)("ELF program header is beyond image end?!"); |
| 881 | goto out; |
| 882 | } |
| 883 | { |
| 884 | Bool offset_set = False; |
| 885 | ElfXX_Addr prev_addr = 0; |
| 886 | Addr baseaddr = 0; |
| 887 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 888 | vg_assert(si->soname == NULL); |
| 889 | |
| 890 | for (i = 0; i < ehdr->e_phnum; i++) { |
| 891 | ElfXX_Phdr *o_phdr; |
| 892 | ElfXX_Addr mapped, mapped_end; |
| 893 | |
| 894 | o_phdr = &((ElfXX_Phdr *)(oimage + ehdr->e_phoff))[i]; |
| 895 | |
| 896 | /* Try to get the soname. If there isn't one, use "NONE". |
| 897 | The seginfo needs to have some kind of soname in order to |
| 898 | facilitate writing redirect functions, since all redirect |
| 899 | specifications require a soname (pattern). */ |
| 900 | if (o_phdr->p_type == PT_DYNAMIC && si->soname == NULL) { |
| 901 | const ElfXX_Dyn *dyn = (const ElfXX_Dyn *)(oimage + o_phdr->p_offset); |
| 902 | Int stroff = -1; |
| 903 | Char *strtab = NULL; |
| 904 | Int j; |
| 905 | |
| 906 | for(j = 0; dyn[j].d_tag != DT_NULL; j++) { |
| 907 | switch(dyn[j].d_tag) { |
| 908 | case DT_SONAME: |
| 909 | stroff = dyn[j].d_un.d_val; |
| 910 | break; |
| 911 | |
| 912 | case DT_STRTAB: |
| 913 | strtab = (Char *)oimage + dyn[j].d_un.d_ptr - baseaddr; |
| 914 | break; |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | if (stroff != -1 && strtab != 0) { |
| 919 | TRACE_SYMTAB("soname=%s\n", strtab+stroff); |
| 920 | si->soname = VG_(arena_strdup)(VG_AR_SYMTAB, strtab+stroff); |
| 921 | } |
| 922 | } |
| 923 | |
| 924 | if (o_phdr->p_type != PT_LOAD) |
| 925 | continue; |
| 926 | |
| 927 | if (!offset_set) { |
| 928 | offset_set = True; |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 929 | offset_oimage = si->start - o_phdr->p_vaddr; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 930 | baseaddr = o_phdr->p_vaddr; |
| 931 | } |
| 932 | |
| 933 | // Make sure the Phdrs are in order |
| 934 | if (o_phdr->p_vaddr < prev_addr) { |
| 935 | ML_(symerr)("ELF Phdrs are out of order!?"); |
| 936 | goto out; |
| 937 | } |
| 938 | prev_addr = o_phdr->p_vaddr; |
| 939 | |
| 940 | // Get the data and bss start/size if appropriate |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 941 | mapped = o_phdr->p_vaddr + offset_oimage; |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 942 | mapped_end = mapped + o_phdr->p_memsz; |
| 943 | if (si->data_start_vma == 0 && |
| 944 | (o_phdr->p_flags & (PF_R|PF_W|PF_X)) == (PF_R|PF_W)) { |
| 945 | si->data_start_vma = mapped; |
| 946 | si->data_size = o_phdr->p_filesz; |
| 947 | si->bss_start_vma = mapped + o_phdr->p_filesz; |
| 948 | if (o_phdr->p_memsz > o_phdr->p_filesz) |
| 949 | si->bss_size = o_phdr->p_memsz - o_phdr->p_filesz; |
| 950 | else |
| 951 | si->bss_size = 0; |
| 952 | } |
| 953 | |
| 954 | mapped = mapped & ~(VKI_PAGE_SIZE-1); |
| 955 | mapped_end = (mapped_end + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE-1); |
| 956 | |
| 957 | if (VG_(needs).data_syms && |
| 958 | (mapped >= si->start && mapped <= (si->start+si->size)) && |
| 959 | (mapped_end > (si->start+si->size))) { |
| 960 | UInt newsz = mapped_end - si->start; |
| 961 | if (newsz > si->size) { |
| 962 | if (0) |
| 963 | VG_(printf)("extending mapping %p..%p %d -> ..%p %d\n", |
| 964 | si->start, si->start+si->size, si->size, |
| 965 | si->start+newsz, newsz); |
| 966 | |
| 967 | si->size = newsz; |
| 968 | } |
| 969 | } |
| 970 | } |
| 971 | } |
| 972 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 973 | si->offset = offset_oimage; |
| 974 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 975 | /* If, after looking at all the program headers, we still didn't |
| 976 | find a soname, add a fake one. */ |
| 977 | if (si->soname == NULL) { |
| 978 | TRACE_SYMTAB("soname(fake)=\"NONE\"\n"); |
| 979 | si->soname = "NONE"; |
| 980 | } |
| 981 | |
| 982 | TRACE_SYMTAB("shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n", |
| 983 | ehdr->e_shoff, ehdr->e_shnum, sizeof(ElfXX_Shdr), n_oimage ); |
| 984 | |
| 985 | if (ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) > n_oimage) { |
| 986 | ML_(symerr)("ELF section header is beyond image end?!"); |
| 987 | goto out; |
| 988 | } |
| 989 | |
| 990 | shdr = (ElfXX_Shdr*)(oimage + ehdr->e_shoff); |
| 991 | sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset); |
| 992 | |
| 993 | /* Find interesting sections, read the symbol table(s), read any debug |
| 994 | information */ |
| 995 | { |
| 996 | /* Pointers to start of sections (in the oimage, not in the |
| 997 | running image) */ |
| 998 | UChar* o_strtab = NULL; /* .strtab */ |
| 999 | ElfXX_Sym* o_symtab = NULL; /* .symtab */ |
| 1000 | UChar* o_dynstr = NULL; /* .dynstr */ |
| 1001 | ElfXX_Sym* o_dynsym = NULL; /* .dynsym */ |
| 1002 | Char* debuglink = NULL; /* .gnu_debuglink */ |
| 1003 | UChar* stab = NULL; /* .stab (stabs) */ |
| 1004 | UChar* stabstr = NULL; /* .stabstr (stabs) */ |
| 1005 | UChar* debug_line = NULL; /* .debug_line (dwarf2) */ |
| 1006 | UChar* debug_info = NULL; /* .debug_info (dwarf2) */ |
| 1007 | UChar* debug_abbv = NULL; /* .debug_abbrev (dwarf2) */ |
| 1008 | UChar* debug_str = NULL; /* .debug_str (dwarf2) */ |
| 1009 | UChar* dwarf1d = NULL; /* .debug (dwarf1) */ |
| 1010 | UChar* dwarf1l = NULL; /* .line (dwarf1) */ |
| 1011 | UChar* ehframe = NULL; /* .eh_frame (dwarf2) */ |
| 1012 | UChar* opd_filea = NULL; /* .opd (dwarf2, ppc64-linux) */ |
| 1013 | UChar* dummy_filea = NULL; |
| 1014 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1015 | OffT o_symtab_offset = offset_oimage; |
| 1016 | OffT o_dynsym_offset = offset_oimage; |
| 1017 | OffT debug_offset = offset_oimage; |
| 1018 | OffT opd_offset = offset_oimage; |
| 1019 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1020 | /* Section sizes, in bytes */ |
| 1021 | UInt o_strtab_sz = 0; |
| 1022 | UInt o_symtab_sz = 0; |
| 1023 | UInt o_dynstr_sz = 0; |
| 1024 | UInt o_dynsym_sz = 0; |
| 1025 | UInt debuglink_sz = 0; |
| 1026 | UInt stab_sz = 0; |
| 1027 | UInt stabstr_sz = 0; |
| 1028 | UInt debug_line_sz = 0; |
| 1029 | UInt debug_info_sz = 0; |
| 1030 | UInt debug_abbv_sz = 0; |
| 1031 | UInt debug_str_sz = 0; |
| 1032 | UInt dwarf1d_sz = 0; |
| 1033 | UInt dwarf1l_sz = 0; |
| 1034 | UInt ehframe_sz = 0; |
| 1035 | |
| 1036 | /* Section virtual addresses */ |
| 1037 | Addr dummy_vma = 0; |
| 1038 | Addr ehframe_vma = 0; |
| 1039 | |
| 1040 | /* Find all interesting sections */ |
| 1041 | |
| 1042 | /* What FIND does: it finds the section called SEC_NAME. The |
| 1043 | size of it is assigned to SEC_SIZE. The address that it will |
| 1044 | appear in the running image is assigned to SEC_VMA (note, |
| 1045 | this will be meaningless for sections which are not marked |
| 1046 | loadable. Even for sections which are marked loadable, the |
| 1047 | client's ld.so may not have loaded them yet, so there is no |
| 1048 | guarantee that we can safely prod around in any such area) |
| 1049 | The address of the section in the transiently loaded oimage |
| 1050 | is assigned to SEC_FILEA. Because the entire object file is |
| 1051 | transiently mapped aboard for inspection, it's always safe to |
| 1052 | inspect that area. */ |
| 1053 | |
| 1054 | for (i = 0; i < ehdr->e_shnum; i++) { |
| 1055 | |
| 1056 | # define FIND(sec_name, sec_size, sec_filea, sec_vma) \ |
| 1057 | if (0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \ |
| 1058 | Bool nobits; \ |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1059 | sec_vma = (Addr)(offset_oimage + shdr[i].sh_addr); \ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1060 | sec_filea = (void*)(oimage + shdr[i].sh_offset); \ |
| 1061 | sec_size = shdr[i].sh_size; \ |
| 1062 | nobits = shdr[i].sh_type == SHT_NOBITS; \ |
| 1063 | TRACE_SYMTAB( "%18s: filea %p .. %p, vma %p .. %p\n", \ |
| 1064 | sec_name, (UChar*)sec_filea, \ |
| 1065 | ((UChar*)sec_filea) + sec_size - 1, \ |
| 1066 | sec_vma, sec_vma + sec_size - 1); \ |
| 1067 | /* SHT_NOBITS sections have zero size in the file. */ \ |
| 1068 | if ( shdr[i].sh_offset + (nobits ? 0 : sec_size) > n_oimage ) { \ |
| 1069 | ML_(symerr)(" section beyond image end?!"); \ |
| 1070 | goto out; \ |
| 1071 | } \ |
| 1072 | } |
| 1073 | |
| 1074 | /* Nb: must find where .got and .plt sections will be in the |
| 1075 | * executable image, not in the object image transiently loaded. */ |
| 1076 | /* NAME SIZE ADDR_IN_OIMAGE ADDR_WHEN_MAPPED */ |
| 1077 | FIND(".dynsym", o_dynsym_sz, o_dynsym, dummy_vma) |
| 1078 | FIND(".dynstr", o_dynstr_sz, o_dynstr, dummy_vma) |
| 1079 | FIND(".symtab", o_symtab_sz, o_symtab, dummy_vma) |
| 1080 | FIND(".strtab", o_strtab_sz, o_strtab, dummy_vma) |
| 1081 | |
| 1082 | FIND(".gnu_debuglink", debuglink_sz, debuglink, dummy_vma) |
| 1083 | |
| 1084 | FIND(".stab", stab_sz, stab, dummy_vma) |
| 1085 | FIND(".stabstr", stabstr_sz, stabstr, dummy_vma) |
| 1086 | |
| 1087 | FIND(".debug_line", debug_line_sz, debug_line, dummy_vma) |
| 1088 | FIND(".debug_info", debug_info_sz, debug_info, dummy_vma) |
| 1089 | FIND(".debug_abbrev", debug_abbv_sz, debug_abbv, dummy_vma) |
| 1090 | FIND(".debug_str", debug_str_sz, debug_str, dummy_vma) |
| 1091 | |
| 1092 | FIND(".debug", dwarf1d_sz, dwarf1d, dummy_vma) |
| 1093 | FIND(".line", dwarf1l_sz, dwarf1l, dummy_vma) |
| 1094 | FIND(".eh_frame", ehframe_sz, ehframe, ehframe_vma) |
| 1095 | |
| 1096 | FIND(".got", si->got_size, dummy_filea, si->got_start_vma) |
| 1097 | FIND(".plt", si->plt_size, dummy_filea, si->plt_start_vma) |
| 1098 | FIND(".opd", si->opd_size, opd_filea, si->opd_start_vma) |
| 1099 | |
| 1100 | # undef FIND |
| 1101 | } |
| 1102 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1103 | /* Did we find a debuglink section? */ |
| 1104 | if (debuglink != NULL) { |
| 1105 | UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink)+1, 4); |
| 1106 | UInt crc; |
| 1107 | |
| 1108 | vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz); |
| 1109 | |
| 1110 | /* Extract the CRC from the debuglink section */ |
| 1111 | crc = *(UInt *)(debuglink + crc_offset); |
| 1112 | |
| 1113 | /* See if we can find a matching debug file */ |
| 1114 | if ((dimage = find_debug_file(si->filename, debuglink, crc, &n_dimage)) != 0) { |
| 1115 | ehdr = (ElfXX_Ehdr*)dimage; |
| 1116 | |
| 1117 | if (n_dimage >= sizeof(ElfXX_Ehdr) |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1118 | && ML_(is_elf_object_file(ehdr)) |
| 1119 | && ehdr->e_phoff + ehdr->e_phnum*sizeof(ElfXX_Phdr) <= n_dimage |
| 1120 | && ehdr->e_shoff + ehdr->e_shnum*sizeof(ElfXX_Shdr) <= n_dimage) |
| 1121 | { |
| 1122 | Bool need_symtab = (NULL == o_symtab); |
| 1123 | |
| 1124 | for (i = 0; i < ehdr->e_phnum; i++) { |
| 1125 | ElfXX_Phdr *o_phdr = &((ElfXX_Phdr *)(dimage + ehdr->e_phoff))[i]; |
| 1126 | if (o_phdr->p_type == PT_LOAD) { |
| 1127 | offset_dimage = si->start - o_phdr->p_vaddr; |
| 1128 | break; |
| 1129 | } |
| 1130 | } |
| 1131 | |
| 1132 | debug_offset = offset_dimage; |
| 1133 | if (need_symtab) |
| 1134 | o_symtab_offset = offset_dimage; |
| 1135 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1136 | shdr = (ElfXX_Shdr*)(dimage + ehdr->e_shoff); |
| 1137 | sh_strtab = (UChar*)(dimage + shdr[ehdr->e_shstrndx].sh_offset); |
| 1138 | |
| 1139 | /* Same deal as previous FIND, except simpler - doesn't |
| 1140 | look for vma, only oimage address. */ |
| 1141 | |
| 1142 | /* Find all interesting sections */ |
| 1143 | for (i = 0; i < ehdr->e_shnum; i++) { |
| 1144 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1145 | # define FIND(condition, sec_name, sec_size, sec_filea) \ |
| 1146 | if (condition \ |
| 1147 | && 0 == VG_(strcmp)(sec_name, sh_strtab + shdr[i].sh_name)) { \ |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1148 | Bool nobits; \ |
| 1149 | if (0 != sec_filea) \ |
| 1150 | VG_(core_panic)("repeated section!\n"); \ |
| 1151 | sec_filea = (void*)(dimage + shdr[i].sh_offset); \ |
| 1152 | sec_size = shdr[i].sh_size; \ |
| 1153 | nobits = shdr[i].sh_type == SHT_NOBITS; \ |
| 1154 | TRACE_SYMTAB( "%18s: filea %p .. %p\n", \ |
| 1155 | sec_name, (UChar*)sec_filea, \ |
| 1156 | ((UChar*)sec_filea) + sec_size - 1); \ |
| 1157 | /* SHT_NOBITS sections have zero size in the file. */ \ |
| 1158 | if ( shdr[i].sh_offset + (nobits ? 0 : sec_size) > n_dimage ) { \ |
| 1159 | ML_(symerr)(" section beyond image end?!"); \ |
| 1160 | goto out; \ |
| 1161 | } \ |
| 1162 | } |
| 1163 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1164 | FIND(need_symtab, ".symtab", o_symtab_sz, o_symtab) |
| 1165 | FIND(need_symtab, ".strtab", o_strtab_sz, o_strtab) |
| 1166 | FIND(1, ".stab", stab_sz, stab) |
| 1167 | FIND(1, ".stabstr", stabstr_sz, stabstr) |
| 1168 | FIND(1, ".debug_line", debug_line_sz, debug_line) |
| 1169 | FIND(1, ".debug_info", debug_info_sz, debug_info) |
| 1170 | FIND(1, ".debug_abbrev", debug_abbv_sz, debug_abbv) |
| 1171 | FIND(1, ".debug_str", debug_str_sz, debug_str) |
| 1172 | FIND(1, ".debug", dwarf1d_sz, dwarf1d) |
| 1173 | FIND(1, ".line", dwarf1l_sz, dwarf1l) |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1174 | |
| 1175 | # undef FIND |
| 1176 | } |
| 1177 | } |
| 1178 | } |
| 1179 | } |
| 1180 | |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1181 | /* Check some sizes */ |
| 1182 | vg_assert((o_dynsym_sz % sizeof(ElfXX_Sym)) == 0); |
| 1183 | vg_assert((o_symtab_sz % sizeof(ElfXX_Sym)) == 0); |
| 1184 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1185 | /* Read symbols */ |
| 1186 | { |
sewardj | 72c84c9 | 2006-04-06 13:31:17 +0000 | [diff] [blame] | 1187 | void (*read_elf_symtab)(struct _SegInfo*,UChar*,ElfXX_Sym*, |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1188 | UInt,OffT,UChar*,UInt,UChar*,OffT); |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1189 | # if defined(VGP_ppc64_linux) |
| 1190 | read_elf_symtab = read_elf_symtab__ppc64_linux; |
| 1191 | # else |
| 1192 | read_elf_symtab = read_elf_symtab__normal; |
| 1193 | # endif |
| 1194 | read_elf_symtab(si, "symbol table", |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1195 | o_symtab, o_symtab_sz, o_symtab_offset, |
| 1196 | o_strtab, o_strtab_sz, opd_filea, opd_offset); |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1197 | |
| 1198 | read_elf_symtab(si, "dynamic symbol table", |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1199 | o_dynsym, o_dynsym_sz, o_dynsym_offset, |
| 1200 | o_dynstr, o_dynstr_sz, opd_filea, opd_offset); |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1201 | } |
| 1202 | |
| 1203 | /* Read .eh_frame (call-frame-info) if any */ |
| 1204 | if (ehframe) { |
| 1205 | ML_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_vma ); |
| 1206 | } |
| 1207 | |
| 1208 | /* Read the stabs and/or dwarf2 debug information, if any. It |
| 1209 | appears reading stabs stuff on amd64-linux doesn't work, so |
| 1210 | we ignore it. */ |
| 1211 | # if !defined(VGP_amd64_linux) |
| 1212 | if (stab && stabstr) { |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1213 | ML_(read_debuginfo_stabs) ( si, debug_offset, stab, stab_sz, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1214 | stabstr, stabstr_sz ); |
| 1215 | } |
| 1216 | # endif |
| 1217 | /* jrs 2006-01-01: icc-8.1 has been observed to generate |
| 1218 | binaries without debug_str sections. Don't preclude |
| 1219 | debuginfo reading for that reason, but, in |
| 1220 | read_unitinfo_dwarf2, do check that debugstr is non-NULL |
| 1221 | before using it. */ |
| 1222 | if (debug_info && debug_abbv && debug_line /* && debug_str */) { |
sewardj | 534e201 | 2006-04-12 10:08:05 +0000 | [diff] [blame] | 1223 | ML_(read_debuginfo_dwarf2) ( si, debug_offset, |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 1224 | debug_info, debug_info_sz, |
| 1225 | debug_abbv, |
| 1226 | debug_line, debug_line_sz, |
| 1227 | debug_str ); |
| 1228 | } |
| 1229 | if (dwarf1d && dwarf1l) { |
| 1230 | ML_(read_debuginfo_dwarf1) ( si, dwarf1d, dwarf1d_sz, |
| 1231 | dwarf1l, dwarf1l_sz ); |
| 1232 | } |
| 1233 | } |
| 1234 | res = True; |
| 1235 | |
| 1236 | out: { |
| 1237 | SysRes m_res; |
| 1238 | /* Last, but not least, heave the image(s) back overboard. */ |
| 1239 | if (dimage) { |
| 1240 | m_res = VG_(am_munmap_valgrind) ( dimage, n_dimage ); |
| 1241 | vg_assert(!m_res.isError); |
| 1242 | } |
| 1243 | m_res = VG_(am_munmap_valgrind) ( oimage, n_oimage ); |
| 1244 | vg_assert(!m_res.isError); |
| 1245 | return res; |
| 1246 | } |
| 1247 | } |
| 1248 | |
| 1249 | |
| 1250 | /*--------------------------------------------------------------------*/ |
| 1251 | /*--- end ---*/ |
| 1252 | /*--------------------------------------------------------------------*/ |