summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgraydon <graydon>2005-07-29 01:47:56 +0000
committergraydon <graydon>2005-07-29 01:47:56 +0000
commit77de5e9eca19f041e85681439f41ea35d30a37c9 (patch)
tree0d4ec2f749ace9659df8f1082f1a8a8e2797e148
parentb2d5d95caa573e486b6503406b688da824cd20a9 (diff)
downloadsystemtap-steved-77de5e9eca19f041e85681439f41ea35d30a37c9.tar.gz
systemtap-steved-77de5e9eca19f041e85681439f41ea35d30a37c9.tar.xz
systemtap-steved-77de5e9eca19f041e85681439f41ea35d30a37c9.zip
2005-07-28 Graydon Hoare <graydon@redhat.com>
* elaborate.cxx (derived_probe::derived_probe): Accept NULL probe. * staptree.cxx (provide, require): Move from here... * staptree.h: to here, and virtualize deep-copy methods. * translate.cxx (c_unparser::emit_common_header): Include loc2c-runtime.h * tapsets.cxx (dwflpp::iterate_over_modules): Use new, faster getmodules loop. (dwflpp::literal_stmt_for_local): New method, call loc2c. (var_expanding_copy_visitor): New struct which expands $-vars. (dwarf_derived_probe): Rebuild this->body using var expander. (query_function): Refactor logic a bit for speed. * loc2c.{c,h}: Copies (with minor changes) of Roland's work from elfutils CVS. * Makefile.am (AM_CFLAGS): Set to elfutils-style. (stap_SOURCES): Add loc2c.c. * Makefile.in: Regenerate. 2005-07-28 Graydon Hoare <graydon@redhat.com> * loc2c-runtime.h: New file from elfutils CVS.
-rw-r--r--ChangeLog19
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in6
-rw-r--r--elaborate.cxx16
-rw-r--r--loc2c.c1398
-rw-r--r--loc2c.h63
-rw-r--r--runtime/ChangeLog4
-rw-r--r--runtime/loc2c-runtime.h125
-rw-r--r--staptree.cxx19
-rw-r--r--staptree.h84
-rw-r--r--tapsets.cxx338
-rw-r--r--translate.cxx1
12 files changed, 1960 insertions, 117 deletions
diff --git a/ChangeLog b/ChangeLog
index 45a7d919..30c5f715 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2005-07-28 Graydon Hoare <graydon@redhat.com>
+
+ * elaborate.cxx (derived_probe::derived_probe): Accept NULL probe.
+ * staptree.cxx (provide, require): Move from here...
+ * staptree.h: to here, and virtualize deep-copy methods.
+ * translate.cxx
+ (c_unparser::emit_common_header): Include loc2c-runtime.h
+ * tapsets.cxx
+ (dwflpp::iterate_over_modules): Use new, faster getmodules loop.
+ (dwflpp::literal_stmt_for_local): New method, call loc2c.
+ (var_expanding_copy_visitor): New struct which expands $-vars.
+ (dwarf_derived_probe): Rebuild this->body using var expander.
+ (query_function): Refactor logic a bit for speed.
+ * loc2c.{c,h}: Copies (with minor changes) of Roland's work
+ from elfutils CVS.
+ * Makefile.am (AM_CFLAGS): Set to elfutils-style.
+ (stap_SOURCES): Add loc2c.c.
+ * Makefile.in: Regenerate.
+
2005-07-28 Frank Ch. Eigler <fche@redhat.com>
* stap.1: Beginnings of a man page.
diff --git a/Makefile.am b/Makefile.am
index 1a20caf1..b09cc3a8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,11 +6,13 @@ AM_MAKEFLAGS = 'CXXFLAGS=$(CXXFLAGS)' 'LDFLAGS=$(LDFLAGS)'
AM_CPPFLAGS = -DPKGLIBDIR='"${libexecdir}/${PACKAGE}"' \
-DPKGDATADIR='"${datadir}/${PACKAGE}"'
+AM_CFLAGS = -D_GNU_SOURCE -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99
+
man_MANS = stap.1
bin_PROGRAMS = stap
stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
- tapsets.cxx buildrun.cxx
+ tapsets.cxx buildrun.cxx loc2c.c
stap_CXXFLAGS = -Werror $(AM_CXXFLAGS)
libexec_PROGRAMS = stpd
diff --git a/Makefile.in b/Makefile.in
index 2bdf9aab..36cd6448 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -62,7 +62,7 @@ PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS)
am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \
stap-staptree.$(OBJEXT) stap-elaborate.$(OBJEXT) \
stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \
- stap-buildrun.$(OBJEXT)
+ stap-buildrun.$(OBJEXT) loc2c.$(OBJEXT)
stap_OBJECTS = $(am_stap_OBJECTS)
stap_LDADD = $(LDADD)
stap_DEPENDENCIES =
@@ -189,10 +189,11 @@ AM_MAKEFLAGS = 'CXXFLAGS=$(CXXFLAGS)' 'LDFLAGS=$(LDFLAGS)'
AM_CPPFLAGS = -DPKGLIBDIR='"${libexecdir}/${PACKAGE}"' \
-DPKGDATADIR='"${datadir}/${PACKAGE}"'
+AM_CFLAGS = -D_GNU_SOURCE -Wall -Werror -Wshadow -Wunused -Wformat=2 -Wextra -std=gnu99
man_MANS = stap.1
stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
- tapsets.cxx buildrun.cxx
+ tapsets.cxx buildrun.cxx loc2c.c
stap_CXXFLAGS = -Werror $(AM_CXXFLAGS)
stpd_SOURCES = runtime/stpd/stpd.c runtime/stpd/librelay.c
@@ -336,6 +337,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librelay.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loc2c.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-buildrun.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-elaborate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-main.Po@am__quote@
diff --git a/elaborate.cxx b/elaborate.cxx
index ca5237df..76c5b39c 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -38,9 +38,12 @@ using namespace std;
derived_probe::derived_probe (probe *p):
base (p)
{
- this->locations = p->locations;
- this->tok = p->tok;
- this->body = deep_copy_visitor::deep_copy(p->body);
+ if (p)
+ {
+ this->locations = p->locations;
+ this->tok = p->tok;
+ this->body = deep_copy_visitor::deep_copy(p->body);
+ }
}
@@ -48,8 +51,11 @@ derived_probe::derived_probe (probe *p, probe_point *l):
base (p)
{
this->locations.push_back (l);
- this->tok = p->tok;
- this->body = deep_copy_visitor::deep_copy(p->body);
+ if (p)
+ {
+ this->tok = p->tok;
+ this->body = deep_copy_visitor::deep_copy(p->body);
+ }
}
// ------------------------------------------------------------------------
diff --git a/loc2c.c b/loc2c.c
new file mode 100644
index 00000000..86e7e82d
--- /dev/null
+++ b/loc2c.c
@@ -0,0 +1,1398 @@
+#include <config.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <obstack.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+#include <dwarf.h>
+#include <libdw.h>
+#include <assert.h>
+
+#define _(x) x
+
+#define STACK_TYPE "intptr_t" /* Must be the signed type. */
+#define UTYPE "uintptr_t" /* Must be the unsigned type. */
+#define SFORMAT "%" PRId64 "L"
+#define UFORMAT "%" PRIu64 "UL"
+#define AFORMAT "%#" PRIx64 "UL"
+#define STACKFMT "s%u"
+
+struct location
+{
+ struct location *next;
+
+ const Dwarf_Loc *ops;
+ size_t nops;
+
+ Dwarf_Word byte_size;
+
+ enum { loc_address, loc_register, loc_noncontiguous, loc_final } type;
+ union
+ {
+ struct /* loc_address or loc_final */
+ {
+ char *program; /* C fragment, leaves address in s0. */
+ unsigned int stack_depth; /* Temporaries "s0..<N>" used by it. */
+ struct location *frame_base;
+ bool used_deref; /* Program uses "deref" macro. */
+ } address;
+ unsigned int regno; /* loc_register */
+ struct location *pieces; /* loc_noncontiguous */
+ };
+};
+
+
+static const char *
+dwarf_diename_integrate (Dwarf_Die *die)
+{
+ Dwarf_Attribute attr_mem;
+ return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
+}
+
+/* Synthesize a new loc_address using the program on the obstack. */
+static struct location *
+new_synthetic_loc (struct obstack *pool, struct location *origin, bool deref)
+{
+ obstack_1grow (pool, '\0');
+ char *program = obstack_finish (pool);
+
+ struct location *loc = obstack_alloc (pool, sizeof *loc);
+ loc->next = NULL;
+ loc->byte_size = 0;
+ loc->type = loc_address;
+ loc->address.program = program;
+ loc->address.stack_depth = 0;
+ loc->address.frame_base = NULL;
+ loc->address.used_deref = deref;
+
+ if (origin->type == loc_register)
+ {
+ loc->ops = origin->ops;
+ loc->nops = origin->nops;
+ }
+ else
+ {
+ loc->ops = NULL;
+ loc->nops = 0;
+ }
+
+ return loc;
+}
+
+
+/* Die in the middle of an expression. */
+static struct location *
+lose (const char *failure, const Dwarf_Loc *lexpr, size_t i)
+{
+ error (2, 0, _("%s in DWARF expression [%Zu] at %" PRIu64
+ " (%#x: %" PRId64 ", %" PRId64 ")"),
+ failure, i, lexpr[i].offset,
+ lexpr[i].atom, lexpr[i].number, lexpr[i].number2);
+ return NULL;
+}
+
+/* Translate a (constrained) DWARF expression into C code
+ emitted to the obstack POOL. INDENT is the number of indentation levels.
+ ADDRBIAS is the difference between runtime and Dwarf info addresses.
+ INPUT is null or an expression to be initially pushed on the stack.
+ If NEED_FB is null, fail on DW_OP_fbreg, else set *NEED_FB to true
+ and emit "frame_base" for it. On success, set *MAX_STACK to the number
+ of stack slots required. On failure, set *LOSER to the index in EXPR
+ of the operation we could not handle.
+
+ Returns a failure message or null for success. */
+
+static const char *
+translate (struct obstack *pool, int indent, Dwarf_Addr addrbias,
+ const Dwarf_Loc *expr, const size_t len,
+ struct location *input,
+ bool *need_fb, size_t *loser,
+ struct location *loc)
+{
+ loc->ops = expr;
+ loc->nops = len;
+
+#define DIE(msg) return (*loser = i, _(msg))
+
+#define emit(fmt, ...) obstack_printf (pool, fmt, ## __VA_ARGS__)
+
+ unsigned int stack_depth = 0, max_stack = 0;
+ inline void deepen (void)
+ {
+ if (stack_depth == max_stack)
+ ++max_stack;
+ }
+
+#define POP(var) \
+ if (stack_depth > 0) \
+ --stack_depth; \
+ else if (tos_register != -1) \
+ fetch_tos_register (); \
+ else \
+ goto underflow; \
+ int var = stack_depth
+#define PUSH (deepen (), stack_depth++)
+#define STACK(idx) (stack_depth - 1 - (idx))
+
+ /* Don't put stack operations in the arguments to this. */
+#define push(fmt, ...) \
+ emit ("%*s" STACKFMT " = " fmt ";\n", indent * 2, "", PUSH, ## __VA_ARGS__)
+
+ int tos_register = -1;
+ inline void fetch_tos_register (void)
+ {
+ deepen ();
+ emit ("%*s" STACKFMT " = fetch_register (%d);\n",
+ indent * 2, "", stack_depth, tos_register);
+ tos_register = -1;
+ }
+
+ if (input != NULL)
+ switch (input->type)
+ {
+ case loc_address:
+ push ("addr");
+ break;
+
+ case loc_register:
+ tos_register = input->regno;
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ size_t i;
+
+ inline const char *finish (struct location *piece)
+ {
+ if (stack_depth > 1)
+ DIE ("multiple values left on stack");
+ if (stack_depth == 1)
+ {
+ obstack_1grow (pool, '\0');
+ char *program = obstack_finish (pool);
+ piece->type = loc_address;
+ piece->address.program = program;
+ piece->address.stack_depth = max_stack;
+ piece->address.frame_base = NULL;
+ }
+ else if (tos_register == -1)
+ DIE ("stack underflow");
+ else if (obstack_object_size (pool) != 0)
+ DIE ("register value must stand alone in location expression");
+ else
+ {
+ piece->type = loc_register;
+ piece->regno = tos_register;
+ }
+ return NULL;
+ }
+
+ struct location *pieces = NULL, **tailpiece = &pieces;
+ size_t piece_expr_start = 0;
+ for (i = 0; i < len; ++i)
+ {
+ unsigned int reg;
+ uint_fast8_t sp;
+ Dwarf_Word value;
+
+ switch (expr[i].atom)
+ {
+ /* Basic stack operations. */
+ case DW_OP_nop:
+ break;
+
+ case DW_OP_dup:
+ if (stack_depth < 1)
+ goto underflow;
+ else
+ {
+ unsigned int tos = STACK (0);
+ push (STACKFMT, tos);
+ }
+ break;
+
+ case DW_OP_drop:
+ POP (ignore);
+ emit ("%*s/* drop " STACKFMT "*/\n", indent * 2, "", ignore);
+ break;
+
+ case DW_OP_pick:
+ sp = expr[i].number;
+ op_pick:
+ if (sp >= stack_depth)
+ goto underflow;
+ sp = STACK (sp);
+ push (STACKFMT, sp);
+ break;
+
+ case DW_OP_over:
+ sp = 1;
+ goto op_pick;
+
+ case DW_OP_swap:
+ if (stack_depth < 2)
+ goto underflow;
+ deepen (); /* Use a temporary slot. */
+ emit ("%*s"
+ STACKFMT " = " STACKFMT ", "
+ STACKFMT " = " STACKFMT ", "
+ STACKFMT " = " STACKFMT ";\n",
+ indent * 2, "",
+ STACK (-1), STACK (0),
+ STACK (0), STACK (1),
+ STACK (1), STACK (-1));
+ break;
+
+ case DW_OP_rot:
+ if (stack_depth < 3)
+ goto underflow;
+ deepen (); /* Use a temporary slot. */
+ emit ("%*s"
+ STACKFMT " = " STACKFMT ", "
+ STACKFMT " = " STACKFMT ", "
+ STACKFMT " = " STACKFMT ", "
+ STACKFMT " = " STACKFMT ";\n",
+ indent * 2, "",
+ STACK (-1), STACK (0),
+ STACK (0), STACK (1),
+ STACK (1), STACK (2),
+ STACK (3), STACK (-1));
+ break;
+
+
+ /* Control flow operations. */
+ case DW_OP_skip:
+ {
+ Dwarf_Off target = expr[i].offset + 3 + expr[i].number;
+ while (i + 1 < len && expr[i + 1].offset < target)
+ ++i;
+ if (expr[i + 1].offset != target)
+ DIE ("invalid skip target");
+ break;
+ }
+
+ case DW_OP_bra:
+ DIE ("conditional branches not supported");
+ break;
+
+
+ /* Memory access. */
+ case DW_OP_deref:
+ {
+ POP (addr);
+ push ("deref (sizeof (void *), " STACKFMT ")", addr);
+ loc->address.used_deref = true;
+ }
+ break;
+
+ case DW_OP_deref_size:
+ {
+ POP (addr);
+ push ("deref (" UFORMAT ", " STACKFMT ")",
+ expr[i].number, addr);
+ loc->address.used_deref = true;
+ }
+ break;
+
+ case DW_OP_xderef:
+ {
+ POP (addr);
+ POP (as);
+ push ("xderef (sizeof (void *), " STACKFMT ", " STACKFMT ")",
+ addr, as);
+ loc->address.used_deref = true;
+ }
+ break;
+
+ case DW_OP_xderef_size:
+ {
+ POP (addr);
+ POP (as);
+ push ("xderef (" UFORMAT ", " STACKFMT ", " STACKFMT ")",
+ expr[i].number, addr, as);
+ loc->address.used_deref = true;
+ }
+ break;
+
+ /* Constant-value operations. */
+
+ case DW_OP_addr:
+ push (AFORMAT, addrbias + expr[i].number);
+ break;
+
+ case DW_OP_lit0 ... DW_OP_lit31:
+ value = expr[i].atom - DW_OP_lit0;
+ goto op_const;
+
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ case DW_OP_constu:
+ case DW_OP_consts:
+ value = expr[i].number;
+ op_const:
+ push (SFORMAT, value);
+ break;
+
+ /* Arithmetic operations. */
+#define UNOP(dw_op, c_op) \
+ case DW_OP_##dw_op: \
+ { \
+ POP (tos); \
+ push ("%s (" STACKFMT ")", #c_op, tos); \
+ } \
+ break
+#define BINOP(dw_op, c_op) \
+ case DW_OP_##dw_op: \
+ { \
+ POP (b); \
+ POP (a); \
+ push (STACKFMT " %s " STACKFMT, a, #c_op, b); \
+ } \
+ break
+
+ UNOP (abs, op_abs);
+ BINOP (and, &);
+ BINOP (div, /);
+ BINOP (minus, -);
+ BINOP (mod, %);
+ BINOP (mul, *);
+ UNOP (neg, -);
+ UNOP (not, ~);
+ BINOP (or, |);
+ BINOP (plus, +);
+ BINOP (shl, <<);
+ BINOP (shra, >>);
+ BINOP (xor, ^);
+
+ /* Comparisons are binary operators too. */
+ BINOP (le, <=);
+ BINOP (ge, >=);
+ BINOP (eq, ==);
+ BINOP (lt, <);
+ BINOP (gt, >);
+ BINOP (ne, !=);
+
+#undef UNOP
+#undef BINOP
+
+ case DW_OP_shr:
+ {
+ POP (b);
+ POP (a);
+ push ("(%s) " STACKFMT " >> (%s)" STACKFMT,
+ UTYPE, a, UTYPE, b);
+ break;
+ }
+
+ case DW_OP_plus_uconst:
+ {
+ POP (x);
+ push (STACKFMT " + " UFORMAT, x, expr[i].number);
+ }
+ break;
+
+
+ /* Register-relative addressing. */
+ case DW_OP_breg0 ... DW_OP_breg31:
+ reg = expr[i].atom - DW_OP_breg0;
+ value = expr[i].number;
+ goto op_breg;
+
+ case DW_OP_bregx:
+ reg = expr[i].number;
+ value = expr[i].number2;
+ op_breg:
+ push ("fetch_register (%u) + " SFORMAT, reg, value);
+ break;
+
+ case DW_OP_fbreg:
+ if (need_fb == NULL)
+ DIE ("DW_OP_fbreg from DW_AT_frame_base");
+ *need_fb = true;
+ push ("frame_base + " SFORMAT, expr[i].number);
+ break;
+
+ /* Direct register contents. */
+ case DW_OP_reg0 ... DW_OP_reg31:
+ reg = expr[i].atom - DW_OP_reg0;
+ goto op_reg;
+
+ case DW_OP_regx:
+ reg = expr[i].number;
+ op_reg:
+ tos_register = reg;
+ break;
+
+ /* Special magic. */
+ case DW_OP_piece:
+ if (stack_depth > 1)
+ /* If this ever happens we could copy the program. */
+ DIE ("DW_OP_piece left multiple values on stack");
+ else
+ {
+ struct location *piece = obstack_alloc (pool, sizeof *piece);
+ const char *failure = finish (piece);
+ if (failure != NULL)
+ return failure;
+
+ piece->ops = &expr[piece_expr_start];
+ piece->nops = i - piece_expr_start;
+ piece_expr_start = i + 1;
+
+ piece->byte_size = expr[i].number;
+
+ *tailpiece = piece;
+ tailpiece = &piece->next;
+ piece->next = NULL;
+ }
+ break;
+
+ case DW_OP_push_object_address:
+ DIE ("XXX DW_OP_push_object_address");
+ break;
+
+ default:
+ DIE ("unrecognized operation");
+ break;
+ }
+ }
+
+ if (pieces == NULL)
+ return finish (loc);
+
+ if (piece_expr_start != i)
+ DIE ("extra operations after last DW_OP_piece");
+
+ loc->type = loc_noncontiguous;
+ loc->pieces = pieces;
+
+ return NULL;
+
+ underflow:
+ DIE ("stack underflow");
+
+#undef emit
+#undef push
+#undef PUSH
+#undef POP
+#undef STACK
+#undef DIE
+}
+
+/* Translate a location starting from an address or nothing. */
+static struct location *
+location_from_address (struct obstack *pool,
+ int indent, Dwarf_Addr dwbias,
+ const Dwarf_Loc *expr, size_t len, Dwarf_Addr address,
+ struct location **input, Dwarf_Attribute *fb_attr)
+{
+ bool need_fb = false;
+ size_t loser;
+ struct location *loc = obstack_alloc (pool, sizeof *loc);
+ const char *failure = translate (pool, indent + 1, dwbias, expr, len,
+ *input, &need_fb, &loser, loc);
+ if (failure != NULL)
+ return lose (failure, expr, loser);
+
+ loc->next = NULL;
+ if (need_fb)
+ {
+ /* The main expression uses DW_OP_fbreg, so we need to compute
+ the DW_AT_frame_base attribute expression's value first. */
+
+ Dwarf_Loc *fb_expr;
+ size_t fb_len;
+ switch (dwarf_addrloclists (fb_attr, address - dwbias,
+ &fb_expr, &fb_len, 1))
+ {
+ case 1: /* Should always happen. */
+ if (fb_len == 0)
+ goto fb_inaccessible;
+ break;
+
+ default: /* Shouldn't happen. */
+ case -1:
+ error (2, 0, "dwarf_addrloclists (form %#x): %s",
+ dwarf_whatform (fb_attr), dwarf_errmsg (-1));
+ return NULL;
+
+ case 0: /* Shouldn't happen. */
+ fb_inaccessible:
+ error (2, 0, "DW_AT_frame_base not accessible at this address");
+ return NULL;
+ }
+
+ loc->address.frame_base = obstack_alloc (pool, sizeof *loc);
+ failure = translate (pool, indent + 1, dwbias, fb_expr, fb_len, NULL,
+ NULL, &loser, loc->address.frame_base);
+ if (failure != NULL)
+ return lose (failure, fb_expr, loser);
+ }
+
+ if (*input != NULL)
+ (*input)->next = loc;
+ *input = loc;
+
+ return loc;
+}
+
+/* Translate a location starting from a non-address "on the top of the
+ stack". The *INPUT location is a register name or noncontiguous
+ object specification, and this expression wants to find the "address"
+ of an object relative to that "address". */
+
+static struct location *
+location_relative (struct obstack *pool,
+ int indent, Dwarf_Addr dwbias,
+ const Dwarf_Loc *expr, size_t len, Dwarf_Addr address,
+ struct location **input, Dwarf_Attribute *fb_attr)
+{
+ Dwarf_Sword *stack;
+ unsigned int stack_depth = 0, max_stack = 0;
+ inline void deepen (void)
+ {
+ if (stack_depth == max_stack)
+ {
+ ++max_stack;
+ obstack_blank (pool, sizeof stack[0]);
+ stack = (void *) obstack_base (pool);
+ }
+ }
+
+#define POP(var) \
+ if (stack_depth > 0) \
+ --stack_depth; \
+ else \
+ goto underflow; \
+ int var = stack_depth
+#define PUSH (deepen (), stack_depth++)
+#define STACK(idx) (stack_depth - 1 - (idx))
+#define STACKWORD(idx) stack[STACK (idx)]
+
+ /* Don't put stack operations in the arguments to this. */
+#define push(value) (stack[PUSH] = (value))
+
+ const char *failure = NULL;
+#define DIE(msg) do { failure = _(msg); goto fail; } while (0)
+
+ struct location *head = NULL;
+ size_t i;
+ for (i = 0; i < len; ++i)
+ {
+ uint_fast8_t sp;
+ Dwarf_Word value;
+
+ switch (expr[i].atom)
+ {
+ /* Basic stack operations. */
+ case DW_OP_nop:
+ break;
+
+ case DW_OP_dup:
+ if (stack_depth < 1)
+ goto underflow;
+ else
+ {
+ unsigned int tos = STACK (0);
+ push (stack[tos]);
+ }
+ break;
+
+ case DW_OP_drop:
+ if (stack_depth > 0)
+ --stack_depth;
+ else if (*input != NULL)
+ /* Mark that we have consumed the input. */
+ *input = NULL;
+ else
+ /* Hits if cleared above, or if we had no input at all. */
+ goto underflow;
+ break;
+
+ case DW_OP_pick:
+ sp = expr[i].number;
+ op_pick:
+ if (sp >= stack_depth)
+ goto underflow;
+ sp = STACK (sp);
+ push (stack[sp]);
+ break;
+
+ case DW_OP_over:
+ sp = 1;
+ goto op_pick;
+
+ case DW_OP_swap:
+ if (stack_depth < 2)
+ goto underflow;
+ deepen (); /* Use a temporary slot. */
+ STACKWORD (-1) = STACKWORD (0);
+ STACKWORD (0) = STACKWORD (1);
+ STACKWORD (1) = STACKWORD (-1);
+ break;
+
+ case DW_OP_rot:
+ if (stack_depth < 3)
+ goto underflow;
+ deepen (); /* Use a temporary slot. */
+ STACKWORD (-1) = STACKWORD (0);
+ STACKWORD (0) = STACKWORD (1);
+ STACKWORD (2) = STACKWORD (2);
+ STACKWORD (2) = STACKWORD (-1);
+ break;
+
+
+ /* Control flow operations. */
+ case DW_OP_bra:
+ {
+ POP (taken);
+ if (stack[taken] == 0)
+ break;
+ }
+ /*FALLTHROUGH*/
+
+ case DW_OP_skip:
+ {
+ Dwarf_Off target = expr[i].offset + 3 + expr[i].number;
+ while (i + 1 < len && expr[i + 1].offset < target)
+ ++i;
+ if (expr[i + 1].offset != target)
+ DIE ("invalid skip target");
+ break;
+ }
+
+ /* Memory access. */
+ case DW_OP_deref:
+ case DW_OP_deref_size:
+ case DW_OP_xderef:
+ case DW_OP_xderef_size:
+
+ /* Register-relative addressing. */
+ case DW_OP_breg0 ... DW_OP_breg31:
+ case DW_OP_bregx:
+ case DW_OP_fbreg:
+
+ /* 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, indent, dwbias,
+ expr, len, address, input, fb_attr);
+
+
+ /* Constant-value operations. */
+ case DW_OP_addr:
+ push (dwbias + expr[i].number);
+ break;
+
+ case DW_OP_lit0 ... DW_OP_lit31:
+ value = expr[i].atom - DW_OP_lit0;
+ goto op_const;
+
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ case DW_OP_constu:
+ case DW_OP_consts:
+ value = expr[i].number;
+ op_const:
+ push (value);
+ break;
+
+ /* Arithmetic operations. */
+#define UNOP(dw_op, c_op) \
+ case DW_OP_##dw_op: \
+ { \
+ POP (tos); \
+ push (c_op (stack[tos])); \
+ } \
+ break
+#define BINOP(dw_op, c_op) \
+ case DW_OP_##dw_op: \
+ { \
+ POP (b); \
+ POP (a); \
+ push (stack[a] c_op stack[b]); \
+ } \
+ break
+
+#define op_abs(x) (x < 0 ? -x : x)
+ UNOP (abs, op_abs);
+ BINOP (and, &);
+ BINOP (div, /);
+ BINOP (mod, %);
+ BINOP (mul, *);
+ UNOP (neg, -);
+ UNOP (not, ~);
+ BINOP (or, |);
+ BINOP (shl, <<);
+ BINOP (shra, >>);
+ BINOP (xor, ^);
+
+ /* Comparisons are binary operators too. */
+ BINOP (le, <=);
+ BINOP (ge, >=);
+ BINOP (eq, ==);
+ BINOP (lt, <);
+ BINOP (gt, >);
+ BINOP (ne, !=);
+
+#undef UNOP
+#undef BINOP
+
+ case DW_OP_shr:
+ {
+ POP (b);
+ POP (a);
+ push ((Dwarf_Word) stack[a] >> (Dwarf_Word) stack[b]);
+ break;
+ }
+
+ /* Simple addition we may be able to handle relative to
+ the starting register name. */
+ case DW_OP_minus:
+ {
+ POP (tos);
+ value = -stack[tos];
+ goto plus;
+ }
+ case DW_OP_plus:
+ {
+ POP (tos);
+ value = stack[tos];
+ goto plus;
+ }
+ case DW_OP_plus_uconst:
+ value = expr[i].number;
+ plus:
+ if (stack_depth > 0)
+ {
+ /* It's just private diddling after all. */
+ POP (a);
+ push (stack[a] + value);
+ break;
+ }
+ if (*input == NULL)
+ goto underflow;
+
+ /* This is the primary real-world case: the expression takes
+ the input address and adds a constant offset. */
+
+ while ((*input)->type == loc_noncontiguous)
+ {
+ /* We are starting from a noncontiguous object (DW_OP_piece).
+ Find the piece we want. */
+
+ struct location *piece = (*input)->pieces;
+ while (piece != NULL && value >= piece->byte_size)
+ {
+ value -= piece->byte_size;
+ piece = piece->next;
+ }
+ if (piece == NULL)
+ DIE ("offset outside available pieces");
+
+ *input = piece;
+ }
+
+ switch ((*input)->type)
+ {
+ case loc_address:
+ {
+ /* The piece we want is actually in memory. Use the same
+ program to compute the address from the preceding input. */
+
+ struct location *loc = obstack_alloc (pool, sizeof *loc);
+ *loc = **input;
+ if (head == NULL)
+ head = loc;
+ (*input)->next = loc;
+ if (value == 0)
+ {
+ /* The piece addresses exactly where we want to go. */
+ loc->next = NULL;
+ *input = loc;
+ }
+ else
+ {
+ /* Add a second fragment to offset the piece address. */
+ obstack_printf (pool, "%*saddr += " SFORMAT "\n",
+ indent * 2, "", value);
+ *input = loc->next = new_synthetic_loc (pool, *input,
+ false);
+ }
+
+ if (i + 1 < len)
+ {
+ /* This expression keeps going, but further
+ computations now have an address to start with.
+ So we can punt to the address computation generator. */
+ loc = location_from_address (pool, indent, dwbias,
+ &expr[i + 1], len - i - 1,
+ address, input, fb_attr);
+ if (loc == NULL)
+ return NULL;
+ }
+
+ /* That's all she wrote. */
+ return head;
+ }
+
+ case loc_register:
+ // XXX
+
+ default:
+ abort ();
+ }
+ break;
+
+ /* Direct register contents. */
+ case DW_OP_reg0 ... DW_OP_reg31:
+ case DW_OP_regx:
+ DIE ("register");
+ break;
+
+ /* Special magic. */
+ case DW_OP_piece:
+ DIE ("DW_OP_piece");
+ break;
+
+ case DW_OP_push_object_address:
+ DIE ("XXX DW_OP_push_object_address");
+ break;
+
+ default:
+ DIE ("unrecognized operation");
+ break;
+ }
+ }
+
+ if (stack_depth > 1)
+ DIE ("multiple values left on stack");
+
+ if (stack_depth > 0) /* stack_depth == 1 */
+ {
+ if (*input != NULL)
+ DIE ("multiple values left on stack");
+
+ /* Could handle this if it ever actually happened. */
+ DIE ("relative expression computed constant");
+ }
+
+ return head;
+
+ underflow:
+ if (*input == NULL)
+ DIE ("stack underflow");
+ else
+ DIE ("cannot handle location expression");
+
+ fail:
+ return lose (failure, expr, i);
+}
+
+
+/* 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.
+
+ On errors, exit and never return (XXX ?). On success, return the
+ first fragment created, which is also chained onto (*INPUT)->next.
+ *INPUT is then updated with the new tail of that chain. */
+
+struct location *
+c_translate_location (struct obstack *pool,
+ int indent, Dwarf_Addr dwbias,
+ Dwarf_Attribute *loc_attr, Dwarf_Addr address,
+ struct location **input, Dwarf_Attribute *fb_attr)
+{
+ Dwarf_Loc *expr;
+ size_t len;
+ switch (dwarf_addrloclists (loc_attr, address - dwbias, &expr, &len, 1))
+ {
+ case 1: /* Should always happen. */
+ if (len == 0)
+ goto inaccessible;
+ break;
+
+ default: /* Shouldn't happen. */
+ case -1:
+ error (2, 0, "dwarf_addrloclists (form %#x): %s",
+ dwarf_whatform (fb_attr), dwarf_errmsg (-1));
+ return NULL;
+
+ case 0: /* Shouldn't happen. */
+ inaccessible:
+ error (2, 0, "not accessible at this address");
+ return NULL;
+ }
+
+ ++indent;
+ switch (*input == NULL ? loc_address : (*input)->type)
+ {
+ case loc_address:
+ /* We have a previous address computation.
+ This expression will compute starting with that on the stack. */
+ return location_from_address (pool, indent, dwbias, expr, len, address,
+ input, fb_attr);
+
+ 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, address,
+ input, fb_attr);
+
+ case loc_final: /* Bogus caller. */
+ default:
+ abort ();
+ break;
+ }
+
+ return NULL;
+}
+
+
+/* Emit "uintNN_t TARGET = ...;". */
+static bool
+emit_base_fetch (struct obstack *pool, Dwarf_Word byte_size,
+ const char *target, bool decl, struct location *loc)
+{
+ if (decl)
+ obstack_printf (pool, "uint%" PRIu64 "_t ", byte_size * 8);
+
+ switch (loc->type)
+ {
+ case loc_address:
+ if (byte_size != 0 && byte_size != (Dwarf_Word) -1)
+ obstack_printf (pool, "%s = deref (%" PRIu64 ", addr); ",
+ target, byte_size);
+ else
+ obstack_printf (pool, "%s = deref (sizeof %s, addr); ",
+ target, target);
+ return true;
+
+ case loc_register:
+ obstack_printf (pool, "%s = fetch_register (%u);", target, loc->regno);
+ break;
+
+ case loc_noncontiguous:
+ /* Could be handled if it ever happened. */
+ error (2, 0, _("noncontiguous locations not supported"));
+ break;
+
+ default:
+ abort ();
+ break;
+ }
+
+ return false;
+}
+
+/* Translate a fragment to dereference the given pointer type,
+ where *INPUT is the location of the pointer with that type.
+
+ We chain on a loc_address program that yields this pointer value
+ (i.e. the location of what it points to). */
+
+void
+c_translate_pointer (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias __attribute__ ((unused)),
+ Dwarf_Die *typedie, struct location **input)
+{
+ obstack_printf (pool, "%*s{ ", (indent + 2) * 2, "");
+
+ bool deref = false;
+ Dwarf_Attribute attr_mem;
+ Dwarf_Word byte_size;
+ if (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem) == NULL)
+ {
+ obstack_printf (pool, "uintptr_t ");
+ emit_base_fetch (pool, 0, "tmp", false, *input);
+ }
+ else if (dwarf_formudata (&attr_mem, &byte_size) != 0)
+ error (2, 0,
+ _("cannot get byte_size attribute for type %s: %s"),
+ dwarf_diename_integrate (typedie) ?: "<anonymous>",
+ dwarf_errmsg (-1));
+ else
+ deref = emit_base_fetch (pool, byte_size, "tmp", true, *input);
+
+ obstack_printf (pool, " addr = tmp; }\n");
+
+ struct location *loc = new_synthetic_loc (pool, *input, deref);
+ (*input)->next = loc;
+ *input = loc;
+}
+
+/* Determine the byte size of a base type. */
+static Dwarf_Word
+base_byte_size (Dwarf_Die *typedie)
+{
+ Dwarf_Attribute attr_mem;
+ Dwarf_Word size;
+ if (dwarf_attr_integrate (typedie, DW_AT_byte_size, &attr_mem) != NULL
+ && dwarf_formudata (&attr_mem, &size) == 0)
+ return size;
+
+ error (2, 0,
+ _("cannot get byte_size attribute for type %s: %s"),
+ dwarf_diename_integrate (typedie) ?: "<anonymous>",
+ dwarf_errmsg (-1));
+ return -1;
+}
+
+/* Emit a code fragment like:
+ { uintNN_t tmp = ...; S1 S2 S3, tmp, B0, Bn); }
+*/
+static void
+emit_bitfield (struct obstack *pool, int indent,
+ Dwarf_Die *die, Dwarf_Word byte_size, struct location *loc,
+ const char *s1, const char *s2, const char *s3)
+{
+ Dwarf_Word bit_offset, bit_size;
+ Dwarf_Attribute attr_mem;
+ if (dwarf_attr_integrate (die, DW_AT_bit_offset, &attr_mem) == NULL
+ || dwarf_formudata (&attr_mem, &bit_offset) != 0
+ || dwarf_attr_integrate (die, DW_AT_bit_size, &attr_mem) == NULL
+ || dwarf_formudata (&attr_mem, &bit_size) != 0)
+ error (2, 0, _("cannot get bit field parameters: %s"),
+ dwarf_errmsg (-1));
+
+ /* Emit "{ uintNN_t tmp = ...;" to fetch the base type. */
+
+ obstack_printf (pool, "%*s{ ", indent * 2, "");
+ emit_base_fetch (pool, byte_size, "tmp", true, loc);
+
+ obstack_printf (pool, "%s%s%s, tmp, %" PRIu64 ", %" PRIu64 "); }\n",
+ s1, s2, s3, bit_offset, bit_size);
+}
+
+/* Translate a fragment to fetch the value of variable or member DIE
+ at the *INPUT location and store it in variable TARGET. */
+
+void
+c_translate_fetch (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias __attribute__ ((unused)),
+ Dwarf_Die *die, Dwarf_Attribute *typeattr,
+ struct location **input, const char *target)
+{
+ ++indent;
+
+ Dwarf_Attribute size_attr;
+ Dwarf_Word byte_size;
+ if (dwarf_attr_integrate (die, DW_AT_byte_size, &size_attr) == NULL
+ || dwarf_formudata (&size_attr, &byte_size) != 0)
+ {
+ Dwarf_Die basedie;
+ if (dwarf_formref_die (typeattr, &basedie) == NULL)
+ error (2, 0, _("cannot get type of field: %s"), dwarf_errmsg (-1));
+ byte_size = base_byte_size (&basedie);
+ }
+
+ bool deref = false;
+ if (dwarf_hasattr_integrate (die, DW_AT_bit_offset))
+ /* This is a bit field. */
+ emit_bitfield (pool, indent, die, byte_size, *input,
+ "fetch_bitfield (", target, "");
+ else
+ switch (byte_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ obstack_printf (pool, "%*s", indent * 2, "");
+ deref = emit_base_fetch (pool, byte_size, target, false, *input);
+ obstack_printf (pool, "\n");
+ break;
+
+ default:
+ /* Could handle this generating call to memcpy equivalent. */
+ error (2, 0, _("fetch is larger than base integer types"));
+ break;
+ }
+
+ struct location *loc = new_synthetic_loc (pool, *input, deref);
+ loc->type = loc_final;
+ (*input)->next = loc;
+ *input = loc;
+}
+
+void
+c_translate_addressof (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias __attribute__ ((unused)),
+ Dwarf_Die *die,
+ Dwarf_Attribute *typeattr __attribute__ ((unused)),
+ struct location **input, const char *target)
+{
+ ++indent;
+
+ if (dwarf_hasattr_integrate (die, DW_AT_bit_offset))
+ error (2, 0, _("cannot take the address of a bit field"));
+
+ switch ((*input)->type)
+ {
+ case loc_address:
+ obstack_printf (pool, "%*s%s = addr;\n", indent * 2, "", target);
+ (*input)->next = new_synthetic_loc (pool, *input, false);
+ (*input)->next->type = loc_final;
+ break;
+
+ case loc_register:
+ error (2, 0, _("cannot take address of object in register"));
+ break;
+ case loc_noncontiguous:
+ error (2, 0, _("cannot take address of noncontiguous object"));
+ break;
+
+ default:
+ abort();
+ break;
+ }
+}
+
+
+/* Determine the element stride of an array type. */
+static Dwarf_Word
+array_stride (Dwarf_Die *typedie)
+{
+ Dwarf_Attribute attr_mem;
+ if (dwarf_attr_integrate (typedie, DW_AT_stride_size, &attr_mem) != NULL)
+ {
+ Dwarf_Word stride;
+ if (dwarf_formudata (&attr_mem, &stride) == 0)
+ return stride;
+ error (2, 0, _("cannot get stride_size attribute array type %s: %s"),
+ dwarf_diename_integrate (typedie) ?: "<anonymous>",
+ dwarf_errmsg (-1));
+ }
+
+ Dwarf_Die die_mem;
+ if (dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem) == NULL
+ || dwarf_formref_die (&attr_mem, &die_mem) == NULL)
+ error (2, 0, _("cannot get element type of array type %s: %s"),
+ dwarf_diename_integrate (typedie) ?: "<anonymous>",
+ dwarf_errmsg (-1));
+
+ if (dwarf_attr_integrate (&die_mem, DW_AT_byte_size, &attr_mem) != NULL)
+ {
+ Dwarf_Word stride;
+ if (dwarf_formudata (&attr_mem, &stride) == 0)
+ return stride;
+ error (2, 0,
+ _("cannot get byte_size attribute for array element type %s: %s"),
+ dwarf_diename_integrate (&die_mem) ?: "<anonymous>",
+ dwarf_errmsg (-1));
+ }
+
+ error (2, 0, _("confused about array element size"));
+ return 0;
+}
+
+void
+c_translate_array (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias __attribute__ ((unused)),
+ Dwarf_Die *typedie, struct location **input,
+ const char *idx, Dwarf_Word const_idx)
+{
+ ++indent;
+
+ Dwarf_Word stride = array_stride (typedie);
+
+ struct location *loc = *input;
+ while (loc->type == loc_noncontiguous)
+ {
+ if (idx != NULL)
+ error (2, 0, _("cannot dynamically index noncontiguous array"));
+ else
+ {
+ Dwarf_Word offset = const_idx * stride;
+ struct location *piece = loc->pieces;
+ while (piece != NULL && offset >= piece->byte_size)
+ {
+ offset -= piece->byte_size;
+ piece = piece->next;
+ }
+ if (piece == NULL)
+ error (2, 0, _("constant index is outside noncontiguous array"));
+ if (offset % stride != 0)
+ error (2, 0, _("noncontiguous array splits elements"));
+ const_idx = offset / stride;
+ loc = piece;
+ }
+ }
+
+ switch (loc->type)
+ {
+ case loc_address:
+ ++indent;
+ if (idx != NULL)
+ obstack_printf (pool, "%*saddr += %s * " UFORMAT ";\n",
+ indent * 2, "", idx, stride);
+ else
+ obstack_printf (pool, "%*saddr += " UFORMAT " * " UFORMAT ";\n",
+ indent * 2, "", const_idx, stride);
+ loc = new_synthetic_loc (pool, loc, false);
+ break;
+
+ case loc_register:
+ error (2, 0, _("cannot index array stored in a register"));
+ break;
+
+ default:
+ abort();
+ break;
+ }
+
+ (*input)->next = loc;
+ *input = (*input)->next;
+}
+
+
+/* Emitting C code for finalized fragments. */
+
+
+#define emit(fmt, ...) fprintf (out, fmt, ## __VA_ARGS__)
+
+/* Open a block with a comment giving the original DWARF expression. */
+static void
+emit_header (FILE *out, struct location *loc, unsigned int hindent)
+{
+ if (loc->ops == NULL)
+ emit ("%*s{ // synthesized\n", hindent * 2, "");
+ else
+ {
+ emit ("%*s{ // DWARF expression:", hindent * 2, "");
+ for (size_t i = 0; i < loc->nops; ++i)
+ {
+ emit (" %#x", loc->ops[i].atom);
+ if (loc->ops[i].number2 == 0)
+ {
+ if (loc->ops[i].number != 0)
+ emit ("(%" PRId64 ")", loc->ops[i].number);
+ }
+ else
+ emit ("(%" PRId64 ",%" PRId64 ")",
+ loc->ops[i].number, loc->ops[i].number2);
+ }
+ emit ("\n");
+ }
+}
+
+/* Emit a code fragment to assign the target variable to a register value. */
+static void
+emit_loc_register (FILE *out, struct location *loc, unsigned int indent,
+ const char *target)
+{
+ assert (loc->type == loc_register);
+
+ emit ("%*s%s = fetch_register (%u);\n",
+ indent * 2, "", target, loc->regno);
+}
+
+/* Emit a code fragment to assign the target variable to an address. */
+static void
+emit_loc_address (FILE *out, struct location *loc, unsigned int indent,
+ const char *target)
+{
+ assert (loc->type == loc_address);
+
+ if (loc->address.stack_depth == 0)
+ /* Synthetic program. */
+ emit ("%s", loc->address.program);
+ else
+ {
+ emit ("%*s%s " STACKFMT, (indent + 1) * 2, "", STACK_TYPE, 0);
+ for (unsigned int i = 1; i < loc->address.stack_depth; ++i)
+ emit (", " STACKFMT, i);
+ emit (";\n");
+
+ emit ("%s%*s%s = " STACKFMT ";\n", loc->address.program,
+ (indent + 1) * 2, "", target, 0);
+ }
+}
+
+/* Emit a code fragment to declare the target variable and
+ assign it to an address-sized value. */
+static void
+emit_loc_value (FILE *out, struct location *loc, unsigned int indent,
+ const char *target, bool declare)
+{
+ if (declare)
+ emit ("%*s%s %s;\n", indent * 2, "", STACK_TYPE, target);
+
+ emit_header (out, loc, indent);
+
+ switch (loc->type)
+ {
+ default:
+ abort ();
+ break;
+
+ case loc_register:
+ emit_loc_register (out, loc, indent, target);
+ break;
+
+ case loc_address:
+ if (loc->address.frame_base != NULL)
+ emit_loc_value (out, loc->address.frame_base, indent,
+ "frame_base", true);
+ emit_loc_address (out, loc, indent, target);
+ break;
+ }
+
+ emit ("%*s}\n", indent * 2, "");
+}
+
+bool
+c_emit_location (FILE *out, struct location *loc, int indent)
+{
+ emit ("%*s{\n", indent * 2, "");
+
+ bool deref = false;
+ for (bool declare_addr = true; loc->next != NULL; loc = loc->next)
+ switch (loc->type)
+ {
+ case loc_address:
+ /* Emit the program fragment to calculate the address. */
+ emit_loc_value (out, loc, indent + 1, "addr", declare_addr);
+ declare_addr = false;
+ deref = deref || loc->address.used_deref;
+ break;
+
+ case loc_register:
+ case loc_noncontiguous:
+ /* These don't produce any code directly.
+ The next address/final record incorporates the value. */
+ break;
+
+ case loc_final: /* Should be last in chain! */
+ default:
+ abort ();
+ break;
+ }
+
+ if (loc->type != loc_final) /* Unfinished chain. */
+ abort ();
+
+ emit ("%s%*s}\n", loc->address.program, indent * 2, "");
+
+ return deref;
+}
+
+#undef emit
diff --git a/loc2c.h b/loc2c.h
new file mode 100644
index 00000000..15d89280
--- /dev/null
+++ b/loc2c.h
@@ -0,0 +1,63 @@
+#include <libdw.h>
+
+struct obstack; /* Use <obstack.h> */
+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.
+
+ On errors, exit and never return (XXX ?). On success, return the
+ first fragment created, which is also chained onto (*INPUT)->next.
+ *INPUT is then updated with the new tail of that chain.
+ *USED_DEREF is set to true iff the "deref" runtime operation
+ was used, otherwise it is not modified. */
+struct location *c_translate_location (struct obstack *, int indent,
+ Dwarf_Addr bias,
+ Dwarf_Attribute *loc_attr,
+ Dwarf_Addr address,
+ struct location **input,
+ Dwarf_Attribute *fb_attr);
+
+/* Translate a fragment to dereference the given pointer type,
+ where *INPUT is the location of the pointer with that type. */
+void c_translate_pointer (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias, Dwarf_Die *typedie,
+ struct location **input);
+
+/* Translate a fragment to index an array (turning the location
+ of the array into the location of an element). If IDX is non-null,
+ it's a string of C code to emit in the fragment as the array index.
+ If the index is a known constant, IDX should be null and CONST_IDX
+ is used instead (this case can handle local arrays in registers). */
+void c_translate_array (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias, Dwarf_Die *typedie,
+ struct location **input,
+ const char *idx, Dwarf_Word const_idx);
+
+/* Translate a fragment to compute the address of the input location
+ and assign it to the variable TARGET. This doesn't really do anything
+ (it always emits "TARGET = addr;"), but it will barf if the location
+ is a register or noncontiguous object. */
+void c_translate_addressof (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias, Dwarf_Die *die,
+ Dwarf_Attribute *typeattr,
+ struct location **input, const char *target);
+
+/* Translate a fragment to fetch the value of variable or member DIE
+ at the *INPUT location and store it in variable TARGET.
+ This handles base integer types and bit fields. */
+void c_translate_fetch (struct obstack *pool, int indent,
+ Dwarf_Addr dwbias __attribute__ ((unused)),
+ Dwarf_Die *die, Dwarf_Attribute *typeattr,
+ struct location **input, const char *target);
+
+/* Emit the C fragment built up at LOC (i.e., the return value from the
+ first c_translate_location call made). INDENT should match that
+ passed to c_translate_* previously.
+
+ Writes complete lines of C99, code forming a complete C block, to STREAM.
+ Return value is true iff that code uses the `deref' runtime macros. */
+bool c_emit_location (FILE *stream, struct location *loc, int indent);
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index e5050775..34615687 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,7 @@
+2005-07-28 Graydon Hoare <graydon@redhat.com>
+
+ * loc2c-runtime.h: New file from elfutils CVS.
+
2005-07-20 Martin Hunt <hunt@redhat.com>
* io.c (_stp_vlog): Don't count transport failures for
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
new file mode 100644
index 00000000..6385ec83
--- /dev/null
+++ b/runtime/loc2c-runtime.h
@@ -0,0 +1,125 @@
+/* target operations */
+
+#include <linux/types.h>
+#define intptr_t long
+#define uintptr_t unsigned long
+
+
+/* These three macro definitions are generic, just shorthands
+ used by the generated code. */
+
+#define op_abs(x) (x < 0 ? -x : x)
+
+#define fetch_bitfield(target, base, higherbits, nbits) \
+ target = (((base) >> (sizeof (base) * 8 - (higherbits) - (nbits))) \
+ & (((__typeof (base)) 1 << (nbits)) - 1))
+
+#define store_bitfield(target, base, higherbits, nbits) \
+ target = (target \
+ &~ ((((__typeof (base)) 1 << (nbits)) - 1) \
+ << (sizeof (base) * 8 - (higherbits) - (nbits))) \
+ | ((__typeof (base)) (value) \
+ << (sizeof (base) * 8 - (higherbits) - (nbits))))
+
+
+/* These operations are target-specific. */
+#include <asm/uaccess.h>
+
+#define fetch_register(regno) ((intptr_t) c->regs->dwarf_register_##regno)
+
+#if defined __i386__
+
+#define dwarf_register_0 eax
+#define dwarf_register_1 ecx
+#define dwarf_register_2 edx
+#define dwarf_register_3 ebx
+#define dwarf_register_4 esp
+#define dwarf_register_5 ebp
+#define dwarf_register_6 esi
+#define dwarf_register_7 edi
+
+#elif defined __x86_64__
+
+#define dwarf_register_0 eax
+#define dwarf_register_1 edx
+#define dwarf_register_2 ecx
+#define dwarf_register_3 ebx
+#define dwarf_register_4 esi
+#define dwarf_register_5 edi
+#define dwarf_register_6 ebp
+#define dwarf_register_7 esp
+#define dwarf_register_8 r8
+#define dwarf_register_9 r9
+#define dwarf_register_10 r10
+#define dwarf_register_11 r11
+#define dwarf_register_12 r12
+#define dwarf_register_13 r13
+#define dwarf_register_14 r14
+#define dwarf_register_15 r15
+
+#elif defined __powerpc__
+
+#undef fetch_register
+#define fetch_register(regno) ((intptr_t) c->regs->gpr[regno])
+
+#endif
+
+#if defined __i386__ || defined __x86_64__
+
+#define deref(size, addr) \
+ ({ \
+ int _bad = 0; \
+ u8 _b; u16 _w; u32 _l; u64 _q; \
+ intptr_t _v; \
+ switch (size) \
+ { \
+ case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \
+ case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \
+ case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \
+ case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \
+ default: _v = __get_user_bad(); \
+ } \
+ if (_bad) \
+ goto deref_fault; \
+ _v; \
+ })
+
+#elif defined __powerpc64__
+
+#define deref(size, addr) \
+ ({ \
+ int _bad = 0; \
+ intptr_t _v; \
+ switch (size) \
+ { \
+ case 1: __get_user_asm(_v,addr,_bad,"lbz",1); break; \
+ case 2: __get_user_asm(_v,addr,_bad,"lhz",1); break; \
+ case 4: __get_user_asm(_v,addr,_bad,"lwz",1); break; \
+ case 8: __get_user_asm(_v,addr,_bad,"ld",1); break; \
+ default: _v = __get_user_bad(); \
+ } \
+ if (_bad) \
+ goto deref_fault; \
+ _v; \
+ })
+
+#elif defined __powerpc__
+
+#define deref(size, addr) \
+ ({ \
+ int _bad = 0; \
+ intptr_t _v; \
+ switch (size) \
+ { \
+ case 1: __get_user_asm(_v,addr,_bad,"lbz"); break; \
+ case 2: __get_user_asm(_v,addr,_bad,"lhz"); break; \
+ case 4: __get_user_asm(_v,addr,_bad,"lwz"); break; \
+ case 8: __get_user_asm(_v,addr,_bad,"ld"); break; \
+ default: _v = __get_user_bad(); \
+ } \
+ if (_bad) \
+ goto deref_fault; \
+ _v; \
+ })
+
+#endif
diff --git a/staptree.cxx b/staptree.cxx
index fb7c56aa..7f672c38 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -1020,25 +1020,6 @@ throwing_visitor::visit_functioncall (functioncall* e)
// ------------------------------------------------------------------------
-template <typename T> static void
-require (deep_copy_visitor* v, T* dst, T src)
-{
- *dst = NULL;
- if (src != NULL)
- {
- v->targets.push(static_cast<void* >(dst));
- src->visit(v);
- v->targets.pop();
- assert(*dst);
- }
-}
-
-template <typename T> static void
-provide (deep_copy_visitor* v, T src)
-{
- assert(!v->targets.empty());
- *(static_cast<T*>(v->targets.top())) = src;
-}
void
deep_copy_visitor::visit_block (block* s)
diff --git a/staptree.h b/staptree.h
index bcde8f8b..d731f33d 100644
--- a/staptree.h
+++ b/staptree.h
@@ -22,7 +22,7 @@ struct semantic_error: public std::runtime_error
const token* tok1;
const std::string msg2;
const token* tok2;
-
+
~semantic_error () throw () {}
semantic_error (const std::string& msg):
runtime_error (msg), tok1 (0), tok2 (0) {}
@@ -544,37 +544,55 @@ struct deep_copy_visitor: public visitor
static statement *deep_copy (statement *s);
static block *deep_copy (block *s);
-
- void visit_block (block *s);
- void visit_embeddedcode (embeddedcode *s);
- void visit_null_statement (null_statement *s);
- void visit_expr_statement (expr_statement *s);
- void visit_if_statement (if_statement* s);
- void visit_for_loop (for_loop* s);
- void visit_foreach_loop (foreach_loop* s);
- void visit_return_statement (return_statement* s);
- void visit_delete_statement (delete_statement* s);
- void visit_next_statement (next_statement* s);
- void visit_break_statement (break_statement* s);
- void visit_continue_statement (continue_statement* s);
- void visit_literal_string (literal_string* e);
- void visit_literal_number (literal_number* e);
- void visit_binary_expression (binary_expression* e);
- void visit_unary_expression (unary_expression* e);
- void visit_pre_crement (pre_crement* e);
- void visit_post_crement (post_crement* e);
- void visit_logical_or_expr (logical_or_expr* e);
- void visit_logical_and_expr (logical_and_expr* e);
- void visit_array_in (array_in* e);
- void visit_comparison (comparison* e);
- void visit_concatenation (concatenation* e);
- void visit_ternary_expression (ternary_expression* e);
- void visit_assignment (assignment* e);
- void visit_symbol (symbol* e);
- void visit_arrayindex (arrayindex* e);
- void visit_functioncall (functioncall* e);
-};
-
-
+
+ virtual void visit_block (block *s);
+ virtual void visit_embeddedcode (embeddedcode *s);
+ virtual void visit_null_statement (null_statement *s);
+ virtual void visit_expr_statement (expr_statement *s);
+ virtual void visit_if_statement (if_statement* s);
+ virtual void visit_for_loop (for_loop* s);
+ virtual void visit_foreach_loop (foreach_loop* s);
+ virtual void visit_return_statement (return_statement* s);
+ virtual void visit_delete_statement (delete_statement* s);
+ virtual void visit_next_statement (next_statement* s);
+ virtual void visit_break_statement (break_statement* s);
+ virtual void visit_continue_statement (continue_statement* s);
+ virtual void visit_literal_string (literal_string* e);
+ virtual void visit_literal_number (literal_number* e);
+ virtual void visit_binary_expression (binary_expression* e);
+ virtual void visit_unary_expression (unary_expression* e);
+ virtual void visit_pre_crement (pre_crement* e);
+ virtual void visit_post_crement (post_crement* e);
+ virtual void visit_logical_or_expr (logical_or_expr* e);
+ virtual void visit_logical_and_expr (logical_and_expr* e);
+ virtual void visit_array_in (array_in* e);
+ virtual void visit_comparison (comparison* e);
+ virtual void visit_concatenation (concatenation* e);
+ virtual void visit_ternary_expression (ternary_expression* e);
+ virtual void visit_assignment (assignment* e);
+ virtual void visit_symbol (symbol* e);
+ virtual void visit_arrayindex (arrayindex* e);
+ virtual void visit_functioncall (functioncall* e);
+};
+
+template <typename T> static void
+require (deep_copy_visitor* v, T* dst, T src)
+{
+ *dst = NULL;
+ if (src != NULL)
+ {
+ v->targets.push(static_cast<void* >(dst));
+ src->visit(v);
+ v->targets.pop();
+ assert(*dst);
+ }
+}
+
+template <typename T> static void
+provide (deep_copy_visitor* v, T src)
+{
+ assert(!v->targets.empty());
+ *(static_cast<T*>(v->targets.top())) = src;
+}
#endif // STAPTREE_H
diff --git a/tapsets.cxx b/tapsets.cxx
index bbe0481c..d60cb480 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -21,9 +21,16 @@
#include <vector>
#ifdef HAVE_ELFUTILS_LIBDWFL_H
+
extern "C" {
#include <elfutils/libdwfl.h>
+#include <libdw.h>
+#include <dwarf.h>
+#include <elf.h>
+#include <obstack.h>
+#include "loc2c.h"
}
+
#endif
#include <fnmatch.h>
@@ -142,6 +149,16 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
// Dwarf derived probes.
// ------------------------------------------------------------------------
+template <typename OUT, typename IN> inline OUT
+lex_cast(IN const & in)
+{
+ stringstream ss;
+ OUT out;
+ if (!(ss << in && ss >> out))
+ throw runtime_error("bad lexical cast");
+ return out;
+}
+
// Helper for dealing with selected portions of libdwfl in a more readable
// fashion, and with specific cleanup / checking / logging options.
@@ -362,7 +379,7 @@ dwflpp
void iterate_over_modules(int (* callback)(Dwfl_Module *, void **,
const char *, Dwarf_Addr,
- Dwarf *, Dwarf_Addr, void *),
+ void *),
void * data)
{
if (false && sess.verbose)
@@ -370,7 +387,7 @@ dwflpp
ptrdiff_t off = 0;
do
{
- off = dwfl_getdwarf(dwfl, callback, data, off);
+ off = dwfl_getmodules (dwfl, callback, data, off);
}
while (off > 0);
if (false && sess.verbose)
@@ -476,6 +493,106 @@ dwflpp
}
+ string literal_stmt_for_local(Dwarf_Addr pc,
+ string const & local)
+ {
+ assert (cu);
+
+ Dwarf_Die *scopes;
+ Dwarf_Die vardie;
+
+ int nscopes = dwarf_getscopes (cu, pc, &scopes);
+ if (nscopes == 0)
+ {
+ throw semantic_error ("unable to find any scopes containing "
+ + lex_cast<string>(pc)
+ + " while searching for local '" + local + "'");
+ }
+
+ int declaring_scope = dwarf_getscopevar (scopes, nscopes,
+ local.c_str(),
+ 0, NULL, 0, 0,
+ &vardie);
+ if (declaring_scope < 0)
+ {
+ throw semantic_error ("unable to find local '" + local + "'"
+ + " near pc " + lex_cast<string>(pc));
+ }
+
+ Dwarf_Attribute fb_attr_mem, *fb_attr = NULL;
+ for (int inner = 0; inner < nscopes; ++inner)
+ {
+ switch (dwarf_tag (&scopes[inner]))
+ {
+ default:
+ continue;
+ case DW_TAG_subprogram:
+ case DW_TAG_entry_point:
+ case DW_TAG_inlined_subroutine: /* XXX */
+ if (inner >= declaring_scope)
+ fb_attr = dwarf_attr_integrate (&scopes[inner],
+ DW_AT_frame_base,
+ &fb_attr_mem);
+ break;
+ }
+ }
+
+ if (sess.verbose)
+ clog << "finding location for local '" << local
+ << "' near address " << hex << "0x" << pc
+ << ", module bias " << hex << "0x" << module_bias
+ << endl;
+
+ Dwarf_Attribute attr_mem;
+ if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL)
+ throw semantic_error("failed to retrieve location "
+ "attribute for local '" + local + "'");
+
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+ struct obstack pool;
+ obstack_init (&pool);
+ struct location *tail = NULL;
+ struct location *head = c_translate_location (&pool, 1, module_bias,
+ &attr_mem, pc,
+ &tail, fb_attr);
+
+ if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL)
+ throw semantic_error("failed to retrieve type "
+ "attribute for local '" + local + "'");
+
+ c_translate_fetch (&pool, 1, module_bias, &vardie,
+ &attr_mem, &tail,
+ "THIS->__retvalue");
+
+
+ size_t bufsz = 1024;
+ char *buf = static_cast<char*>(malloc(bufsz));
+ assert(buf);
+
+ FILE *memstream = open_memstream (&buf, &bufsz);
+ assert(memstream);
+
+ bool deref = c_emit_location (memstream, head, 1);
+
+ fprintf(memstream, "goto out;\n");
+ if (deref)
+ {
+ fprintf(memstream,
+ "deref_fault:\n"
+ " c->errorcount++; \n"
+ " goto out;\n\n");
+ }
+
+ fclose (memstream);
+ string result(buf);
+ free (buf);
+ return result;
+ }
+
+
+
~dwflpp()
{
if (dwfl)
@@ -512,10 +629,11 @@ dwarf_probe_type
};
struct dwarf_builder;
+struct dwarf_query;
+
struct dwarf_derived_probe : public derived_probe
{
- dwarf_derived_probe (probe * p,
- probe_point * l,
+ dwarf_derived_probe (dwarf_query & q,
string const & module_name,
dwarf_probe_type type,
Dwarf_Addr addr);
@@ -562,6 +680,8 @@ dwarf_query
static bool get_number_param(map<string, literal *> const & params,
string const & k, long & v);
+ string pt_regs_member_for_regnum(uint8_t dwarf_regnum);
+
vector<derived_probe *> & results;
void add_kernel_probe(dwarf_probe_type type, Dwarf_Addr addr);
void add_module_probe(string const & module,
@@ -659,12 +779,12 @@ dwarf_query::get_number_param(map<string, literal *> const & params,
return true;
}
+
void
dwarf_query::add_kernel_probe(dwarf_probe_type type,
Dwarf_Addr addr)
{
- results.push_back(new dwarf_derived_probe(base_probe, base_loc,
- "", type, addr));
+ results.push_back(new dwarf_derived_probe(*this, "", type, addr));
}
void
@@ -672,8 +792,7 @@ dwarf_query::add_module_probe(string const & module,
dwarf_probe_type type,
Dwarf_Addr addr)
{
- results.push_back(new dwarf_derived_probe(base_probe, base_loc,
- module, type, addr));
+ results.push_back(new dwarf_derived_probe(*this, module, type, addr));
}
@@ -719,16 +838,6 @@ dwarf_query::dwarf_query(systemtap_session & sess,
}
-template <typename OUT, typename IN> inline OUT
-lex_cast(IN const & in)
-{
- stringstream ss;
- OUT out;
- if (!(ss << in && ss >> out))
- throw runtime_error("bad lexical cast");
- return out;
-}
-
function_spec_type
dwarf_query::parse_function_spec(string & spec)
{
@@ -830,43 +939,61 @@ query_function(Dwarf_Func * func, void * arg)
q->dw.focus_on_function(func);
- // XXX: We assume addr is a global address here. Is it?
- Dwarf_Addr addr;
- if (!q->dw.function_entrypc(&addr))
- {
- if (false && q->sess.verbose)
- clog << "WARNING: cannot find entry PC for function "
- << q->dw.function_name << endl;
- return DWARF_CB_OK;
- }
-
- if ((q->has_statement_str || q->has_function_str)
- && q->dw.function_name_matches(q->function))
- {
- // If this function's name matches a function or statement
- // pattern, we use its entry pc, but we do not abort iteration
- // since there might be other functions matching the pattern.
- query_statement(addr, q);
+ if (q->has_statement_str || q->has_function_str)
+ {
+ if (q->dw.function_name_matches(q->function))
+ {
+ // XXX: We assume addr is a global address here. Is it?
+ // XXX: This code is duplicated below, but it's important
+ // for performance reasons to test things in this order.
+
+ Dwarf_Addr addr;
+ if (!q->dw.function_entrypc(&addr))
+ {
+ if (q->sess.verbose)
+ clog << "WARNING: cannot find entry PC for function "
+ << q->dw.function_name << endl;
+ return DWARF_CB_OK;
+ }
+
+ // If this function's name matches a function or statement
+ // pattern, we use its entry pc, but we do not abort iteration
+ // since there might be other functions matching the pattern.
+ query_statement(addr, q);
+ }
}
- else if (q->has_kernel
- && q->has_function_num
- && q->dw.function_includes_global_addr(q->function_num_val))
- {
- // If this function's address range matches a kernel-relative
- // function address, we use its entry pc and break out of the
- // iteration, since there can only be one such function.
- query_statement(addr, q);
- return DWARF_CB_ABORT;
- }
- else if (q->has_module
- && q->has_function_num
- && q->dw.function_includes_module_addr(q->function_num_val))
+ else
{
- // If this function's address range matches a module-relative
- // function address, we use its entry pc and break out of the
- // iteration, since there can only be one such function.
- query_statement(addr, q);
- return DWARF_CB_ABORT;
+ // XXX: We assume addr is a global address here. Is it?
+ Dwarf_Addr addr;
+ if (!q->dw.function_entrypc(&addr))
+ {
+ if (false && q->sess.verbose)
+ clog << "WARNING: cannot find entry PC for function "
+ << q->dw.function_name << endl;
+ return DWARF_CB_OK;
+ }
+
+ if (q->has_kernel
+ && q->has_function_num
+ && q->dw.function_includes_global_addr(q->function_num_val))
+ {
+ // If this function's address range matches a kernel-relative
+ // function address, we use its entry pc and break out of the
+ // iteration, since there can only be one such function.
+ query_statement(addr, q);
+ return DWARF_CB_ABORT;
+ }
+ else if (q->has_module
+ && q->has_function_num
+ && q->dw.function_includes_module_addr(q->function_num_val))
+ {
+ // If this function's address range matches a module-relative
+ // function address, we use its entry pc and break out of the
+ // iteration, since there can only be one such function.
+ query_statement(addr, q);
+ return DWARF_CB_ABORT;
+ }
}
return DWARF_CB_OK;
@@ -910,7 +1037,6 @@ static int
query_module (Dwfl_Module *mod __attribute__ ((unused)),
void **userdata __attribute__ ((unused)),
const char *name, Dwarf_Addr base,
- Dwarf *dw, Dwarf_Addr bias,
void *arg __attribute__ ((unused)))
{
@@ -961,16 +1087,114 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
return DWARF_CB_OK;
}
-dwarf_derived_probe::dwarf_derived_probe (probe * p,
- probe_point * l,
+struct
+var_expanding_copy_visitor
+ : public deep_copy_visitor
+{
+ // Alas, we cannot easily mixin lvalue_aware_traversing_visitor.
+ // But behold the *awesome power* of copy and paste.
+
+ static unsigned tick;
+
+ dwarf_query & q;
+ unsigned lval_depth;
+ Dwarf_Addr addr;
+
+ var_expanding_copy_visitor(dwarf_query & q, Dwarf_Addr a)
+ : q(q), lval_depth(0), addr(a)
+ {}
+
+ bool is_in_lvalue()
+ {
+ return lval_depth > 0;
+ }
+
+ void visit_pre_crement (pre_crement* e)
+ {
+ ++lval_depth;
+ e->operand->visit (this);
+ --lval_depth;
+ }
+
+ void visit_post_crement (post_crement* e)
+ {
+ ++lval_depth;
+ e->operand->visit (this);
+ --lval_depth;
+ }
+
+ void visit_assignment (assignment* e)
+ {
+ ++lval_depth;
+ e->left->visit (this);
+ --lval_depth;
+ e->right->visit (this);
+ }
+
+ void visit_delete_statement (delete_statement* s)
+ {
+ ++lval_depth;
+ s->value->visit (this);
+ --lval_depth;
+ }
+
+ void visit_symbol (symbol* e);
+};
+
+
+unsigned var_expanding_copy_visitor::tick = 0;
+
+
+void
+var_expanding_copy_visitor::visit_symbol (symbol *e)
+{
+ if (e->name.size() > 0 &&
+ e->name[0] == '$')
+ {
+ if (is_in_lvalue())
+ {
+ throw semantic_error("read-only special variable "
+ + e->name + " used in lvalue", e->tok);
+ }
+
+ string fname = "get_" + e->name.substr(1) + "_" + lex_cast<string>(tick++);
+
+ // synthesize a function
+ functiondecl *fdecl = new functiondecl;
+ embeddedcode *ec = new embeddedcode;
+ ec->code = q.dw.literal_stmt_for_local(addr, e->name.substr(1));
+ fdecl->name = fname;
+ fdecl->body = ec;
+ fdecl->type = pe_long;
+ q.sess.functions.push_back(fdecl);
+
+ // synthesize a call
+ functioncall* n = new functioncall;
+ n->tok = e->tok;
+ n->function = fname;
+ n->referent = NULL;
+ provide <functioncall*> (this, n);
+
+ }
+ else
+ {
+ deep_copy_visitor::visit_symbol (e);
+ }
+}
+
+
+dwarf_derived_probe::dwarf_derived_probe (dwarf_query & q,
string const & module_name,
dwarf_probe_type type,
Dwarf_Addr addr)
- : derived_probe (p, l),
+ : derived_probe (NULL, q.base_loc),
module_name(module_name),
type(type),
addr(addr)
{
+ var_expanding_copy_visitor v (q, addr);
+ require <block*> (&v, &(this->body), q.base_probe->body);
+ this->tok = q.base_probe->tok;
}
void
diff --git a/translate.cxx b/translate.cxx
index 2667d7ab..78a75d91 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -492,6 +492,7 @@ c_unparser::emit_common_header ()
{
// XXX: tapsets.cxx should be able to add additional definitions
+ o->newline() << "#include \"loc2c-runtime.h\" ";
o->newline() << "#define MAXNESTING 30";
o->newline() << "#define MAXCONCURRENCY NR_CPUS";
o->newline() << "#define MAXSTRINGLEN 128";