diff --git a/frysk-imports/libunwind/include/dwarf.h b/frysk-imports/libunwind/include/dwarf.h index 47896f6..cf8a74a 100644 --- a/frysk-imports/libunwind/include/dwarf.h +++ b/frysk-imports/libunwind/include/dwarf.h @@ -362,6 +362,7 @@ extern int dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, int *is_register); extern int dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, + unw_word_t table_start, unw_word_t *fde_addr, unw_proc_info_t *pi, int need_unwind_info, diff --git a/frysk-imports/libunwind/src/dwarf/Gfde.c b/frysk-imports/libunwind/src/dwarf/Gfde.c index 11a6433..de2b193 100644 --- a/frysk-imports/libunwind/src/dwarf/Gfde.c +++ b/frysk-imports/libunwind/src/dwarf/Gfde.c @@ -1,6 +1,8 @@ /* libunwind - a platform-independent unwind library Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. Contributed by David Mosberger-Tang + Copyright (c) 2008 Red Hat, Inc. + Contributed by Mark Wielaard This file is part of libunwind. @@ -25,15 +27,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "dwarf_i.h" -static inline int -is_cie_id (unw_word_t val) -{ - /* DWARF spec says CIE_id is 0xffffffff (for 32-bit ELF) or - 0xffffffffffffffff (for 64-bit ELF). However, the GNU toolchain - uses 0. */ - return (val == 0 || val == - (unw_word_t) 1); -} - /* Note: we don't need to keep track of more than the first four characters of the augmentation string, because we (a) ignore any augmentation string contents once we find an unrecognized character @@ -80,7 +73,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0) return ret; /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */ - if (cie_id != 0) + if (cie_id != 0 && cie_id != 0xffffffff) { Debug (1, "Unexpected CIE id %x\n", cie_id); return -UNW_EINVAL; @@ -99,7 +92,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, return ret; /* DWARF says CIE id should be 0xffffffffffffffff, but in .eh_frame, it's 0 */ - if (cie_id != 0) + if (cie_id != 0 && cie_id != 0xffffffffffffffff) { Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id); return -UNW_EINVAL; @@ -217,7 +210,8 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, HIDDEN int dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, - unw_word_t *addrp, unw_proc_info_t *pi, + unw_word_t table_start, unw_word_t *addrp, + unw_proc_info_t *pi, int need_unwind_info, void *arg) { @@ -252,7 +246,12 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0) return ret; - if (is_cie_id (cie_offset)) + /* DWARF spec says CIE_id is 0xffffffff (for 32-bit ELF) or + 0xffffffffffffffff (for 64-bit ELF). However, the GNU toolchain + uses 0. */ + if ((pi->format != UNW_INFO_FORMAT_TABLE && cie_offset == 0) + || (pi->format == UNW_INFO_FORMAT_TABLE + && cie_offset == 0xffffffff)) /* ignore CIEs (happens during linear searches) */ return 0; @@ -260,7 +259,10 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, .debug_frame-relative offset, but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, which is just as fine as it's self-contained. */ - cie_addr = cie_offset_addr - cie_offset; + if (pi->format == UNW_INFO_FORMAT_TABLE) + cie_addr = table_start + cie_offset; + else + cie_addr = cie_offset_addr - cie_offset; } else { @@ -277,7 +279,12 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0) return ret; - if (is_cie_id (cie_offset)) + /* DWARF spec says CIE_id is 0xffffffff (for 32-bit ELF) or + 0xffffffffffffffff (for 64-bit ELF). However, the GNU toolchain + uses 0. */ + if ((pi->format != UNW_INFO_FORMAT_TABLE && cie_offset == 0) + || (pi->format == UNW_INFO_FORMAT_TABLE + && cie_offset == 0xffffffffffffffff)) /* ignore CIEs (happens during linear searches) */ return 0; @@ -285,7 +292,10 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, .debug_frame-relative offset, but the GCC-generated .eh_frame sections instead store a "pcrelative" offset, which is just as fine as it's self-contained. */ - cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); + if (pi->format == UNW_INFO_FORMAT_TABLE) + cie_addr = (unw_word_t) ((uint64_t) table_start + cie_offset); + else + cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset); } if ((ret = parse_cie (as, a, cie_addr, pi, &dci, arg)) < 0) @@ -320,11 +330,12 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a, if (need_unwind_info) { - pi->format = UNW_INFO_FORMAT_TABLE; + // FRYSK LOCAL - we already set this. + // pi->format = UNW_INFO_FORMAT_TABLE; pi->unwind_info_size = sizeof (dci); pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool); if (!pi->unwind_info) - return UNW_ENOMEM; + return -UNW_ENOMEM; if (dci.have_abi_marker) { diff --git a/frysk-imports/libunwind/src/dwarf/Gfind_proc_info-lsb.c b/frysk-imports/libunwind/src/dwarf/Gfind_proc_info-lsb.c index a8a3b69..be22e3e 100644 --- a/frysk-imports/libunwind/src/dwarf/Gfind_proc_info-lsb.c +++ b/frysk-imports/libunwind/src/dwarf/Gfind_proc_info-lsb.c @@ -1,6 +1,8 @@ /* libunwind - a platform-independent unwind library Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. Contributed by David Mosberger-Tang + Copyright (c) 2008, Red Hat, Inc. + Contributed by Mark Wielaard This file is part of libunwind. @@ -52,20 +54,23 @@ struct callback_data unw_dyn_info_t di; /* table info (if single_fde is false) */ }; +#endif /* !UNW_REMOTE_ONLY */ + static int linear_search (unw_addr_space_t as, unw_word_t ip, unw_word_t eh_frame_start, unw_word_t eh_frame_end, unw_word_t fde_count, unw_proc_info_t *pi, int need_unwind_info, void *arg) { - unw_accessors_t *a = unw_get_accessors (unw_local_addr_space); + unw_accessors_t *a = unw_get_accessors (as); unw_word_t i = 0, fde_addr, addr = eh_frame_start; int ret; while (i++ < fde_count && addr < eh_frame_end) { fde_addr = addr; - if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, arg)) + if ((ret = dwarf_extract_proc_info_from_fde (as, a, eh_frame_start, + &addr, pi, 0, arg)) < 0) return ret; @@ -74,7 +79,8 @@ linear_search (unw_addr_space_t as, unw_word_t ip, if (!need_unwind_info) return 1; addr = fde_addr; - if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, + if ((ret = dwarf_extract_proc_info_from_fde (as, a, eh_frame_start, + &addr, pi, need_unwind_info, arg)) < 0) return ret; @@ -84,6 +90,8 @@ linear_search (unw_addr_space_t as, unw_word_t ip, return -UNW_ENOINFO; } +#ifndef UNW_REMOTE_ONLY + /* Info is a pointer to a unw_dyn_info_t structure and, on entry, member u.rti.segbase contains the instruction-pointer we're looking for. */ @@ -361,6 +369,15 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, #endif int ret; + if (di->format == UNW_INFO_FORMAT_TABLE) + { + ret = linear_search (as, ip, di->u.rti.table_data, + di->u.rti.table_data + + di->u.rti.table_len * sizeof (unw_word_t), + ~0UL, pi, need_unwind_info, arg); + return ret; + } + assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE && (ip >= di->start_ip && ip < di->end_ip)); @@ -397,7 +414,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, Debug (15, "ip=0x%lx, start_ip=0x%lx\n", (long) ip, (long) (e->start_ip_offset + segbase)); fde_addr = e->fde_offset + segbase; - if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, + if ((ret = dwarf_extract_proc_info_from_fde (as, a, segbase, &fde_addr, pi, need_unwind_info, arg)) < 0) return ret; diff --git a/frysk-imports/libunwind/src/mi/Gget_unwind_table.c b/frysk-imports/libunwind/src/mi/Gget_unwind_table.c index fc46269..0223013 100644 --- a/frysk-imports/libunwind/src/mi/Gget_unwind_table.c +++ b/frysk-imports/libunwind/src/mi/Gget_unwind_table.c @@ -1,4 +1,4 @@ -// Copyright 2007, Red Hat Inc. +// Copyright 2007, 2008, Red Hat Inc. /* This file is part of libunwind. @@ -25,11 +25,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "dwarf_i.h" #include "dwarf-eh.h" -int -unw_get_unwind_table(unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, - unw_accessors_t *eh_frame_accessors, - unw_word_t eh_frame_hdr_address, - void *eh_frame_arg) +#include + +static int +get_frame_table(unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, + unw_accessors_t *eh_frame_accessors, + unw_word_t eh_frame_hdr_address, + void *eh_frame_arg) { int ret; unw_addr_space_t as = unw_create_addr_space (eh_frame_accessors, 0); @@ -87,7 +89,51 @@ unw_get_unwind_table(unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, di.u.rti.table_data = eh_frame_hdr_address + 12; di.u.rti.segbase = eh_frame_hdr_address; + pi->start_ip = 0; + pi->end_ip = 0; ret = tdep_search_unwind_table (as, ip, &di, pi, need_unwind_info, eh_frame_arg); return ret; } + +static int +get_debug_table(unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, + unw_accessors_t *accessors, + unw_word_t address, + void *arg) +{ + unw_addr_space_t as = unw_create_addr_space (accessors, 0); + + unw_dyn_info_t di; + di.start_ip = pi->start_ip; + di.end_ip = pi->end_ip; + di.format = UNW_INFO_FORMAT_TABLE; + di.gp = pi->gp; + + // XXX Should we use the ti struct of the union? + di.u.rti.name_ptr = 0; + di.u.rti.segbase = address; + di.u.rti.table_data = address; + di.u.rti.table_len = pi->unwind_info_size; + + pi->start_ip = 0; + pi->end_ip = 0; + return tdep_search_unwind_table (as, ip, &di, pi, need_unwind_info, arg); +} + +int +unw_get_unwind_table(unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, + unw_accessors_t *accessors, + unw_word_t address, + void *arg) +{ + if (pi->format == UNW_INFO_FORMAT_TABLE) + return get_debug_table(ip, pi, need_unwind_info, accessors, + address, arg); + + if (pi->format == UNW_INFO_FORMAT_REMOTE_TABLE) + return get_frame_table(ip, pi, need_unwind_info, accessors, + address, arg); + + return -UNW_EINVAL; +} diff --git a/frysk-sys/lib/unwind/cni/UnwindH.hxx b/frysk-sys/lib/unwind/cni/UnwindH.hxx index e69e031..08c8ce1 100644 --- a/frysk-sys/lib/unwind/cni/UnwindH.hxx +++ b/frysk-sys/lib/unwind/cni/UnwindH.hxx @@ -1,6 +1,6 @@ // This file is part of the program FRYSK. // -// Copyright 2007, Red Hat Inc. +// Copyright 2007, 2008, Red Hat Inc. // // FRYSK is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by @@ -488,7 +488,26 @@ get_eh_frame_hdr_addr(unw_proc_info_t *pi, char *image, size_t size, } } - if (ptxt_ndx == -1 || peh_hdr_ndx == -1) + Elf_Data *debug_frame_data = NULL; + size_t shstrndx; + if (elf_getshstrndx (elf, &shstrndx) >= 0) + { + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL + && debug_frame_data == NULL) + { + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) != NULL + && shdr.sh_type == SHT_PROGBITS) + { + const char *name = elf_strptr (elf, shstrndx, shdr.sh_name); + if (strcmp (name, ".debug_frame") == 0) + debug_frame_data = elf_getdata (scn, NULL); + } + } + } + + if (ptxt_ndx == -1 || (peh_hdr_ndx == -1 && debug_frame_data == NULL)) return NULL; GElf_Phdr ptxt, peh_hdr; @@ -547,7 +566,23 @@ get_eh_frame_hdr_addr(unw_proc_info_t *pi, char *image, size_t size, *peh_vaddr = peh_hdr.p_vaddr; - char *hdr = image + peh_hdr.p_offset; + char *hdr; + // FIXME. Currently we prefer eh_frame, but we should switch to + // prefer debug_frame when all bugs have been squashed out of that + // in libunwind. + if (peh_hdr_ndx == -1 + && debug_frame_data != NULL && debug_frame_data->d_buf != NULL + && debug_frame_data->d_size != 0) + { + pi->format = UNW_INFO_FORMAT_TABLE; + pi->unwind_info_size = debug_frame_data->d_size / sizeof (unw_word_t); + hdr = (char *) debug_frame_data->d_buf; + } + else + { + pi->format = UNW_INFO_FORMAT_REMOTE_TABLE; + hdr = image + peh_hdr.p_offset; + } return hdr; } @@ -600,14 +635,26 @@ lib::unwind::TARGET::createProcInfoFromElfImage(lib::unwind::AddressSpace* addre if (eh_table_hdr == NULL) return new lib::unwind::ProcInfo(-UNW_ENOINFO); - int ret = unw_get_unwind_table((unw_word_t) ip, - procInfo, - (int) needUnwindInfo, - &local_accessors, - // virtual address - peh_vaddr, - // address adjustment - eh_table_hdr - peh_vaddr); + int ret; + if (procInfo->format == UNW_INFO_FORMAT_REMOTE_TABLE) + ret = unw_get_unwind_table((unw_word_t) ip, + procInfo, + (int) needUnwindInfo, + &local_accessors, + // virtual address + peh_vaddr, + // address adjustment + eh_table_hdr - peh_vaddr); + else + ret = unw_get_unwind_table((unw_word_t) ip, + procInfo, + (int) needUnwindInfo, + &local_accessors, + // virtual address + 0, + // address adjustment + eh_table_hdr); + logFine(this, logger, "Post unw_get_unwind_table"); lib::unwind::ProcInfo *myInfo;