Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [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 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 11 | Copyright (C) 2000-2012 Julian Seward |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 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 | #if defined(VGO_linux) |
| 33 | |
| 34 | #include "pub_core_basics.h" |
| 35 | #include "pub_core_vki.h" |
| 36 | #include "pub_core_debuginfo.h" |
| 37 | #include "pub_core_libcbase.h" |
| 38 | #include "pub_core_libcprint.h" |
| 39 | #include "pub_core_libcassert.h" |
| 40 | #include "pub_core_libcfile.h" |
| 41 | #include "pub_core_aspacemgr.h" /* for mmaping debuginfo files */ |
| 42 | #include "pub_core_machine.h" /* VG_ELF_CLASS */ |
| 43 | #include "pub_core_options.h" |
| 44 | #include "pub_core_oset.h" |
| 45 | #include "pub_core_tooliface.h" /* VG_(needs) */ |
| 46 | #include "pub_core_xarray.h" |
| 47 | #include "priv_misc.h" /* dinfo_zalloc/free/strdup */ |
| 48 | #include "priv_d3basics.h" |
| 49 | #include "priv_tytypes.h" |
| 50 | #include "priv_storage.h" |
| 51 | #include "priv_readelf.h" /* self */ |
| 52 | #include "priv_readdwarf.h" /* 'cos ELF contains DWARF */ |
| 53 | #include "priv_readdwarf3.h" |
| 54 | #include "priv_readstabs.h" /* and stabs, if we're unlucky */ |
| 55 | |
| 56 | /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ |
| 57 | #include <elf.h> |
| 58 | /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ |
| 59 | |
| 60 | /*------------------------------------------------------------*/ |
| 61 | /*--- 32/64-bit parameterisation ---*/ |
| 62 | /*------------------------------------------------------------*/ |
| 63 | |
| 64 | /* For all the ELF macros and types which specify '32' or '64', |
| 65 | select the correct variant for this platform and give it |
| 66 | an 'XX' name. Then use the 'XX' variant consistently in |
| 67 | the rest of this file. |
| 68 | */ |
| 69 | #if VG_WORDSIZE == 4 |
| 70 | # define ElfXX_Ehdr Elf32_Ehdr |
| 71 | # define ElfXX_Shdr Elf32_Shdr |
| 72 | # define ElfXX_Phdr Elf32_Phdr |
| 73 | # define ElfXX_Nhdr Elf32_Nhdr |
| 74 | # define ElfXX_Sym Elf32_Sym |
| 75 | # define ElfXX_Off Elf32_Off |
| 76 | # define ElfXX_Word Elf32_Word |
| 77 | # define ElfXX_Addr Elf32_Addr |
| 78 | # define ElfXX_Dyn Elf32_Dyn |
| 79 | # define ELFXX_ST_BIND ELF32_ST_BIND |
| 80 | # define ELFXX_ST_TYPE ELF32_ST_TYPE |
| 81 | |
| 82 | #elif VG_WORDSIZE == 8 |
| 83 | # define ElfXX_Ehdr Elf64_Ehdr |
| 84 | # define ElfXX_Shdr Elf64_Shdr |
| 85 | # define ElfXX_Phdr Elf64_Phdr |
| 86 | # define ElfXX_Nhdr Elf64_Nhdr |
| 87 | # define ElfXX_Sym Elf64_Sym |
| 88 | # define ElfXX_Off Elf64_Off |
| 89 | # define ElfXX_Word Elf64_Word |
| 90 | # define ElfXX_Addr Elf64_Addr |
| 91 | # define ElfXX_Dyn Elf64_Dyn |
| 92 | # define ELFXX_ST_BIND ELF64_ST_BIND |
| 93 | # define ELFXX_ST_TYPE ELF64_ST_TYPE |
| 94 | |
| 95 | #else |
| 96 | # error "VG_WORDSIZE should be 4 or 8" |
| 97 | #endif |
| 98 | |
| 99 | |
| 100 | /*------------------------------------------------------------*/ |
| 101 | /*--- ---*/ |
| 102 | /*--- Read symbol table and line info from ELF files. ---*/ |
| 103 | /*--- ---*/ |
| 104 | /*------------------------------------------------------------*/ |
| 105 | |
| 106 | /* readelf.c parses ELF files and acquires symbol table info from |
| 107 | them. It calls onwards to readdwarf.c to read DWARF2/3 line number |
| 108 | and call frame info found. */ |
| 109 | |
| 110 | |
| 111 | /* Identify an ELF object file by peering at the first few bytes of |
| 112 | it. */ |
| 113 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 114 | Bool ML_(is_elf_object_file)( void* image, SizeT n_image, Bool rel_ok ) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 115 | { |
| 116 | ElfXX_Ehdr* ehdr = (ElfXX_Ehdr*)image; |
| 117 | Int ok = 1; |
| 118 | |
| 119 | if (n_image < sizeof(ElfXX_Ehdr)) |
| 120 | return False; |
| 121 | |
| 122 | ok &= (ehdr->e_ident[EI_MAG0] == 0x7F |
| 123 | && ehdr->e_ident[EI_MAG1] == 'E' |
| 124 | && ehdr->e_ident[EI_MAG2] == 'L' |
| 125 | && ehdr->e_ident[EI_MAG3] == 'F'); |
| 126 | ok &= (ehdr->e_ident[EI_CLASS] == VG_ELF_CLASS |
| 127 | && ehdr->e_ident[EI_DATA] == VG_ELF_DATA2XXX |
| 128 | && ehdr->e_ident[EI_VERSION] == EV_CURRENT); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 129 | ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN |
| 130 | || (rel_ok && ehdr->e_type == ET_REL)); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 131 | ok &= (ehdr->e_machine == VG_ELF_MACHINE); |
| 132 | ok &= (ehdr->e_version == EV_CURRENT); |
| 133 | ok &= (ehdr->e_shstrndx != SHN_UNDEF); |
| 134 | ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 135 | ok &= ((ehdr->e_phoff != 0 && ehdr->e_phnum != 0) |
| 136 | || ehdr->e_type == ET_REL); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 137 | |
| 138 | if (ok) |
| 139 | return True; |
| 140 | else |
| 141 | return False; |
| 142 | } |
| 143 | |
| 144 | |
| 145 | /* Show a raw ELF symbol, given its in-image address and name. */ |
| 146 | |
| 147 | static |
| 148 | void show_raw_elf_symbol ( Int i, |
| 149 | ElfXX_Sym* sym, Char* sym_name, Addr sym_svma, |
| 150 | Bool ppc64_linux_format ) |
| 151 | { |
| 152 | HChar* space = ppc64_linux_format ? " " : ""; |
| 153 | VG_(printf)("raw symbol [%4d]: ", i); |
| 154 | switch (ELFXX_ST_BIND(sym->st_info)) { |
| 155 | case STB_LOCAL: VG_(printf)("LOC "); break; |
| 156 | case STB_GLOBAL: VG_(printf)("GLO "); break; |
| 157 | case STB_WEAK: VG_(printf)("WEA "); break; |
| 158 | case STB_LOPROC: VG_(printf)("lop "); break; |
| 159 | case STB_HIPROC: VG_(printf)("hip "); break; |
| 160 | default: VG_(printf)("??? "); break; |
| 161 | } |
| 162 | switch (ELFXX_ST_TYPE(sym->st_info)) { |
| 163 | case STT_NOTYPE: VG_(printf)("NOT "); break; |
| 164 | case STT_OBJECT: VG_(printf)("OBJ "); break; |
| 165 | case STT_FUNC: VG_(printf)("FUN "); break; |
| 166 | case STT_SECTION: VG_(printf)("SEC "); break; |
| 167 | case STT_FILE: VG_(printf)("FIL "); break; |
| 168 | case STT_LOPROC: VG_(printf)("lop "); break; |
| 169 | case STT_HIPROC: VG_(printf)("hip "); break; |
| 170 | default: VG_(printf)("??? "); break; |
| 171 | } |
| 172 | VG_(printf)(": svma %#010lx, %ssz %4ld %s\n", |
| 173 | sym_svma, space, sym->st_size + 0UL, |
| 174 | ( sym->st_name ? sym_name : (Char*)"NONAME" ) ); |
| 175 | } |
| 176 | |
| 177 | |
| 178 | /* Decide whether SYM is something we should collect, and if so, copy |
| 179 | relevant info to the _OUT arguments. For {x86,amd64,ppc32}-linux |
| 180 | this is straightforward - the name, address, size are copied out |
| 181 | unchanged. |
| 182 | |
| 183 | There is a bit of a kludge re data symbols (see KLUDGED BSS CHECK |
| 184 | below): we assume that the .bss is mapped immediately after .data, |
| 185 | and so accept any data symbol which exists in the range [start of |
| 186 | .data, size of .data + size of .bss). I don't know if this is |
| 187 | really correct/justifiable, or not. |
| 188 | |
| 189 | For ppc64-linux it's more complex. If the symbol is seen to be in |
| 190 | the .opd section, it is taken to be a function descriptor, and so |
| 191 | a dereference is attempted, in order to get hold of the real entry |
| 192 | point address. Also as part of the dereference, there is an attempt |
| 193 | to calculate the TOC pointer (R2 value) associated with the symbol. |
| 194 | |
| 195 | To support the ppc64-linux pre-"dotless" ABI (prior to gcc 4.0.0), |
| 196 | if the symbol is seen to be outside the .opd section and its name |
| 197 | starts with a dot, an .opd deference is not attempted, and no TOC |
| 198 | pointer is calculated, but the the leading dot is removed from the |
| 199 | name. |
| 200 | |
| 201 | As a result, on ppc64-linux, the caller of this function may have |
| 202 | to piece together the real size, address, name of the symbol from |
| 203 | multiple calls to this function. Ugly and confusing. |
| 204 | */ |
| 205 | static |
| 206 | Bool get_elf_symbol_info ( |
| 207 | /* INPUTS */ |
| 208 | struct _DebugInfo* di, /* containing DebugInfo */ |
| 209 | ElfXX_Sym* sym, /* ELF symbol */ |
| 210 | Char* sym_name, /* name */ |
| 211 | Addr sym_svma, /* address as stated in the object file */ |
| 212 | Bool symtab_in_debug, /* symbol table is in the debug file */ |
| 213 | UChar* opd_img, /* oimage of .opd sec (ppc64-linux only) */ |
| 214 | PtrdiffT opd_bias, /* for biasing AVMAs found in .opd */ |
| 215 | /* OUTPUTS */ |
| 216 | Char** sym_name_out, /* name we should record */ |
| 217 | Addr* sym_avma_out, /* addr we should record */ |
| 218 | Int* sym_size_out, /* symbol size */ |
| 219 | Addr* sym_tocptr_out, /* ppc64-linux only: R2 value to be |
| 220 | used on entry */ |
| 221 | Bool* from_opd_out, /* ppc64-linux only: did we deref an |
| 222 | .opd entry? */ |
| 223 | Bool* is_text_out, /* is this a text symbol? */ |
| 224 | Bool* is_ifunc /* is this a STT_GNU_IFUNC function ?*/ |
| 225 | ) |
| 226 | { |
| 227 | Bool plausible; |
| 228 | # if defined(VGP_ppc64_linux) |
| 229 | Bool is_in_opd; |
| 230 | # endif |
| 231 | Bool in_text, in_data, in_sdata, in_rodata, in_bss, in_sbss; |
| 232 | Addr text_svma, data_svma, sdata_svma, rodata_svma, bss_svma, sbss_svma; |
| 233 | PtrdiffT text_bias, data_bias, sdata_bias, rodata_bias, bss_bias, sbss_bias; |
| 234 | |
| 235 | /* Set defaults */ |
| 236 | *sym_name_out = sym_name; |
| 237 | *sym_avma_out = sym_svma; /* we will bias this shortly */ |
| 238 | *is_text_out = True; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 239 | *sym_tocptr_out = 0; /* unknown/inapplicable */ |
| 240 | *from_opd_out = False; |
| 241 | *is_ifunc = False; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 242 | /* Get the symbol size, but restrict it to fit in a signed 32 bit |
| 243 | int. Also, deal with the stupid case of negative size by making |
| 244 | the size be 1. Note that sym->st_size has type UWord, |
| 245 | effectively. */ |
| 246 | { Word size_tmp = (Word)sym->st_size; |
| 247 | Word max_Int = (1LL << 31) - 1; |
| 248 | if (size_tmp < 0) size_tmp = 1; |
| 249 | if (size_tmp > max_Int) size_tmp = max_Int; |
| 250 | *sym_size_out = (Int)size_tmp; |
| 251 | } |
| 252 | /* After this point refer only to *sym_size_out and not to |
| 253 | sym->st_size. */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 254 | |
| 255 | /* Figure out if we're interested in the symbol. Firstly, is it of |
| 256 | the right flavour? */ |
| 257 | plausible |
| 258 | = (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL |
| 259 | || ELFXX_ST_BIND(sym->st_info) == STB_LOCAL |
| 260 | || ELFXX_ST_BIND(sym->st_info) == STB_WEAK |
| 261 | ) |
| 262 | && |
| 263 | (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC |
| 264 | || ELFXX_ST_TYPE(sym->st_info) == STT_OBJECT |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 265 | # ifdef STT_GNU_IFUNC |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 266 | || ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 267 | # endif |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 268 | ); |
| 269 | |
| 270 | /* Work out the svma and bias for each section as it will appear in |
| 271 | addresses in the symbol table. */ |
| 272 | if (symtab_in_debug) { |
| 273 | text_svma = di->text_debug_svma; |
| 274 | text_bias = di->text_debug_bias; |
| 275 | data_svma = di->data_debug_svma; |
| 276 | data_bias = di->data_debug_bias; |
| 277 | sdata_svma = di->sdata_debug_svma; |
| 278 | sdata_bias = di->sdata_debug_bias; |
| 279 | rodata_svma = di->rodata_debug_svma; |
| 280 | rodata_bias = di->rodata_debug_bias; |
| 281 | bss_svma = di->bss_debug_svma; |
| 282 | bss_bias = di->bss_debug_bias; |
| 283 | sbss_svma = di->sbss_debug_svma; |
| 284 | sbss_bias = di->sbss_debug_bias; |
| 285 | } else { |
| 286 | text_svma = di->text_svma; |
| 287 | text_bias = di->text_bias; |
| 288 | data_svma = di->data_svma; |
| 289 | data_bias = di->data_bias; |
| 290 | sdata_svma = di->sdata_svma; |
| 291 | sdata_bias = di->sdata_bias; |
| 292 | rodata_svma = di->rodata_svma; |
| 293 | rodata_bias = di->rodata_bias; |
| 294 | bss_svma = di->bss_svma; |
| 295 | bss_bias = di->bss_bias; |
| 296 | sbss_svma = di->sbss_svma; |
| 297 | sbss_bias = di->sbss_bias; |
| 298 | } |
| 299 | |
| 300 | /* Now bias sym_avma_out accordingly by figuring out exactly which |
| 301 | section the symbol is from and bias accordingly. Screws up if |
| 302 | the previously deduced section svma address ranges are wrong. */ |
| 303 | if (di->text_present |
| 304 | && di->text_size > 0 |
| 305 | && sym_svma >= text_svma |
| 306 | && sym_svma < text_svma + di->text_size) { |
| 307 | *is_text_out = True; |
| 308 | *sym_avma_out += text_bias; |
| 309 | } else |
| 310 | if (di->data_present |
| 311 | && di->data_size > 0 |
| 312 | && sym_svma >= data_svma |
| 313 | && sym_svma < data_svma + di->data_size) { |
| 314 | *is_text_out = False; |
| 315 | *sym_avma_out += data_bias; |
| 316 | } else |
| 317 | if (di->sdata_present |
| 318 | && di->sdata_size > 0 |
| 319 | && sym_svma >= sdata_svma |
| 320 | && sym_svma < sdata_svma + di->sdata_size) { |
| 321 | *is_text_out = False; |
| 322 | *sym_avma_out += sdata_bias; |
| 323 | } else |
| 324 | if (di->rodata_present |
| 325 | && di->rodata_size > 0 |
| 326 | && sym_svma >= rodata_svma |
| 327 | && sym_svma < rodata_svma + di->rodata_size) { |
| 328 | *is_text_out = False; |
| 329 | *sym_avma_out += rodata_bias; |
| 330 | } else |
| 331 | if (di->bss_present |
| 332 | && di->bss_size > 0 |
| 333 | && sym_svma >= bss_svma |
| 334 | && sym_svma < bss_svma + di->bss_size) { |
| 335 | *is_text_out = False; |
| 336 | *sym_avma_out += bss_bias; |
| 337 | } else |
| 338 | if (di->sbss_present |
| 339 | && di->sbss_size > 0 |
| 340 | && sym_svma >= sbss_svma |
| 341 | && sym_svma < sbss_svma + di->sbss_size) { |
| 342 | *is_text_out = False; |
| 343 | *sym_avma_out += sbss_bias; |
| 344 | } else { |
| 345 | /* Assume it's in .text. Is this a good idea? */ |
| 346 | *is_text_out = True; |
| 347 | *sym_avma_out += text_bias; |
| 348 | } |
| 349 | |
| 350 | # ifdef STT_GNU_IFUNC |
| 351 | /* Check for indirect functions. */ |
| 352 | if (*is_text_out |
| 353 | && ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) { |
| 354 | *is_ifunc = True; |
| 355 | } |
| 356 | # endif |
| 357 | |
| 358 | # if defined(VGP_ppc64_linux) |
| 359 | /* Allow STT_NOTYPE in the very special case where we're running on |
| 360 | ppc64-linux and the symbol is one which the .opd-chasing hack |
| 361 | below will chase. */ |
| 362 | if (!plausible |
| 363 | && *is_text_out |
| 364 | && ELFXX_ST_TYPE(sym->st_info) == STT_NOTYPE |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 365 | && *sym_size_out > 0 |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 366 | && di->opd_present |
| 367 | && di->opd_size > 0 |
| 368 | && *sym_avma_out >= di->opd_avma |
| 369 | && *sym_avma_out < di->opd_avma + di->opd_size) |
| 370 | plausible = True; |
| 371 | # endif |
| 372 | |
| 373 | if (!plausible) |
| 374 | return False; |
| 375 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 376 | /* Ignore if nameless. */ |
| 377 | if (sym_name == (ElfXX_Word)0 |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 378 | || /* VG_(strlen)(sym_name) == 0 */ |
| 379 | /* equivalent but cheaper ... */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 380 | sym_name[0] == 0) { |
| 381 | TRACE_SYMTAB(" ignore -- nameless: %s\n", sym_name); |
| 382 | return False; |
| 383 | } |
| 384 | |
| 385 | /* Ignore if zero-sized. Except on Android: |
| 386 | |
| 387 | On Android 2.3.5, some of the symbols that Memcheck needs to |
| 388 | intercept (for noise reduction purposes) have zero size, due to |
| 389 | lack of .size directives in handwritten assembly sources. So we |
| 390 | can't reject them out of hand -- instead give them a bogusly |
| 391 | large size and let canonicaliseSymtab trim them so they don't |
| 392 | overlap any following symbols. At least the following symbols |
| 393 | are known to be affected: |
| 394 | |
| 395 | in /system/lib/libc.so: strlen strcmp strcpy memcmp memcpy |
| 396 | in /system/bin/linker: __dl_strcmp __dl_strlen |
| 397 | */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 398 | if (*sym_size_out == 0) { |
| 399 | # if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) |
| 400 | *sym_size_out = 2048; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 401 | # else |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 402 | TRACE_SYMTAB(" ignore -- size=0: %s\n", sym_name); |
| 403 | return False; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 404 | # endif |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 405 | } |
| 406 | |
| 407 | /* This seems to significantly reduce the number of junk |
| 408 | symbols, and particularly reduces the number of |
| 409 | overlapping address ranges. Don't ask me why ... */ |
| 410 | if ((Int)sym->st_value == 0) { |
| 411 | TRACE_SYMTAB( " ignore -- valu=0: %s\n", sym_name); |
| 412 | return False; |
| 413 | } |
| 414 | |
| 415 | /* If it's apparently in a GOT or PLT, it's really a reference to a |
| 416 | symbol defined elsewhere, so ignore it. */ |
| 417 | if (di->got_present |
| 418 | && di->got_size > 0 |
| 419 | && *sym_avma_out >= di->got_avma |
| 420 | && *sym_avma_out < di->got_avma + di->got_size) { |
| 421 | TRACE_SYMTAB(" ignore -- in GOT: %s\n", sym_name); |
| 422 | return False; |
| 423 | } |
| 424 | if (di->plt_present |
| 425 | && di->plt_size > 0 |
| 426 | && *sym_avma_out >= di->plt_avma |
| 427 | && *sym_avma_out < di->plt_avma + di->plt_size) { |
| 428 | TRACE_SYMTAB(" ignore -- in PLT: %s\n", sym_name); |
| 429 | return False; |
| 430 | } |
| 431 | |
| 432 | /* ppc64-linux nasty hack: if the symbol is in an .opd section, |
| 433 | then really what we have is the address of a function |
| 434 | descriptor. So use the first word of that as the function's |
| 435 | text. |
| 436 | |
| 437 | See thread starting at |
| 438 | http://gcc.gnu.org/ml/gcc-patches/2004-08/msg00557.html |
| 439 | */ |
| 440 | # if defined(VGP_ppc64_linux) |
| 441 | is_in_opd = False; |
| 442 | # endif |
| 443 | |
| 444 | if (di->opd_present |
| 445 | && di->opd_size > 0 |
| 446 | && *sym_avma_out >= di->opd_avma |
| 447 | && *sym_avma_out < di->opd_avma + di->opd_size) { |
| 448 | # if !defined(VGP_ppc64_linux) |
| 449 | TRACE_SYMTAB(" ignore -- in OPD: %s\n", sym_name); |
| 450 | return False; |
| 451 | # else |
| 452 | Int offset_in_opd; |
| 453 | ULong* fn_descr; |
| 454 | Bool details = 1||False; |
| 455 | |
| 456 | if (details) |
| 457 | TRACE_SYMTAB("opdXXX: opd_bias %p, sym_svma_out %p\n", |
| 458 | (void*)(opd_bias), (void*)*sym_avma_out); |
| 459 | |
| 460 | if (!VG_IS_8_ALIGNED(*sym_avma_out)) { |
| 461 | TRACE_SYMTAB(" ignore -- not 8-aligned: %s\n", sym_name); |
| 462 | return False; |
| 463 | } |
| 464 | |
| 465 | /* *sym_avma_out is a vma pointing into the .opd section. We |
| 466 | know the vma of the opd section start, so we can figure out |
| 467 | how far into the opd section this is. */ |
| 468 | |
| 469 | offset_in_opd = (Addr)(*sym_avma_out) - (Addr)(di->opd_avma); |
| 470 | if (offset_in_opd < 0 || offset_in_opd >= di->opd_size) { |
| 471 | TRACE_SYMTAB(" ignore -- invalid OPD offset: %s\n", sym_name); |
| 472 | return False; |
| 473 | } |
| 474 | |
| 475 | /* Now we want to know what's at that offset in the .opd |
| 476 | section. We can't look in the running image since it won't |
| 477 | necessarily have been mapped. But we can consult the oimage. |
| 478 | opd_img is the start address of the .opd in the oimage. |
| 479 | Hence: */ |
| 480 | |
| 481 | fn_descr = (ULong*)(opd_img + offset_in_opd); |
| 482 | |
| 483 | if (details) |
| 484 | TRACE_SYMTAB("opdXXY: offset %d, fn_descr %p\n", |
| 485 | offset_in_opd, fn_descr); |
| 486 | if (details) |
| 487 | TRACE_SYMTAB("opdXXZ: *fn_descr %p\n", (void*)(fn_descr[0])); |
| 488 | |
| 489 | /* opd_bias is the what we have to add to SVMAs found in .opd to |
| 490 | get plausible .text AVMAs for the entry point, and .data |
| 491 | AVMAs (presumably) for the TOC locations. We use the caller |
| 492 | supplied value (which is di->text_bias) for both of these. |
| 493 | Not sure why that is correct - it seems to work, and sounds |
| 494 | OK for fn_descr[0], but surely we need to use the data bias |
| 495 | and not the text bias for fn_descr[1] ? Oh Well. |
| 496 | */ |
| 497 | *sym_avma_out = fn_descr[0] + opd_bias; |
| 498 | *sym_tocptr_out = fn_descr[1] + opd_bias; |
| 499 | *from_opd_out = True; |
| 500 | is_in_opd = True; |
| 501 | |
| 502 | /* Do a final sanity check: if the symbol falls outside the |
| 503 | DebugInfo's mapped range, ignore it. Since *sym_avma_out has |
| 504 | been updated, that can be achieved simply by falling through |
| 505 | to the test below. */ |
| 506 | |
| 507 | # endif /* ppc64-linux nasty hack */ |
| 508 | } |
| 509 | |
| 510 | /* Here's yet another ppc64-linux hack. Get rid of leading dot if |
| 511 | the symbol is outside .opd. */ |
| 512 | # if defined(VGP_ppc64_linux) |
| 513 | if (di->opd_size > 0 |
| 514 | && !is_in_opd |
| 515 | && sym_name[0] == '.') { |
| 516 | vg_assert(!(*from_opd_out)); |
| 517 | *sym_name_out = &sym_name[1]; |
| 518 | } |
| 519 | # endif |
| 520 | |
| 521 | /* If no part of the symbol falls within the mapped range, |
| 522 | ignore it. */ |
| 523 | |
| 524 | in_text |
| 525 | = di->text_present |
| 526 | && di->text_size > 0 |
| 527 | && !(*sym_avma_out + *sym_size_out <= di->text_avma |
| 528 | || *sym_avma_out >= di->text_avma + di->text_size); |
| 529 | |
| 530 | in_data |
| 531 | = di->data_present |
| 532 | && di->data_size > 0 |
| 533 | && !(*sym_avma_out + *sym_size_out <= di->data_avma |
| 534 | || *sym_avma_out >= di->data_avma + di->data_size); |
| 535 | |
| 536 | in_sdata |
| 537 | = di->sdata_present |
| 538 | && di->sdata_size > 0 |
| 539 | && !(*sym_avma_out + *sym_size_out <= di->sdata_avma |
| 540 | || *sym_avma_out >= di->sdata_avma + di->sdata_size); |
| 541 | |
| 542 | in_rodata |
| 543 | = di->rodata_present |
| 544 | && di->rodata_size > 0 |
| 545 | && !(*sym_avma_out + *sym_size_out <= di->rodata_avma |
| 546 | || *sym_avma_out >= di->rodata_avma + di->rodata_size); |
| 547 | |
| 548 | in_bss |
| 549 | = di->bss_present |
| 550 | && di->bss_size > 0 |
| 551 | && !(*sym_avma_out + *sym_size_out <= di->bss_avma |
| 552 | || *sym_avma_out >= di->bss_avma + di->bss_size); |
| 553 | |
| 554 | in_sbss |
| 555 | = di->sbss_present |
| 556 | && di->sbss_size > 0 |
| 557 | && !(*sym_avma_out + *sym_size_out <= di->sbss_avma |
| 558 | || *sym_avma_out >= di->sbss_avma + di->sbss_size); |
| 559 | |
| 560 | |
| 561 | if (*is_text_out) { |
| 562 | /* This used to reject any symbol falling outside the text |
| 563 | segment ("if (!in_text) ..."). Now it is relaxed slightly, |
| 564 | to reject only symbols which fall outside the area mapped |
| 565 | r-x. This is in accordance with r7427. See |
| 566 | "Comment_Regarding_Text_Range_Checks" in storage.c for |
| 567 | background. */ |
| 568 | Bool in_rx; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 569 | vg_assert(di->fsm.have_rx_map); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 570 | /* This could actually wrap around and cause |
| 571 | ML_(find_rx_mapping) to assert. But that seems so unlikely, |
| 572 | let's wait for it to happen before fixing it. */ |
| 573 | in_rx = (ML_(find_rx_mapping)(di, *sym_avma_out, |
| 574 | *sym_avma_out + *sym_size_out) != NULL); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 575 | if (in_text) |
| 576 | vg_assert(in_rx); |
| 577 | if (!in_rx) { |
| 578 | TRACE_SYMTAB( |
| 579 | "ignore -- %#lx .. %#lx outside .text svma range %#lx .. %#lx\n", |
| 580 | *sym_avma_out, *sym_avma_out + *sym_size_out, |
| 581 | di->text_avma, |
| 582 | di->text_avma + di->text_size); |
| 583 | return False; |
| 584 | } |
| 585 | } else { |
| 586 | if (!(in_data || in_sdata || in_rodata || in_bss || in_sbss)) { |
| 587 | TRACE_SYMTAB( |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 588 | "ignore -- %#lx .. %#lx outside .data / .sdata / .rodata " |
| 589 | "/ .bss / .sbss svma ranges\n", |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 590 | *sym_avma_out, *sym_avma_out + *sym_size_out); |
| 591 | return False; |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | # if defined(VGP_ppc64_linux) |
| 596 | /* It's crucial that we never add symbol addresses in the .opd |
| 597 | section. This would completely mess up function redirection and |
| 598 | intercepting. This assert ensures that anysymbols that make it |
| 599 | into the symbol table on ppc64-linux don't point into .opd. */ |
| 600 | if (di->opd_present && di->opd_size > 0) { |
| 601 | vg_assert(*sym_avma_out + *sym_size_out <= di->opd_avma |
| 602 | || *sym_avma_out >= di->opd_avma + di->opd_size); |
| 603 | } |
| 604 | # endif |
| 605 | |
| 606 | /* Acquire! */ |
| 607 | return True; |
| 608 | } |
| 609 | |
| 610 | |
| 611 | /* Read an ELF symbol table (normal or dynamic). This one is for the |
| 612 | "normal" case ({x86,amd64,ppc32}-linux). */ |
| 613 | static |
| 614 | __attribute__((unused)) /* not referred to on all targets */ |
| 615 | void read_elf_symtab__normal( |
| 616 | struct _DebugInfo* di, UChar* tab_name, |
| 617 | ElfXX_Sym* symtab_img, SizeT symtab_szB, |
| 618 | UChar* strtab_img, SizeT strtab_szB, |
| 619 | Bool symtab_in_debug, |
| 620 | UChar* opd_img /* ppc64-linux only */ |
| 621 | ) |
| 622 | { |
| 623 | Word i; |
| 624 | Addr sym_svma, sym_avma_really; |
| 625 | Char *sym_name, *sym_name_really; |
| 626 | Int sym_size; |
| 627 | Addr sym_tocptr; |
| 628 | Bool from_opd, is_text, is_ifunc; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 629 | DiSym disym; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 630 | ElfXX_Sym *sym; |
| 631 | |
| 632 | if (strtab_img == NULL || symtab_img == NULL) { |
| 633 | Char buf[80]; |
| 634 | vg_assert(VG_(strlen)(tab_name) < 40); |
| 635 | VG_(sprintf)(buf, " object doesn't have a %s", tab_name); |
| 636 | ML_(symerr)(di, False, buf); |
| 637 | return; |
| 638 | } |
| 639 | |
| 640 | TRACE_SYMTAB("\n--- Reading (ELF, standard) %s (%ld entries) ---\n", |
| 641 | tab_name, symtab_szB/sizeof(ElfXX_Sym) ); |
| 642 | |
| 643 | /* Perhaps should start at i = 1; ELF docs suggest that entry |
| 644 | 0 always denotes 'unknown symbol'. */ |
| 645 | for (i = 1; i < (Word)(symtab_szB/sizeof(ElfXX_Sym)); i++) { |
| 646 | sym = & symtab_img[i]; |
| 647 | sym_name = (UChar*)(strtab_img + sym->st_name); |
| 648 | sym_svma = sym->st_value; |
| 649 | |
| 650 | if (di->trace_symtab) |
| 651 | show_raw_elf_symbol(i, sym, sym_name, sym_svma, False); |
| 652 | |
| 653 | if (get_elf_symbol_info(di, sym, sym_name, sym_svma, |
| 654 | symtab_in_debug, |
| 655 | opd_img, di->text_bias, |
| 656 | &sym_name_really, |
| 657 | &sym_avma_really, |
| 658 | &sym_size, |
| 659 | &sym_tocptr, |
| 660 | &from_opd, &is_text, &is_ifunc)) { |
| 661 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 662 | disym.addr = sym_avma_really; |
| 663 | disym.tocptr = sym_tocptr; |
| 664 | disym.pri_name = ML_(addStr) ( di, sym_name_really, -1 ); |
| 665 | disym.sec_names = NULL; |
| 666 | disym.size = sym_size; |
| 667 | disym.isText = is_text; |
| 668 | disym.isIFunc = is_ifunc; |
| 669 | vg_assert(disym.pri_name); |
| 670 | vg_assert(disym.tocptr == 0); /* has no role except on ppc64-linux */ |
| 671 | ML_(addSym) ( di, &disym ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 672 | |
| 673 | if (di->trace_symtab) { |
| 674 | VG_(printf)(" rec(%c) [%4ld]: " |
| 675 | " val %#010lx, sz %4d %s\n", |
| 676 | is_text ? 't' : 'd', |
| 677 | i, |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 678 | disym.addr, |
| 679 | (Int)disym.size, |
| 680 | (HChar*)disym.pri_name |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 681 | ); |
| 682 | } |
| 683 | |
| 684 | } |
| 685 | } |
| 686 | } |
| 687 | |
| 688 | |
| 689 | /* Read an ELF symbol table (normal or dynamic). This one is for |
| 690 | ppc64-linux, which requires special treatment. */ |
| 691 | |
| 692 | typedef |
| 693 | struct { |
| 694 | Addr addr; |
| 695 | UChar* name; |
| 696 | } |
| 697 | TempSymKey; |
| 698 | |
| 699 | typedef |
| 700 | struct { |
| 701 | TempSymKey key; |
| 702 | Addr tocptr; |
| 703 | Int size; |
| 704 | Bool from_opd; |
| 705 | Bool is_text; |
| 706 | Bool is_ifunc; |
| 707 | } |
| 708 | TempSym; |
| 709 | |
| 710 | static Word cmp_TempSymKey ( TempSymKey* key1, TempSym* elem2 ) { |
| 711 | if (key1->addr < elem2->key.addr) return -1; |
| 712 | if (key1->addr > elem2->key.addr) return 1; |
| 713 | return (Word)VG_(strcmp)(key1->name, elem2->key.name); |
| 714 | } |
| 715 | |
| 716 | static |
| 717 | __attribute__((unused)) /* not referred to on all targets */ |
| 718 | void read_elf_symtab__ppc64_linux( |
| 719 | struct _DebugInfo* di, UChar* tab_name, |
| 720 | ElfXX_Sym* symtab_img, SizeT symtab_szB, |
| 721 | UChar* strtab_img, SizeT strtab_szB, |
| 722 | Bool symtab_in_debug, |
| 723 | UChar* opd_img /* ppc64-linux only */ |
| 724 | ) |
| 725 | { |
| 726 | Word i; |
| 727 | Int old_size; |
| 728 | Addr sym_svma, sym_avma_really; |
| 729 | Char *sym_name, *sym_name_really; |
| 730 | Int sym_size; |
| 731 | Addr sym_tocptr; |
| 732 | Bool from_opd, modify_size, modify_tocptr, is_text, is_ifunc; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 733 | DiSym disym; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 734 | ElfXX_Sym *sym; |
| 735 | OSet *oset; |
| 736 | TempSymKey key; |
| 737 | TempSym *elem; |
| 738 | TempSym *prev; |
| 739 | |
| 740 | if (strtab_img == NULL || symtab_img == NULL) { |
| 741 | Char buf[80]; |
| 742 | vg_assert(VG_(strlen)(tab_name) < 40); |
| 743 | VG_(sprintf)(buf, " object doesn't have a %s", tab_name); |
| 744 | ML_(symerr)(di, False, buf); |
| 745 | return; |
| 746 | } |
| 747 | |
| 748 | TRACE_SYMTAB("\n--- Reading (ELF, ppc64-linux) %s (%ld entries) ---\n", |
| 749 | tab_name, symtab_szB/sizeof(ElfXX_Sym) ); |
| 750 | |
| 751 | oset = VG_(OSetGen_Create)( offsetof(TempSym,key), |
| 752 | (OSetCmp_t)cmp_TempSymKey, |
| 753 | ML_(dinfo_zalloc), "di.respl.1", |
| 754 | ML_(dinfo_free) ); |
| 755 | vg_assert(oset); |
| 756 | |
| 757 | /* Perhaps should start at i = 1; ELF docs suggest that entry |
| 758 | 0 always denotes 'unknown symbol'. */ |
| 759 | for (i = 1; i < (Word)(symtab_szB/sizeof(ElfXX_Sym)); i++) { |
| 760 | sym = & symtab_img[i]; |
| 761 | sym_name = (Char*)(strtab_img + sym->st_name); |
| 762 | sym_svma = sym->st_value; |
| 763 | |
| 764 | if (di->trace_symtab) |
| 765 | show_raw_elf_symbol(i, sym, sym_name, sym_svma, True); |
| 766 | |
| 767 | if (get_elf_symbol_info(di, sym, sym_name, sym_svma, |
| 768 | symtab_in_debug, |
| 769 | opd_img, di->text_bias, |
| 770 | &sym_name_really, |
| 771 | &sym_avma_really, |
| 772 | &sym_size, |
| 773 | &sym_tocptr, |
| 774 | &from_opd, &is_text, &is_ifunc)) { |
| 775 | |
| 776 | /* Check if we've seen this (name,addr) key before. */ |
| 777 | key.addr = sym_avma_really; |
| 778 | key.name = sym_name_really; |
| 779 | prev = VG_(OSetGen_Lookup)( oset, &key ); |
| 780 | |
| 781 | if (prev) { |
| 782 | |
| 783 | /* Seen it before. Fold in whatever new info we can. */ |
| 784 | modify_size = False; |
| 785 | modify_tocptr = False; |
| 786 | old_size = 0; |
| 787 | |
| 788 | if (prev->from_opd && !from_opd |
| 789 | && (prev->size == 24 || prev->size == 16) |
| 790 | && sym_size != prev->size) { |
| 791 | /* Existing one is an opd-redirect, with a bogus size, |
| 792 | so the only useful new fact we have is the real size |
| 793 | of the symbol. */ |
| 794 | modify_size = True; |
| 795 | old_size = prev->size; |
| 796 | prev->size = sym_size; |
| 797 | } |
| 798 | else |
| 799 | if (!prev->from_opd && from_opd |
| 800 | && (sym_size == 24 || sym_size == 16)) { |
| 801 | /* Existing one is non-opd, new one is opd. What we |
| 802 | can acquire from the new one is the TOC ptr to be |
| 803 | used. Since the existing sym is non-toc, it |
| 804 | shouldn't currently have an known TOC ptr. */ |
| 805 | vg_assert(prev->tocptr == 0); |
| 806 | modify_tocptr = True; |
| 807 | prev->tocptr = sym_tocptr; |
| 808 | } |
| 809 | else { |
| 810 | /* ignore. can we do better here? */ |
| 811 | } |
| 812 | |
| 813 | /* Only one or the other is possible (I think) */ |
| 814 | vg_assert(!(modify_size && modify_tocptr)); |
| 815 | |
| 816 | if (modify_size && di->trace_symtab) { |
| 817 | VG_(printf)(" modify (old sz %4d) " |
| 818 | " val %#010lx, toc %#010lx, sz %4d %s\n", |
| 819 | old_size, |
| 820 | prev->key.addr, |
| 821 | prev->tocptr, |
| 822 | (Int) prev->size, |
| 823 | (HChar*)prev->key.name |
| 824 | ); |
| 825 | } |
| 826 | if (modify_tocptr && di->trace_symtab) { |
| 827 | VG_(printf)(" modify (upd tocptr) " |
| 828 | " val %#010lx, toc %#010lx, sz %4d %s\n", |
| 829 | prev->key.addr, |
| 830 | prev->tocptr, |
| 831 | (Int) prev->size, |
| 832 | (HChar*)prev->key.name |
| 833 | ); |
| 834 | } |
| 835 | |
| 836 | } else { |
| 837 | |
| 838 | /* A new (name,addr) key. Add and continue. */ |
| 839 | elem = VG_(OSetGen_AllocNode)(oset, sizeof(TempSym)); |
| 840 | vg_assert(elem); |
| 841 | elem->key = key; |
| 842 | elem->tocptr = sym_tocptr; |
| 843 | elem->size = sym_size; |
| 844 | elem->from_opd = from_opd; |
| 845 | elem->is_text = is_text; |
| 846 | elem->is_ifunc = is_ifunc; |
| 847 | VG_(OSetGen_Insert)(oset, elem); |
| 848 | if (di->trace_symtab) { |
| 849 | VG_(printf)(" to-oset [%4ld]: " |
| 850 | " val %#010lx, toc %#010lx, sz %4d %s\n", |
| 851 | i, |
| 852 | elem->key.addr, |
| 853 | elem->tocptr, |
| 854 | (Int) elem->size, |
| 855 | (HChar*)elem->key.name |
| 856 | ); |
| 857 | } |
| 858 | |
| 859 | } |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | /* All the syms that matter are in the oset. Now pull them out, |
| 864 | build a "standard" symbol table, and nuke the oset. */ |
| 865 | |
| 866 | i = 0; |
| 867 | VG_(OSetGen_ResetIter)( oset ); |
| 868 | |
| 869 | while ( (elem = VG_(OSetGen_Next)(oset)) ) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 870 | disym.addr = elem->key.addr; |
| 871 | disym.tocptr = elem->tocptr; |
| 872 | disym.pri_name = ML_(addStr) ( di, elem->key.name, -1 ); |
| 873 | disym.sec_names = NULL; |
| 874 | disym.size = elem->size; |
| 875 | disym.isText = elem->is_text; |
| 876 | disym.isIFunc = elem->is_ifunc; |
| 877 | vg_assert(disym.pri_name != NULL); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 878 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 879 | ML_(addSym) ( di, &disym ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 880 | if (di->trace_symtab) { |
| 881 | VG_(printf)(" rec(%c) [%4ld]: " |
| 882 | " val %#010lx, toc %#010lx, sz %4d %s\n", |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 883 | disym.isText ? 't' : 'd', |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 884 | i, |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 885 | disym.addr, |
| 886 | disym.tocptr, |
| 887 | (Int) disym.size, |
| 888 | (HChar*)disym.pri_name |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 889 | ); |
| 890 | } |
| 891 | i++; |
| 892 | } |
| 893 | |
| 894 | VG_(OSetGen_Destroy)( oset ); |
| 895 | } |
| 896 | |
| 897 | |
| 898 | /* |
| 899 | * Look for a build-id in an ELF image. The build-id specification |
| 900 | * can be found here: |
| 901 | * |
| 902 | * http://fedoraproject.org/wiki/RolandMcGrath/BuildID |
| 903 | */ |
| 904 | static |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 905 | Char *find_buildid(Addr image, UWord n_image, Bool rel_ok) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 906 | { |
| 907 | Char* buildid = NULL; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 908 | __attribute__((unused)) /* on Android, at least */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 909 | ElfXX_Ehdr* ehdr = (ElfXX_Ehdr*)image; |
| 910 | |
| 911 | #ifdef NT_GNU_BUILD_ID |
| 912 | if (n_image >= sizeof(ElfXX_Ehdr) && |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 913 | ML_(is_elf_object_file)(ehdr, n_image, rel_ok)) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 914 | Word i; |
| 915 | |
| 916 | for (i = 0; i < ehdr->e_phnum; i++) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 917 | ElfXX_Phdr* phdr |
| 918 | = (ElfXX_Phdr*)(image + ehdr->e_phoff + i * ehdr->e_phentsize); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 919 | |
| 920 | if (phdr->p_type == PT_NOTE) { |
| 921 | ElfXX_Off offset = phdr->p_offset; |
| 922 | |
| 923 | while (offset < phdr->p_offset + phdr->p_filesz) { |
| 924 | ElfXX_Nhdr* note = (ElfXX_Nhdr*)(image + offset); |
| 925 | Char* name = (Char *)note + sizeof(ElfXX_Nhdr); |
| 926 | UChar *desc = (UChar *)name + ((note->n_namesz + 3) & ~3); |
| 927 | Word j; |
| 928 | |
| 929 | if (VG_(strcmp)(name, ELF_NOTE_GNU) == 0 && |
| 930 | note->n_type == NT_GNU_BUILD_ID) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 931 | buildid = ML_(dinfo_zalloc)("di.fbi.1", |
| 932 | note->n_descsz * 2 + 1); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 933 | |
| 934 | for (j = 0; j < note->n_descsz; j++) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 935 | VG_(sprintf)(buildid + VG_(strlen)(buildid), |
| 936 | "%02x", desc[j]); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 937 | } |
| 938 | } |
| 939 | |
| 940 | offset = offset + sizeof(ElfXX_Nhdr) |
| 941 | + ((note->n_namesz + 3) & ~3) |
| 942 | + ((note->n_descsz + 3) & ~3); |
| 943 | } |
| 944 | } |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 945 | } |
| 946 | |
| 947 | if (buildid || !rel_ok) |
| 948 | return buildid; |
| 949 | |
| 950 | for (i = 0; i < ehdr->e_shnum; i++) { |
| 951 | ElfXX_Shdr* shdr |
| 952 | = (ElfXX_Shdr*)(image + ehdr->e_shoff + i * ehdr->e_shentsize); |
| 953 | |
| 954 | if (shdr->sh_type == SHT_NOTE) { |
| 955 | ElfXX_Off offset = shdr->sh_offset; |
| 956 | |
| 957 | while (offset < shdr->sh_offset + shdr->sh_size) { |
| 958 | ElfXX_Nhdr* note = (ElfXX_Nhdr*)(image + offset); |
| 959 | Char* name = (Char *)note + sizeof(ElfXX_Nhdr); |
| 960 | UChar *desc = (UChar *)name + ((note->n_namesz + 3) & ~3); |
| 961 | Word j; |
| 962 | |
| 963 | if (VG_(strcmp)(name, ELF_NOTE_GNU) == 0 && |
| 964 | note->n_type == NT_GNU_BUILD_ID) { |
| 965 | buildid = ML_(dinfo_zalloc)("di.fbi.1", |
| 966 | note->n_descsz * 2 + 1); |
| 967 | |
| 968 | for (j = 0; j < note->n_descsz; j++) { |
| 969 | VG_(sprintf)(buildid + VG_(strlen)(buildid), |
| 970 | "%02x", desc[j]); |
| 971 | } |
| 972 | } |
| 973 | |
| 974 | offset = offset + sizeof(ElfXX_Nhdr) |
| 975 | + ((note->n_namesz + 3) & ~3) |
| 976 | + ((note->n_descsz + 3) & ~3); |
| 977 | } |
| 978 | } |
| 979 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 980 | } |
| 981 | #endif |
| 982 | |
| 983 | return buildid; |
| 984 | } |
| 985 | |
| 986 | /* |
| 987 | * This routine for calculating the CRC for a separate debug file |
| 988 | * is GPLed code borrowed from GNU binutils. |
| 989 | */ |
| 990 | static UInt |
| 991 | calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len) |
| 992 | { |
| 993 | static const UInt crc32_table[256] = |
| 994 | { |
| 995 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, |
| 996 | 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, |
| 997 | 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, |
| 998 | 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, |
| 999 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, |
| 1000 | 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, |
| 1001 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, |
| 1002 | 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, |
| 1003 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, |
| 1004 | 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, |
| 1005 | 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, |
| 1006 | 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
| 1007 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, |
| 1008 | 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, |
| 1009 | 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, |
| 1010 | 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, |
| 1011 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, |
| 1012 | 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, |
| 1013 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, |
| 1014 | 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, |
| 1015 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, |
| 1016 | 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, |
| 1017 | 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, |
| 1018 | 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
| 1019 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, |
| 1020 | 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, |
| 1021 | 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, |
| 1022 | 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, |
| 1023 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, |
| 1024 | 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, |
| 1025 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, |
| 1026 | 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, |
| 1027 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, |
| 1028 | 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, |
| 1029 | 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, |
| 1030 | 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
| 1031 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, |
| 1032 | 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, |
| 1033 | 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, |
| 1034 | 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, |
| 1035 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, |
| 1036 | 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, |
| 1037 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, |
| 1038 | 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, |
| 1039 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, |
| 1040 | 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, |
| 1041 | 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, |
| 1042 | 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
| 1043 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, |
| 1044 | 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, |
| 1045 | 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, |
| 1046 | 0x2d02ef8d |
| 1047 | }; |
| 1048 | const UChar *end; |
| 1049 | |
| 1050 | crc = ~crc & 0xffffffff; |
| 1051 | for (end = buf + len; buf < end; ++ buf) |
| 1052 | crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); |
| 1053 | return ~crc & 0xffffffff;; |
| 1054 | } |
| 1055 | |
| 1056 | /* |
| 1057 | * Try and open a separate debug file, ignoring any where the CRC does |
| 1058 | * not match the value from the main object file. |
| 1059 | */ |
| 1060 | static |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1061 | Addr open_debug_file( Char* name, Char* buildid, UInt crc, Bool rel_ok, |
| 1062 | /*OUT*/UWord* size ) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1063 | { |
| 1064 | SysRes fd, sres; |
| 1065 | struct vg_stat stat_buf; |
| 1066 | UInt calccrc; |
| 1067 | |
| 1068 | fd = VG_(open)(name, VKI_O_RDONLY, 0); |
| 1069 | if (sr_isError(fd)) |
| 1070 | return 0; |
| 1071 | |
| 1072 | if (VG_(fstat)(sr_Res(fd), &stat_buf) != 0) { |
| 1073 | VG_(close)(sr_Res(fd)); |
| 1074 | return 0; |
| 1075 | } |
| 1076 | |
| 1077 | if (VG_(clo_verbosity) > 1) |
| 1078 | VG_(message)(Vg_DebugMsg, " Considering %s ..\n", name); |
| 1079 | |
| 1080 | *size = stat_buf.size; |
| 1081 | |
| 1082 | sres = VG_(am_mmap_file_float_valgrind) |
| 1083 | ( *size, VKI_PROT_READ, sr_Res(fd), 0 ); |
| 1084 | |
| 1085 | VG_(close)(sr_Res(fd)); |
| 1086 | |
| 1087 | if (sr_isError(sres)) |
| 1088 | return 0; |
| 1089 | |
| 1090 | if (buildid) { |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1091 | Char* debug_buildid = find_buildid(sr_Res(sres), *size, rel_ok); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1092 | if (debug_buildid == NULL || VG_(strcmp)(buildid, debug_buildid) != 0) { |
| 1093 | SysRes res = VG_(am_munmap_valgrind)(sr_Res(sres), *size); |
| 1094 | vg_assert(!sr_isError(res)); |
| 1095 | if (VG_(clo_verbosity) > 1) |
| 1096 | VG_(message)(Vg_DebugMsg, |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1097 | " .. build-id mismatch (found %s wanted %s)\n", |
| 1098 | debug_buildid, buildid); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1099 | ML_(dinfo_free)(debug_buildid); |
| 1100 | return 0; |
| 1101 | } |
| 1102 | ML_(dinfo_free)(debug_buildid); |
| 1103 | |
| 1104 | if (VG_(clo_verbosity) > 1) |
| 1105 | VG_(message)(Vg_DebugMsg, " .. build-id is valid\n"); |
| 1106 | } else { |
| 1107 | calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sr_Res(sres), *size); |
| 1108 | if (calccrc != crc) { |
| 1109 | SysRes res = VG_(am_munmap_valgrind)(sr_Res(sres), *size); |
| 1110 | vg_assert(!sr_isError(res)); |
| 1111 | if (VG_(clo_verbosity) > 1) |
| 1112 | VG_(message)(Vg_DebugMsg, |
| 1113 | " .. CRC mismatch (computed %08x wanted %08x)\n", calccrc, crc); |
| 1114 | return 0; |
| 1115 | } |
| 1116 | |
| 1117 | if (VG_(clo_verbosity) > 1) |
| 1118 | VG_(message)(Vg_DebugMsg, " .. CRC is valid\n"); |
| 1119 | } |
| 1120 | |
| 1121 | return sr_Res(sres); |
| 1122 | } |
| 1123 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1124 | |
| 1125 | /* Try to find and map in a debuginfo file by some totally ad-hoc |
| 1126 | scheme. If successful, set *dimage and *n_dimage to point to the |
| 1127 | image, and return True, else return False. A temporary hack for |
| 1128 | Android; does nothing on any other platform. */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1129 | static |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1130 | Bool find_ad_hoc_debug_image( struct _DebugInfo* di, |
| 1131 | Char* filename, |
| 1132 | /*OUT*/Addr* dimage, |
| 1133 | /*OUT*/SizeT* n_dimage ) |
| 1134 | { |
| 1135 | vg_assert(*dimage == 0 && *n_dimage == 0); |
| 1136 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1137 | # if !defined(VGPV_arm_linux_android) && !defined(VGPV_x86_linux_android) |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1138 | return False; /* we don't know narfink */ |
| 1139 | |
| 1140 | # else /* android specific hacks; look away now. */ |
| 1141 | |
| 1142 | /* The deal is: if we're looking for for a debuginfo file for some |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1143 | object /path/to/object (which can be any path), see if we can |
| 1144 | find the file /sdcard/symbols/path/to/object. So for example it |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1145 | produces the following mappings, both of which are important for |
| 1146 | Memcheck: |
| 1147 | |
| 1148 | /system/bin/linker --> /sdcard/symbols/system/bin/linker |
| 1149 | /system/lib/libc.so --> /sdcard/symbols/system/lib/libc.so |
| 1150 | |
| 1151 | These /symbols files come from the AOSP build tree for your |
| 1152 | device, for example out/target/product/crespo/symbols/system |
| 1153 | (for a Nexus S), so one simple thing you can do is take the tree |
| 1154 | rooted at out/target/product/crespo/symbols/system on the host |
| 1155 | and park it at /sdcard/symbols/system on the device. Then, |
| 1156 | assuming it matches what's actually running on the device, |
| 1157 | you'll have full debuginfo for all the libraries on the device. |
| 1158 | |
| 1159 | But beware: there is no checking that the debuginfo file, if |
| 1160 | found, matches the main file in any way. |
| 1161 | */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1162 | if (!filename || *filename != '/') |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1163 | return False; |
| 1164 | |
| 1165 | HChar* nm = ML_(dinfo_zalloc)("di.fahdi.1", |
| 1166 | 50 + VG_(strlen)(filename)); |
| 1167 | VG_(sprintf)(nm, "/sdcard/symbols%s", filename); |
| 1168 | |
| 1169 | SysRes fd = VG_(open)(nm, VKI_O_RDONLY, 0); |
| 1170 | if (sr_isError(fd)) goto fail; |
| 1171 | |
| 1172 | struct vg_stat stat_buf; |
| 1173 | if (VG_(fstat)(sr_Res(fd), &stat_buf) != 0) { |
| 1174 | VG_(close)(sr_Res(fd)); |
| 1175 | goto fail; |
| 1176 | } |
| 1177 | |
| 1178 | *n_dimage = stat_buf.size; |
| 1179 | |
| 1180 | SysRes sres = VG_(am_mmap_file_float_valgrind) |
| 1181 | ( *n_dimage, VKI_PROT_READ, sr_Res(fd), 0 ); |
| 1182 | |
| 1183 | VG_(close)(sr_Res(fd)); |
| 1184 | if (sr_isError(sres)) |
| 1185 | goto fail; |
| 1186 | |
| 1187 | *dimage = sr_Res(sres); |
| 1188 | |
| 1189 | if (VG_(clo_verbosity) > 1) |
| 1190 | VG_(dmsg)(" Using debuginfo from %s\n", nm); |
| 1191 | |
| 1192 | ML_(dinfo_free)(nm); |
| 1193 | return True; |
| 1194 | |
| 1195 | fail: |
| 1196 | if (nm) ML_(dinfo_free)(nm); |
| 1197 | return False; |
| 1198 | |
| 1199 | # endif |
| 1200 | } |
| 1201 | |
| 1202 | |
| 1203 | /* Try to find a separate debug file for a given object file. If |
| 1204 | found, it will be mapped in and the address and size returned in |
| 1205 | *dimage and *n_dimage. If not, *dimage and *n_dimage will be |
| 1206 | unchanged. The caller should set them to zero before the call. */ |
| 1207 | static |
| 1208 | void find_debug_file( struct _DebugInfo* di, |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1209 | Char* objpath, Char* buildid, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1210 | Char* debugname, UInt crc, Bool rel_ok, |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1211 | /*OUT*/Addr* dimage, |
| 1212 | /*OUT*/SizeT* n_dimage ) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1213 | { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1214 | Char* debugpath = NULL; |
| 1215 | Addr addr = 0; |
| 1216 | UWord size = 0; |
| 1217 | |
| 1218 | vg_assert(*dimage == 0 && *n_dimage == 0); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1219 | |
| 1220 | if (buildid != NULL) { |
| 1221 | debugpath = ML_(dinfo_zalloc)( |
| 1222 | "di.fdf.1", |
| 1223 | VG_(strlen)(buildid) + 33); |
| 1224 | |
| 1225 | VG_(sprintf)(debugpath, "/usr/lib/debug/.build-id/%c%c/%s.debug", |
| 1226 | buildid[0], buildid[1], buildid + 2); |
| 1227 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1228 | if ((addr = open_debug_file(debugpath, buildid, 0, |
| 1229 | rel_ok, &size)) == 0) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1230 | ML_(dinfo_free)(debugpath); |
| 1231 | debugpath = NULL; |
| 1232 | } |
| 1233 | } |
| 1234 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1235 | if (addr == 0 && debugname != NULL && !rel_ok) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1236 | Char *objdir = ML_(dinfo_strdup)("di.fdf.2", objpath); |
| 1237 | Char *objdirptr; |
| 1238 | |
| 1239 | if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL) |
| 1240 | *objdirptr = '\0'; |
| 1241 | |
| 1242 | debugpath = ML_(dinfo_zalloc)( |
| 1243 | "di.fdf.3", |
| 1244 | VG_(strlen)(objdir) + VG_(strlen)(debugname) + 32); |
| 1245 | |
| 1246 | VG_(sprintf)(debugpath, "%s/%s", objdir, debugname); |
| 1247 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1248 | if ((addr = open_debug_file(debugpath, NULL, crc, rel_ok, &size)) == 0) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1249 | VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1250 | if ((addr = open_debug_file(debugpath, NULL, crc, rel_ok, &size)) == 0) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1251 | VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname); |
Ben Cheng | 753e069 | 2013-02-01 11:28:22 -0800 | [diff] [blame^] | 1252 | if ((addr = open_debug_file(debugpath, NULL, crc, rel_ok, &size)) == 0) { |
| 1253 | #if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) |
| 1254 | VG_(sprintf)(debugpath, "/data/local/symbols%s/%s", objdir, |
| 1255 | debugname); |
| 1256 | addr = open_debug_file(debugpath, NULL, crc, rel_ok, &size); |
| 1257 | #endif |
| 1258 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1259 | } |
| 1260 | } |
| 1261 | |
| 1262 | ML_(dinfo_free)(objdir); |
| 1263 | } |
| 1264 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1265 | if (addr > 0 && size > 0) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1266 | TRACE_SYMTAB("\n"); |
| 1267 | TRACE_SYMTAB("------ Found a debuginfo file: %s\n", debugpath); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1268 | *dimage = addr; |
| 1269 | *n_dimage = size; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1270 | } |
| 1271 | |
| 1272 | ML_(dinfo_free)(debugpath); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1273 | } |
| 1274 | |
| 1275 | |
| 1276 | static Bool contained_within ( Addr outer, UWord n_outer, |
| 1277 | Addr inner, UWord n_inner ) |
| 1278 | { |
| 1279 | if (n_outer == 0 || n_inner == 0) |
| 1280 | return False; |
| 1281 | /* Simplistic .. assumes no wraparound (reasonably enough) */ |
| 1282 | if (inner >= outer && inner+n_inner <= outer+n_outer) |
| 1283 | return True; |
| 1284 | return False; |
| 1285 | } |
| 1286 | |
| 1287 | static void* INDEX_BIS ( void* base, Word idx, Word scale ) { |
| 1288 | return (void*)( ((UChar*)base) + idx * scale ); |
| 1289 | } |
| 1290 | |
| 1291 | |
| 1292 | /* Find the file offset corresponding to SVMA by using the program |
| 1293 | headers. This is taken from binutils-2.17/binutils/readelf.c |
| 1294 | offset_from_vma(). */ |
| 1295 | static |
| 1296 | Word file_offset_from_svma ( /*OUT*/Bool* ok, |
| 1297 | Addr svma, |
| 1298 | ElfXX_Phdr* phdr_img, |
| 1299 | Word phdr_nent, |
| 1300 | Word phdr_ent_szB ) |
| 1301 | { |
| 1302 | Word i; |
| 1303 | ElfXX_Phdr* seg; |
| 1304 | for (i = 0; i < phdr_nent; i++) { |
| 1305 | seg = INDEX_BIS( phdr_img, i, phdr_ent_szB ); |
| 1306 | if (seg->p_type != PT_LOAD) |
| 1307 | continue; |
| 1308 | if (svma >= (seg->p_vaddr & -seg->p_align) |
| 1309 | && svma + 1 <= seg->p_vaddr + seg->p_filesz) { |
| 1310 | *ok = True; |
| 1311 | return svma - seg->p_vaddr + seg->p_offset; |
| 1312 | } |
| 1313 | } |
| 1314 | *ok = False; |
| 1315 | return 0; |
| 1316 | } |
| 1317 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1318 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1319 | /* The central function for reading ELF debug info. For the |
| 1320 | object/exe specified by the DebugInfo, find ELF sections, then read |
| 1321 | the symbols, line number info, file name info, CFA (stack-unwind |
| 1322 | info) and anything else we want, into the tables within the |
| 1323 | supplied DebugInfo. |
| 1324 | */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1325 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1326 | Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) |
| 1327 | { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1328 | /* This function is long and complex. That, and the presence of |
| 1329 | nested scopes, means it's not always easy to see which parts are |
| 1330 | in loops/conditionals and which aren't. To make it easier to |
| 1331 | follow, points executed exactly once -- that is, those which are |
| 1332 | the top level of the function -- are marked TOPLEVEL. |
| 1333 | */ |
| 1334 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1335 | Bool res, ok; |
| 1336 | SysRes fd, sres; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1337 | Word i, j; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1338 | Bool dynbss_present = False; |
| 1339 | Bool sdynbss_present = False; |
| 1340 | |
| 1341 | /* Image addresses for the ELF file we're working with. */ |
| 1342 | Addr oimage = 0; |
| 1343 | UWord n_oimage = 0; |
| 1344 | |
| 1345 | /* Ditto for any ELF debuginfo file that we might happen to load. */ |
| 1346 | Addr dimage = 0; |
| 1347 | UWord n_dimage = 0; |
| 1348 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1349 | /* Ditto for alternate ELF debuginfo file that we might happen to load. */ |
| 1350 | Addr aimage = 0; |
| 1351 | UWord n_aimage = 0; |
| 1352 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1353 | /* ELF header for the main file. Should == oimage since is at |
| 1354 | start of file. */ |
| 1355 | ElfXX_Ehdr* ehdr_img = NULL; |
| 1356 | |
| 1357 | /* Program header table image addr, # entries, entry size */ |
| 1358 | ElfXX_Phdr* phdr_img = NULL; |
| 1359 | UWord phdr_nent = 0; |
| 1360 | UWord phdr_ent_szB = 0; |
| 1361 | |
| 1362 | /* Section header image addr, # entries, entry size. Also the |
| 1363 | associated string table. */ |
| 1364 | ElfXX_Shdr* shdr_img = NULL; |
| 1365 | UWord shdr_nent = 0; |
| 1366 | UWord shdr_ent_szB = 0; |
| 1367 | UChar* shdr_strtab_img = NULL; |
| 1368 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1369 | /* SVMAs covered by rx and rw segments and corresponding biases. |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1370 | Normally each object would provide just one rx and one rw area, |
| 1371 | but various ELF mangling tools create objects with multiple |
| 1372 | such entries, hence the generality. */ |
| 1373 | typedef |
| 1374 | struct { |
| 1375 | Addr svma_base; |
| 1376 | Addr svma_limit; |
| 1377 | PtrdiffT bias; |
| 1378 | Bool exec; |
| 1379 | } |
| 1380 | RangeAndBias; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1381 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1382 | XArray* /* of RangeAndBias */ svma_ranges = NULL; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1383 | |
| 1384 | /* Build ID */ |
| 1385 | Char* buildid = NULL; |
| 1386 | |
| 1387 | vg_assert(di); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1388 | vg_assert(di->fsm.have_rx_map == True); |
| 1389 | vg_assert(di->fsm.have_rw_map == True); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1390 | vg_assert(di->have_dinfo == False); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1391 | vg_assert(di->fsm.filename); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1392 | vg_assert(!di->symtab); |
| 1393 | vg_assert(!di->loctab); |
| 1394 | vg_assert(!di->cfsi); |
| 1395 | vg_assert(!di->cfsi_exprs); |
| 1396 | vg_assert(!di->strchunks); |
| 1397 | vg_assert(!di->soname); |
| 1398 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1399 | { |
| 1400 | Bool has_nonempty_rx = False; |
| 1401 | Bool has_nonempty_rw = False; |
| 1402 | for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { |
| 1403 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); |
| 1404 | if (!map->rx && !map->rw) |
| 1405 | continue; |
| 1406 | if (map->rx && map->size > 0) |
| 1407 | has_nonempty_rx = True; |
| 1408 | if (map->rw && map->size > 0) |
| 1409 | has_nonempty_rw = True; |
| 1410 | /* If this doesn't hold true, it means that m_syswrap/m_aspacemgr |
| 1411 | managed to do a mapping where the start isn't page aligned. |
| 1412 | Which sounds pretty bogus to me. */ |
| 1413 | vg_assert(VG_IS_PAGE_ALIGNED(map->avma)); |
| 1414 | } |
| 1415 | vg_assert(has_nonempty_rx); |
| 1416 | vg_assert(has_nonempty_rw); |
| 1417 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1418 | |
| 1419 | /* ---------------------------------------------------------- |
| 1420 | At this point, there is very little information in the |
| 1421 | DebugInfo. We only know that something that looks like an ELF |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1422 | file has been mapped rx-ishly and rw-ishly as recorded in the |
| 1423 | di->fsm.maps array items. First we examine the file's ELF |
| 1424 | Program Header, and, by comparing that against the di->fsm.maps |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1425 | info, try to figure out the AVMAs for the sections we care |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1426 | about, that should have been mapped: text, data, sdata, bss, |
| 1427 | got, plt, and toc. |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1428 | ---------------------------------------------------------- */ |
| 1429 | |
| 1430 | res = False; |
| 1431 | |
| 1432 | oimage = (Addr)NULL; |
| 1433 | if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir)) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1434 | VG_(message)(Vg_DebugMsg, "Reading syms from %s\n", |
| 1435 | di->fsm.filename ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1436 | |
| 1437 | /* mmap the object image aboard, so that we can read symbols and |
| 1438 | line number info out of it. It will be munmapped immediately |
| 1439 | thereafter; it is only aboard transiently. */ |
| 1440 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1441 | fd = VG_(open)(di->fsm.filename, VKI_O_RDONLY, 0); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1442 | if (sr_isError(fd)) { |
| 1443 | ML_(symerr)(di, True, "Can't open .so/.exe to read symbols?!"); |
| 1444 | return False; |
| 1445 | } |
| 1446 | |
| 1447 | { Long n_oimageLL = VG_(fsize)(sr_Res(fd)); |
| 1448 | if (n_oimageLL <= 0) { |
| 1449 | ML_(symerr)(di, True, "Can't stat .so/.exe (to determine its size)?!"); |
| 1450 | VG_(close)(sr_Res(fd)); |
| 1451 | return False; |
| 1452 | } |
| 1453 | n_oimage = (UWord)(ULong)n_oimageLL; |
| 1454 | } |
| 1455 | |
| 1456 | sres = VG_(am_mmap_file_float_valgrind) |
| 1457 | ( n_oimage, VKI_PROT_READ, sr_Res(fd), 0 ); |
| 1458 | |
| 1459 | VG_(close)(sr_Res(fd)); |
| 1460 | |
| 1461 | if (sr_isError(sres)) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1462 | VG_(message)(Vg_UserMsg, "warning: mmap failed on %s\n", |
| 1463 | di->fsm.filename ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1464 | VG_(message)(Vg_UserMsg, " no symbols or debug info loaded\n" ); |
| 1465 | return False; |
| 1466 | } |
| 1467 | |
| 1468 | oimage = sr_Res(sres); |
| 1469 | /* Check against wraparound. am_mmap_file_float_valgrind should |
| 1470 | not produce a wrapped-around mapping. */ |
| 1471 | vg_assert(n_oimage > 0); |
| 1472 | vg_assert(oimage + n_oimage > oimage); |
| 1473 | |
| 1474 | if (0) { |
| 1475 | VG_(printf)("read_elf_debug_info: OIMAGE = %p - %p\n", |
| 1476 | (void*)oimage, (void*)(oimage + (UWord)n_oimage)); |
| 1477 | } |
| 1478 | |
| 1479 | /* Ok, the object image is safely in oimage[0 .. n_oimage-1]. Now |
| 1480 | verify that it is a valid ELF .so or executable image. */ |
| 1481 | res = False; |
| 1482 | ok = (n_oimage >= sizeof(ElfXX_Ehdr)); |
| 1483 | ehdr_img = (ElfXX_Ehdr*)oimage; |
| 1484 | |
| 1485 | if (ok) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1486 | ok &= ML_(is_elf_object_file)(ehdr_img, n_oimage, False); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1487 | |
| 1488 | if (!ok) { |
| 1489 | ML_(symerr)(di, True, "Invalid ELF Header"); |
| 1490 | goto out; |
| 1491 | } |
| 1492 | |
| 1493 | /* Find where the program and section header tables are, and give |
| 1494 | up if either is missing or outside the image (bogus). */ |
| 1495 | phdr_img = (ElfXX_Phdr*)( ((UChar*)ehdr_img) + ehdr_img->e_phoff ); |
| 1496 | phdr_nent = ehdr_img->e_phnum; |
| 1497 | phdr_ent_szB = ehdr_img->e_phentsize; |
| 1498 | |
| 1499 | shdr_img = (ElfXX_Shdr*)( ((UChar*)ehdr_img) + ehdr_img->e_shoff ); |
| 1500 | shdr_nent = ehdr_img->e_shnum; |
| 1501 | shdr_ent_szB = ehdr_img->e_shentsize; |
| 1502 | |
| 1503 | TRACE_SYMTAB("------ Basic facts about the object ------\n"); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1504 | TRACE_SYMTAB("object: img %p n_oimage %ld\n", |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1505 | (void*)oimage, n_oimage); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1506 | TRACE_SYMTAB("phdr: img %p nent %ld ent_szB %ld\n", |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1507 | phdr_img, phdr_nent, phdr_ent_szB); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1508 | TRACE_SYMTAB("shdr: img %p nent %ld ent_szB %ld\n", |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1509 | shdr_img, shdr_nent, shdr_ent_szB); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1510 | for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { |
| 1511 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); |
| 1512 | if (map->rx) |
| 1513 | TRACE_SYMTAB("rx_map: avma %#lx size %lu foff %lu\n", |
| 1514 | map->avma, map->size, map->foff); |
| 1515 | } |
| 1516 | for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { |
| 1517 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); |
| 1518 | if (map->rw) |
| 1519 | TRACE_SYMTAB("rw_map: avma %#lx size %lu foff %lu\n", |
| 1520 | map->avma, map->size, map->foff); |
| 1521 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1522 | |
| 1523 | if (phdr_nent == 0 |
| 1524 | || !contained_within( |
| 1525 | oimage, n_oimage, |
| 1526 | (Addr)phdr_img, phdr_nent * phdr_ent_szB)) { |
| 1527 | ML_(symerr)(di, True, "Missing or invalid ELF Program Header Table"); |
| 1528 | goto out; |
| 1529 | } |
| 1530 | |
| 1531 | if (shdr_nent == 0 |
| 1532 | || !contained_within( |
| 1533 | oimage, n_oimage, |
| 1534 | (Addr)shdr_img, shdr_nent * shdr_ent_szB)) { |
| 1535 | ML_(symerr)(di, True, "Missing or invalid ELF Section Header Table"); |
| 1536 | goto out; |
| 1537 | } |
| 1538 | |
| 1539 | /* Also find the section header's string table, and validate. */ |
| 1540 | /* checked previously by is_elf_object_file: */ |
| 1541 | vg_assert( ehdr_img->e_shstrndx != SHN_UNDEF ); |
| 1542 | |
| 1543 | shdr_strtab_img |
| 1544 | = (UChar*)( ((UChar*)ehdr_img) |
| 1545 | + shdr_img[ehdr_img->e_shstrndx].sh_offset); |
| 1546 | if (!contained_within( oimage, n_oimage, |
| 1547 | (Addr)shdr_strtab_img, |
| 1548 | 1/*bogus, but we don't know the real size*/ )) { |
| 1549 | ML_(symerr)(di, True, "Invalid ELF Section Header String Table"); |
| 1550 | goto out; |
| 1551 | } |
| 1552 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1553 | TRACE_SYMTAB("shdr: string table at %p\n", shdr_strtab_img ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1554 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1555 | svma_ranges = VG_(newXA)(ML_(dinfo_zalloc), "di.relfdi.1", |
| 1556 | ML_(dinfo_free), sizeof(RangeAndBias)); |
| 1557 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1558 | /* TOPLEVEL */ |
| 1559 | /* Look through the program header table, and: |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1560 | - copy information from suitable PT_LOAD entries into svma_ranges |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1561 | - find (or fake up) the .soname for this object. |
| 1562 | */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1563 | TRACE_SYMTAB("\n"); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1564 | TRACE_SYMTAB("------ Examining the program headers ------\n"); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1565 | vg_assert(di->soname == NULL); |
| 1566 | { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1567 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1568 | ElfXX_Addr prev_svma = 0; |
| 1569 | |
| 1570 | for (i = 0; i < phdr_nent; i++) { |
| 1571 | ElfXX_Phdr* phdr = INDEX_BIS( phdr_img, i, phdr_ent_szB ); |
| 1572 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1573 | /* Make sure the PT_LOADable entries are in order and |
| 1574 | non-overlapping. This in turn means the address ranges |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1575 | slurped into svma_ranges are in order and |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1576 | non-overlapping. */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1577 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1578 | if (phdr->p_type == PT_LOAD) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1579 | TRACE_SYMTAB("PT_LOAD[%ld]: p_vaddr %#lx (prev %#lx)\n", |
| 1580 | i, (UWord)phdr->p_vaddr, (UWord)prev_svma); |
| 1581 | TRACE_SYMTAB("PT_LOAD[%ld]: p_offset %lu, p_filesz %lu," |
| 1582 | " perms %c%c%c\n", |
| 1583 | i, (UWord)phdr->p_offset, (UWord)phdr->p_filesz, |
| 1584 | phdr->p_flags & PF_R ? 'r' : '-', |
| 1585 | phdr->p_flags & PF_W ? 'w' : '-', |
| 1586 | phdr->p_flags & PF_X ? 'x' : '-'); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1587 | if (phdr->p_vaddr < prev_svma) { |
| 1588 | ML_(symerr)(di, True, |
| 1589 | "ELF Program Headers are not in ascending order"); |
| 1590 | goto out; |
| 1591 | } |
| 1592 | prev_svma = phdr->p_vaddr; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1593 | if (phdr->p_memsz > 0) { |
| 1594 | Bool loaded = False; |
| 1595 | for (j = 0; j < VG_(sizeXA)(di->fsm.maps); j++) { |
| 1596 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, j); |
| 1597 | if ( (map->rx || map->rw) |
| 1598 | && phdr->p_offset >= map->foff |
| 1599 | && phdr->p_offset < map->foff + map->size |
| 1600 | && phdr->p_offset + phdr->p_filesz <= map->foff |
| 1601 | + map->size) { |
| 1602 | RangeAndBias item; |
| 1603 | item.svma_base = phdr->p_vaddr; |
| 1604 | item.svma_limit = phdr->p_vaddr + phdr->p_memsz; |
| 1605 | item.bias = map->avma - map->foff |
| 1606 | + phdr->p_offset - phdr->p_vaddr; |
| 1607 | if ( map->rw |
| 1608 | && (phdr->p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) { |
| 1609 | item.exec = False; |
| 1610 | VG_(addToXA)(svma_ranges, &item); |
| 1611 | TRACE_SYMTAB("PT_LOAD[%ld]: acquired as rw\n", i); |
| 1612 | loaded = True; |
| 1613 | } |
| 1614 | if ( map->rx |
| 1615 | && (phdr->p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) { |
| 1616 | item.exec = True; |
| 1617 | VG_(addToXA)(svma_ranges, &item); |
| 1618 | TRACE_SYMTAB("PT_LOAD[%ld]: acquired as rx\n", i); |
| 1619 | loaded = True; |
| 1620 | } |
| 1621 | } |
| 1622 | } |
| 1623 | if (!loaded) { |
| 1624 | ML_(symerr)(di, False, |
| 1625 | "ELF section outside all mapped regions"); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1626 | goto out; |
| 1627 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1628 | } |
| 1629 | } |
| 1630 | |
| 1631 | /* Try to get the soname. If there isn't one, use "NONE". |
| 1632 | The seginfo needs to have some kind of soname in order to |
| 1633 | facilitate writing redirect functions, since all redirect |
| 1634 | specifications require a soname (pattern). */ |
| 1635 | if (phdr->p_type == PT_DYNAMIC && di->soname == NULL) { |
| 1636 | ElfXX_Dyn* dyn_img = (ElfXX_Dyn*)( ((UChar*)ehdr_img) |
| 1637 | + phdr->p_offset); |
| 1638 | Word stroff = -1; |
| 1639 | UChar* strtab = NULL; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1640 | for (j = 0; dyn_img[j].d_tag != DT_NULL; j++) { |
| 1641 | switch (dyn_img[j].d_tag) { |
| 1642 | case DT_SONAME: { |
| 1643 | stroff = dyn_img[j].d_un.d_val; |
| 1644 | break; |
| 1645 | } |
| 1646 | case DT_STRTAB: { |
| 1647 | Bool ok2 = False; |
| 1648 | Word offset = file_offset_from_svma( |
| 1649 | &ok2, |
| 1650 | dyn_img[j].d_un.d_ptr, |
| 1651 | phdr_img, |
| 1652 | phdr_nent, phdr_ent_szB |
| 1653 | ); |
| 1654 | if (ok2 && strtab == NULL) { |
| 1655 | vg_assert(offset >= 0 && offset <= n_oimage); |
| 1656 | strtab = ((UChar*)ehdr_img) + offset; |
| 1657 | } |
| 1658 | break; |
| 1659 | } |
| 1660 | default: |
| 1661 | break; |
| 1662 | } |
| 1663 | } |
| 1664 | if (stroff != -1 && strtab != NULL) { |
| 1665 | TRACE_SYMTAB("Found soname = %s\n", strtab+stroff); |
| 1666 | di->soname = ML_(dinfo_strdup)("di.redi.1", strtab+stroff); |
| 1667 | } |
| 1668 | } |
| 1669 | } /* for (i = 0; i < phdr_nent; i++) ... */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1670 | /* TOPLEVEL */ |
| 1671 | |
| 1672 | } /* examine the program headers (local scope) */ |
| 1673 | |
| 1674 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1675 | |
| 1676 | /* If, after looking at all the program headers, we still didn't |
| 1677 | find a soname, add a fake one. */ |
| 1678 | if (di->soname == NULL) { |
| 1679 | TRACE_SYMTAB("No soname found; using (fake) \"NONE\"\n"); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1680 | di->soname = ML_(dinfo_strdup)("di.redi.2", "NONE"); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1681 | } |
| 1682 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1683 | vg_assert(VG_(sizeXA)(svma_ranges) != 0); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1684 | |
| 1685 | /* Now read the section table. */ |
| 1686 | TRACE_SYMTAB("\n"); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1687 | TRACE_SYMTAB("------ Examining the section headers ------\n"); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1688 | for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { |
| 1689 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); |
| 1690 | if (map->rx) |
| 1691 | TRACE_SYMTAB("rx: at %#lx are mapped foffsets %ld .. %ld\n", |
| 1692 | map->avma, map->foff, map->foff + map->size - 1 ); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1693 | } |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1694 | TRACE_SYMTAB("rx: contains these svma regions:\n"); |
| 1695 | for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) { |
| 1696 | RangeAndBias* reg = VG_(indexXA)(svma_ranges, i); |
| 1697 | if (reg->exec) |
| 1698 | TRACE_SYMTAB(" svmas %#lx .. %#lx with bias %#lx\n", |
| 1699 | reg->svma_base, reg->svma_limit - 1, reg->bias ); |
| 1700 | } |
| 1701 | for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { |
| 1702 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); |
| 1703 | if (map->rw) |
| 1704 | TRACE_SYMTAB("rw: at %#lx are mapped foffsets %ld .. %ld\n", |
| 1705 | map->avma, map->foff, map->foff + map->size - 1 ); |
| 1706 | } |
| 1707 | TRACE_SYMTAB("rw: contains these svma regions:\n"); |
| 1708 | for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) { |
| 1709 | RangeAndBias* reg = VG_(indexXA)(svma_ranges, i); |
| 1710 | if (!reg->exec) |
| 1711 | TRACE_SYMTAB(" svmas %#lx .. %#lx with bias %#lx\n", |
| 1712 | reg->svma_base, reg->svma_limit - 1, reg->bias ); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1713 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1714 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1715 | /* TOPLEVEL */ |
| 1716 | /* Iterate over section headers */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1717 | for (i = 0; i < shdr_nent; i++) { |
| 1718 | ElfXX_Shdr* shdr = INDEX_BIS( shdr_img, i, shdr_ent_szB ); |
| 1719 | UChar* name = shdr_strtab_img + shdr->sh_name; |
| 1720 | Addr svma = shdr->sh_addr; |
| 1721 | OffT foff = shdr->sh_offset; |
| 1722 | UWord size = shdr->sh_size; |
| 1723 | UInt alyn = shdr->sh_addralign; |
| 1724 | Bool bits = !(shdr->sh_type == SHT_NOBITS); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1725 | /* Look through our collection of info obtained from the PT_LOAD |
| 1726 | headers, and make 'inrx' and 'inrw' point to the first entry |
| 1727 | in each that intersects 'avma'. If in each case none is found, |
| 1728 | leave the relevant pointer at NULL. */ |
| 1729 | RangeAndBias* inrx = NULL; |
| 1730 | RangeAndBias* inrw = NULL; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1731 | for (j = 0; j < VG_(sizeXA)(svma_ranges); j++) { |
| 1732 | RangeAndBias* rng = VG_(indexXA)(svma_ranges, j); |
| 1733 | if (svma >= rng->svma_base && svma < rng->svma_limit) { |
| 1734 | if (!inrx && rng->exec) { |
| 1735 | inrx = rng; |
| 1736 | } else if (!inrw && !rng->exec) { |
| 1737 | inrw = rng; |
| 1738 | } |
| 1739 | if (inrx && inrw) |
| 1740 | break; |
| 1741 | } |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1742 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1743 | |
| 1744 | TRACE_SYMTAB(" [sec %2ld] %s %s al%2u foff %6ld .. %6ld " |
| 1745 | " svma %p name \"%s\"\n", |
| 1746 | i, inrx ? "rx" : " ", inrw ? "rw" : " ", alyn, |
| 1747 | foff, foff+size-1, (void*)svma, name ); |
| 1748 | |
| 1749 | /* Check for sane-sized segments. SHT_NOBITS sections have zero |
| 1750 | size in the file. */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 1751 | if ((foff >= n_oimage) || (foff + (bits ? size : 0) > n_oimage)) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1752 | ML_(symerr)(di, True, "ELF Section extends beyond image end"); |
| 1753 | goto out; |
| 1754 | } |
| 1755 | |
| 1756 | /* Check for a sane alignment value. */ |
| 1757 | if (alyn > 0 && -1 == VG_(log2)(alyn)) { |
| 1758 | ML_(symerr)(di, True, "ELF Section contains invalid " |
| 1759 | ".sh_addralign value"); |
| 1760 | goto out; |
| 1761 | } |
| 1762 | |
| 1763 | # define BAD(_secname) \ |
| 1764 | do { ML_(symerr)(di, True, \ |
| 1765 | "Can't make sense of " _secname \ |
| 1766 | " section mapping"); \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1767 | /* make sure we don't assert if we find */ \ |
| 1768 | /* ourselves back in this routine later, */ \ |
| 1769 | /* with the same di */ \ |
| 1770 | di->soname = NULL; \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1771 | goto out; \ |
| 1772 | } while (0) |
| 1773 | |
| 1774 | /* Find avma-s for: .text .data .sdata .rodata .bss .sbss .plt .got .opd |
| 1775 | and .eh_frame */ |
| 1776 | |
| 1777 | /* Accept .text where mapped as rx (code), even if zero-sized */ |
| 1778 | if (0 == VG_(strcmp)(name, ".text")) { |
| 1779 | if (inrx && size >= 0 && !di->text_present) { |
| 1780 | di->text_present = True; |
| 1781 | di->text_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1782 | di->text_avma = svma + inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1783 | di->text_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1784 | di->text_bias = inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1785 | di->text_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1786 | di->text_debug_bias = inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1787 | TRACE_SYMTAB("acquiring .text svma = %#lx .. %#lx\n", |
| 1788 | di->text_svma, |
| 1789 | di->text_svma + di->text_size - 1); |
| 1790 | TRACE_SYMTAB("acquiring .text avma = %#lx .. %#lx\n", |
| 1791 | di->text_avma, |
| 1792 | di->text_avma + di->text_size - 1); |
| 1793 | TRACE_SYMTAB("acquiring .text bias = %#lx\n", di->text_bias); |
| 1794 | } else { |
| 1795 | BAD(".text"); |
| 1796 | } |
| 1797 | } |
| 1798 | |
| 1799 | /* Accept .data where mapped as rw (data), even if zero-sized */ |
| 1800 | if (0 == VG_(strcmp)(name, ".data")) { |
| 1801 | if (inrw && size >= 0 && !di->data_present) { |
| 1802 | di->data_present = True; |
| 1803 | di->data_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1804 | di->data_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1805 | di->data_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1806 | di->data_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1807 | di->data_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1808 | di->data_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1809 | TRACE_SYMTAB("acquiring .data svma = %#lx .. %#lx\n", |
| 1810 | di->data_svma, |
| 1811 | di->data_svma + di->data_size - 1); |
| 1812 | TRACE_SYMTAB("acquiring .data avma = %#lx .. %#lx\n", |
| 1813 | di->data_avma, |
| 1814 | di->data_avma + di->data_size - 1); |
| 1815 | TRACE_SYMTAB("acquiring .data bias = %#lx\n", di->data_bias); |
| 1816 | } else { |
| 1817 | BAD(".data"); |
| 1818 | } |
| 1819 | } |
| 1820 | |
| 1821 | /* Accept .sdata where mapped as rw (data) */ |
| 1822 | if (0 == VG_(strcmp)(name, ".sdata")) { |
| 1823 | if (inrw && size > 0 && !di->sdata_present) { |
| 1824 | di->sdata_present = True; |
| 1825 | di->sdata_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1826 | di->sdata_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1827 | di->sdata_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1828 | di->sdata_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1829 | di->sdata_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1830 | di->sdata_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1831 | TRACE_SYMTAB("acquiring .sdata svma = %#lx .. %#lx\n", |
| 1832 | di->sdata_svma, |
| 1833 | di->sdata_svma + di->sdata_size - 1); |
| 1834 | TRACE_SYMTAB("acquiring .sdata avma = %#lx .. %#lx\n", |
| 1835 | di->sdata_avma, |
| 1836 | di->sdata_avma + di->sdata_size - 1); |
| 1837 | TRACE_SYMTAB("acquiring .sdata bias = %#lx\n", di->sdata_bias); |
| 1838 | } else { |
| 1839 | BAD(".sdata"); |
| 1840 | } |
| 1841 | } |
| 1842 | |
| 1843 | /* Accept .rodata where mapped as rx (data), even if zero-sized */ |
| 1844 | if (0 == VG_(strcmp)(name, ".rodata")) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1845 | if (inrx && size >= 0 && !di->rodata_present) { |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1846 | di->rodata_present = True; |
| 1847 | di->rodata_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1848 | di->rodata_avma = svma + inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1849 | di->rodata_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1850 | di->rodata_bias = inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1851 | di->rodata_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1852 | di->rodata_debug_bias = inrx->bias; |
| 1853 | /* NB was 'inrw' prior to r11794 */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1854 | TRACE_SYMTAB("acquiring .rodata svma = %#lx .. %#lx\n", |
| 1855 | di->rodata_svma, |
| 1856 | di->rodata_svma + di->rodata_size - 1); |
| 1857 | TRACE_SYMTAB("acquiring .rodata avma = %#lx .. %#lx\n", |
| 1858 | di->rodata_avma, |
| 1859 | di->rodata_avma + di->rodata_size - 1); |
| 1860 | TRACE_SYMTAB("acquiring .rodata bias = %#lx\n", di->rodata_bias); |
| 1861 | } else { |
| 1862 | BAD(".rodata"); |
| 1863 | } |
| 1864 | } |
| 1865 | |
| 1866 | if (0 == VG_(strcmp)(name, ".dynbss")) { |
| 1867 | if (inrw && size > 0 && !di->bss_present) { |
| 1868 | dynbss_present = True; |
| 1869 | di->bss_present = True; |
| 1870 | di->bss_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1871 | di->bss_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1872 | di->bss_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1873 | di->bss_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1874 | di->bss_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1875 | di->bss_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1876 | TRACE_SYMTAB("acquiring .dynbss svma = %#lx .. %#lx\n", |
| 1877 | di->bss_svma, |
| 1878 | di->bss_svma + di->bss_size - 1); |
| 1879 | TRACE_SYMTAB("acquiring .dynbss avma = %#lx .. %#lx\n", |
| 1880 | di->bss_avma, |
| 1881 | di->bss_avma + di->bss_size - 1); |
| 1882 | TRACE_SYMTAB("acquiring .dynbss bias = %#lx\n", di->bss_bias); |
| 1883 | } |
| 1884 | } |
| 1885 | |
| 1886 | /* Accept .bss where mapped as rw (data), even if zero-sized */ |
| 1887 | if (0 == VG_(strcmp)(name, ".bss")) { |
| 1888 | if (inrw && size > 0 && dynbss_present) { |
| 1889 | vg_assert(di->bss_present); |
| 1890 | dynbss_present = False; |
| 1891 | vg_assert(di->bss_svma + di->bss_size == svma); |
| 1892 | di->bss_size += size; |
| 1893 | TRACE_SYMTAB("acquiring .bss svma = %#lx .. %#lx\n", |
| 1894 | svma, svma + size - 1); |
| 1895 | TRACE_SYMTAB("acquiring .bss avma = %#lx .. %#lx\n", |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1896 | svma + inrw->bias, svma + inrw->bias + size - 1); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1897 | TRACE_SYMTAB("acquiring .bss bias = %#lx\n", di->bss_bias); |
| 1898 | } else |
| 1899 | |
| 1900 | if (inrw && size >= 0 && !di->bss_present) { |
| 1901 | di->bss_present = True; |
| 1902 | di->bss_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1903 | di->bss_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1904 | di->bss_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1905 | di->bss_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1906 | di->bss_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1907 | di->bss_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1908 | TRACE_SYMTAB("acquiring .bss svma = %#lx .. %#lx\n", |
| 1909 | di->bss_svma, |
| 1910 | di->bss_svma + di->bss_size - 1); |
| 1911 | TRACE_SYMTAB("acquiring .bss avma = %#lx .. %#lx\n", |
| 1912 | di->bss_avma, |
| 1913 | di->bss_avma + di->bss_size - 1); |
| 1914 | TRACE_SYMTAB("acquiring .bss bias = %#lx\n", di->bss_bias); |
| 1915 | } else |
| 1916 | |
| 1917 | /* Now one from the wtf?! department ... */ |
| 1918 | if (inrx && (!inrw) && size >= 0 && !di->bss_present) { |
| 1919 | /* File contains a .bss, but it got mapped as rx only. |
| 1920 | This is very strange. For now, just pretend we didn't |
| 1921 | see it :-) */ |
| 1922 | di->bss_present = False; |
| 1923 | di->bss_svma = 0; |
| 1924 | di->bss_avma = 0; |
| 1925 | di->bss_size = 0; |
| 1926 | di->bss_bias = 0; |
| 1927 | di->bss_debug_svma = 0; |
| 1928 | di->bss_debug_bias = 0; |
| 1929 | if (!VG_(clo_xml)) { |
| 1930 | VG_(message)(Vg_UserMsg, |
| 1931 | "Warning: the following file's .bss is " |
| 1932 | "mapped r-x only - ignoring .bss syms\n"); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1933 | VG_(message)(Vg_UserMsg, " %s\n", di->fsm.filename |
| 1934 | ? di->fsm.filename |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1935 | : (UChar*)"(null?!)" ); |
| 1936 | } |
| 1937 | } else |
| 1938 | |
| 1939 | if ((!inrw) && (!inrx) && size >= 0 && !di->bss_present) { |
| 1940 | /* File contains a .bss, but it didn't get mapped. Ignore. */ |
| 1941 | di->bss_present = False; |
| 1942 | di->bss_svma = 0; |
| 1943 | di->bss_avma = 0; |
| 1944 | di->bss_size = 0; |
| 1945 | di->bss_bias = 0; |
| 1946 | } else { |
| 1947 | BAD(".bss"); |
| 1948 | } |
| 1949 | } |
| 1950 | |
| 1951 | if (0 == VG_(strcmp)(name, ".sdynbss")) { |
| 1952 | if (inrw && size >= 0 && !di->sbss_present) { |
| 1953 | sdynbss_present = True; |
| 1954 | di->sbss_present = True; |
| 1955 | di->sbss_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1956 | di->sbss_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1957 | di->sbss_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1958 | di->sbss_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1959 | di->sbss_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1960 | di->sbss_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1961 | TRACE_SYMTAB("acquiring .sdynbss svma = %#lx .. %#lx\n", |
| 1962 | di->sbss_svma, |
| 1963 | di->sbss_svma + di->sbss_size - 1); |
| 1964 | TRACE_SYMTAB("acquiring .sdynbss avma = %#lx .. %#lx\n", |
| 1965 | di->sbss_avma, |
| 1966 | di->sbss_avma + di->sbss_size - 1); |
| 1967 | TRACE_SYMTAB("acquiring .sdynbss bias = %#lx\n", di->sbss_bias); |
| 1968 | } |
| 1969 | } |
| 1970 | |
| 1971 | /* Accept .sbss where mapped as rw (data) */ |
| 1972 | if (0 == VG_(strcmp)(name, ".sbss")) { |
| 1973 | if (inrw && size > 0 && sdynbss_present) { |
| 1974 | vg_assert(di->sbss_present); |
| 1975 | sdynbss_present = False; |
| 1976 | vg_assert(di->sbss_svma + di->sbss_size == svma); |
| 1977 | di->sbss_size += size; |
| 1978 | TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n", |
| 1979 | svma, svma + size - 1); |
| 1980 | TRACE_SYMTAB("acquiring .sbss avma = %#lx .. %#lx\n", |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1981 | svma + inrw->bias, svma + inrw->bias + size - 1); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1982 | TRACE_SYMTAB("acquiring .sbss bias = %#lx\n", di->sbss_bias); |
| 1983 | } else |
| 1984 | |
| 1985 | if (inrw && size > 0 && !di->sbss_present) { |
| 1986 | di->sbss_present = True; |
| 1987 | di->sbss_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1988 | di->sbss_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1989 | di->sbss_size = size; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1990 | di->sbss_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1991 | di->sbss_debug_svma = svma; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 1992 | di->sbss_debug_bias = inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 1993 | TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n", |
| 1994 | di->sbss_svma, |
| 1995 | di->sbss_svma + di->sbss_size - 1); |
| 1996 | TRACE_SYMTAB("acquiring .sbss avma = %#lx .. %#lx\n", |
| 1997 | di->sbss_avma, |
| 1998 | di->sbss_avma + di->sbss_size - 1); |
| 1999 | TRACE_SYMTAB("acquiring .sbss bias = %#lx\n", di->sbss_bias); |
| 2000 | } else { |
| 2001 | BAD(".sbss"); |
| 2002 | } |
| 2003 | } |
| 2004 | |
| 2005 | /* Accept .got where mapped as rw (data) */ |
| 2006 | if (0 == VG_(strcmp)(name, ".got")) { |
| 2007 | if (inrw && size > 0 && !di->got_present) { |
| 2008 | di->got_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2009 | di->got_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2010 | di->got_size = size; |
| 2011 | TRACE_SYMTAB("acquiring .got avma = %#lx\n", di->got_avma); |
| 2012 | } else { |
| 2013 | BAD(".got"); |
| 2014 | } |
| 2015 | } |
| 2016 | |
| 2017 | /* Accept .got.plt where mapped as rw (data) */ |
| 2018 | if (0 == VG_(strcmp)(name, ".got.plt")) { |
| 2019 | if (inrw && size > 0 && !di->gotplt_present) { |
| 2020 | di->gotplt_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2021 | di->gotplt_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2022 | di->gotplt_size = size; |
| 2023 | TRACE_SYMTAB("acquiring .got.plt avma = %#lx\n", di->gotplt_avma); |
| 2024 | } else if (size != 0) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2025 | BAD(".got.plt"); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2026 | } |
| 2027 | } |
| 2028 | |
| 2029 | /* PLT is different on different platforms, it seems. */ |
| 2030 | # if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2031 | || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \ |
| 2032 | || defined(VGP_mips32_linux) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2033 | /* Accept .plt where mapped as rx (code) */ |
| 2034 | if (0 == VG_(strcmp)(name, ".plt")) { |
| 2035 | if (inrx && size > 0 && !di->plt_present) { |
| 2036 | di->plt_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2037 | di->plt_avma = svma + inrx->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2038 | di->plt_size = size; |
| 2039 | TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma); |
| 2040 | } else { |
| 2041 | BAD(".plt"); |
| 2042 | } |
| 2043 | } |
| 2044 | # elif defined(VGP_ppc32_linux) |
| 2045 | /* Accept .plt where mapped as rw (data) */ |
| 2046 | if (0 == VG_(strcmp)(name, ".plt")) { |
| 2047 | if (inrw && size > 0 && !di->plt_present) { |
| 2048 | di->plt_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2049 | di->plt_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2050 | di->plt_size = size; |
| 2051 | TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma); |
| 2052 | } else { |
| 2053 | BAD(".plt"); |
| 2054 | } |
| 2055 | } |
| 2056 | # elif defined(VGP_ppc64_linux) |
| 2057 | /* Accept .plt where mapped as rw (data), or unmapped */ |
| 2058 | if (0 == VG_(strcmp)(name, ".plt")) { |
| 2059 | if (inrw && size > 0 && !di->plt_present) { |
| 2060 | di->plt_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2061 | di->plt_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2062 | di->plt_size = size; |
| 2063 | TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma); |
| 2064 | } else |
| 2065 | if ((!inrw) && (!inrx) && size > 0 && !di->plt_present) { |
| 2066 | /* File contains a .plt, but it didn't get mapped. |
| 2067 | Presumably it is not required on this platform. At |
| 2068 | least don't reject the situation as invalid. */ |
| 2069 | di->plt_present = True; |
| 2070 | di->plt_avma = 0; |
| 2071 | di->plt_size = 0; |
| 2072 | } else { |
| 2073 | BAD(".plt"); |
| 2074 | } |
| 2075 | } |
| 2076 | # else |
| 2077 | # error "Unsupported platform" |
| 2078 | # endif |
| 2079 | |
| 2080 | /* Accept .opd where mapped as rw (data) */ |
| 2081 | if (0 == VG_(strcmp)(name, ".opd")) { |
| 2082 | if (inrw && size > 0 && !di->opd_present) { |
| 2083 | di->opd_present = True; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2084 | di->opd_avma = svma + inrw->bias; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2085 | di->opd_size = size; |
| 2086 | TRACE_SYMTAB("acquiring .opd avma = %#lx\n", di->opd_avma); |
| 2087 | } else { |
| 2088 | BAD(".opd"); |
| 2089 | } |
| 2090 | } |
| 2091 | |
| 2092 | /* Accept .eh_frame where mapped as rx (code). This seems to be |
| 2093 | the common case. However, if that doesn't pan out, try for |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2094 | rw (data) instead. We can handle up to N_EHFRAME_SECTS per |
| 2095 | ELF object. */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2096 | if (0 == VG_(strcmp)(name, ".eh_frame")) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2097 | if (inrx && size > 0 && di->n_ehframe < N_EHFRAME_SECTS) { |
| 2098 | di->ehframe_avma[di->n_ehframe] = svma + inrx->bias; |
| 2099 | di->ehframe_size[di->n_ehframe] = size; |
| 2100 | TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n", |
| 2101 | di->ehframe_avma[di->n_ehframe]); |
| 2102 | di->n_ehframe++; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2103 | } else |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2104 | if (inrw && size > 0 && di->n_ehframe < N_EHFRAME_SECTS) { |
| 2105 | di->ehframe_avma[di->n_ehframe] = svma + inrw->bias; |
| 2106 | di->ehframe_size[di->n_ehframe] = size; |
| 2107 | TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n", |
| 2108 | di->ehframe_avma[di->n_ehframe]); |
| 2109 | di->n_ehframe++; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2110 | } else { |
| 2111 | BAD(".eh_frame"); |
| 2112 | } |
| 2113 | } |
| 2114 | |
| 2115 | # undef BAD |
| 2116 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2117 | } /* iterate over the section headers */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2118 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2119 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2120 | if (0) VG_(printf)("YYYY text_: avma %#lx size %ld bias %#lx\n", |
| 2121 | di->text_avma, di->text_size, di->text_bias); |
| 2122 | |
| 2123 | if (VG_(clo_verbosity) > 2 || VG_(clo_trace_redir)) |
| 2124 | VG_(message)(Vg_DebugMsg, " svma %#010lx, avma %#010lx\n", |
| 2125 | di->text_avma - di->text_bias, |
| 2126 | di->text_avma ); |
| 2127 | |
| 2128 | TRACE_SYMTAB("\n"); |
| 2129 | TRACE_SYMTAB("------ Finding image addresses " |
| 2130 | "for debug-info sections ------\n"); |
| 2131 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2132 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2133 | /* Find interesting sections, read the symbol table(s), read any debug |
| 2134 | information */ |
| 2135 | { |
| 2136 | /* IMAGE addresses: pointers to start of sections in the |
| 2137 | transiently loaded oimage, not in the fragments of the file |
| 2138 | mapped in by the guest's dynamic linker. */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2139 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2140 | UChar* strtab_img = NULL; /* .strtab */ |
| 2141 | ElfXX_Sym* symtab_img = NULL; /* .symtab */ |
| 2142 | UChar* dynstr_img = NULL; /* .dynstr */ |
| 2143 | ElfXX_Sym* dynsym_img = NULL; /* .dynsym */ |
| 2144 | UChar* debuglink_img = NULL; /* .gnu_debuglink */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2145 | UChar* debugaltlink_img = NULL; /* .gnu_debugaltlink */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2146 | UChar* stab_img = NULL; /* .stab (stabs) */ |
| 2147 | UChar* stabstr_img = NULL; /* .stabstr (stabs) */ |
| 2148 | UChar* debug_line_img = NULL; /* .debug_line (dwarf2) */ |
| 2149 | UChar* debug_info_img = NULL; /* .debug_info (dwarf2) */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2150 | UChar* debug_types_img = NULL; /* .debug_types (dwarf4) */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2151 | UChar* debug_abbv_img = NULL; /* .debug_abbrev (dwarf2) */ |
| 2152 | UChar* debug_str_img = NULL; /* .debug_str (dwarf2) */ |
| 2153 | UChar* debug_ranges_img = NULL; /* .debug_ranges (dwarf2) */ |
| 2154 | UChar* debug_loc_img = NULL; /* .debug_loc (dwarf2) */ |
| 2155 | UChar* debug_frame_img = NULL; /* .debug_frame (dwarf2) */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2156 | UChar* debug_line_alt_img = NULL; /* .debug_line (alternate) */ |
| 2157 | UChar* debug_info_alt_img = NULL; /* .debug_info (alternate) */ |
| 2158 | UChar* debug_abbv_alt_img = NULL; /* .debug_abbrev (alternate) */ |
| 2159 | UChar* debug_str_alt_img = NULL; /* .debug_str (alternate) */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2160 | UChar* dwarf1d_img = NULL; /* .debug (dwarf1) */ |
| 2161 | UChar* dwarf1l_img = NULL; /* .line (dwarf1) */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2162 | UChar* opd_img = NULL; /* .opd (dwarf2, |
| 2163 | ppc64-linux) */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2164 | UChar* ehframe_img[N_EHFRAME_SECTS]; /* .eh_frame (dwarf2) */ |
| 2165 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2166 | /* Section sizes, in bytes */ |
| 2167 | SizeT strtab_sz = 0; |
| 2168 | SizeT symtab_sz = 0; |
| 2169 | SizeT dynstr_sz = 0; |
| 2170 | SizeT dynsym_sz = 0; |
| 2171 | SizeT debuglink_sz = 0; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2172 | SizeT debugaltlink_sz = 0; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2173 | SizeT stab_sz = 0; |
| 2174 | SizeT stabstr_sz = 0; |
| 2175 | SizeT debug_line_sz = 0; |
| 2176 | SizeT debug_info_sz = 0; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2177 | SizeT debug_types_sz = 0; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2178 | SizeT debug_abbv_sz = 0; |
| 2179 | SizeT debug_str_sz = 0; |
| 2180 | SizeT debug_ranges_sz = 0; |
| 2181 | SizeT debug_loc_sz = 0; |
| 2182 | SizeT debug_frame_sz = 0; |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2183 | SizeT debug_line_alt_sz = 0; |
| 2184 | SizeT debug_info_alt_sz = 0; |
| 2185 | SizeT debug_abbv_alt_sz = 0; |
| 2186 | SizeT debug_str_alt_sz = 0; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2187 | SizeT dwarf1d_sz = 0; |
| 2188 | SizeT dwarf1l_sz = 0; |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2189 | SizeT opd_sz_unused = 0; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2190 | SizeT ehframe_sz[N_EHFRAME_SECTS]; |
| 2191 | |
| 2192 | for (i = 0; i < N_EHFRAME_SECTS; i++) { |
| 2193 | ehframe_img[i] = NULL; |
| 2194 | ehframe_sz[i] = 0; |
| 2195 | } |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2196 | |
| 2197 | /* Find all interesting sections */ |
| 2198 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2199 | UInt ehframe_ix = 0; |
Evgeniy Stepanov | 8f943af | 2011-12-06 18:30:06 +0400 | [diff] [blame] | 2200 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2201 | /* What FIND does: it finds the section called _SEC_NAME. The |
| 2202 | size of it is assigned to _SEC_SIZE. The address of the |
| 2203 | section in the transiently loaded oimage is assigned to |
| 2204 | _SEC_IMG. If the section is found, _POST_FX is executed |
| 2205 | after _SEC_NAME and _SEC_SIZE have been assigned to. |
| 2206 | |
| 2207 | Even for sections which are marked loadable, the client's |
| 2208 | ld.so may not have loaded them yet, so there is no guarantee |
| 2209 | that we can safely prod around in any such area). Because |
| 2210 | the entire object file is transiently mapped aboard for |
| 2211 | inspection, it's always safe to inspect that area. */ |
| 2212 | |
| 2213 | /* TOPLEVEL */ |
| 2214 | /* Iterate over section headers (again) */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2215 | for (i = 0; i < ehdr_img->e_shnum; i++) { |
| 2216 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2217 | # define FINDX(_sec_name, _sec_size, _sec_img, _post_fx) \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2218 | do { ElfXX_Shdr* shdr \ |
| 2219 | = INDEX_BIS( shdr_img, i, shdr_ent_szB ); \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2220 | if (0 == VG_(strcmp)(_sec_name, shdr_strtab_img \ |
| 2221 | + shdr->sh_name)) { \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2222 | Bool nobits; \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2223 | _sec_img = (void*)(oimage + shdr->sh_offset); \ |
| 2224 | _sec_size = shdr->sh_size; \ |
| 2225 | nobits = shdr->sh_type == SHT_NOBITS; \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2226 | TRACE_SYMTAB( "%18s: img %p .. %p\n", \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2227 | _sec_name, (UChar*)_sec_img, \ |
| 2228 | ((UChar*)_sec_img) + _sec_size - 1); \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2229 | /* SHT_NOBITS sections have zero size in the file. */ \ |
| 2230 | if ( shdr->sh_offset \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2231 | + (nobits ? 0 : _sec_size) > n_oimage ) { \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2232 | ML_(symerr)(di, True, \ |
| 2233 | " section beyond image end?!"); \ |
| 2234 | goto out; \ |
| 2235 | } \ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2236 | _post_fx; \ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2237 | } \ |
| 2238 | } while (0); |
| 2239 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2240 | /* Version with no post-effects */ |
| 2241 | # define FIND(_sec_name, _sec_size, _sec_img) \ |
| 2242 | FINDX(_sec_name, _sec_size, _sec_img, /**/) |
| 2243 | |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2244 | /* NAME SIZE IMAGE addr */ |
| 2245 | FIND(".dynsym", dynsym_sz, dynsym_img) |
| 2246 | FIND(".dynstr", dynstr_sz, dynstr_img) |
| 2247 | FIND(".symtab", symtab_sz, symtab_img) |
| 2248 | FIND(".strtab", strtab_sz, strtab_img) |
| 2249 | |
| 2250 | FIND(".gnu_debuglink", debuglink_sz, debuglink_img) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2251 | FIND(".gnu_debugaltlink", debugaltlink_sz, debugaltlink_img) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2252 | |
| 2253 | FIND(".stab", stab_sz, stab_img) |
| 2254 | FIND(".stabstr", stabstr_sz, stabstr_img) |
| 2255 | |
| 2256 | FIND(".debug_line", debug_line_sz, debug_line_img) |
| 2257 | FIND(".debug_info", debug_info_sz, debug_info_img) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2258 | FIND(".debug_types", debug_types_sz, debug_types_img) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2259 | FIND(".debug_abbrev", debug_abbv_sz, debug_abbv_img) |
| 2260 | FIND(".debug_str", debug_str_sz, debug_str_img) |
| 2261 | FIND(".debug_ranges", debug_ranges_sz, debug_ranges_img) |
| 2262 | FIND(".debug_loc", debug_loc_sz, debug_loc_img) |
| 2263 | FIND(".debug_frame", debug_frame_sz, debug_frame_img) |
| 2264 | |
| 2265 | FIND(".debug", dwarf1d_sz, dwarf1d_img) |
| 2266 | FIND(".line", dwarf1l_sz, dwarf1l_img) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2267 | |
| 2268 | FIND(".opd", opd_sz_unused, opd_img) |
| 2269 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2270 | FINDX(".eh_frame", ehframe_sz[ehframe_ix], |
| 2271 | ehframe_img[ehframe_ix], |
| 2272 | do { ehframe_ix++; vg_assert(ehframe_ix <= N_EHFRAME_SECTS); } |
| 2273 | while (0) |
| 2274 | ) |
| 2275 | /* Comment_on_EH_FRAME_MULTIPLE_INSTANCES: w.r.t. .eh_frame |
| 2276 | multi-instance kludgery, how are we assured that the order |
| 2277 | in which we fill in ehframe_sz[] and ehframe_img[] is |
| 2278 | consistent with the order in which we previously filled in |
| 2279 | di->ehframe_avma[] and di->ehframe_size[] ? By the fact |
| 2280 | that in both cases, these arrays were filled in by |
| 2281 | iterating over the section headers top-to-bottom. So both |
| 2282 | loops (this one and the previous one) encounter the |
| 2283 | .eh_frame entries in the same order and so fill in these |
| 2284 | arrays in a consistent order. |
| 2285 | */ |
| 2286 | |
| 2287 | # undef FINDX |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2288 | # undef FIND |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2289 | } /* Iterate over section headers (again) */ |
| 2290 | |
| 2291 | /* TOPLEVEL */ |
| 2292 | /* Now, see if we can find a debuginfo object, and if so map it in, and |
| 2293 | put the mapping address and size in dimage and n_dimage. */ |
| 2294 | vg_assert(dimage == 0 && n_dimage == 0); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2295 | |
| 2296 | /* Look for a build-id */ |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2297 | buildid = find_buildid(oimage, n_oimage, False); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2298 | |
| 2299 | /* Look for a debug image */ |
| 2300 | if (buildid != NULL || debuglink_img != NULL) { |
| 2301 | /* Do have a debuglink section? */ |
| 2302 | if (debuglink_img != NULL) { |
| 2303 | UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink_img)+1, 4); |
| 2304 | UInt crc; |
| 2305 | |
| 2306 | vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz); |
| 2307 | |
| 2308 | /* Extract the CRC from the debuglink section */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2309 | crc = ML_(read_UInt)(debuglink_img + crc_offset); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2310 | |
| 2311 | /* See if we can find a matching debug file */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2312 | find_debug_file( di, di->fsm.filename, buildid, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2313 | debuglink_img, crc, False, &dimage, &n_dimage ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2314 | } else { |
| 2315 | /* See if we can find a matching debug file */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2316 | find_debug_file( di, di->fsm.filename, buildid, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2317 | NULL, 0, False, &dimage, &n_dimage ); |
Kenny Root | 9bea4c1 | 2011-12-09 15:14:13 -0800 | [diff] [blame] | 2318 | } |
| 2319 | } |
| 2320 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2321 | if (buildid) { |
| 2322 | ML_(dinfo_free)(buildid); |
| 2323 | buildid = NULL; /* paranoia */ |
| 2324 | } |
| 2325 | |
| 2326 | /* Still no luck? Let's have one last roll of the dice. */ |
| 2327 | if (dimage == 0) { |
| 2328 | vg_assert(n_dimage == 0); |
| 2329 | Bool found = find_ad_hoc_debug_image( di, di->fsm.filename, |
| 2330 | &dimage, &n_dimage ); |
| 2331 | if (found) |
| 2332 | vg_assert(dimage != 0); |
| 2333 | } |
| 2334 | |
| 2335 | /* TOPLEVEL */ |
| 2336 | /* If we were successful in finding a debug image, pull various |
| 2337 | SVMA/bias/size and image addresses out of it. */ |
| 2338 | if (dimage != 0 |
| 2339 | && n_dimage >= sizeof(ElfXX_Ehdr) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2340 | && ML_(is_elf_object_file)((void*)dimage, n_dimage, False)) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2341 | |
| 2342 | /* Pull out and validate program header and section header info */ |
| 2343 | ElfXX_Ehdr* ehdr_dimg = (ElfXX_Ehdr*)dimage; |
| 2344 | ElfXX_Phdr* phdr_dimg = (ElfXX_Phdr*)( ((UChar*)ehdr_dimg) |
| 2345 | + ehdr_dimg->e_phoff ); |
| 2346 | UWord phdr_dnent = ehdr_dimg->e_phnum; |
| 2347 | UWord phdr_dent_szB = ehdr_dimg->e_phentsize; |
| 2348 | ElfXX_Shdr* shdr_dimg = (ElfXX_Shdr*)( ((UChar*)ehdr_dimg) |
| 2349 | + ehdr_dimg->e_shoff ); |
| 2350 | UWord shdr_dnent = ehdr_dimg->e_shnum; |
| 2351 | UWord shdr_dent_szB = ehdr_dimg->e_shentsize; |
| 2352 | UChar* shdr_strtab_dimg = NULL; |
| 2353 | |
| 2354 | /* SVMAs covered by rx and rw segments and corresponding bias. */ |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2355 | Addr rx_dsvma_limit = 0; |
| 2356 | PtrdiffT rx_dbias = 0; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2357 | Addr rw_dsvma_limit = 0; |
| 2358 | PtrdiffT rw_dbias = 0; |
| 2359 | |
| 2360 | Bool need_symtab, need_stabs, need_dwarf2, need_dwarf1; |
| 2361 | |
| 2362 | if (phdr_dnent == 0 |
| 2363 | || !contained_within( |
| 2364 | dimage, n_dimage, |
| 2365 | (Addr)phdr_dimg, phdr_dnent * phdr_dent_szB)) { |
| 2366 | ML_(symerr)(di, True, |
| 2367 | "Missing or invalid ELF Program Header Table" |
| 2368 | " (debuginfo file)"); |
| 2369 | goto out; |
| 2370 | } |
| 2371 | |
| 2372 | if (shdr_dnent == 0 |
| 2373 | || !contained_within( |
| 2374 | dimage, n_dimage, |
| 2375 | (Addr)shdr_dimg, shdr_dnent * shdr_dent_szB)) { |
| 2376 | ML_(symerr)(di, True, |
| 2377 | "Missing or invalid ELF Section Header Table" |
| 2378 | " (debuginfo file)"); |
| 2379 | goto out; |
| 2380 | } |
| 2381 | |
| 2382 | /* Also find the section header's string table, and validate. */ |
| 2383 | /* checked previously by is_elf_object_file: */ |
| 2384 | vg_assert( ehdr_dimg->e_shstrndx != SHN_UNDEF ); |
| 2385 | |
| 2386 | shdr_strtab_dimg |
| 2387 | = (UChar*)( ((UChar*)ehdr_dimg) |
| 2388 | + shdr_dimg[ehdr_dimg->e_shstrndx].sh_offset); |
| 2389 | if (!contained_within( |
| 2390 | dimage, n_dimage, |
| 2391 | (Addr)shdr_strtab_dimg, |
| 2392 | 1/*bogus, but we don't know the real size*/ )) { |
| 2393 | ML_(symerr)(di, True, |
| 2394 | "Invalid ELF Section Header String Table" |
| 2395 | " (debuginfo file)"); |
| 2396 | goto out; |
| 2397 | } |
| 2398 | |
| 2399 | need_symtab = (NULL == symtab_img); |
| 2400 | need_stabs = (NULL == stab_img); |
| 2401 | need_dwarf2 = (NULL == debug_info_img); |
| 2402 | need_dwarf1 = (NULL == dwarf1d_img); |
| 2403 | |
| 2404 | for (i = 0; i < ehdr_dimg->e_phnum; i++) { |
| 2405 | ElfXX_Phdr* phdr |
| 2406 | = INDEX_BIS( (void*)(dimage + ehdr_dimg->e_phoff), |
| 2407 | i, phdr_ent_szB ); |
| 2408 | if (phdr->p_type == PT_LOAD) { |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2409 | for (j = 0; j < VG_(sizeXA)(di->fsm.maps); j++) { |
| 2410 | struct _DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, j); |
| 2411 | if ( phdr->p_offset >= map->foff |
| 2412 | && phdr->p_offset < map->foff + map->size |
| 2413 | && phdr->p_offset + phdr->p_filesz < map->foff |
| 2414 | + map->size) { |
| 2415 | if (map->rx && rx_dsvma_limit == 0) { |
| 2416 | rx_dsvma_limit = phdr->p_vaddr + phdr->p_memsz; |
| 2417 | rx_dbias = map->avma - map->foff + phdr->p_offset |
| 2418 | - phdr->p_vaddr; |
| 2419 | } |
| 2420 | if (map->rw && rw_dsvma_limit == 0) { |
| 2421 | rw_dsvma_limit = phdr->p_vaddr + phdr->p_memsz; |
| 2422 | rw_dbias = map->avma - map->foff + phdr->p_offset |
| 2423 | - phdr->p_vaddr; |
| 2424 | } |
| 2425 | break; |
| 2426 | } |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2427 | } |
| 2428 | } |
| 2429 | } |
| 2430 | |
| 2431 | /* Find all interesting sections */ |
| 2432 | for (i = 0; i < ehdr_dimg->e_shnum; i++) { |
| 2433 | |
| 2434 | /* Find debug svma and bias information for sections |
| 2435 | we found in the main file. */ |
| 2436 | |
| 2437 | # define FIND(sec, seg) \ |
| 2438 | do { ElfXX_Shdr* shdr \ |
| 2439 | = INDEX_BIS( shdr_dimg, i, shdr_dent_szB ); \ |
| 2440 | if (di->sec##_present \ |
| 2441 | && 0 == VG_(strcmp)("." #sec, \ |
| 2442 | shdr_strtab_dimg + shdr->sh_name)) { \ |
| 2443 | vg_assert(di->sec##_size == shdr->sh_size); \ |
| 2444 | vg_assert(di->sec##_avma + shdr->sh_addr + seg##_dbias); \ |
| 2445 | /* Assume we have a correct value for the main */ \ |
| 2446 | /* object's bias. Use that to derive the debuginfo */ \ |
| 2447 | /* object's bias, by adding the difference in SVMAs */ \ |
| 2448 | /* for the corresponding sections in the two files. */ \ |
| 2449 | /* That should take care of all prelinking effects. */ \ |
| 2450 | di->sec##_debug_svma = shdr->sh_addr; \ |
| 2451 | di->sec##_debug_bias \ |
| 2452 | = di->sec##_bias + \ |
| 2453 | di->sec##_svma - di->sec##_debug_svma; \ |
| 2454 | TRACE_SYMTAB("acquiring ." #sec \ |
| 2455 | " debug svma = %#lx .. %#lx\n", \ |
| 2456 | di->sec##_debug_svma, \ |
| 2457 | di->sec##_debug_svma + di->sec##_size - 1); \ |
| 2458 | TRACE_SYMTAB("acquiring ." #sec " debug bias = %#lx\n", \ |
| 2459 | di->sec##_debug_bias); \ |
| 2460 | } \ |
| 2461 | } while (0); |
| 2462 | |
| 2463 | /* SECTION SEGMENT */ |
| 2464 | FIND(text, rx) |
| 2465 | FIND(data, rw) |
| 2466 | FIND(sdata, rw) |
| 2467 | FIND(rodata, rw) |
| 2468 | FIND(bss, rw) |
| 2469 | FIND(sbss, rw) |
| 2470 | |
| 2471 | # undef FIND |
| 2472 | |
| 2473 | /* Same deal as previous FIND, except only do it for those |
| 2474 | sections for which we didn't find anything useful in |
| 2475 | the main file. */ |
| 2476 | |
| 2477 | # define FIND(condition, sec_name, sec_size, sec_img) \ |
| 2478 | do { ElfXX_Shdr* shdr \ |
| 2479 | = INDEX_BIS( shdr_dimg, i, shdr_dent_szB ); \ |
| 2480 | if (condition \ |
| 2481 | && 0 == VG_(strcmp)(sec_name, \ |
| 2482 | shdr_strtab_dimg + shdr->sh_name)) { \ |
| 2483 | Bool nobits; \ |
| 2484 | if (0 != sec_img) \ |
| 2485 | VG_(core_panic)("repeated section!\n"); \ |
| 2486 | sec_img = (void*)(dimage + shdr->sh_offset); \ |
| 2487 | sec_size = shdr->sh_size; \ |
| 2488 | nobits = shdr->sh_type == SHT_NOBITS; \ |
| 2489 | TRACE_SYMTAB( "%18s: dimg %p .. %p\n", \ |
| 2490 | sec_name, \ |
| 2491 | (UChar*)sec_img, \ |
| 2492 | ((UChar*)sec_img) + sec_size - 1); \ |
| 2493 | /* SHT_NOBITS sections have zero size in the file. */ \ |
| 2494 | if ( shdr->sh_offset \ |
| 2495 | + (nobits ? 0 : sec_size) > n_dimage ) { \ |
| 2496 | ML_(symerr)(di, True, \ |
| 2497 | " section beyond image end?!"); \ |
| 2498 | goto out; \ |
| 2499 | } \ |
| 2500 | } \ |
| 2501 | } while (0); |
| 2502 | |
| 2503 | /* NEEDED? NAME SIZE IMAGE addr */ |
| 2504 | FIND(need_symtab, ".symtab", symtab_sz, symtab_img) |
| 2505 | FIND(need_symtab, ".strtab", strtab_sz, strtab_img) |
| 2506 | FIND(need_stabs, ".stab", stab_sz, stab_img) |
| 2507 | FIND(need_stabs, ".stabstr", stabstr_sz, stabstr_img) |
| 2508 | FIND(need_dwarf2, ".debug_line", debug_line_sz, debug_line_img) |
| 2509 | FIND(need_dwarf2, ".debug_info", debug_info_sz, debug_info_img) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2510 | FIND(need_dwarf2, ".debug_types", debug_types_sz, |
| 2511 | debug_types_img) |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2512 | FIND(need_dwarf2, ".debug_abbrev", debug_abbv_sz, debug_abbv_img) |
| 2513 | FIND(need_dwarf2, ".debug_str", debug_str_sz, debug_str_img) |
| 2514 | FIND(need_dwarf2, ".debug_ranges", debug_ranges_sz, |
| 2515 | debug_ranges_img) |
| 2516 | FIND(need_dwarf2, ".debug_loc", debug_loc_sz, debug_loc_img) |
| 2517 | FIND(need_dwarf2, ".debug_frame", debug_frame_sz, |
| 2518 | debug_frame_img) |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2519 | FIND(need_dwarf2, ".gnu_debugaltlink", debugaltlink_sz, |
| 2520 | debugaltlink_img) |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2521 | FIND(need_dwarf1, ".debug", dwarf1d_sz, dwarf1d_img) |
| 2522 | FIND(need_dwarf1, ".line", dwarf1l_sz, dwarf1l_img) |
| 2523 | |
| 2524 | # undef FIND |
| 2525 | } /* Find all interesting sections */ |
| 2526 | } /* do we have a debug image? */ |
| 2527 | |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2528 | /* Look for alternate debug image */ |
| 2529 | if (debugaltlink_img != NULL) { |
| 2530 | UInt buildid_offset = VG_(strlen)(debugaltlink_img)+1; |
| 2531 | |
| 2532 | vg_assert(buildid_offset < debugaltlink_sz); |
| 2533 | |
| 2534 | Char *altbuildid |
| 2535 | = ML_(dinfo_zalloc)("di.fbi.4", |
| 2536 | (debugaltlink_sz - buildid_offset) |
| 2537 | * 2 + 1); |
| 2538 | |
| 2539 | for (j = 0; j < debugaltlink_sz - buildid_offset; j++) |
| 2540 | VG_(sprintf)(altbuildid + 2 * j, |
| 2541 | "%02x", debugaltlink_img[buildid_offset + j]); |
| 2542 | |
| 2543 | /* See if we can find a matching debug file */ |
| 2544 | find_debug_file( di, di->fsm.filename, altbuildid, |
| 2545 | NULL, 0, True, &aimage, &n_aimage ); |
| 2546 | |
| 2547 | ML_(dinfo_free)(altbuildid); |
| 2548 | } |
| 2549 | |
| 2550 | /* TOPLEVEL */ |
| 2551 | /* If we were successful in finding alternate debug image, pull various |
| 2552 | size and image addresses out of it. */ |
| 2553 | if (aimage != 0 |
| 2554 | && n_aimage >= sizeof(ElfXX_Ehdr) |
| 2555 | && ML_(is_elf_object_file)((void*)aimage, n_aimage, True)) { |
| 2556 | |
| 2557 | /* Pull out and validate program header and section header info */ |
| 2558 | ElfXX_Ehdr* ehdr_aimg = (ElfXX_Ehdr*)aimage; |
| 2559 | ElfXX_Shdr* shdr_aimg = (ElfXX_Shdr*)( ((UChar*)ehdr_aimg) |
| 2560 | + ehdr_aimg->e_shoff ); |
| 2561 | UWord shdr_dnent = ehdr_aimg->e_shnum; |
| 2562 | UWord shdr_dent_szB = ehdr_aimg->e_shentsize; |
| 2563 | UChar* shdr_strtab_aimg = NULL; |
| 2564 | |
| 2565 | if (shdr_dnent == 0 |
| 2566 | || !contained_within( |
| 2567 | aimage, n_aimage, |
| 2568 | (Addr)shdr_aimg, shdr_dnent * shdr_dent_szB)) { |
| 2569 | ML_(symerr)(di, True, |
| 2570 | "Missing or invalid ELF Section Header Table" |
| 2571 | " (alternate debuginfo file)"); |
| 2572 | goto out; |
| 2573 | } |
| 2574 | |
| 2575 | /* Also find the section header's string table, and validate. */ |
| 2576 | /* checked previously by is_elf_object_file: */ |
| 2577 | vg_assert( ehdr_aimg->e_shstrndx != SHN_UNDEF ); |
| 2578 | |
| 2579 | shdr_strtab_aimg |
| 2580 | = (UChar*)( ((UChar*)ehdr_aimg) |
| 2581 | + shdr_aimg[ehdr_aimg->e_shstrndx].sh_offset); |
| 2582 | if (!contained_within( |
| 2583 | aimage, n_aimage, |
| 2584 | (Addr)shdr_strtab_aimg, |
| 2585 | 1/*bogus, but we don't know the real size*/ )) { |
| 2586 | ML_(symerr)(di, True, |
| 2587 | "Invalid ELF Section Header String Table" |
| 2588 | " (alternate debuginfo file)"); |
| 2589 | goto out; |
| 2590 | } |
| 2591 | |
| 2592 | /* Find all interesting sections */ |
| 2593 | for (i = 0; i < ehdr_aimg->e_shnum; i++) { |
| 2594 | |
| 2595 | # define FIND(sec_name, sec_size, sec_img) \ |
| 2596 | do { ElfXX_Shdr* shdr \ |
| 2597 | = INDEX_BIS( shdr_aimg, i, shdr_dent_szB ); \ |
| 2598 | if (0 == VG_(strcmp)(sec_name, \ |
| 2599 | shdr_strtab_aimg + shdr->sh_name)) { \ |
| 2600 | if (0 != sec_img) \ |
| 2601 | VG_(core_panic)("repeated section!\n"); \ |
| 2602 | sec_img = (void*)(aimage + shdr->sh_offset); \ |
| 2603 | sec_size = shdr->sh_size; \ |
| 2604 | TRACE_SYMTAB( "%18s: aimg %p .. %p\n", \ |
| 2605 | sec_name, \ |
| 2606 | (UChar*)sec_img, \ |
| 2607 | ((UChar*)sec_img) + sec_size - 1); \ |
| 2608 | } \ |
| 2609 | } while (0); |
| 2610 | |
| 2611 | /* NAME SIZE IMAGE addr */ |
| 2612 | FIND(".debug_line", debug_line_alt_sz, debug_line_alt_img) |
| 2613 | FIND(".debug_info", debug_info_alt_sz, debug_info_alt_img) |
| 2614 | FIND(".debug_abbrev", debug_abbv_alt_sz, debug_abbv_alt_img) |
| 2615 | FIND(".debug_str", debug_str_alt_sz, debug_str_alt_img) |
| 2616 | |
| 2617 | # undef FIND |
| 2618 | } /* Find all interesting sections */ |
| 2619 | } /* do we have a debug image? */ |
| 2620 | |
| 2621 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2622 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2623 | /* Check some sizes */ |
| 2624 | vg_assert((dynsym_sz % sizeof(ElfXX_Sym)) == 0); |
| 2625 | vg_assert((symtab_sz % sizeof(ElfXX_Sym)) == 0); |
| 2626 | |
| 2627 | /* Read symbols */ |
| 2628 | { |
| 2629 | void (*read_elf_symtab)(struct _DebugInfo*,UChar*, |
| 2630 | ElfXX_Sym*,SizeT, |
| 2631 | UChar*,SizeT, |
| 2632 | Bool,UChar*); |
| 2633 | Bool symtab_in_debug; |
| 2634 | # if defined(VGP_ppc64_linux) |
| 2635 | read_elf_symtab = read_elf_symtab__ppc64_linux; |
| 2636 | # else |
| 2637 | read_elf_symtab = read_elf_symtab__normal; |
| 2638 | # endif |
| 2639 | symtab_in_debug = (Addr)symtab_img >= dimage |
| 2640 | && (Addr)symtab_img < dimage + n_dimage; |
| 2641 | read_elf_symtab(di, "symbol table", |
| 2642 | symtab_img, symtab_sz, |
| 2643 | strtab_img, strtab_sz, |
| 2644 | symtab_in_debug, opd_img); |
| 2645 | |
| 2646 | read_elf_symtab(di, "dynamic symbol table", |
| 2647 | dynsym_img, dynsym_sz, |
| 2648 | dynstr_img, dynstr_sz, |
| 2649 | False, opd_img); |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2650 | } /* Read symbols */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2651 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2652 | /* TOPLEVEL */ |
| 2653 | /* Read .eh_frame and .debug_frame (call-frame-info) if any. Do |
| 2654 | the .eh_frame section(s) first. */ |
| 2655 | vg_assert(di->n_ehframe >= 0 && di->n_ehframe <= N_EHFRAME_SECTS); |
| 2656 | for (i = 0; i < di->n_ehframe; i++) { |
| 2657 | /* see Comment_on_EH_FRAME_MULTIPLE_INSTANCES above for why |
| 2658 | this next assertion should hold. */ |
| 2659 | vg_assert(ehframe_sz[i] == di->ehframe_size[i]); |
| 2660 | ML_(read_callframe_info_dwarf3)( di, |
| 2661 | ehframe_img[i], |
| 2662 | ehframe_sz[i], |
| 2663 | di->ehframe_avma[i], |
| 2664 | True/*is_ehframe*/ ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2665 | } |
| 2666 | if (debug_frame_sz) { |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2667 | ML_(read_callframe_info_dwarf3)( di, |
| 2668 | debug_frame_img, debug_frame_sz, |
| 2669 | 0/*assume zero avma*/, |
| 2670 | False/*!is_ehframe*/ ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2671 | } |
| 2672 | |
| 2673 | /* Read the stabs and/or dwarf2 debug information, if any. It |
| 2674 | appears reading stabs stuff on amd64-linux doesn't work, so |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2675 | we ignore it. On s390x stabs also doesnt work and we always |
| 2676 | have the dwarf info in the eh_frame. We also segfault on |
| 2677 | ppc64-linux when reading stabs, so skip that. ppc32-linux |
| 2678 | seems OK though. Also skip on Android. */ |
| 2679 | # if !defined(VGP_amd64_linux) \ |
| 2680 | && !defined(VGP_s390x_linux) \ |
| 2681 | && !defined(VGP_ppc64_linux) \ |
| 2682 | && !defined(VGPV_arm_linux_android) \ |
| 2683 | && !defined(VGPV_x86_linux_android) |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2684 | if (stab_img && stabstr_img) { |
| 2685 | ML_(read_debuginfo_stabs) ( di, stab_img, stab_sz, |
| 2686 | stabstr_img, stabstr_sz ); |
| 2687 | } |
| 2688 | # endif |
| 2689 | /* jrs 2006-01-01: icc-8.1 has been observed to generate |
| 2690 | binaries without debug_str sections. Don't preclude |
| 2691 | debuginfo reading for that reason, but, in |
| 2692 | read_unitinfo_dwarf2, do check that debugstr is non-NULL |
| 2693 | before using it. */ |
| 2694 | if (debug_info_img && debug_abbv_img && debug_line_img |
| 2695 | /* && debug_str_img */) { |
| 2696 | |
| 2697 | /* The old reader: line numbers and unwind info only */ |
| 2698 | ML_(read_debuginfo_dwarf3) ( di, |
| 2699 | debug_info_img, debug_info_sz, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2700 | debug_types_img, debug_types_sz, |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2701 | debug_abbv_img, debug_abbv_sz, |
| 2702 | debug_line_img, debug_line_sz, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2703 | debug_str_img, debug_str_sz, |
| 2704 | debug_str_alt_img, debug_str_alt_sz ); |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2705 | |
| 2706 | /* The new reader: read the DIEs in .debug_info to acquire |
| 2707 | information on variable types and locations. But only if |
| 2708 | the tool asks for it, or the user requests it on the |
| 2709 | command line. */ |
| 2710 | if (VG_(needs).var_info /* the tool requires it */ |
| 2711 | || VG_(clo_read_var_info) /* the user asked for it */) { |
| 2712 | ML_(new_dwarf3_reader)( |
| 2713 | di, debug_info_img, debug_info_sz, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2714 | debug_types_img, debug_types_sz, |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2715 | debug_abbv_img, debug_abbv_sz, |
| 2716 | debug_line_img, debug_line_sz, |
| 2717 | debug_str_img, debug_str_sz, |
| 2718 | debug_ranges_img, debug_ranges_sz, |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2719 | debug_loc_img, debug_loc_sz, |
| 2720 | debug_info_alt_img, debug_info_alt_sz, |
| 2721 | debug_abbv_alt_img, debug_abbv_alt_sz, |
| 2722 | debug_line_alt_img, debug_line_alt_sz, |
| 2723 | debug_str_alt_img, debug_str_alt_sz |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2724 | ); |
| 2725 | } |
| 2726 | } |
| 2727 | if (dwarf1d_img && dwarf1l_img) { |
| 2728 | ML_(read_debuginfo_dwarf1) ( di, dwarf1d_img, dwarf1d_sz, |
| 2729 | dwarf1l_img, dwarf1l_sz ); |
| 2730 | } |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2731 | /* TOPLEVEL */ |
| 2732 | |
| 2733 | } /* "Find interesting sections, read the symbol table(s), read any debug |
| 2734 | information" (a local scope) */ |
| 2735 | |
| 2736 | /* TOPLEVEL */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2737 | res = True; |
| 2738 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2739 | /* If reading Dwarf3 variable type/location info, print a line |
| 2740 | showing the number of variables read for each object. |
| 2741 | (Currently disabled -- is a sanity-check mechanism for |
| 2742 | exp-sgcheck.) */ |
| 2743 | if (0 && (VG_(needs).var_info || VG_(clo_read_var_info))) { |
| 2744 | UWord nVars = 0; |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2745 | if (di->varinfo) { |
| 2746 | for (j = 0; j < VG_(sizeXA)(di->varinfo); j++) { |
| 2747 | OSet* /* of DiAddrRange */ scope |
| 2748 | = *(OSet**)VG_(indexXA)(di->varinfo, j); |
| 2749 | vg_assert(scope); |
| 2750 | VG_(OSetGen_ResetIter)( scope ); |
| 2751 | while (True) { |
| 2752 | DiAddrRange* range = VG_(OSetGen_Next)( scope ); |
| 2753 | if (!range) break; |
| 2754 | vg_assert(range->vars); |
| 2755 | Word w = VG_(sizeXA)(range->vars); |
| 2756 | vg_assert(w >= 0); |
| 2757 | if (0) VG_(printf)("range %#lx %#lx %ld\n", |
| 2758 | range->aMin, range->aMax, w); |
| 2759 | nVars += (UWord)w; |
| 2760 | } |
| 2761 | } |
| 2762 | } |
| 2763 | VG_(umsg)("VARINFO: %7lu vars %7ld text_size %s\n", |
| 2764 | nVars, di->text_size, di->fsm.filename); |
Kenny Root | 9bea4c1 | 2011-12-09 15:14:13 -0800 | [diff] [blame] | 2765 | } |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2766 | /* TOPLEVEL */ |
| 2767 | |
| 2768 | out: |
| 2769 | { |
| 2770 | SysRes m_res; |
| 2771 | /* Last, but not least, heave the image(s) back overboard. */ |
| 2772 | if (dimage) { |
| 2773 | m_res = VG_(am_munmap_valgrind) ( dimage, n_dimage ); |
| 2774 | vg_assert(!sr_isError(m_res)); |
| 2775 | } |
| 2776 | m_res = VG_(am_munmap_valgrind) ( oimage, n_oimage ); |
| 2777 | vg_assert(!sr_isError(m_res)); |
Ben Cheng | 663860b | 2013-01-31 15:38:14 -0800 | [diff] [blame] | 2778 | |
| 2779 | if (svma_ranges) |
| 2780 | VG_(deleteXA)(svma_ranges); |
| 2781 | |
Evgeniy Stepanov | b32f580 | 2011-12-20 11:21:56 +0400 | [diff] [blame] | 2782 | return res; |
| 2783 | } /* out: */ |
| 2784 | |
| 2785 | /* NOTREACHED */ |
Jeff Brown | ed07e00 | 2011-02-03 17:46:23 -0800 | [diff] [blame] | 2786 | } |
| 2787 | |
| 2788 | #endif // defined(VGO_linux) |
| 2789 | |
| 2790 | /*--------------------------------------------------------------------*/ |
| 2791 | /*--- end ---*/ |
| 2792 | /*--------------------------------------------------------------------*/ |