From: Mark Wielaard <mark@klomp.org>
To: frysk@sourceware.org
Subject: [patch] Add debug_frame parsing
Date: Thu, 17 Jan 2008 11:12:00 -0000 [thread overview]
Message-ID: <1200568336.2470.18.camel@dijkstra.wildebeest.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 2020 bytes --]
Hi,
This patch widens out libunwind interface to accept either eh_frame or
debug_frame tables and adds support for parsing debug_frame data. It
currently does a linear search through the data to find the right fde
and corresponding cie by making the right adjustments. Although it does
find the right fde covering the ip ranges, it doesn't always run the cfi
program correctly. So for now the default is still the default and
debug_frame is only used as fallback when eh_frame data cannot be found
(that can be changed in a simple if statement, see the FIXME in UnwindH
- that will however give a couple of test failures). It also fixes a
couple of libunwind issues found when working on this (direct usage of
local memory space, error values not being negative and unw_word being
64bit != dwarf 64 format is always in use).
frysk-imports/libunwind/ChangeLog
2008-01-17 Mark Wielaard <mwielaard@redhat.com>
* include/dwarf.h (dwarf_extract_proc_info_from_fde): Pass
table_start.
* src/dwarf/Gfde.c (is_cie_id): Removed.
(parse_cie): Accept debug and eh cie ids.
(dwarf_extract_proc_info_from_fde): Accept table_start. Calculate
correct cie_addr. Fix error reporting.
* src/dwarf/Gfind_proc_info-lsb.c (linear_search): Don't depend
on local address space. Pass table start for fde parsing.
(dwarf_search_unwind_table): Handle debug_frame by linear search.
* src/mi/Gget_unwind_table.c (get_frame_table, get_debug_table):
new functions.
(unw_get_unwind_table): Call either get_frame_table or
get_debug_table depending on format.
frysk-sys/lib/unwind/ChangeLog
2008-01-17 Mark Wielaard <mwielaard@redhat.com>
* cni/UnwindH.hxx (get_eh_frame_hdr_addr): Find and return
debug_frame address and set pi->format.
(createProcInfoFromElfImage): Handle either debug_frame or
eh_frame addresses.
Tested on x86_64 and x86 (fedora and centos, which both have full
eh_frame coverage, so admittedly most of the new code paths aren't hit
yet).
Cheers,
Mark
[-- Attachment #2: debug_frame.patch --]
[-- Type: text/x-patch, Size: 14394 bytes --]
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 <davidm@hpl.hp.com>
+ Copyright (c) 2008 Red Hat, Inc.
+ Contributed by Mark Wielaard <mwielaard@redhat.com>
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 <davidm@hpl.hp.com>
+ Copyright (c) 2008, Red Hat, Inc.
+ Contributed by Mark Wielaard <mwielaard@redhat.com>
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 <stdio.h>
+
+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;
next reply other threads:[~2008-01-17 11:12 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-17 11:12 Mark Wielaard [this message]
2008-01-17 14:34 ` Andrew Cagney
2008-01-20 15:08 ` Mark Wielaard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1200568336.2470.18.camel@dijkstra.wildebeest.org \
--to=mark@klomp.org \
--cc=frysk@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).