summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Cohen <wcohen@redhat.com>2009-05-20 19:03:34 -0400
committerWilliam Cohen <wcohen@redhat.com>2009-05-20 19:03:34 -0400
commitc14aff52d5ec1f8a1326060b6378a973d3bb5b2a (patch)
treea6c5f4ce56a8367153cd2ed6399275fa0029422d
parent34029cd3afe690f8481f8921047ec39dc325d945 (diff)
parent4acb6884cdfa8205a60b203aa9e48ab79efd9ea2 (diff)
downloadsystemtap-steved-c14aff52d5ec1f8a1326060b6378a973d3bb5b2a.tar.gz
systemtap-steved-c14aff52d5ec1f8a1326060b6378a973d3bb5b2a.tar.xz
systemtap-steved-c14aff52d5ec1f8a1326060b6378a973d3bb5b2a.zip
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
-rw-r--r--runtime/sym.h8
-rw-r--r--runtime/unwind.c203
-rw-r--r--runtime/unwind/unwind.h4
-rw-r--r--tapset/timestamp_gtod.stp17
-rwxr-xr-xtestsuite/buildok/gtod_init.stp13
-rwxr-xr-xtestsuite/buildok/gtod_noinit.stp13
-rw-r--r--testsuite/systemtap.base/gtod_init.exp29
-rw-r--r--translate.cxx144
8 files changed, 258 insertions, 173 deletions
diff --git a/runtime/sym.h b/runtime/sym.h
index 80c334fb..7e28ebe6 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -42,11 +42,13 @@ struct _stp_module {
unsigned long dwarf_module_base;
/* the stack unwind data for this module */
- void *unwind_data;
+ void *debug_frame;
+ void *eh_frame;
void *unwind_hdr;
- uint32_t unwind_data_len;
+ uint32_t debug_frame_len;
+ uint32_t eh_frame_len;
uint32_t unwind_hdr_len;
- uint32_t unwind_is_ehframe; /* unwind data comes from .eh_frame */
+ unsigned long eh_frame_addr; /* Orig load address (offset) .eh_frame */
/* build-id information */
unsigned char *build_id_bits;
unsigned long build_id_offset;
diff --git a/runtime/unwind.c b/runtime/unwind.c
index f03534bd..43bda717 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -8,9 +8,9 @@
*
* This code is released under version 2 of the GNU GPL.
*
- * This code currently does stack unwinding in the
- * kernel and modules. It will need some extension to handle
- * userspace unwinding.
+ * This code currently does stack unwinding in the kernel and modules.
+ * It has been extended to handle userspace unwinding using systemtap
+ * data structures.
*/
#include "unwind/unwind.h"
@@ -87,7 +87,8 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
}
/* given an FDE, find its CIE */
-static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m)
+static const u32 *cie_for_fde(const u32 *fde, void *unwind_data,
+ int is_ehframe)
{
const u32 *cie;
@@ -96,7 +97,7 @@ static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m)
return &bad_cie;
/* CIE id for eh_frame is 0, otherwise 0xffffffff */
- if (m->unwind_is_ehframe && fde[1] == 0)
+ if (is_ehframe && fde[1] == 0)
return &not_fde;
else if (fde[1] == 0xffffffff)
return &not_fde;
@@ -104,18 +105,18 @@ static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m)
/* OK, must be an FDE. Now find its CIE. */
/* CIE_pointer must be a proper offset */
- if ((fde[1] & (sizeof(*fde) - 1)) || fde[1] > (unsigned long)(fde + 1) - (unsigned long)m->unwind_data) {
+ if ((fde[1] & (sizeof(*fde) - 1)) || fde[1] > (unsigned long)(fde + 1) - (unsigned long)unwind_data) {
dbug_unwind(1, "fde[1]=%lx fde+1=%lx, unwind_data=%lx %lx\n",
(unsigned long)fde[1], (unsigned long)(fde + 1),
- (unsigned long)m->unwind_data, (unsigned long)(fde + 1) - (unsigned long)m->unwind_data);
+ (unsigned long)unwind_data, (unsigned long)(fde + 1) - (unsigned long)unwind_data);
return NULL; /* this is not a valid FDE */
}
/* cie pointer field is different in eh_frame vs debug_frame */
- if (m->unwind_is_ehframe)
+ if (is_ehframe)
cie = fde + 1 - fde[1] / sizeof(*fde);
else
- cie = m->unwind_data + fde[1];
+ cie = unwind_data + fde[1];
if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
|| (*cie & (sizeof(*cie) - 1))
@@ -427,21 +428,81 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
return result && ptr.p8 == end && (targetLoc == 0 || state->label == NULL);
}
+#ifdef DEBUG_UNWIND
+static const char *_stp_enc_hi_name[] = {
+ "DW_EH_PE",
+ "DW_EH_PE_pcrel",
+ "DW_EH_PE_textrel",
+ "DW_EH_PE_datarel",
+ "DW_EH_PE_funcrel",
+ "DW_EH_PE_aligned"
+};
+static const char *_stp_enc_lo_name[] = {
+ "_absptr",
+ "_uleb128",
+ "_udata2",
+ "_udata4",
+ "_udata8",
+ "_sleb128",
+ "_sdata2",
+ "_sdata4",
+ "_sdata8"
+};
+static char *_stp_eh_enc_name(signed type)
+{
+ static char buf[64];
+ int hi, low;
+ if (type == DW_EH_PE_omit)
+ return "DW_EH_PE_omit";
+
+ hi = (type & DW_EH_PE_ADJUST) >> 4;
+ low = type & DW_EH_PE_FORM;
+ if (hi > 5 || low > 4 || (low == 0 && (type & DW_EH_PE_signed))) {
+ sprintf(buf, "ERROR:encoding=0x%x", type);
+ return buf;
+ }
+
+ buf[0] = 0;
+ if (type & DW_EH_PE_indirect)
+ strlcpy(buf, "DW_EH_PE_indirect|", sizeof(buf));
+ strlcat(buf, _stp_enc_hi_name[hi], sizeof(buf));
+
+ if (type & DW_EH_PE_signed)
+ low += 4;
+ strlcat(buf, _stp_enc_lo_name[low], sizeof(buf));
+ return buf;
+}
+#endif /* DEBUG_UNWIND */
+
// If this is an address inside a module, adjust for section relocation
// and the elfutils base relocation done during loading of the .dwarf_frame
// in translate.cxx.
static unsigned long
adjustStartLoc (unsigned long startLoc,
struct _stp_module *m,
- struct _stp_section *s)
+ struct _stp_section *s,
+ unsigned ptrType, int is_ehframe)
{
/* XXX - some, or all, of this should really be done by
- _stp_module_relocate. */
+ _stp_module_relocate and/or read_pointer. */
+ dbug_unwind(2, "adjustStartLoc=%lx, ptrType=%s, m=%s, s=%s eh=%d\n",
+ startLoc, _stp_eh_enc_name(ptrType), m->name, s->name, is_ehframe);
if (startLoc == 0
|| strcmp (m->name, "kernel") == 0
- || strcmp (s->name, ".absolute") == 0)
+ || (strcmp (s->name, ".absolute") == 0 && !is_ehframe))
return startLoc;
+ /* eh_frame data has been loaded in the kernel, so readjust offset. */
+ if (is_ehframe) {
+ dbug_unwind(2, "eh_frame=%lx, eh_frame_addr=%lx\n", (unsigned long) m->eh_frame, m->eh_frame_addr);
+ if ((ptrType & DW_EH_PE_ADJUST) == DW_EH_PE_pcrel) {
+ startLoc -= (unsigned long) m->eh_frame;
+ startLoc += m->eh_frame_addr;
+ }
+ if (strcmp (s->name, ".absolute") == 0)
+ return startLoc;
+ }
+
if (strcmp (s->name, ".dynamic") == 0)
return startLoc + s->addr;
@@ -451,7 +512,7 @@ adjustStartLoc (unsigned long startLoc,
}
/* If we previously created an unwind header, then use it now to binary search */
-/* for the FDE corresponding to pc. */
+/* for the FDE corresponding to pc. XXX FIXME not currently supported. */
static u32 *_stp_search_unwind_hdr(unsigned long pc,
struct _stp_module *m,
@@ -488,7 +549,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
ptr = hdr + 4;
end = hdr + m->unwind_hdr_len;
- if (read_pointer(&ptr, end, hdr[1]) != (unsigned long)m->unwind_data) {
+ if (read_pointer(&ptr, end, hdr[1]) != (unsigned long)m->debug_frame) {
dbug_unwind(1, "eh_frame_ptr not valid");
return NULL;
}
@@ -502,7 +563,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
do {
const u8 *cur = ptr + (num / 2) * (2 * tableSize);
startLoc = read_pointer(&cur, cur + tableSize, hdr[3]);
- startLoc = adjustStartLoc(startLoc, m, s);
+ startLoc = adjustStartLoc(startLoc, m, s, hdr[3], true);
if (pc < startLoc)
num /= 2;
else {
@@ -511,63 +572,19 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
}
} while (startLoc && num > 1);
- if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), m, s)) != 0 && pc >= startLoc)
+ if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), m, s, hdr[3], true)) != 0 && pc >= startLoc)
fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]);
dbug_unwind(1, "returning fde=%lx startLoc=%lx", fde, startLoc);
return fde;
}
-#ifdef DEBUG_UNWIND
-static const char *_stp_enc_hi_name[] = {
- "DW_EH_PE",
- "DW_EH_PE_pcrel",
- "DW_EH_PE_textrel",
- "DW_EH_PE_datarel",
- "DW_EH_PE_funcrel",
- "DW_EH_PE_aligned"
-};
-static const char *_stp_enc_lo_name[] = {
- "_absptr",
- "_uleb128",
- "_udata2",
- "_udata4",
- "_udata8",
- "_sleb128",
- "_sdata2",
- "_sdata4",
- "_sdata8"
-};
-static char *_stp_eh_enc_name(signed type)
-{
- static char buf[64];
- int hi, low;
- if (type == DW_EH_PE_omit)
- return "DW_EH_PE_omit";
-
- hi = (type & DW_EH_PE_ADJUST) >> 4;
- low = type & DW_EH_PE_FORM;
- if (hi > 5 || low > 4 || (low == 0 && (type & DW_EH_PE_signed))) {
- sprintf(buf, "ERROR:encoding=0x%x", type);
- return buf;
- }
-
- buf[0] = 0;
- if (type & DW_EH_PE_indirect)
- strlcpy(buf, "DW_EH_PE_indirect|", sizeof(buf));
- strlcat(buf, _stp_enc_hi_name[hi], sizeof(buf));
-
- if (type & DW_EH_PE_signed)
- low += 4;
- strlcat(buf, _stp_enc_lo_name[low], sizeof(buf));
- return buf;
-}
-#endif /* DEBUG_UNWIND */
-
/* Unwind to previous to frame. Returns 0 if successful, negative
* number in case of an error. A positive return means unwinding is finished;
* don't try to fallback to dumping addresses on the stack. */
-static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
+static int unwind_frame(struct unwind_frame_info *frame,
+ struct _stp_module *m, struct _stp_section *s,
+ void *table, uint32_t table_len, int is_ehframe)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde, *cie = NULL;
@@ -577,23 +594,10 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
unsigned i;
signed ptrType = -1;
uleb128_t retAddrReg = 0;
- struct _stp_module *m;
- struct _stp_section *s = NULL;
struct unwind_state state;
- dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame));
-
- if (UNW_PC(frame) == 0)
- return -EINVAL;
-
- m = _stp_mod_sec_lookup (pc, tsk, &s);
- if (unlikely(m == NULL)) {
- dbug_unwind(1, "No module found for pc=%lx", pc);
- return -EINVAL;
- }
-
- if (unlikely(m->unwind_data_len == 0 || m->unwind_data_len & (sizeof(*fde) - 1))) {
- dbug_unwind(1, "Module %s: unwind_data_len=%d", m->name, m->unwind_data_len);
+ if (unlikely(table_len == 0 || table_len & (sizeof(*fde) - 1))) {
+ dbug_unwind(1, "Module %s: frame_len=%d", m->name, table_len);
goto err;
}
@@ -602,12 +606,12 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
/* found the fde, now set startLoc and endLoc */
if (fde != NULL) {
- cie = cie_for_fde(fde, m);
+ cie = cie_for_fde(fde, table, is_ehframe);
if (likely(cie != NULL && cie != &bad_cie && cie != &not_fde)) {
ptr = (const u8 *)(fde + 2);
ptrType = fde_pointer_type(cie);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s);
+ startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!(ptrType & DW_EH_PE_indirect))
@@ -625,10 +629,10 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
/* did not a good fde find with binary search, so do slow linear search */
if (fde == NULL) {
- for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde)
- && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ for (fde = table, tableSize = table_len; cie = NULL, tableSize > sizeof(*fde)
+ && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize);
- cie = cie_for_fde(fde, m);
+ cie = cie_for_fde(fde, table, is_ehframe);
if (cie == &bad_cie) {
cie = NULL;
break;
@@ -638,7 +642,7 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
ptr = (const u8 *)(fde + 2);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s);
+ startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!startLoc)
continue;
@@ -651,7 +655,7 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
}
}
- dbug_unwind(1, "cie=%lx fde=%lx startLoc=%lx endLoc=%lx\n", cie, fde, startLoc, endLoc);
+ dbug_unwind(1, "cie=%lx fde=%lx startLoc=%lx endLoc=%lx, pc=%lx\n", cie, fde, startLoc, endLoc, pc);
if (cie == NULL || fde == NULL)
goto err;
@@ -855,5 +859,34 @@ done:
#undef FRAME_REG
}
+static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
+{
+ struct _stp_module *m;
+ struct _stp_section *s = NULL;
+ unsigned long pc = UNW_PC(frame) - frame->call_frame;
+ int res;
+
+ dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame));
+
+ if (UNW_PC(frame) == 0)
+ return -EINVAL;
+
+ m = _stp_mod_sec_lookup (pc, tsk, &s);
+ if (unlikely(m == NULL)) {
+ dbug_unwind(1, "No module found for pc=%lx", pc);
+ return -EINVAL;
+ }
+
+ dbug_unwind(1, "trying debug_frame\n");
+ res = unwind_frame (frame, m, s, m->debug_frame,
+ m->debug_frame_len, false);
+ if (res != 0) {
+ dbug_unwind(1, "debug_frame failed: %d, trying eh_frame\n", res);
+ res = unwind_frame (frame, m, s, m->eh_frame,
+ m->eh_frame_len, true);
+ }
+
+ return res;
+}
#endif /* STP_USE_DWARF_UNWINDER */
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
index 3b6d0de0..285a3a34 100644
--- a/runtime/unwind/unwind.h
+++ b/runtime/unwind/unwind.h
@@ -1,7 +1,7 @@
/* -*- linux-c -*-
*
* dwarf unwinder header file
- * Copyright (C) 2008 Red Hat Inc.
+ * Copyright (C) 2008, 2009 Red Hat Inc.
* Copyright (C) 2002-2006 Novell, Inc.
*
* This file is part of systemtap, and is free software. You can
@@ -143,7 +143,7 @@ static unsigned long read_pointer(const u8 **pLoc,
const void *end,
signed ptrType);
static const u32 bad_cie, not_fde;
-static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *);
+static const u32 *cie_for_fde(const u32 *fde, void *table, int is_ehframe);
static signed fde_pointer_type(const u32 *cie);
diff --git a/tapset/timestamp_gtod.stp b/tapset/timestamp_gtod.stp
index 43b127dc..b916a3b1 100644
--- a/tapset/timestamp_gtod.stp
+++ b/tapset/timestamp_gtod.stp
@@ -7,23 +7,10 @@
// Public License (GPL); either version 2, or (at your option) any
// later version.
-function _gettimeofday_init:long() %{
- THIS->__retvalue = _stp_init_time(); /* Kick off the Big Bang. */
+%{
+#define STAP_NEED_GETTIMEOFDAY 1
%}
-probe begin(-0x8000000000000000) {
- if (_gettimeofday_init() != 0)
- error("couldn't initialize gettimeofday")
-}
-
-function _gettimeofday_kill() %{
- _stp_kill_time(); /* Go to a beach. Drink a beer. */
-%}
-
-probe end(0x7FFFFFFFFFFFFFFF), error(0x7FFFFFFFFFFFFFFF) {
- _gettimeofday_kill()
-}
-
/**
* sfunction gettimeofday_ns - Number of nanoseconds since UNIX epoch.
diff --git a/testsuite/buildok/gtod_init.stp b/testsuite/buildok/gtod_init.stp
new file mode 100755
index 00000000..1d76aeab
--- /dev/null
+++ b/testsuite/buildok/gtod_init.stp
@@ -0,0 +1,13 @@
+#! stap -gp4
+
+# check that STAP_NEED_GETTIMEOFDAY is defined with a gettimeofday
+function check() %{
+#ifndef STAP_NEED_GETTIMEOFDAY
+#error "gettimeofday should define STAP_NEED_GETTIMEOFDAY!"
+#endif
+%}
+
+probe begin {
+ check()
+ println(gettimeofday_s())
+}
diff --git a/testsuite/buildok/gtod_noinit.stp b/testsuite/buildok/gtod_noinit.stp
new file mode 100755
index 00000000..94a9dfdc
--- /dev/null
+++ b/testsuite/buildok/gtod_noinit.stp
@@ -0,0 +1,13 @@
+#! stap -gp4
+
+# check that STAP_NEED_GETTIMEOFDAY is NOT defined without a gettimeofday
+function check() %{
+#ifdef STAP_NEED_GETTIMEOFDAY
+#error "STAP_NEED_GETTIMEOFDAY should not be defined!"
+#endif
+%}
+
+probe begin {
+ check()
+ println(get_cycles())
+}
diff --git a/testsuite/systemtap.base/gtod_init.exp b/testsuite/systemtap.base/gtod_init.exp
deleted file mode 100644
index 48616b1f..00000000
--- a/testsuite/systemtap.base/gtod_init.exp
+++ /dev/null
@@ -1,29 +0,0 @@
-# test for checking initialization of the time subsystem
-set test "gtod_init"
-
-# check that init and kill are both present with a gettimeofday
-set time_init 0
-set time_kill 0
-spawn stap -p2 -e {probe begin { println(gettimeofday_s()) }}
-expect {
- -timeout 120
- -re {\n_gettimeofday_init:} { incr time_init; exp_continue }
- -re {\n_gettimeofday_kill:} { incr time_kill; exp_continue }
- timeout { fail "$test (timeout)" }
- eof {
- if {$time_init == 1} { pass "$test (init)" } { fail "$test (init $time_init)" }
- if {$time_kill == 1} { pass "$test (kill)" } { fail "$test (kill $time_kill)" }
- }
-}
-wait
-
-# check that init and kill are both NOT present without a gettimeofday
-spawn stap -p2 -e {probe begin { println(get_cycles()) }}
-expect {
- -timeout 120
- -re {\n_gettimeofday_init:} { fail "$test (bad init)" }
- -re {\n_gettimeofday_kill:} { fail "$test (bad kill)" }
- timeout { fail "$test (timeout)" }
- eof { pass "$test (no init/kill)" }
-}
-wait
diff --git a/translate.cxx b/translate.cxx
index 87811e9f..505c9fc6 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -1133,6 +1133,15 @@ c_unparser::emit_module_init ()
o->newline(-1) << "}";
o->newline() << "if (rc) goto out;";
+ // initialize gettimeofday (if needed)
+ o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY";
+ o->newline() << "rc = _stp_init_time();"; // Kick off the Big Bang.
+ o->newline() << "if (rc) {";
+ o->newline(1) << "_stp_error (\"couldn't initialize gettimeofday\");";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
+ o->newline() << "#endif";
+
o->newline() << "(void) probe_point;";
o->newline() << "(void) i;";
o->newline() << "(void) j;";
@@ -1359,6 +1368,11 @@ c_unparser::emit_module_exit ()
o->newline() << "#endif";
}
+ // teardown gettimeofday (if needed)
+ o->newline() << "#ifdef STAP_NEED_GETTIMEOFDAY";
+ o->newline() << " _stp_kill_time();"; // Go to a beach. Drink a beer.
+ o->newline() << "#endif";
+
// print final error/skipped counts if non-zero
o->newline() << "if (atomic_read (& skipped_count) || "
<< "atomic_read (& error_count) || "
@@ -4413,41 +4427,56 @@ struct unwindsym_dump_context
};
-// Get the .debug_frame section for the given module.
-// l will be set to the length of the size of the unwind data if found.
-static void *get_unwind_data (Dwfl_Module *m, size_t *l)
+// Get the .debug_frame end .eh_frame sections for the given module.
+// Also returns the lenght of both sections when found, plus the section
+// address of the eh_frame data.
+static void get_unwind_data (Dwfl_Module *m,
+ void **debug_frame, void **eh_frame,
+ size_t *debug_len, size_t *eh_len,
+ Dwarf_Addr *eh_addr)
{
Dwarf_Addr bias = 0;
- Dwarf *dw;
GElf_Ehdr *ehdr, ehdr_mem;
GElf_Shdr *shdr, shdr_mem;
- Elf_Scn *scn = NULL;
- Elf_Data *data = NULL;
-
- dw = dwfl_module_getdwarf(m, &bias);
- if (dw != NULL)
+ Elf_Scn *scn;
+ Elf_Data *data;
+ Elf *elf;
+
+ // fetch .eh_frame info preferably from main elf file.
+ elf = dwfl_module_getelf(m, &bias);
+ ehdr = gelf_getehdr(elf, &ehdr_mem);
+ scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)))
{
- Elf *elf = dwarf_getelf(dw);
- ehdr = gelf_getehdr(elf, &ehdr_mem);
- while ((scn = elf_nextscn(elf, scn)))
+ shdr = gelf_getshdr(scn, &shdr_mem);
+ if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name),
+ ".eh_frame") == 0)
{
- shdr = gelf_getshdr(scn, &shdr_mem);
- if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name),
- ".debug_frame") == 0)
- {
- data = elf_rawdata(scn, NULL);
- break;
- }
+ data = elf_rawdata(scn, NULL);
+ *eh_frame = data->d_buf;
+ *eh_len = data->d_size;
+ *eh_addr = shdr->sh_addr;
+ break;
}
}
- if (data != NULL)
+ // fetch .debug_frame info preferably from dwarf debuginfo file.
+ elf = (dwarf_getelf (dwfl_module_getdwarf (m, &bias))
+ ?: dwfl_module_getelf (m, &bias));
+ ehdr = gelf_getehdr(elf, &ehdr_mem);
+ scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)))
{
- *l = data->d_size;
- return data->d_buf;
+ shdr = gelf_getshdr(scn, &shdr_mem);
+ if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name),
+ ".debug_frame") == 0)
+ {
+ data = elf_rawdata(scn, NULL);
+ *debug_frame = data->d_buf;
+ *debug_len = data->d_size;
+ break;
+ }
}
-
- return NULL;
}
static int
@@ -4680,17 +4709,21 @@ dump_unwindsyms (Dwfl_Module *m,
}
// Add unwind data to be included if it exists for this module.
- size_t len = 0;
- void *unwind = get_unwind_data (m, &len);
- if (unwind != NULL)
+ void *debug_frame = NULL;
+ size_t debug_len = 0;
+ void *eh_frame = NULL;
+ size_t eh_len = 0;
+ Dwarf_Addr eh_addr = 0;
+ get_unwind_data (m, &debug_frame, &eh_frame, &debug_len, &eh_len, &eh_addr);
+ if (debug_frame != NULL && debug_len > 0)
{
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
c->output << "static uint8_t _stp_module_" << stpmod_idx
- << "_unwind_data[] = \n";
+ << "_debug_frame[] = \n";
c->output << " {";
- for (size_t i = 0; i < len; i++)
+ for (size_t i = 0; i < debug_len; i++)
{
- int h = ((uint8_t *)unwind)[i];
+ int h = ((uint8_t *)debug_frame)[i];
c->output << "0x" << hex << h << dec << ",";
if ((i + 1) % 16 == 0)
c->output << "\n" << " ";
@@ -4698,7 +4731,25 @@ dump_unwindsyms (Dwfl_Module *m,
c->output << "};\n";
c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA */\n";
}
- else
+
+ if (eh_frame != NULL && eh_len > 0)
+ {
+ c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
+ c->output << "static uint8_t _stp_module_" << stpmod_idx
+ << "_eh_frame[] = \n";
+ c->output << " {";
+ for (size_t i = 0; i < eh_len; i++)
+ {
+ int h = ((uint8_t *)eh_frame)[i];
+ c->output << "0x" << hex << h << dec << ",";
+ if ((i + 1) % 16 == 0)
+ c->output << "\n" << " ";
+ }
+ c->output << "};\n";
+ c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA */\n";
+ }
+
+ if (debug_frame == NULL && eh_frame == NULL)
{
// There would be only a small benefit to warning. A user
// likely can't do anything about this; backtraces for the
@@ -4755,25 +4806,40 @@ dump_unwindsyms (Dwfl_Module *m,
c->output << ".path = " << lex_cast_qstring (mainfile) << ",\n";
c->output << ".dwarf_module_base = 0x" << hex << base << dec << ", \n";
+ c->output << ".eh_frame_addr = 0x" << hex << eh_addr << dec << ", \n";
+
+ if (debug_frame != NULL)
+ {
+ c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
+ c->output << ".debug_frame = "
+ << "_stp_module_" << stpmod_idx << "_debug_frame, \n";
+ c->output << ".debug_frame_len = " << debug_len << ", \n";
+ c->output << "#else\n";
+ }
+
+ c->output << ".debug_frame = NULL,\n";
+ c->output << ".debug_frame_len = 0,\n";
+
+ if (debug_frame != NULL)
+ c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n";
- if (unwind != NULL)
+ if (eh_frame != NULL)
{
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
- c->output << ".unwind_data = "
- << "_stp_module_" << stpmod_idx << "_unwind_data, \n";
- c->output << ".unwind_data_len = " << len << ", \n";
+ c->output << ".eh_frame = "
+ << "_stp_module_" << stpmod_idx << "_eh_frame, \n";
+ c->output << ".eh_frame_len = " << eh_len << ", \n";
c->output << "#else\n";
}
- c->output << ".unwind_data = NULL,\n";
- c->output << ".unwind_data_len = 0,\n";
+ c->output << ".eh_frame = NULL,\n";
+ c->output << ".eh_frame_len = 0,\n";
- if (unwind != NULL)
+ if (eh_frame != NULL)
c->output << "#endif /* STP_USE_DWARF_UNWINDER && STP_NEED_UNWIND_DATA*/\n";
c->output << ".unwind_hdr = NULL,\n";
c->output << ".unwind_hdr_len = 0,\n";
- c->output << ".unwind_is_ehframe = 0,\n";
c->output << ".sections = _stp_module_" << stpmod_idx << "_sections" << ",\n";
c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/"