diff --git a/frysk-imports/libunwind/include/libunwind-common.h.in b/frysk-imports/libunwind/include/libunwind-common.h.in index 497a7b4..a837055 100644 --- a/frysk-imports/libunwind/include/libunwind-common.h.in +++ b/frysk-imports/libunwind/include/libunwind-common.h.in @@ -252,8 +252,10 @@ extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *); extern const char *unw_strerror (int); extern int unw_get_unwind_table(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, int need_unwind_info, - void *image, size_t size, - unsigned long segbase, unsigned long mapoff, - void *arg); + void *arg, + unw_accessors_t *eh_frame_accessors, + unw_word_t eh_frame_hdr_address, + void *eh_frame_arg, + unw_word_t peh_vaddr); extern unw_addr_space_t unw_local_addr_space; diff --git a/frysk-imports/libunwind/src/mi/Gget_unwind_table.c b/frysk-imports/libunwind/src/mi/Gget_unwind_table.c index 2acb947..1d905b6 100644 --- a/frysk-imports/libunwind/src/mi/Gget_unwind_table.c +++ b/frysk-imports/libunwind/src/mi/Gget_unwind_table.c @@ -22,177 +22,72 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "libunwind_i.h" -//#include "remote.h" +#include "dwarf_i.h" #include "dwarf-eh.h" int -unw_get_unwind_table(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, - int need_unwind_info, void *image, size_t size, - unsigned long segbase, unsigned long mapoff, void *arg) +unw_get_unwind_table(unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg, + unw_accessors_t *eh_frame_accessors, + unw_word_t eh_frame_hdr_address, + void *eh_frame_arg, + unw_word_t peh_vaddr) { - Debug(99, "Entering get_unwind_table\n"); - Elf_W(Phdr) *phdr, *ptxt = NULL, *peh_hdr = NULL, *pdyn = NULL; - unw_word_t eh_frame_start, fde_count, load_base; - char *addr; - struct dwarf_eh_frame_hdr *hdr; - Elf_W(Ehdr) *ehdr; - int i, ret; - unw_dyn_info_t di_cache; - - if (size <= EI_CLASS) - return -1; - - Debug(99, "Checking elf size\n"); - if (!(memcmp (image, ELFMAG, SELFMAG) == 0 - && ((uint8_t *) image)[EI_CLASS] == ELF_CLASS)) - return -1; - - Debug(99, "Checked elf class\n"); - ehdr = image; - phdr = (Elf_W(Phdr) *) ((char *) image + ehdr->e_phoff); - for (i = 0; i < ehdr->e_phnum; ++i) - { - switch (phdr[i].p_type) - { - case PT_LOAD: - if (phdr[i].p_offset == mapoff) - ptxt = phdr + i; - break; - - case PT_GNU_EH_FRAME: - peh_hdr = phdr + i; - break; - - case PT_DYNAMIC: - pdyn = phdr + i; - break; - - default: - break; - } - } - - Debug(99, "Traversed headers\n"); - if (!ptxt || !peh_hdr) - return -UNW_ENOINFO; - - if (pdyn) - { - Debug(99, "Got dynamic header\n"); - /* For dynamicly linked executables and shared libraries, - DT_PLTGOT is the value that data-relative addresses are - relative to for that object. We call this the "gp". */ - Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(pdyn->p_offset - + (char *) image); - for (; dyn->d_tag != DT_NULL; ++dyn) - if (dyn->d_tag == DT_PLTGOT) - { - /* Assume that _DYNAMIC is writable and GLIBC has - relocated it (true for x86 at least). */ - di_cache.gp = dyn->d_un.d_ptr; - break; - } - } - else - /* Otherwise this is a static executable with no _DYNAMIC. Assume - that data-relative addresses are relative to 0, i.e., - absolute. */ - di_cache.gp = 0; - - Debug(99, "Got eh_frame_hdr\n"); - hdr = (struct dwarf_eh_frame_hdr *) (peh_hdr->p_offset - + (char *) image); - if (hdr->version != DW_EH_VERSION) - { - Debug (1, "table has unexpected version %d\n", - hdr->version); - return 0; - } - - Debug(99, "EH_VERSION is correct\n"); - - addr = hdr + 1; - Debug (99, "Got addr\n"); - /* Fill in a dummy proc_info structure. We just need to fill in - enough to ensure that dwarf_read_encoded_pointer() can do it's - job. Since we don't have a procedure-context at this point, all - we have to do is fill in the global-pointer. */ - memset (pi, 0, sizeof (*pi)); - Debug(99, "cleared pi\n"); - pi->gp = di_cache.gp; - - Debug(99, "set pi gp\n"); - -// The following is a local address space memory accessor used by -// dwarf_read_encoded_pointer. The arg pointer is the base address, -// addr is the offset from the base address. - int - local_access_mem (unw_addr_space_t as, unw_word_t addr, - unw_word_t *val, int write, void *arg) - { - Debug(99, "entering local_access_mem, reading addr: 0x%lx into: %p\n", - (long) addr, val); - if (write) - { - // Writing is not supported - return -UNW_EINVAL; - } - else - { - *val = *(unw_word_t *) (addr + (char *) arg); - Debug (16, "mem[%x] -> %x\n", (addr + (char *) arg), *val); - } - Debug(99, "leaving local_access_mem\n"); - return 0; - } - - unw_accessors_t local_accessors = {NULL, NULL, NULL, local_access_mem, - NULL, NULL, NULL, NULL, NULL}; - unw_addr_space_t local_addr_space - = unw_create_addr_space(&local_accessors, 0); - - unw_word_t start = 0; + int ret; + unw_word_t start = eh_frame_hdr_address; + + // Version + unsigned char version; + if ((ret = dwarf_readu8 (as, eh_frame_accessors, &start, + &version, eh_frame_arg)) < 0) + return -UNW_ENOINFO; + + if (version != DW_EH_VERSION) + return -UNW_ENOINFO; + + unsigned char eh_frame_ptr_enc; + if ((ret = dwarf_readu8 (as, eh_frame_accessors, &start, + &eh_frame_ptr_enc, eh_frame_arg)) < 0) + return -UNW_ENOINFO; + + unsigned char fde_count_enc; + if ((ret = dwarf_readu8 (as, eh_frame_accessors, &start, + &fde_count_enc, eh_frame_arg)) < 0) + return -UNW_ENOINFO; + + unsigned char table_enc; + if ((ret = dwarf_readu8 (as, eh_frame_accessors, &start, + &table_enc, eh_frame_arg)) < 0) + return -UNW_ENOINFO; - /* (Optionally) read eh_frame_ptr: */ - if ((ret = dwarf_read_encoded_pointer (local_addr_space, &local_accessors, - &start, hdr->eh_frame_ptr_enc, pi, - &eh_frame_start, addr)) < 0) - return -1; - - Debug(99, "read eh_frame_start: 0x%lx\n", (long) eh_frame_start); - - /* (Optionally) read fde_count: */ - if ((ret = dwarf_read_encoded_pointer (local_addr_space, &local_accessors, - &start, hdr->fde_count_enc, pi, - &fde_count, addr)) < 0) - return -1; - - Debug(99, "read fde_count: 0x%lx\n", (long) fde_count); - if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) - { - return -1; - } + if (table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) + return -UNW_ENOINFO; + + unw_word_t eh_frame_start; + if ((ret = dwarf_read_encoded_pointer (as, eh_frame_accessors, + &start, eh_frame_ptr_enc, pi, + &eh_frame_start, eh_frame_arg)) < 0) + return -UNW_ENOINFO; - addr += start; - - load_base = segbase - ptxt->p_vaddr; - - di_cache.start_ip = segbase; - di_cache.end_ip = di_cache.start_ip + ptxt->p_memsz; - di_cache.format = UNW_INFO_FORMAT_REMOTE_TABLE; - di_cache.u.rti.name_ptr = 0; - /* two 32-bit values (ip_offset/fde_offset) per table-entry: */ - di_cache.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); - di_cache.u.rti.table_data = ((load_base + peh_hdr->p_vaddr) - + (addr - (unw_word_t) image - - peh_hdr->p_offset)); - - /* For the binary-search table in the eh_frame_hdr, data-relative - means relative to the start of that section... */ - di_cache.u.rti.segbase = ((load_base + peh_hdr->p_vaddr) - + ((unw_word_t) hdr - (unw_word_t) image - - peh_hdr->p_offset)); - - Debug(99, "Leaving get_unwind_table\n"); - return tdep_search_unwind_table (as, ip, &di_cache, pi, need_unwind_info, arg); + unw_word_t fde_count; + if ((ret = dwarf_read_encoded_pointer (as, eh_frame_accessors, + &start, fde_count_enc, pi, + &fde_count, eh_frame_arg)) < 0) + return -UNW_ENOINFO; + + unw_dyn_info_t di; + di.start_ip = pi->start_ip; + di.end_ip = pi->end_ip; + di.format = UNW_INFO_FORMAT_REMOTE_TABLE; + di.gp = pi->gp; + di.u.rti.name_ptr = 0; + /* two 32-bit values (ip_offset/fde_offset) per table-entry: + For the binary-search table in the eh_frame_hdr, data-relative + means relative to the start of that section... + So for now we pass in peh_vaddr and use the main as for access. */ + di.u.rti.table_len = (fde_count * 8) / sizeof (unw_word_t); + di.u.rti.table_data = peh_vaddr + 12; + di.u.rti.segbase = peh_vaddr; + + return tdep_search_unwind_table (as, ip, &di, pi, need_unwind_info, arg); } diff --git a/frysk-sys/lib/unwind/ElfImage.java b/frysk-sys/lib/unwind/ElfImage.java index 7707f09..e938c96 100644 --- a/frysk-sys/lib/unwind/ElfImage.java +++ b/frysk-sys/lib/unwind/ElfImage.java @@ -43,6 +43,8 @@ package lib.unwind; public class ElfImage { + final String name; + long elfImage; long size; @@ -53,8 +55,9 @@ public class ElfImage int ret = 0; - public ElfImage (long elfImage, long size, long segbase, long mapoff) + public ElfImage (String name, long elfImage, long size, long segbase, long mapoff) { + this.name = name; this.elfImage = elfImage; this.size = size; this.segbase = segbase; @@ -63,6 +66,7 @@ public class ElfImage public ElfImage (int ret) { + this.name = "ERROR: " + Integer.toString(ret); this.ret = ret; } @@ -71,7 +75,7 @@ public class ElfImage if (ret != 0) return "Bad Elf Image, ret: " + ret; - return "Elf Image: 0x" + Long.toHexString(elfImage) + " size: " + size + return "Elf Image (" + name + "): 0x" + Long.toHexString(elfImage) + " size: " + size + " segbase: 0x" + Long.toHexString(segbase) + " mapoff: 0x" + Long.toHexString(mapoff); } diff --git a/frysk-sys/lib/unwind/cni/ElfImage.cxx b/frysk-sys/lib/unwind/cni/ElfImage.cxx index d521643..3f7fdd3 100644 --- a/frysk-sys/lib/unwind/cni/ElfImage.cxx +++ b/frysk-sys/lib/unwind/cni/ElfImage.cxx @@ -80,7 +80,7 @@ lib::unwind::ElfImage::mapElfImage(jstring elfImageName, jlong segbase, jlong hi return new lib::unwind::ElfImage((jint) -1); lib::unwind::ElfImage* elfImage - = new lib::unwind::ElfImage((jlong) image, (jlong) size, + = new lib::unwind::ElfImage(elfImageName, (jlong) image, (jlong) size, (jlong) segbase, (jlong) mapoff); return elfImage; diff --git a/frysk-sys/lib/unwind/cni/UnwindH.hxx b/frysk-sys/lib/unwind/cni/UnwindH.hxx index 1d13156..e1cc430 100644 --- a/frysk-sys/lib/unwind/cni/UnwindH.hxx +++ b/frysk-sys/lib/unwind/cni/UnwindH.hxx @@ -47,7 +47,9 @@ #include #include LIBUNWIND_TARGET_H -#include + +#include +#include #include @@ -135,11 +137,22 @@ static int access_mem (::unw_addr_space_t as, ::unw_word_t addr, ::unw_word_t *valp, int write, void *arg) { - jbyteArray tmp = JvNewByteArray (sizeof (unw_word_t)); - memcpy (elements(tmp), valp, JvGetArrayLength(tmp)); - int ret = addressSpace(arg)->accessMem((jlong) addr, tmp, (jboolean) write); - memcpy(valp, elements(tmp), JvGetArrayLength(tmp)); - return ret; + try + { + jbyteArray tmp = JvNewByteArray (sizeof (unw_word_t)); + memcpy (elements(tmp), valp, JvGetArrayLength(tmp)); + int ret = addressSpace(arg)->accessMem((jlong) addr, + tmp, (jboolean) write); + memcpy(valp, elements(tmp), JvGetArrayLength(tmp)); + return ret; + } + catch (java::lang::RuntimeException *t) + { + // We have to catch all RuntimeExceptions here since there + // is no indicator for just "invalid memory location". + // Core files might have "holes" in their memory. + return -UNW_EINVAL; + } } /* @@ -429,26 +442,177 @@ lib::unwind::TARGET::getProcInfo(gnu::gcj::RawDataManaged* cursor) return myInfo; } +// Return NULL when eh_frame_hdr cannot be found. +// Also fills in ip->start_ip, ip->end_ip and ip->gp. +// peh_vaddr will point to the address of the eh_frame_hdr in the main +// address space of the inferior. +static void * +get_eh_frame_hdr_addr(unw_proc_info_t *pi, char *image, size_t size, + unsigned long segbase, unw_word_t *peh_vaddr) +{ + if (elf_version(EV_CURRENT) == EV_NONE) + return NULL; + + Elf *elf = elf_memory(image, size); + if (elf == NULL) + return NULL; + + GElf_Ehdr ehdr; + if (gelf_getehdr(elf, &ehdr) == NULL) + return NULL; + + GElf_Phdr phdr; + int ptxt_ndx = -1, peh_hdr_ndx = -1, pdyn_ndx = -1; + for (int i = 0; i < ehdr.e_phnum; i++) + { + if (gelf_getphdr (elf, i, &phdr) == NULL) + return NULL; + + switch (phdr.p_type) + { + case PT_LOAD: + if (phdr.p_vaddr == segbase) + ptxt_ndx = i; + break; + + case PT_GNU_EH_FRAME: + peh_hdr_ndx = i; + break; + + case PT_DYNAMIC: + pdyn_ndx = i; + break; + + default: + break; + } + } + + if (ptxt_ndx == -1 || peh_hdr_ndx == -1) + return NULL; + + GElf_Phdr ptxt, peh_hdr; + if (gelf_getphdr (elf, ptxt_ndx, &ptxt) == NULL) + return NULL; + + if (gelf_getphdr (elf, peh_hdr_ndx, &peh_hdr) == NULL) + return NULL; + + if (pdyn_ndx != -1) + { + /* For dynamicly linked executables and shared libraries, + DT_PLTGOT is the value that data-relative addresses are + relative to for that object. We call this the "gp". */ + GElf_Phdr pdyn; + if (gelf_getphdr (elf, pdyn_ndx, &pdyn) == NULL) + return NULL; + + Elf_Scn *pdyn_scn = gelf_offscn(elf, pdyn.p_offset); + if (pdyn_scn == NULL) + return NULL; + + Elf_Data *pdyn_data; + pdyn_data = elf_getdata (pdyn_scn, NULL); + if (pdyn_data == NULL) + return NULL; + + GElf_Shdr pdyn_shdr; + if (gelf_getshdr (pdyn_scn, &pdyn_shdr) == NULL) + return NULL; + + for (unsigned int i = 0; + i < pdyn_shdr.sh_size / pdyn_shdr.sh_entsize; i++) + { + GElf_Dyn dyn; + if (gelf_getdyn (pdyn_data, i, &dyn) == NULL) + return NULL; + + if (dyn.d_tag == DT_PLTGOT) + { + /* Assume that _DYNAMIC is writable and GLIBC has + relocated it (true for x86 at least). */ + pi->gp = dyn.d_un.d_ptr; + break; + } + } + } + else + /* Otherwise this is a static executable with no _DYNAMIC. Assume + that data-relative addresses are relative to 0, i.e., + absolute. */ + pi->gp = 0; + + pi->start_ip = segbase; + pi->end_ip = segbase + ptxt.p_memsz; + + *peh_vaddr = peh_hdr.p_vaddr; + + char *hdr = image + peh_hdr.p_offset; + return hdr; +} + +// The following is a local address space memory accessor used by +// unw_get_unwind_table to access the eh_frame_hdr. The arg pointer +// is the base address, addr is the offset from the base address. +static int +local_access_mem (unw_addr_space_t as, unw_word_t addr, + unw_word_t *val, int write, void *arg) +{ + // Writing is not supported + if (write) + return -UNW_EINVAL; + else + *val = *(unw_word_t *) (addr + (char *) arg); + + return UNW_ESUCCESS; +} + +static unw_accessors_t local_accessors + = {NULL, NULL, NULL, local_access_mem, NULL, NULL, NULL, NULL}; + lib::unwind::ProcInfo* lib::unwind::TARGET::createProcInfoFromElfImage(lib::unwind::AddressSpace* addressSpace, jlong ip, jboolean needUnwindInfo, lib::unwind::ElfImage* elfImage) { - if (elfImage == NULL) - return new lib::unwind::ProcInfo(UNW_ENOINFO); + if (elfImage == NULL || elfImage->ret != 0) + return new lib::unwind::ProcInfo(-UNW_ENOINFO); unw_proc_info_t *procInfo = (::unw_proc_info_t *) JvAllocBytes(sizeof (::unw_proc_info_t)); + unw_addr_space_t as = (unw_addr_space_t) addressSpace->addressSpace; + logFine(this, logger, "Pre unw_get_unwind_table"); - int ret = unw_get_unwind_table((unw_addr_space_t) addressSpace->addressSpace, - (unw_word_t) ip, procInfo, + + unw_word_t peh_vaddr = 0; + void *eh_table_hdr = get_eh_frame_hdr_addr(procInfo, + (char *) elfImage->elfImage, + elfImage->size, + elfImage->segbase, + &peh_vaddr); + + //jsize length = JvGetStringUTFLength (elfImage->name); + //char buffer[length + 1]; + //JvGetStringUTFRegion (elfImage->name, 0, elfImage->name->length(), buffer); + //buffer[length] = '\0'; + //fprintf(stderr, "%s: %p\n", buffer, eh_table_hdr); + + if (eh_table_hdr == NULL) + return new lib::unwind::ProcInfo(-UNW_ENOINFO); + + int ret = unw_get_unwind_table(as, + (unw_word_t) ip, + procInfo, (int) needUnwindInfo, - (void *) elfImage->elfImage, - elfImage->size, elfImage->segbase, - elfImage->mapoff, (void *) addressSpace); - + (void *) addressSpace, + &local_accessors, + 0, + eh_table_hdr, + peh_vaddr); + + logFine(this, logger, "Post unw_get_unwind_table"); lib::unwind::ProcInfo *myInfo; if (ret < 0) @@ -541,7 +705,7 @@ lib::unwind::TARGET::createElfImageFromVDSO(lib::unwind::AddressSpace* addressSp mapoff = 0; lib::unwind::ElfImage* elfImage - = new lib::unwind::ElfImage((jlong) image, (jlong) size, + = new lib::unwind::ElfImage(JvNewStringLatin1("[vdso]"), (jlong) image, (jlong) size, (jlong) segbase, (jlong) mapoff); jLogFine(this, logger, "elfImage returned: {1}", elfImage);