This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)
- From: Tom Tromey <tromey at redhat dot com>
- To: Stan Shebs <stan at codesourcery dot com>
- Cc: gdb-patches at sourceware dot org, Jan Kratochvil <jkratoch at redhat dot com>
- Date: Thu, 03 Jun 2010 14:12:13 -0600
- Subject: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)
- References: <m3ljbgdc4a.fsf@fleche.redhat.com> <4BF327D2.3000802@codesourcery.com> <m3632j79fw.fsf@fleche.redhat.com> <4BF48941.4090500@codesourcery.com> <m3y6ff5k0h.fsf@fleche.redhat.com> <m38w7f5c0h.fsf@fleche.redhat.com> <m3r5kyl3zt.fsf@fleche.redhat.com>
- Reply-to: Tom Tromey <tromey at redhat dot com>
>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:
Here is a new version of my patch to rewrite the DWARF->AX translator.
Tom> I haven't handled DW_OP_*piece yet, so it is a slight regression
Tom> from what is in the tree.
I fixed this. It now handles a larger subset of DW_OP_*piece operators.
It still can't handle all of them. That would require several changes.
A bit more could be done by adding arguments to
symbol_computed_ops::tracepoint_var_ref, and then changing ax-gdb.c to
specially handle a LOC_COMPUTED symbol as the LHS of a STRUCTOP_STRUCT.
I think supporting absolutely everything would require agent expression
updates.
Tom> For the long term I think AX needs some updates to deal with the full
Tom> range of DWARF. I don't plan to tackle this, but I will at least file a
Tom> bug report.
Now http://sourceware.org/bugzilla/show_bug.cgi?id=11662
Built and regtested on x86-64 (compile farm).
Let me know what you think. In the absence of comments I suppose I will
check this in next week sometime.
Tom
2010-06-03 Tom Tromey <tromey@redhat.com>
* vec.h (VEC_cleanup): New macro.
(DEF_VEC_ALLOC_FUNC_I): Update.
(DEF_VEC_ALLOC_FUNC_P): Likewise.
(DEF_VEC_ALLOC_FUNC_O): Likewise.
* dwarf2loc.c (struct axs_var_loc): Remove.
(unimplemented): New function.
(translate_register): Likewise.
(access_memory): Likewise.
(compile_dwarf_to_ax): Likewise.
(dwarf2_tracepoint_var_loc): Remove.
(dwarf2_tracepoint_var_access): Likewise.
(dwarf2_tracepoint_var_ref): Likewise.
(locexpr_tracepoint_var_ref): Use compile_dwarf_to_ax.
(loclist_tracepoint_var_ref): Likewise.
* dwarf2expr.h (dwarf_expr_require_composition): Declare.
* dwarf2expr.c (dwarf_expr_require_composition): Rename from
require_composition. No longer static.
(execute_stack_op): Update.
* ax-gdb.h (trace_kludge): Declare.
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index 4ec21e1..924df08 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -108,4 +108,6 @@ extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct gdbarch *,
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
+extern int trace_kludge;
+
#endif /* AX_GDB_H */
diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index c145cf4..ff77111 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -334,9 +334,9 @@ signed_address_type (struct gdbarch *gdbarch, int addr_size)
/* Check that the current operator is either at the end of an
expression, or that it is followed by a composition operator. */
-static void
-require_composition (const gdb_byte *op_ptr, const gdb_byte *op_end,
- const char *op_name)
+void
+dwarf_expr_require_composition (const gdb_byte *op_ptr, const gdb_byte *op_end,
+ const char *op_name)
{
/* It seems like DW_OP_GNU_uninit should be handled here. However,
it doesn't seem to make sense for DW_OP_*_value, and it was not
@@ -511,7 +511,7 @@ execute_stack_op (struct dwarf_expr_context *ctx,
case DW_OP_regx:
op_ptr = read_uleb128 (op_ptr, op_end, ®);
- require_composition (op_ptr, op_end, "DW_OP_regx");
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
result = reg;
ctx->location = DWARF_VALUE_REGISTER;
@@ -528,13 +528,14 @@ execute_stack_op (struct dwarf_expr_context *ctx,
ctx->data = op_ptr;
ctx->location = DWARF_VALUE_LITERAL;
op_ptr += len;
- require_composition (op_ptr, op_end, "DW_OP_implicit_value");
+ dwarf_expr_require_composition (op_ptr, op_end,
+ "DW_OP_implicit_value");
}
goto no_push;
case DW_OP_stack_value:
ctx->location = DWARF_VALUE_STACK;
- require_composition (op_ptr, op_end, "DW_OP_stack_value");
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
goto no_push;
case DW_OP_breg0:
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index 8ebbf87..7abdf24 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -210,4 +210,7 @@ CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
const char *dwarf_stack_op_name (unsigned int, int);
+void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
+ const char *);
+
#endif /* dwarf2expr.h */
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 8fff824..1f0c0df 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -997,266 +997,722 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size,
return baton.needs_frame || in_reg;
}
-/* This struct keeps track of the pieces that make up a multi-location
- object, for use in agent expression generation. It is
- superficially similar to struct dwarf_expr_piece, but
- dwarf_expr_piece is designed for use in immediate evaluation, and
- does not, for example, have a way to record both base register and
- offset. */
-
-struct axs_var_loc
+/* A helper function that throws an unimplemented error mentioning a
+ given DWARF operator. */
+
+static void
+unimplemented (unsigned int op)
{
- /* Memory vs register, etc */
- enum axs_lvalue_kind kind;
+ error (_("DWARF operator %s cannot be translated to an agent expression"),
+ dwarf_stack_op_name (op, 1));
+}
- /* If non-zero, number of bytes in this fragment */
- unsigned bytes;
+/* A helper function to convert a DWARF register to an arch register.
+ ARCH is the architecture.
+ DWARF_REG is the register.
+ This will throw an exception if the DWARF register cannot be
+ translated to an architecture register. */
- /* (GDB-numbered) reg, or base reg if >= 0 */
- int reg;
+static int
+translate_register (struct gdbarch *arch, int dwarf_reg)
+{
+ int reg = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_reg);
+ if (reg == -1)
+ error (_("Unable to access DWARF register number %d"), dwarf_reg);
+ return reg;
+}
- /* offset from reg */
- LONGEST offset;
-};
+/* A helper function that emits an access to memory. ARCH is the
+ target architecture. EXPR is the expression which we are building.
+ NBITS is the number of bits we want to read. This emits the
+ opcodes needed to read the memory and then extract the desired
+ bits. */
-static const gdb_byte *
-dwarf2_tracepoint_var_loc (struct symbol *symbol,
- struct agent_expr *ax,
- struct axs_var_loc *loc,
- struct gdbarch *gdbarch,
- const gdb_byte *data, const gdb_byte *end)
+static void
+access_memory (struct gdbarch *arch, struct agent_expr *expr, ULONGEST nbits)
{
- if (data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31)
+ ULONGEST nbytes = (nbits + 7) / 8;
+
+ gdb_assert (nbits > 0 && nbits <= sizeof (LONGEST));
+
+ if (trace_kludge)
+ ax_trace_quick (expr, nbytes);
+
+ if (nbits <= 8)
+ ax_simple (expr, aop_ref8);
+ else if (nbits <= 16)
+ ax_simple (expr, aop_ref16);
+ else if (nbits <= 32)
+ ax_simple (expr, aop_ref32);
+ else
+ ax_simple (expr, aop_ref64);
+
+ /* If we read exactly the number of bytes we wanted, we're done. */
+ if (8 * nbytes == nbits)
+ return;
+
+ if (gdbarch_bits_big_endian (arch))
{
- loc->kind = axs_lvalue_register;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_reg0);
- data += 1;
+ /* On a bits-big-endian machine, we want the high-order
+ NBITS. */
+ ax_const_l (expr, 8 * nbytes - nbits);
+ ax_simple (expr, aop_rsh_unsigned);
}
- else if (data[0] == DW_OP_regx)
+ else
{
- ULONGEST reg;
-
- data = read_uleb128 (data + 1, end, ®);
- loc->kind = axs_lvalue_register;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
+ /* On a bits-little-endian box, we want the low-order NBITS. */
+ ax_zero_ext (expr, nbits);
}
- else if (data[0] == DW_OP_fbreg)
- {
- struct block *b;
- struct symbol *framefunc;
- int frame_reg = 0;
- LONGEST frame_offset;
- const gdb_byte *base_data;
- size_t base_size;
- LONGEST base_offset = 0;
+}
- b = block_for_pc (ax->scope);
+/* Compile a DWARF location expression to an agent expression.
+
+ EXPR is the agent expression we are building.
+ LOC is the agent value we modify.
+ ARCH is the architecture.
+ ADDR_SIZE is the size of addresses, in bytes.
+ OP_PTR is the start of the location expression.
+ OP_END is one past the last byte of the location expression.
+
+ This will throw an exception for various kinds of errors -- for
+ example, if the expression cannot be compiled, or if the expression
+ is invalid. */
- if (!b)
- error (_("No block found for address"));
+static void
+compile_dwarf_to_ax (struct agent_expr *expr, struct axs_value *loc,
+ struct gdbarch *arch, unsigned int addr_size,
+ const gdb_byte *op_ptr, const gdb_byte *op_end)
+{
+ struct cleanup *cleanups;
+ int i, *offsets;
+ VEC(int) *dw_labels = NULL, *patches = NULL;
+ const gdb_byte * const base = op_ptr;
+ const gdb_byte *previous_piece = op_ptr;
+ enum bfd_endian byte_order = gdbarch_byte_order (arch);
+ ULONGEST bits_collected = 0;
+ unsigned int addr_size_bits = 8 * addr_size;
+ int bits_big_endian = gdbarch_bits_big_endian (arch);
- framefunc = block_linkage_function (b);
+ offsets = xmalloc ((op_end - op_ptr) * sizeof (int));
+ cleanups = make_cleanup (xfree, offsets);
- if (!framefunc)
- error (_("No function found for block"));
+ for (i = 0; i < op_end - op_ptr; ++i)
+ offsets[i] = -1;
- dwarf_expr_frame_base_1 (framefunc, ax->scope,
- &base_data, &base_size);
+ make_cleanup (VEC_cleanup (int), &dw_labels);
+ make_cleanup (VEC_cleanup (int), &patches);
- if (base_data[0] >= DW_OP_breg0 && base_data[0] <= DW_OP_breg31)
- {
- const gdb_byte *buf_end;
+ /* By default we are making an address. */
+ loc->kind = axs_lvalue_memory;
- frame_reg = base_data[0] - DW_OP_breg0;
- buf_end = read_sleb128 (base_data + 1,
- base_data + base_size, &base_offset);
- if (buf_end != base_data + base_size)
- error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."),
- frame_reg, SYMBOL_PRINT_NAME (symbol));
- }
- else if (base_data[0] >= DW_OP_reg0 && base_data[0] <= DW_OP_reg31)
- {
- /* The frame base is just the register, with no offset. */
- frame_reg = base_data[0] - DW_OP_reg0;
- base_offset = 0;
- }
- else
+ while (op_ptr < op_end)
+ {
+ enum dwarf_location_atom op = *op_ptr;
+ CORE_ADDR result;
+ ULONGEST uoffset, reg;
+ LONGEST offset;
+ int i;
+
+ offsets[op_ptr - base] = expr->len;
+ ++op_ptr;
+
+ /* Our basic approach to code generation is to map DWARF
+ operations directly to AX operations. However, there are
+ some differences.
+
+ First, DWARF works on address-sized units, but AX always uses
+ LONGEST. For most operations we simply ignore this
+ difference; instead we generate sign extensions as needed
+ before division and comparison operations. It would be nice
+ to omit the sign extensions, but there is no way to determine
+ the size of the target's LONGEST. (This code uses the size
+ of the host LONGEST in some cases -- that is a bug but it is
+ difficult to fix.)
+
+ Second, some DWARF operations cannot be translated to AX.
+ For these we simply fail. See
+ http://sourceware.org/bugzilla/show_bug.cgi?id=11662. */
+ switch (op)
{
- /* We don't know what to do with the frame base expression,
- so we can't trace this variable; give up. */
- error (_("Cannot generate expression to collect symbol \"%s\"; DWARF 2 encoding not handled, first opcode in base data is 0x%x."),
- SYMBOL_PRINT_NAME (symbol), base_data[0]);
- }
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ ax_const_l (expr, op - DW_OP_lit0);
+ break;
- data = read_sleb128 (data + 1, end, &frame_offset);
+ case DW_OP_addr:
+ result = dwarf2_read_address (arch, op_ptr, op_end, addr_size);
+ ax_const_l (expr, result);
+ op_ptr += addr_size;
+ break;
- loc->kind = axs_lvalue_memory;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
- loc->offset = base_offset + frame_offset;
- }
- else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
- {
- unsigned int reg;
- LONGEST offset;
+ case DW_OP_const1u:
+ ax_const_l (expr, extract_unsigned_integer (op_ptr, 1, byte_order));
+ op_ptr += 1;
+ break;
+ case DW_OP_const1s:
+ ax_const_l (expr, extract_signed_integer (op_ptr, 1, byte_order));
+ op_ptr += 1;
+ break;
+ case DW_OP_const2u:
+ ax_const_l (expr, extract_unsigned_integer (op_ptr, 2, byte_order));
+ op_ptr += 2;
+ break;
+ case DW_OP_const2s:
+ ax_const_l (expr, extract_signed_integer (op_ptr, 2, byte_order));
+ op_ptr += 2;
+ break;
+ case DW_OP_const4u:
+ ax_const_l (expr, extract_unsigned_integer (op_ptr, 4, byte_order));
+ op_ptr += 4;
+ break;
+ case DW_OP_const4s:
+ ax_const_l (expr, extract_signed_integer (op_ptr, 4, byte_order));
+ op_ptr += 4;
+ break;
+ case DW_OP_const8u:
+ ax_const_l (expr, extract_unsigned_integer (op_ptr, 8, byte_order));
+ op_ptr += 8;
+ break;
+ case DW_OP_const8s:
+ ax_const_l (expr, extract_signed_integer (op_ptr, 8, byte_order));
+ op_ptr += 8;
+ break;
+ case DW_OP_constu:
+ op_ptr = read_uleb128 (op_ptr, op_end, &uoffset);
+ ax_const_l (expr, uoffset);
+ break;
+ case DW_OP_consts:
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ ax_const_l (expr, offset);
+ break;
- reg = data[0] - DW_OP_breg0;
- data = read_sleb128 (data + 1, end, &offset);
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
+ loc->u.reg = translate_register (arch, op - DW_OP_reg0);
+ loc->kind = axs_lvalue_register;
+ break;
- loc->kind = axs_lvalue_memory;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
- loc->offset = offset;
- }
- else
- error (_("Unsupported DWARF opcode 0x%x in the location of \"%s\"."),
- data[0], SYMBOL_PRINT_NAME (symbol));
-
- return data;
-}
+ case DW_OP_regx:
+ op_ptr = read_uleb128 (op_ptr, op_end, ®);
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
+ loc->u.reg = translate_register (arch, reg);
+ loc->kind = axs_lvalue_register;
+ break;
-/* Given the location of a piece, issue bytecodes that will access it. */
+ case DW_OP_implicit_value:
+ {
+ ULONGEST len;
+
+ op_ptr = read_uleb128 (op_ptr, op_end, &len);
+ if (op_ptr + len > op_end)
+ error (_("DW_OP_implicit_value: too few bytes available."));
+ if (len > sizeof (ULONGEST))
+ error (_("Cannot translate DW_OP_implicit_value of %d bytes"),
+ (int) len);
+
+ ax_const_l (expr, extract_unsigned_integer (op_ptr, len,
+ byte_order));
+ op_ptr += len;
+ dwarf_expr_require_composition (op_ptr, op_end,
+ "DW_OP_implicit_value");
+
+ loc->kind = axs_rvalue;
+ }
+ break;
-static void
-dwarf2_tracepoint_var_access (struct agent_expr *ax,
- struct axs_value *value,
- struct axs_var_loc *loc)
-{
- value->kind = loc->kind;
-
- switch (loc->kind)
- {
- case axs_lvalue_register:
- value->u.reg = loc->reg;
- break;
-
- case axs_lvalue_memory:
- ax_reg (ax, loc->reg);
- if (loc->offset)
- {
- ax_const_l (ax, loc->offset);
- ax_simple (ax, aop_add);
- }
- break;
-
- default:
- internal_error (__FILE__, __LINE__, _("Unhandled value kind in dwarf2_tracepoint_var_access"));
- }
-}
+ case DW_OP_stack_value:
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
+ loc->kind = axs_rvalue;
+ break;
-static void
-dwarf2_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
- struct agent_expr *ax, struct axs_value *value,
- const gdb_byte *data, int size)
-{
- const gdb_byte *end = data + size;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- /* In practice, a variable is not going to be spread across
- dozens of registers or memory locations. If someone comes up
- with a real-world example, revisit this. */
-#define MAX_FRAGS 16
- struct axs_var_loc fragments[MAX_FRAGS];
- int nfrags = 0, frag;
- int length = 0;
- int piece_ok = 0;
- int bad = 0;
- int first = 1;
-
- if (!data || size == 0)
- {
- value->optimized_out = 1;
- return;
- }
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ i = translate_register (arch, op - DW_OP_breg0);
+ ax_reg (expr, i);
+ if (offset != 0)
+ {
+ ax_const_l (expr, offset);
+ ax_simple (expr, aop_add);
+ }
+ break;
+ case DW_OP_bregx:
+ {
+ op_ptr = read_uleb128 (op_ptr, op_end, ®);
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ i = translate_register (arch, reg);
+ ax_reg (expr, i);
+ if (offset != 0)
+ {
+ ax_const_l (expr, offset);
+ ax_simple (expr, aop_add);
+ }
+ }
+ break;
+ case DW_OP_fbreg:
+ {
+ const gdb_byte *datastart;
+ size_t datalen;
+ unsigned int before_stack_len;
+ struct block *b;
+ struct symbol *framefunc;
+ LONGEST base_offset = 0;
- while (data < end)
- {
- if (!piece_ok)
- {
- if (nfrags == MAX_FRAGS)
- error (_("Too many pieces in location for \"%s\"."),
- SYMBOL_PRINT_NAME (symbol));
-
- fragments[nfrags].bytes = 0;
- data = dwarf2_tracepoint_var_loc (symbol, ax, &fragments[nfrags],
- gdbarch, data, end);
- nfrags++;
- piece_ok = 1;
- }
- else if (data[0] == DW_OP_piece)
- {
- ULONGEST bytes;
-
- data = read_uleb128 (data + 1, end, &bytes);
- /* Only deal with 4 byte fragments for now. */
- if (bytes != 4)
- error (_("DW_OP_piece %s not supported in location for \"%s\"."),
- pulongest (bytes), SYMBOL_PRINT_NAME (symbol));
- fragments[nfrags - 1].bytes = bytes;
- length += bytes;
- piece_ok = 0;
- }
- else
- {
- bad = 1;
+ b = block_for_pc (expr->scope);
+
+ if (!b)
+ error (_("No block found for address"));
+
+ framefunc = block_linkage_function (b);
+
+ if (!framefunc)
+ error (_("No function found for block"));
+
+ dwarf_expr_frame_base_1 (framefunc, expr->scope,
+ &datastart, &datalen);
+
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ compile_dwarf_to_ax (expr, loc, arch, addr_size, datastart,
+ datastart + datalen);
+
+ if (offset != 0)
+ {
+ ax_const_l (expr, offset);
+ ax_simple (expr, aop_add);
+ }
+
+ loc->kind = axs_lvalue_memory;
+ }
break;
- }
- }
- if (bad || data > end)
- error (_("Corrupted DWARF expression for \"%s\"."),
- SYMBOL_PRINT_NAME (symbol));
+ case DW_OP_dup:
+ ax_simple (expr, aop_dup);
+ break;
- /* If single expression, no pieces, convert to external format. */
- if (length == 0)
- {
- dwarf2_tracepoint_var_access (ax, value, &fragments[0]);
- return;
- }
+ case DW_OP_drop:
+ ax_simple (expr, aop_pop);
+ break;
- if (length != TYPE_LENGTH (value->type))
- error (_("Inconsistent piece information for \"%s\"."),
- SYMBOL_PRINT_NAME (symbol));
+ case DW_OP_pick:
+ offset = *op_ptr++;
+ unimplemented (op);
+ break;
+
+ case DW_OP_swap:
+ ax_simple (expr, aop_swap);
+ break;
- /* Emit bytecodes to assemble the pieces into a single stack entry. */
+ case DW_OP_over:
+ /* We can't directly support DW_OP_over, but GCC emits it as
+ part of a sequence to implement signed modulus. As a
+ hack, we recognize this sequence. Note that if GCC ever
+ generates a branch to the middle of this sequence, then
+ we will die somehow. */
+ if (op_end - op_ptr >= 4
+ && op_ptr[0] == DW_OP_over
+ && op_ptr[1] == DW_OP_div
+ && op_ptr[2] == DW_OP_mul
+ && op_ptr[3] == DW_OP_minus)
+ {
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_rem_signed);
+ op_ptr += 4;
+ }
+ else
+ unimplemented (op);
+ break;
- for ((frag = (byte_order == BFD_ENDIAN_BIG ? 0 : nfrags - 1));
- nfrags--;
- (frag += (byte_order == BFD_ENDIAN_BIG ? 1 : -1)))
- {
- if (!first)
- {
- /* shift the previous fragment up 32 bits */
- ax_const_l (ax, 32);
- ax_simple (ax, aop_lsh);
- }
+ case DW_OP_rot:
+ unimplemented (op);
+ break;
- dwarf2_tracepoint_var_access (ax, value, &fragments[frag]);
+ case DW_OP_deref:
+ case DW_OP_deref_size:
+ {
+ int size;
- switch (value->kind)
- {
- case axs_lvalue_register:
- ax_reg (ax, value->u.reg);
+ if (op == DW_OP_deref_size)
+ size = *op_ptr++;
+ else
+ size = addr_size;
+
+ switch (size)
+ {
+ case 8:
+ ax_simple (expr, aop_ref8);
+ break;
+ case 16:
+ ax_simple (expr, aop_ref16);
+ break;
+ case 32:
+ ax_simple (expr, aop_ref32);
+ break;
+ case 64:
+ ax_simple (expr, aop_ref64);
+ break;
+ default:
+ error (_("Unsupported size %d in %s"),
+ size, dwarf_stack_op_name (op, 1));
+ }
+ }
+ break;
+
+ case DW_OP_abs:
+ /* Sign extend the operand. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_dup);
+ ax_const_l (expr, 0);
+ ax_simple (expr, aop_less_signed);
+ ax_simple (expr, aop_log_not);
+ i = ax_goto (expr, aop_if_goto);
+ /* We have to emit 0 - X. */
+ ax_const_l (expr, 0);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_sub);
+ ax_label (expr, i, expr->len);
+ break;
+
+ case DW_OP_neg:
+ /* No need to sign extend here. */
+ ax_const_l (expr, 0);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_sub);
+ break;
+
+ case DW_OP_not:
+ /* Sign extend the operand. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_bit_not);
break;
- case axs_lvalue_memory:
+ case DW_OP_plus_uconst:
+ op_ptr = read_uleb128 (op_ptr, op_end, ®);
+ /* It would be really weird to emit `DW_OP_plus_uconst 0',
+ but we micro-optimize anyhow. */
+ if (reg != 0)
+ {
+ ax_const_l (expr, reg);
+ ax_simple (expr, aop_add);
+ }
+ break;
+
+ case DW_OP_and:
+ ax_simple (expr, aop_bit_and);
+ break;
+
+ case DW_OP_div:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_div_signed);
+ break;
+
+ case DW_OP_minus:
+ ax_simple (expr, aop_sub);
+ break;
+
+ case DW_OP_mod:
+ ax_simple (expr, aop_rem_unsigned);
+ break;
+
+ case DW_OP_mul:
+ ax_simple (expr, aop_mul);
+ break;
+
+ case DW_OP_or:
+ ax_simple (expr, aop_bit_or);
+ break;
+
+ case DW_OP_plus:
+ ax_simple (expr, aop_add);
+ break;
+
+ case DW_OP_shl:
+ ax_simple (expr, aop_lsh);
+ break;
+
+ case DW_OP_shr:
+ ax_simple (expr, aop_rsh_unsigned);
+ break;
+
+ case DW_OP_shra:
+ ax_simple (expr, aop_rsh_signed);
+ break;
+
+ case DW_OP_xor:
+ ax_simple (expr, aop_bit_xor);
+ break;
+
+ case DW_OP_le:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ /* Note no swap here: A <= B is !(B < A). */
+ ax_simple (expr, aop_less_signed);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case DW_OP_ge:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ /* A >= B is !(A < B). */
+ ax_simple (expr, aop_less_signed);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case DW_OP_eq:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ /* No need for a second swap here. */
+ ax_simple (expr, aop_equal);
+ break;
+
+ case DW_OP_lt:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_less_signed);
+ break;
+
+ case DW_OP_gt:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ /* Note no swap here: A > B is B < A. */
+ ax_simple (expr, aop_less_signed);
+ break;
+
+ case DW_OP_ne:
+ /* Sign extend the operands. */
+ ax_ext (expr, addr_size_bits);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, addr_size_bits);
+ /* No need for a swap here. */
+ ax_simple (expr, aop_equal);
+ ax_simple (expr, aop_log_not);
+ break;
+
+ case DW_OP_call_frame_cfa:
+ unimplemented (op);
+ break;
+
+ case DW_OP_GNU_push_tls_address:
+ unimplemented (op);
+ break;
+
+ case DW_OP_skip:
+ offset = extract_signed_integer (op_ptr, 2, byte_order);
+ op_ptr += 2;
+ i = ax_goto (expr, aop_goto);
+ VEC_safe_push (int, dw_labels, op_ptr + offset - base);
+ VEC_safe_push (int, patches, i);
+ break;
+
+ case DW_OP_bra:
+ offset = extract_signed_integer (op_ptr, 2, byte_order);
+ op_ptr += 2;
+ /* Zero extend the operand. */
+ ax_zero_ext (expr, addr_size_bits);
+ i = ax_goto (expr, aop_if_goto);
+ VEC_safe_push (int, dw_labels, op_ptr + offset - base);
+ VEC_safe_push (int, patches, i);
+ break;
+
+ case DW_OP_nop:
+ break;
+
+ case DW_OP_piece:
+ case DW_OP_bit_piece:
{
- extern int trace_kludge; /* Ugh. */
+ ULONGEST size, offset;
+
+ if (op_ptr - 1 == previous_piece)
+ error (_("Cannot translate empty pieces to agent expressions"));
+ previous_piece = op_ptr - 1;
+
+ op_ptr = read_uleb128 (op_ptr, op_end, &size);
+ if (op == DW_OP_piece)
+ {
+ size *= 8;
+ offset = 0;
+ }
+ else
+ op_ptr = read_uleb128 (op_ptr, op_end, &offset);
+
+ if (bits_collected + size > 8 * sizeof (LONGEST))
+ error (_("Expression pieces exceed word size"));
- gdb_assert (fragments[frag].bytes == 4);
- if (trace_kludge)
- ax_trace_quick (ax, 4);
- ax_simple (ax, aop_ref32);
+ /* Access the bits. */
+ switch (loc->kind)
+ {
+ case axs_lvalue_register:
+ ax_reg (expr, loc->u.reg);
+ break;
+
+ case axs_lvalue_memory:
+ /* Offset the pointer, if needed. */
+ if (offset > 8)
+ {
+ ax_const_l (expr, offset / 8);
+ ax_simple (expr, aop_add);
+ offset %= 8;
+ }
+ access_memory (arch, expr, size);
+ break;
+ }
+
+ /* For a bits-big-endian target, shift up what we already
+ have. For a bits-little-endian target, shift up the
+ new data. Note that there is a potential bug here if
+ the DWARF expression leaves multiple values on the
+ stack. */
+ if (bits_collected > 0)
+ {
+ if (bits_big_endian)
+ {
+ ax_simple (expr, aop_swap);
+ ax_const_l (expr, size);
+ ax_simple (expr, aop_lsh);
+ /* We don't need a second swap here, because
+ aop_bit_or is symmetric. */
+ }
+ else
+ {
+ ax_const_l (expr, size);
+ ax_simple (expr, aop_lsh);
+ }
+ ax_simple (expr, aop_bit_or);
+ }
+
+ bits_collected += size;
+ loc->kind = axs_rvalue;
}
break;
- }
- if (!first)
- {
- /* or the new fragment into the previous */
- ax_zero_ext (ax, 32);
- ax_simple (ax, aop_bit_or);
+ case DW_OP_GNU_uninit:
+ unimplemented (op);
+
+ default:
+ error (_("Unhandled dwarf expression opcode 0x%x"), op);
}
- first = 0;
}
- value->kind = axs_rvalue;
+
+ /* Patch all the branches we emitted. */
+ for (i = 0; i < VEC_length (int, patches); ++i)
+ {
+ int targ = offsets[VEC_index (int, dw_labels, i)];
+ if (targ == -1)
+ internal_error (__FILE__, __LINE__, _("invalid label"));
+ ax_label (expr, VEC_index (int, patches, i), targ);
+ }
+
+ do_cleanups (cleanups);
}
@@ -1813,9 +2269,10 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value)
{
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
- dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value,
- dlbaton->data, dlbaton->size);
+ compile_dwarf_to_ax (ax, value, gdbarch, addr_size,
+ dlbaton->data, dlbaton->data + dlbaton->size);
}
/* The set of location functions used with the DWARF-2 expression
@@ -1957,10 +2414,11 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
const gdb_byte *data;
size_t size;
+ unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
data = find_location_expression (dlbaton, &size, ax->scope);
- dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size);
+ compile_dwarf_to_ax (ax, value, gdbarch, addr_size, data, data + size);
}
/* The set of location functions used with the DWARF-2 expression
diff --git a/gdb/vec.h b/gdb/vec.h
index 6690588..e9d5a15 100644
--- a/gdb/vec.h
+++ b/gdb/vec.h
@@ -184,6 +184,13 @@
#define VEC_free(T,V) (VEC_OP(T,free)(&V))
+/* A cleanup function for a vector.
+ void VEC_T_cleanup(void *);
+
+ Clean up a vector. */
+
+#define VEC_cleanup(T) (VEC_OP(T,cleanup))
+
/* Use these to determine the required size and initialization of a
vector embedded within another structure (as the final member).
@@ -461,6 +468,15 @@ static inline void VEC_OP (T,free) \
*vec_ = NULL; \
} \
\
+static inline void VEC_OP (T,cleanup) \
+ (void *arg_) \
+{ \
+ VEC(T) **vec_ = arg_; \
+ if (*vec_) \
+ vec_free_ (*vec_); \
+ *vec_ = NULL; \
+} \
+ \
static inline int VEC_OP (T,reserve) \
(VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \
{ \
@@ -699,6 +715,15 @@ static inline void VEC_OP (T,free) \
*vec_ = NULL; \
} \
\
+static inline void VEC_OP (T,cleanup) \
+ (void *arg_) \
+{ \
+ VEC(T) **vec_ = arg_; \
+ if (*vec_) \
+ vec_free_ (*vec_); \
+ *vec_ = NULL; \
+} \
+ \
static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \
{ \
size_t len_ = vec_ ? vec_->num : 0; \
@@ -957,6 +982,15 @@ static inline void VEC_OP (T,free) \
*vec_ = NULL; \
} \
\
+static inline void VEC_OP (T,cleanup) \
+ (void *arg_) \
+{ \
+ VEC(T) **vec_ = arg_; \
+ if (*vec_) \
+ vec_free_ (*vec_); \
+ *vec_ = NULL; \
+} \
+ \
static inline int VEC_OP (T,reserve) \
(VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \
{ \