diff options
author | Mark Wielaard <mjw@redhat.com> | 2009-07-15 12:04:57 +0200 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2009-07-15 12:04:57 +0200 |
commit | 00b01a991cc4300f18c747853e85841d187b1fa4 (patch) | |
tree | 6a165d27d3e44afe1e42298d24b0c36081aa2c39 | |
parent | d52761f89a1826b1cca29b1a63269eafe7197756 (diff) | |
download | systemtap-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.cxx | 39 | ||||
-rw-r--r-- | dwflpp.h | 4 | ||||
-rw-r--r-- | loc2c-test.c | 41 | ||||
-rw-r--r-- | loc2c.c | 41 | ||||
-rw-r--r-- | loc2c.h | 6 |
5 files changed, 115 insertions, 16 deletions
@@ -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 : */ @@ -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); @@ -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 (); @@ -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. */ |