_UPT_find_proc_info.c revision 6aec15799d0572a484065aed3d97317df0702b17
1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2003-2004 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5This file is part of libunwind. 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be 16included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25 26#include <elf.h> 27#include <fcntl.h> 28#include <string.h> 29#include <unistd.h> 30 31#include <sys/mman.h> 32 33#include "_UPT_internal.h" 34 35#if UNW_TARGET_IA64 36 37#include "elf64.h" 38 39static unw_word_t 40find_gp (struct UPT_info *ui, Elf64_Phdr *pdyn, Elf64_Addr load_base) 41{ 42 Elf64_Off soff, str_soff; 43 Elf64_Ehdr *ehdr = ui->ei.image; 44 Elf64_Shdr *shdr; 45 Elf64_Shdr *str_shdr; 46 Elf64_Addr gp = 0; 47 char *strtab; 48 int i; 49 50 if (pdyn) 51 { 52 /* If we have a PT_DYNAMIC program header, fetch the gp-value 53 from the DT_PLTGOT entry. */ 54 Elf64_Dyn *dyn = (Elf64_Dyn *) (pdyn->p_offset + (char *) ui->ei.image); 55 for (; dyn->d_tag != DT_NULL; ++dyn) 56 if (dyn->d_tag == DT_PLTGOT) 57 { 58 gp = (Elf64_Addr) dyn->d_un.d_ptr + load_base; 59 goto done; 60 } 61 } 62 63 /* Without a PT_DYAMIC header, lets try to look for a non-empty .opd 64 section. If there is such a section, we know it's full of 65 function descriptors, and we can simply pick up the gp from the 66 second word of the first entry in this table. */ 67 68 soff = ehdr->e_shoff; 69 str_soff = soff + (ehdr->e_shstrndx * ehdr->e_shentsize); 70 71 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ui->ei.size) 72 { 73 Debug (1, "section table outside of image? (%lu > %lu)", 74 soff + ehdr->e_shnum * ehdr->e_shentsize, 75 ui->ei.size); 76 goto done; 77 } 78 79 shdr = (Elf64_Shdr *) ((char *) ui->ei.image + soff); 80 str_shdr = (Elf64_Shdr *) ((char *) ui->ei.image + str_soff); 81 strtab = (char *) ui->ei.image + str_shdr->sh_offset; 82 for (i = 0; i < ehdr->e_shnum; ++i) 83 { 84 if (strcmp (strtab + shdr->sh_name, ".opd") == 0 85 && shdr->sh_size >= 16) 86 { 87 gp = ((Elf64_Addr *) ((char *) ui->ei.image + shdr->sh_offset))[1]; 88 goto done; 89 } 90 shdr = (Elf64_Shdr *) (((char *) shdr) + ehdr->e_shentsize); 91 } 92 93 done: 94 Debug (16, "image at %p, gp = %lx\n", ui->ei.image, gp); 95 return gp; 96} 97 98HIDDEN unw_dyn_info_t * 99_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, 100 char *path, unw_word_t segbase, unw_word_t mapoff) 101{ 102 Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL; 103 Elf64_Ehdr *ehdr; 104 int i; 105 106 if (!_Uelf64_valid_object (&ui->ei)) 107 return NULL; 108 109 ehdr = ui->ei.image; 110 phdr = (Elf64_Phdr *) ((char *) ui->ei.image + ehdr->e_phoff); 111 112 for (i = 0; i < ehdr->e_phnum; ++i) 113 { 114 switch (phdr[i].p_type) 115 { 116 case PT_LOAD: 117 if (phdr[i].p_offset == mapoff) 118 ptxt = phdr + i; 119 break; 120 121 case PT_IA_64_UNWIND: 122 punw = phdr + i; 123 break; 124 125 case PT_DYNAMIC: 126 pdyn = phdr + i; 127 break; 128 129 default: 130 break; 131 } 132 } 133 if (!ptxt || !punw) 134 return NULL; 135 136 ui->di_cache.start_ip = segbase; 137 ui->di_cache.end_ip = ui->di_cache.start_ip + ptxt->p_memsz; 138 ui->di_cache.gp = find_gp (ui, pdyn, segbase - ptxt->p_vaddr); 139 ui->di_cache.format = UNW_INFO_FORMAT_TABLE; 140 ui->di_cache.u.ti.name_ptr = 0; 141 ui->di_cache.u.ti.segbase = segbase; 142 ui->di_cache.u.ti.table_len = punw->p_memsz / sizeof (unw_word_t); 143 ui->di_cache.u.ti.table_data = (unw_word_t *) 144 ((char *) ui->ei.image + (punw->p_vaddr - ptxt->p_vaddr)); 145 return &ui->di_cache; 146} 147 148#elif UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA \ 149|| UNW_TARGET_PPC32 || UNW_TARGET_PPC64 || UNW_TARGET_ARM 150 151#include "dwarf-eh.h" 152#include "dwarf_i.h" 153 154/* We need our own instance of dwarf_read_encoded_pointer() here since 155 the one in dwarf/Gpe.c is not (and should not be) exported. */ 156int 157dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a, 158 unw_word_t *addr, unsigned char encoding, 159 const unw_proc_info_t *pi, 160 unw_word_t *valp, void *arg) 161{ 162 return dwarf_read_encoded_pointer_inlined (as, a, addr, encoding, 163 pi, valp, arg); 164} 165 166HIDDEN unw_dyn_info_t * 167_UPTi_find_unwind_table (struct UPT_info *ui, unw_addr_space_t as, 168 char *path, unw_word_t segbase, unw_word_t mapoff) 169{ 170 Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL; 171 unw_word_t addr, eh_frame_start, fde_count, load_base; 172 struct dwarf_eh_frame_hdr *hdr; 173 unw_proc_info_t pi; 174 unw_accessors_t *a; 175 Elf_W(Ehdr) *ehdr; 176 int i, ret; 177 178 /* XXX: Much of this code is Linux/LSB-specific. */ 179 180 if (!elf_w(valid_object) (&ui->ei)) 181 return NULL; 182 183 ehdr = ui->ei.image; 184 phdr = (Elf_W(Phdr) *) ((char *) ui->ei.image + ehdr->e_phoff); 185 186 for (i = 0; i < ehdr->e_phnum; ++i) 187 { 188 switch (phdr[i].p_type) 189 { 190 case PT_LOAD: 191 if (phdr[i].p_offset == mapoff) 192 ptxt = phdr + i; 193 break; 194 195 case PT_GNU_EH_FRAME: 196 peh_hdr = phdr + i; 197 break; 198 199 case PT_DYNAMIC: 200 pdyn = phdr + i; 201 break; 202 203 default: 204 break; 205 } 206 } 207 if (!ptxt || !peh_hdr) 208 return NULL; 209 210 if (pdyn) 211 { 212 /* For dynamicly linked executables and shared libraries, 213 DT_PLTGOT is the value that data-relative addresses are 214 relative to for that object. We call this the "gp". */ 215 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset 216 + (char *) ui->ei.image); 217 for (; dyn->d_tag != DT_NULL; ++dyn) 218 if (dyn->d_tag == DT_PLTGOT) 219 { 220 /* Assume that _DYNAMIC is writable and GLIBC has 221 relocated it (true for x86 at least). */ 222 ui->di_cache.gp = dyn->d_un.d_ptr; 223 break; 224 } 225 } 226 else 227 /* Otherwise this is a static executable with no _DYNAMIC. Assume 228 that data-relative addresses are relative to 0, i.e., 229 absolute. */ 230 ui->di_cache.gp = 0; 231 232 hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset 233 + (char *) ui->ei.image); 234 if (hdr->version != DW_EH_VERSION) 235 { 236 Debug (1, "table `%s' has unexpected version %d\n", 237 path, hdr->version); 238 return 0; 239 } 240 241 a = unw_get_accessors (unw_local_addr_space); 242 addr = (unw_word_t) (hdr + 1); 243 244 /* Fill in a dummy proc_info structure. We just need to fill in 245 enough to ensure that dwarf_read_encoded_pointer() can do it's 246 job. Since we don't have a procedure-context at this point, all 247 we have to do is fill in the global-pointer. */ 248 memset (&pi, 0, sizeof (pi)); 249 pi.gp = ui->di_cache.gp; 250 251 /* (Optionally) read eh_frame_ptr: */ 252 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 253 &addr, hdr->eh_frame_ptr_enc, &pi, 254 &eh_frame_start, NULL)) < 0) 255 return NULL; 256 257 /* (Optionally) read fde_count: */ 258 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 259 &addr, hdr->fde_count_enc, &pi, 260 &fde_count, NULL)) < 0) 261 return NULL; 262 263 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) 264 { 265 abort (); 266#if 0 267 /* If there is no search table or it has an unsupported 268 encoding, fall back on linear search. */ 269 if (hdr->table_enc == DW_EH_PE_omit) 270 Debug (4, "table `%s' lacks search table; doing linear search\n", 271 info->dlpi_name); 272 else 273 Debug (4, "table `%s' has encoding 0x%x; doing linear search\n", 274 info->dlpi_name, hdr->table_enc); 275 276 eh_frame_end = max_load_addr; /* XXX can we do better? */ 277 278 if (hdr->fde_count_enc == DW_EH_PE_omit) 279 fde_count = ~0UL; 280 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) 281 abort (); 282 283 cb_data->single_fde = 1; 284 return linear_search (unw_local_addr_space, ip, 285 eh_frame_start, eh_frame_end, fde_count, 286 pi, need_unwind_info, NULL); 287#endif 288 } 289 290 load_base = segbase - ptxt->p_vaddr; 291 292 ui->di_cache.start_ip = segbase; 293 ui->di_cache.end_ip = ui->di_cache.start_ip + ptxt->p_memsz; 294 ui->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; 295 ui->di_cache.u.rti.name_ptr = 0; 296 /* two 32-bit values (ip_offset/fde_offset) per table-entry: */ 297 ui->di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); 298 ui->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr) 299 + (addr - (unw_word_t) ui->ei.image 300 - peh_hdr->p_offset)); 301 302 /* For the binary-search table in the eh_frame_hdr, data-relative 303 means relative to the start of that section... */ 304 ui->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) 305 + ((unw_word_t) hdr - (unw_word_t) ui->ei.image 306 - peh_hdr->p_offset)); 307 308 return &ui->di_cache; 309} 310 311#endif /* UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA*/ 312 313static unw_dyn_info_t * 314get_unwind_info (struct UPT_info *ui, unw_addr_space_t as, unw_word_t ip) 315{ 316 unsigned long segbase, mapoff; 317 char path[PATH_MAX]; 318 unw_dyn_info_t *di; 319 320#if UNW_TARGET_IA64 && defined(__linux) 321 if (!ui->ktab.start_ip && _Uia64_get_kernel_table (&ui->ktab) < 0) 322 return NULL; 323 324 if (ip >= ui->ktab.start_ip && ip < ui->ktab.end_ip) 325 return &ui->ktab; 326#endif 327 328 if (ip >= ui->di_cache.start_ip && ip < ui->di_cache.end_ip) 329 return &ui->di_cache; 330 331 if (ui->ei.image) 332 { 333 munmap (ui->ei.image, ui->ei.size); 334 ui->ei.image = NULL; 335 ui->ei.size = 0; 336 337 /* invalidate the cache: */ 338 ui->di_cache.start_ip = ui->di_cache.end_ip = 0; 339 } 340 341 if (tdep_get_elf_image (&ui->ei, ui->pid, ip, &segbase, &mapoff) < 0) 342 return NULL; 343 344 /* Here, SEGBASE is the starting-address of the (mmap'ped) segment 345 which covers the IP we're looking for. */ 346 di = _UPTi_find_unwind_table (ui, as, path, segbase, mapoff); 347 if (!di 348 /* This can happen in corner cases where dynamically generated 349 code falls into the same page that contains the data-segment 350 and the page-offset of the code is within the first page of 351 the executable. */ 352 || ip < di->start_ip || ip >= di->end_ip) 353 return NULL; 354 355 return di; 356} 357 358int 359_UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 360 int need_unwind_info, void *arg) 361{ 362 struct UPT_info *ui = arg; 363 unw_dyn_info_t *di; 364 365 di = get_unwind_info (ui, as, ip); 366 if (!di) 367 return -UNW_ENOINFO; 368 369#if UNW_TARGET_IA64 370 if (di == &ui->ktab) 371 { 372 /* The kernel unwind table resides in local memory, so we have 373 to use the local address space to search it. Since 374 _UPT_put_unwind_info() has no easy way of detecting this 375 case, we simply make a copy of the unwind-info, so 376 _UPT_put_unwind_info() can always free() the unwind-info 377 without ill effects. */ 378 int ret = tdep_search_unwind_table (unw_local_addr_space, ip, di, pi, 379 need_unwind_info, arg); 380 if (ret >= 0) 381 { 382 if (!need_unwind_info) 383 pi->unwind_info = NULL; 384 else 385 { 386 void *mem = malloc (pi->unwind_info_size); 387 388 if (!mem) 389 return -UNW_ENOMEM; 390 memcpy (mem, pi->unwind_info, pi->unwind_info_size); 391 pi->unwind_info = mem; 392 } 393 } 394 return ret; 395 } 396 else 397#endif 398 return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg); 399} 400