summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2009-07-15 12:04:57 +0200
committerMark Wielaard <mjw@redhat.com>2009-07-15 12:04:57 +0200
commit00b01a991cc4300f18c747853e85841d187b1fa4 (patch)
tree6a165d27d3e44afe1e42298d24b0c36081aa2c39
parentd52761f89a1826b1cca29b1a63269eafe7197756 (diff)
downloadsystemtap-steved-00b01a991cc4300f18c747853e85841d187b1fa4.tar.gz
systemtap-steved-00b01a991cc4300f18c747853e85841d187b1fa4.tar.xz
systemtap-steved-00b01a991cc4300f18c747853e85841d187b1fa4.zip
PR10388 Support DW_OP_call_frame_cfa.
Depends on elfutils 0.142 cfi support. * loc2c.h (c_translate_location): Take (optional) Dwarf_Op *cfa_ops. * loc2c.c (translate): Recognize DW_OP_call_frame_cfa. (location_from_address): Take cfa_ops, examine fb_ops, if it is DW_OP_call_frame_cfa, pass cfa_ops to translate instead. (location_relative): Take cfa_ops, pass to location_from_address. (c_translate_location): Take cfa_ops, pass to location_from_address. * loc2c-test.c (handle_variable): Take cfa_ops, pass to c_translate_location when needed. (main): Fetch cfa_ops, pass to handle_variable. * dwflpp.h (struct dwflpp): Add new method get_cfa_ops. * dwflpp.cxx: Include elfutils/version.h. (translate_location): Fetch cfa_ops when necessary. (get_cfa_ops): New method.
-rw-r--r--dwflpp.cxx39
-rw-r--r--dwflpp.h4
-rw-r--r--loc2c-test.c41
-rw-r--r--loc2c.c41
-rw-r--r--loc2c.h6
5 files changed, 115 insertions, 16 deletions
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 3f30e3a8..dc7af5d8 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -41,6 +41,9 @@ extern "C" {
#include <fcntl.h>
#include <elfutils/libdwfl.h>
#include <elfutils/libdw.h>
+#ifdef HAVE_ELFUTILS_VERSION_H
+#include <elfutils/version.h>
+#endif
#include <dwarf.h>
#include <elf.h>
#include <obstack.h>
@@ -1497,10 +1500,11 @@ dwflpp::translate_location(struct obstack *pool,
e->tok);
}
+ Dwarf_Op *cfa_ops = get_cfa_ops (pc);
return c_translate_location (pool, &loc2c_error, this,
&loc2c_emit_address,
1, 0 /* PR9768 */,
- pc, expr, len, tail, fb_attr);
+ pc, expr, len, tail, fb_attr, cfa_ops);
}
@@ -2085,7 +2089,7 @@ dwflpp::literal_stmt_for_return (Dwarf_Die *scope_die,
&loc2c_emit_address,
1, 0 /* PR9768 */,
pc, locops, nlocops,
- &tail, NULL);
+ &tail, NULL, NULL);
/* Translate the ->bar->baz[NN] parts. */
@@ -2489,5 +2493,36 @@ dwflpp::dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes)
return num_cached_scopes;
}
+Dwarf_Op *
+dwflpp::get_cfa_ops (Dwarf_Addr pc)
+{
+ Dwarf_Op *cfa_ops = NULL;
+
+#ifdef _ELFUTILS_PREREQ
+#if _ELFUTILS_PREREQ(0,142)
+ // Try debug_frame first, then fall back on eh_frame.
+ Dwarf_Addr bias;
+ Dwarf_CFI *cfi = dwfl_module_dwarf_cfi (module, &bias);
+ if (cfi != NULL)
+ {
+ Dwarf_Frame *frame = NULL;
+ if (dwarf_cfi_addrframe (cfi, pc, &frame) == 0)
+ dwarf_frame_cfa (frame, &cfa_ops);
+ }
+ if (cfa_ops == NULL)
+ {
+ cfi = dwfl_module_eh_cfi (module, &bias);
+ if (cfi != NULL)
+ {
+ Dwarf_Frame *frame = NULL;
+ if (dwarf_cfi_addrframe (cfi, pc, &frame) == 0)
+ dwarf_frame_cfa (frame, &cfa_ops);
+ }
+ }
+#endif
+#endif
+
+ return cfa_ops;
+}
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/dwflpp.h b/dwflpp.h
index e0098b9b..a2c38ad8 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -376,6 +376,10 @@ private:
int num_cached_scopes;
Dwarf_Die *cached_scopes;
int dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes);
+
+ // Returns the call frame address operations for the given program counter.
+ Dwarf_Op *get_cfa_ops (Dwarf_Addr pc);
+
};
#endif // DWFLPP_H
diff --git a/loc2c-test.c b/loc2c-test.c
index 688f4a8b..0c992c76 100644
--- a/loc2c-test.c
+++ b/loc2c-test.c
@@ -75,7 +75,7 @@ get_location (Dwarf_Addr dwbias, Dwarf_Addr pc, Dwarf_Attribute *loc_attr,
static void
handle_variable (Dwarf_Die *scopes, int nscopes, int out,
Dwarf_Addr cubias, Dwarf_Die *vardie, Dwarf_Addr pc,
- char **fields)
+ Dwarf_Op *cfa_ops, char **fields)
{
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
@@ -121,7 +121,7 @@ handle_variable (Dwarf_Die *scopes, int nscopes, int out,
struct location *head, *tail = NULL;
head = c_translate_location (&pool, &fail, NULL, NULL,
1, cubias, pc, locexpr, locexpr_len,
- &tail, fb_attr);
+ &tail, fb_attr, cfa_ops);
if (dwarf_attr_integrate (vardie, DW_AT_type, &attr_mem) == NULL)
error (2, 0, _("cannot get type of variable: %s"),
@@ -240,7 +240,7 @@ handle_variable (Dwarf_Die *scopes, int nscopes, int out,
&locexpr_len);
c_translate_location (&pool, NULL, NULL, NULL,
1, cubias, pc, locexpr, locexpr_len,
- &tail, NULL);
+ &tail, NULL, NULL);
break;
}
}
@@ -521,7 +521,40 @@ main (int argc, char **argv)
error (0, 0, "dwarf_getscopevar: %s (+%d, %s:%d:%d): %s",
spec, shadow, at, lineno, colno, dwarf_errmsg (-1));
else
- handle_variable (scopes, n, out, cubias, &vardie, pc, &argv[argi]);
+ {
+ Dwarf_Op *cfa_ops = NULL;
+
+#ifdef _ELFUTILS_PREREQ
+#if _ELFUTILS_PREREQ(0,142)
+ Dwarf_Addr bias;
+ Dwfl_Module *module = dwfl_addrmodule (dwfl, pc);
+ if (module != NULL)
+ {
+ // Try debug_frame first, then fall back on eh_frame.
+ Dwarf_CFI *cfi = dwfl_module_dwarf_cfi (module, &bias);
+ if (cfi != NULL)
+ {
+ Dwarf_Frame *frame = NULL;
+ if (dwarf_cfi_addrframe (cfi, pc, &frame) == 0)
+ dwarf_frame_cfa (frame, &cfa_ops);
+ }
+ if (cfa_ops == NULL)
+ {
+ cfi = dwfl_module_eh_cfi (module, &bias);
+ if (cfi != NULL)
+ {
+ Dwarf_Frame *frame = NULL;
+ if (dwarf_cfi_addrframe (cfi, pc, &frame) == 0)
+ dwarf_frame_cfa (frame, &cfa_ops);
+ }
+ }
+ }
+#endif
+#endif
+
+ handle_variable (scopes, n, out, cubias, &vardie, pc, cfa_ops,
+ &argv[argi]);
+ }
}
free (scopes);
diff --git a/loc2c.c b/loc2c.c
index 15434632..f5efccfe 100644
--- a/loc2c.c
+++ b/loc2c.c
@@ -509,6 +509,15 @@ translate (struct obstack *pool, int indent, Dwarf_Addr addrbias,
}
break;
+ case DW_OP_call_frame_cfa:
+ // We pick this out when processing DW_AT_frame_base in
+ // so it really shouldn't turn up here.
+ if (need_fb == NULL)
+ DIE ("DW_OP_call_frame_cfa while processing frame base");
+ else
+ DIE ("DW_OP_call_frame_cfa not expected outside DW_AT_frame_base");
+ break;
+
case DW_OP_push_object_address:
DIE ("XXX DW_OP_push_object_address");
break;
@@ -552,7 +561,8 @@ location_from_address (struct obstack *pool,
struct obstack *, Dwarf_Addr),
int indent, Dwarf_Addr dwbias,
const Dwarf_Op *expr, size_t len, Dwarf_Addr address,
- struct location **input, Dwarf_Attribute *fb_attr)
+ struct location **input, Dwarf_Attribute *fb_attr,
+ const Dwarf_Op *cfa_ops)
{
struct location *loc = obstack_alloc (pool, sizeof *loc);
loc->fail = *input == NULL ? fail : (*input)->fail;
@@ -599,8 +609,19 @@ location_from_address (struct obstack *pool,
return NULL;
}
+ // If it is DW_OP_call_frame_cfa then get cfi cfa ops.
+ const Dwarf_Op * fb_ops;
+ if (fb_len == 1 && fb_expr[0].atom == DW_OP_call_frame_cfa)
+ {
+ if (cfa_ops == NULL)
+ FAIL (loc, N_("No cfa_ops supplied, but needed by DW_OP_call_frame_cfa"));
+ fb_ops = cfa_ops;
+ }
+ else
+ fb_ops = fb_expr;
+
loc->frame_base = alloc_location (pool, loc);
- failure = translate (pool, indent + 1, dwbias, fb_expr, fb_len, NULL,
+ failure = translate (pool, indent + 1, dwbias, fb_ops, fb_len, NULL,
NULL, &loser, loc->frame_base);
if (failure != NULL)
return lose (loc, failure, fb_expr, loser);
@@ -622,7 +643,8 @@ static struct location *
location_relative (struct obstack *pool,
int indent, Dwarf_Addr dwbias,
const Dwarf_Op *expr, size_t len, Dwarf_Addr address,
- struct location **input, Dwarf_Attribute *fb_attr)
+ struct location **input, Dwarf_Attribute *fb_attr,
+ const Dwarf_Op *cfa_ops)
{
Dwarf_Sword *stack = NULL;
unsigned int stack_depth = 0, max_stack = 0;
@@ -752,7 +774,8 @@ location_relative (struct obstack *pool,
/* This started from a register, but now it's following a pointer.
So we can do the translation starting from address here. */
return location_from_address (pool, NULL, NULL, NULL, indent, dwbias,
- expr, len, address, input, fb_attr);
+ expr, len, address, input, fb_attr,
+ cfa_ops);
/* Constant-value operations. */
@@ -911,7 +934,8 @@ location_relative (struct obstack *pool,
loc = location_from_address (pool, NULL, NULL, NULL,
indent, dwbias,
&expr[i + 1], len - i - 1,
- address, input, fb_attr);
+ address, input, fb_attr,
+ cfa_ops);
if (loc == NULL)
return NULL;
}
@@ -994,7 +1018,8 @@ c_translate_location (struct obstack *pool,
struct obstack *, Dwarf_Addr),
int indent, Dwarf_Addr dwbias, Dwarf_Addr pc_address,
const Dwarf_Op *expr, size_t len,
- struct location **input, Dwarf_Attribute *fb_attr)
+ struct location **input, Dwarf_Attribute *fb_attr,
+ const Dwarf_Op *cfa_ops)
{
indent += 2;
@@ -1006,14 +1031,14 @@ c_translate_location (struct obstack *pool,
return location_from_address (pool, fail, fail_arg,
emit_address ?: &default_emit_address,
indent, dwbias, expr, len, pc_address,
- input, fb_attr);
+ input, fb_attr, cfa_ops);
case loc_noncontiguous:
case loc_register:
/* The starting point is not an address computation, but a
register. We can only handle limited computations from here. */
return location_relative (pool, indent, dwbias, expr, len, pc_address,
- input, fb_attr);
+ input, fb_attr, cfa_ops);
default:
abort ();
diff --git a/loc2c.h b/loc2c.h
index eb1f39d6..449d4499 100644
--- a/loc2c.h
+++ b/loc2c.h
@@ -11,7 +11,8 @@ struct location; /* Opaque */
/* Translate a C fragment for the location expression, using *INPUT
as the starting location, begin from scratch if *INPUT is null.
If DW_OP_fbreg is used, it may have a subfragment computing from
- the FB_ATTR location expression.
+ the FB_ATTR location expression. The call_frame might need to be
+ calculated by the cfa_ops for the given pc_address.
On errors, call FAIL, which should not return. Any later errors will use
FAIL and FAIL_ARG from the first c_translate_location call.
@@ -34,7 +35,8 @@ struct location *c_translate_location (struct obstack *,
const Dwarf_Op *locexpr,
size_t locexprlen,
struct location **input,
- Dwarf_Attribute *fb_attr);
+ Dwarf_Attribute *fb_attr,
+ const Dwarf_Op *cfa_ops);
/* Translate a fragment to dereference the given DW_TAG_pointer_type DIE,
where *INPUT is the location of the pointer with that type. */