_UPT_find_proc_info.c revision 25ee9f81727616f3269032c52483e4421d451291
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 elf_dyn_info *edi, Elf64_Phdr *pdyn, Elf64_Addr load_base) 41{ 42 Elf64_Off soff, str_soff; 43 Elf64_Ehdr *ehdr = edi->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 *) edi->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 > edi->ei.size) 72 { 73 Debug (1, "section table outside of image? (%lu > %lu)", 74 soff + ehdr->e_shnum * ehdr->e_shentsize, 75 edi->ei.size); 76 goto done; 77 } 78 79 shdr = (Elf64_Shdr *) ((char *) edi->ei.image + soff); 80 str_shdr = (Elf64_Shdr *) ((char *) edi->ei.image + str_soff); 81 strtab = (char *) edi->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 *) edi->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", edi->ei.image, gp); 95 return gp; 96} 97 98HIDDEN int 99_UPTi_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, 100 char *path, unw_word_t segbase, unw_word_t mapoff, 101 unw_word_t ip) 102{ 103 Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL; 104 Elf64_Ehdr *ehdr; 105 int i; 106 107 if (!_Uelf64_valid_object (&edi->ei)) 108 return -UNW_ENOINFO; 109 110 ehdr = edi->ei.image; 111 phdr = (Elf64_Phdr *) ((char *) edi->ei.image + ehdr->e_phoff); 112 113 for (i = 0; i < ehdr->e_phnum; ++i) 114 { 115 switch (phdr[i].p_type) 116 { 117 case PT_LOAD: 118 if (phdr[i].p_offset == mapoff) 119 ptxt = phdr + i; 120 break; 121 122 case PT_IA_64_UNWIND: 123 punw = phdr + i; 124 break; 125 126 case PT_DYNAMIC: 127 pdyn = phdr + i; 128 break; 129 130 default: 131 break; 132 } 133 } 134 if (!ptxt || !punw) 135 return 0; 136 137 edi->di_cache.start_ip = segbase; 138 edi->di_cache.end_ip = edi->di_cache.start_ip + ptxt->p_memsz; 139 edi->di_cache.gp = find_gp (edi, pdyn, segbase - ptxt->p_vaddr); 140 edi->di_cache.format = UNW_INFO_FORMAT_TABLE; 141 edi->di_cache.u.ti.name_ptr = 0; 142 edi->di_cache.u.ti.segbase = segbase; 143 edi->di_cache.u.ti.table_len = punw->p_memsz / sizeof (unw_word_t); 144 edi->di_cache.u.ti.table_data = (unw_word_t *) 145 ((char *) edi->ei.image + (punw->p_vaddr - ptxt->p_vaddr)); 146 return 1; 147} 148 149#elif UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA \ 150|| UNW_TARGET_PPC32 || UNW_TARGET_PPC64 || UNW_TARGET_ARM 151 152#include "dwarf-eh.h" 153#include "dwarf_i.h" 154 155/* We need our own instance of dwarf_read_encoded_pointer() here since 156 the one in dwarf/Gpe.c is not (and should not be) exported. */ 157int 158dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a, 159 unw_word_t *addr, unsigned char encoding, 160 const unw_proc_info_t *pi, 161 unw_word_t *valp, void *arg) 162{ 163 return dwarf_read_encoded_pointer_inlined (as, a, addr, encoding, 164 pi, valp, arg); 165} 166 167HIDDEN int 168_UPTi_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, 169 char *path, unw_word_t segbase, unw_word_t mapoff, 170 unw_word_t ip) 171{ 172 Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL; 173 unw_word_t addr, eh_frame_start, fde_count, load_base; 174 unw_word_t max_load_addr = 0; 175 unw_word_t start_ip = (unw_word_t) -1; 176 unw_word_t end_ip = 0; 177 struct dwarf_eh_frame_hdr *hdr; 178 unw_proc_info_t pi; 179 unw_accessors_t *a; 180 Elf_W(Ehdr) *ehdr; 181#if UNW_TARGET_ARM 182 const Elf_W(Phdr) *parm_exidx = NULL; 183#endif 184 int i, ret, found = 0; 185 186 /* XXX: Much of this code is Linux/LSB-specific. */ 187 188 if (!elf_w(valid_object) (&edi->ei)) 189 return -UNW_ENOINFO; 190 191 ehdr = edi->ei.image; 192 phdr = (Elf_W(Phdr) *) ((char *) edi->ei.image + ehdr->e_phoff); 193 194 for (i = 0; i < ehdr->e_phnum; ++i) 195 { 196 switch (phdr[i].p_type) 197 { 198 case PT_LOAD: 199 if (phdr[i].p_vaddr < start_ip) 200 start_ip = phdr[i].p_vaddr; 201 202 if (phdr[i].p_vaddr + phdr[i].p_memsz > end_ip) 203 end_ip = phdr[i].p_vaddr + phdr[i].p_memsz; 204 205 if (phdr[i].p_offset == mapoff) 206 ptxt = phdr + i; 207 if ((uintptr_t) edi->ei.image + phdr->p_filesz > max_load_addr) 208 max_load_addr = (uintptr_t) edi->ei.image + phdr->p_filesz; 209 break; 210 211 case PT_GNU_EH_FRAME: 212 peh_hdr = phdr + i; 213 break; 214 215 case PT_DYNAMIC: 216 pdyn = phdr + i; 217 break; 218 219#if UNW_TARGET_ARM 220 case PT_ARM_EXIDX: 221 parm_exidx = phdr + i; 222 break; 223#endif 224 225 default: 226 break; 227 } 228 } 229 230 if (!ptxt) 231 return 0; 232 233 load_base = segbase - ptxt->p_vaddr; 234 start_ip += load_base; 235 end_ip += load_base; 236 237 if (peh_hdr) 238 { 239 if (pdyn) 240 { 241 /* For dynamicly linked executables and shared libraries, 242 DT_PLTGOT is the value that data-relative addresses are 243 relative to for that object. We call this the "gp". */ 244 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset 245 + (char *) edi->ei.image); 246 for (; dyn->d_tag != DT_NULL; ++dyn) 247 if (dyn->d_tag == DT_PLTGOT) 248 { 249 /* Assume that _DYNAMIC is writable and GLIBC has 250 relocated it (true for x86 at least). */ 251 edi->di_cache.gp = dyn->d_un.d_ptr; 252 break; 253 } 254 } 255 else 256 /* Otherwise this is a static executable with no _DYNAMIC. Assume 257 that data-relative addresses are relative to 0, i.e., 258 absolute. */ 259 edi->di_cache.gp = 0; 260 261 hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset 262 + (char *) edi->ei.image); 263 if (hdr->version != DW_EH_VERSION) 264 { 265 Debug (1, "table `%s' has unexpected version %d\n", 266 path, hdr->version); 267 return -UNW_ENOINFO; 268 } 269 270 a = unw_get_accessors (unw_local_addr_space); 271 addr = (unw_word_t) (hdr + 1); 272 273 /* Fill in a dummy proc_info structure. We just need to fill in 274 enough to ensure that dwarf_read_encoded_pointer() can do it's 275 job. Since we don't have a procedure-context at this point, all 276 we have to do is fill in the global-pointer. */ 277 memset (&pi, 0, sizeof (pi)); 278 pi.gp = edi->di_cache.gp; 279 280 /* (Optionally) read eh_frame_ptr: */ 281 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 282 &addr, hdr->eh_frame_ptr_enc, &pi, 283 &eh_frame_start, NULL)) < 0) 284 return -UNW_ENOINFO; 285 286 /* (Optionally) read fde_count: */ 287 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 288 &addr, hdr->fde_count_enc, &pi, 289 &fde_count, NULL)) < 0) 290 return -UNW_ENOINFO; 291 292 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) 293 { 294 #if 1 295 abort (); 296 #else 297 unw_word_t eh_frame_end; 298 299 /* If there is no search table or it has an unsupported 300 encoding, fall back on linear search. */ 301 if (hdr->table_enc == DW_EH_PE_omit) 302 Debug (4, "EH lacks search table; doing linear search\n"); 303 else 304 Debug (4, "EH table has encoding 0x%x; doing linear search\n", 305 hdr->table_enc); 306 307 eh_frame_end = max_load_addr; /* XXX can we do better? */ 308 309 if (hdr->fde_count_enc == DW_EH_PE_omit) 310 fde_count = ~0UL; 311 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) 312 abort (); 313 314 return linear_search (unw_local_addr_space, ip, 315 eh_frame_start, eh_frame_end, fde_count, 316 pi, need_unwind_info, NULL); 317 #endif 318 } 319 320 edi->di_cache.start_ip = start_ip; 321 edi->di_cache.end_ip = end_ip; 322 edi->di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; 323 edi->di_cache.u.rti.name_ptr = 0; 324 /* two 32-bit values (ip_offset/fde_offset) per table-entry: */ 325 edi->di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); 326 edi->di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr) 327 + (addr - (unw_word_t) edi->ei.image 328 - peh_hdr->p_offset)); 329 330 /* For the binary-search table in the eh_frame_hdr, data-relative 331 means relative to the start of that section... */ 332 edi->di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) 333 + ((unw_word_t) hdr - (unw_word_t) edi->ei.image 334 - peh_hdr->p_offset)); 335 found = 1; 336 } 337 338#if UNW_TARGET_ARM 339 if (parm_exidx) 340 { 341 edi->di_arm.format = UNW_INFO_FORMAT_ARM_EXIDX; 342 edi->di_arm.start_ip = start_ip; 343 edi->di_arm.end_ip = end_ip; 344 edi->di_arm.u.rti.name_ptr = (unw_word_t) path; 345 edi->di_arm.u.rti.table_data = load_base + parm_exidx->p_vaddr; 346 edi->di_arm.u.rti.table_len = parm_exidx->p_memsz; 347 found = 1; 348 } 349#endif 350 351#ifdef CONFIG_DEBUG_FRAME 352 /* Try .debug_frame. */ 353 found = dwarf_find_debug_frame (found, &edi->edi.di_debug, ip, segbase, path, 354 start_ip, end_ip); 355#endif 356 357 return found; 358} 359 360#endif /* UNW_TARGET_X86 || UNW_TARGET_X86_64 || UNW_TARGET_HPPA*/ 361 362static int 363get_unwind_info (struct elf_dyn_info *edi, pid_t pid, unw_addr_space_t as, unw_word_t ip) 364{ 365 unsigned long segbase, mapoff; 366 char path[PATH_MAX]; 367 368#if UNW_TARGET_IA64 && defined(__linux) 369 if (!edi->ktab.start_ip && _Uia64_get_kernel_table (&edi->ktab) < 0) 370 return -UNW_ENOINFO; 371 372 if (edi->ktab.format != -1 && ip >= edi->ktab.start_ip && ip < edi->ktab.end_ip) 373 return 0; 374#endif 375 376 if ((edi->di_cache.format != -1 377 && ip >= edi->di_cache.start_ip && ip < edi->di_cache.end_ip) 378#if UNW_TARGET_ARM 379 || (edi->di_debug.format != -1 380 && ip >= edi->di_arm.start_ip && ip < edi->di_arm.end_ip) 381#endif 382 || (edi->di_debug.format != -1 383 && ip >= edi->di_debug.start_ip && ip < edi->di_debug.end_ip)) 384 return 0; 385 386 invalidate_edi(edi); 387 388 if (tdep_get_elf_image (&edi->ei, pid, ip, &segbase, &mapoff, path, 389 sizeof(path)) < 0) 390 return -UNW_ENOINFO; 391 392 /* Here, SEGBASE is the starting-address of the (mmap'ped) segment 393 which covers the IP we're looking for. */ 394 if (_UPTi_find_unwind_table (edi, as, path, segbase, mapoff, ip) < 0) 395 return -UNW_ENOINFO; 396 397 /* This can happen in corner cases where dynamically generated 398 code falls into the same page that contains the data-segment 399 and the page-offset of the code is within the first page of 400 the executable. */ 401 if (edi->di_cache.format != -1 402 && (ip < edi->di_cache.start_ip || ip >= edi->di_cache.end_ip)) 403 edi->di_cache.format = -1; 404 405 if (edi->di_debug.format != -1 406 && (ip < edi->di_debug.start_ip || ip >= edi->di_debug.end_ip)) 407 edi->di_debug.format = -1; 408 409 if (edi->di_cache.format == -1 410#if UNW_TARGET_ARM 411 && edi->di_arm.format == -1 412#endif 413 && edi->di_debug.format == -1) 414 return -UNW_ENOINFO; 415 416 return 0; 417} 418 419int 420_UPT_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 421 int need_unwind_info, void *arg) 422{ 423 struct UPT_info *ui = arg; 424 int ret = -UNW_ENOINFO; 425 426 if (get_unwind_info (&ui->edi, ui->pid, as, ip) < 0) 427 return -UNW_ENOINFO; 428 429#if UNW_TARGET_IA64 430 if (ui->edi.ktab.format != -1) 431 { 432 /* The kernel unwind table resides in local memory, so we have 433 to use the local address space to search it. Since 434 _UPT_put_unwind_info() has no easy way of detecting this 435 case, we simply make a copy of the unwind-info, so 436 _UPT_put_unwind_info() can always free() the unwind-info 437 without ill effects. */ 438 ret = tdep_search_unwind_table (unw_local_addr_space, ip, &ui->edi.ktab, pi, 439 need_unwind_info, arg); 440 if (ret >= 0) 441 { 442 if (!need_unwind_info) 443 pi->unwind_info = NULL; 444 else 445 { 446 void *mem = malloc (pi->unwind_info_size); 447 448 if (!mem) 449 return -UNW_ENOMEM; 450 memcpy (mem, pi->unwind_info, pi->unwind_info_size); 451 pi->unwind_info = mem; 452 } 453 } 454 } 455#endif 456 457 if (ret == -UNW_ENOINFO && ui->edi.di_cache.format != -1) 458 ret = tdep_search_unwind_table (as, ip, &ui->edi.di_cache, 459 pi, need_unwind_info, arg); 460 461#if UNW_TARGET_ARM 462 if (ret == -UNW_ENOINFO && ui->edi.di_arm.format != -1) 463 ret = tdep_search_unwind_table (as, ip, &ui->edi.di_arm, pi, 464 need_unwind_info, arg); 465#endif 466 467 if (ret == -UNW_ENOINFO && ui->edi.di_debug.format != -1) 468 ret = tdep_search_unwind_table (as, ip, &ui->edi.di_debug, pi, 469 need_unwind_info, arg); 470 471 return ret; 472} 473