Re: RFC: implement DW_OP_bit_piece

Tom Tromey
2010-05-26T21:59:04Z

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> I looked at DWARF->AX translation. I see how most of it can be done,
Tom> except:
[...]

I took a stab at this. Here is my work-in-progress patch. It rewrites
the DWARF->AX code to be a more direct translator, and not work by
pattern matching a few expressions.

It seems to do reasonably well on the handful of expressions I tried.
It generates slightly worse bytecode in some cases. I haven't handled
DW_OP_*piece yet, so it is a slight regression from what is in the tree.

Aside from the regression, what makes this a WIP is that I don't know
how to test it. Any pointers?

I'd appreciate comments on the approach.

Also, I added a new VEC_cleanup function as part of this. I've wanted
this on occasion, and this seemed like a decent opportunity to put it
in.

For the long term I think AX needs some updates to deal with the full
range of DWARF. I don't plan to tackle this, but I will at least file a
bug report.

Tom

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, &reg);
- 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..d1a3e48 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -997,266 +997,605 @@ 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
+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;
+static void
+access_register (struct agent_expr *expr, 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);
+ ax_reg (expr, reg);
+}

- /* (GDB-numbered) reg, or base reg if >= 0 */
- int reg;
+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;

- /* offset from reg */
- LONGEST offset;
-};
+ offsets = xmalloc ((op_end - op_ptr) * sizeof (int));
+ cleanups = make_cleanup (xfree, offsets);

-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)
-{
- if (data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31)
- {
- loc->kind = axs_lvalue_register;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_reg0);
- data += 1;
- }
- else if (data[0] == DW_OP_regx)
- {
- ULONGEST reg;
+ for (i = 0; i < op_end - op_ptr; ++i)
+ offsets[i] = -1;

- data = read_uleb128 (data + 1, end, &reg);
- loc->kind = axs_lvalue_register;
- loc->reg = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
- }
- 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;
+ make_cleanup (VEC_cleanup (int), &dw_labels);
+ make_cleanup (VEC_cleanup (int), &patches);

- b = block_for_pc (ax->scope);
+ /* By default we are making an address. */
+ loc->kind = axs_lvalue_memory;

- if (!b)
- error (_("No block found for address"));
+ while (op_ptr < op_end)
+ {
+ enum dwarf_location_atom op = *op_ptr;
+ CORE_ADDR result;
+ ULONGEST uoffset, reg;
+ LONGEST offset;
+ int i;

- framefunc = block_linkage_function (b);
+ offsets[op_ptr - base] = expr->len;
+ ++op_ptr;

- if (!framefunc)
- error (_("No function found for block"));
+ /* Our basic approach to code generation is to map DWARF
+ operations directly to AX operations. However, there are
+ some differences.

- dwarf_expr_frame_base_1 (framefunc, ax->scope,
- &base_data, &base_size);
+ 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.

- if (base_data[0] >= DW_OP_breg0 && base_data[0] <= DW_OP_breg31)
+ Second, some DWARF operations cannot be translated to AX.
+ For these we simply fail. */
+ switch (op)
{
- const gdb_byte *buf_end;
+ 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;

- 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
- {
- /* 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_addr:
+ result = dwarf2_read_address (arch, op_ptr, op_end, addr_size);
+ ax_const_l (expr, result);
+ op_ptr += addr_size;
+ break;

- data = read_sleb128 (data + 1, end, &frame_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;

- 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;
+ /* The DW_OP_reg operations are required to occur alone in
+ location expressions. */
+ 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");
+ access_register (expr, arch, op - DW_OP_reg0);
+ loc->kind = axs_lvalue_register;
+ break;

- reg = data[0] - DW_OP_breg0;
- data = read_sleb128 (data + 1, end, &offset);
+ case DW_OP_regx:
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
+ access_register (expr, arch, reg);
+ 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_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;

-/* Given the location of a piece, issue bytecodes that will access it. */
+ 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_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_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);
+ access_register (expr, arch, op - DW_OP_breg0);
+ ax_const_l (expr, offset);
+ ax_simple (expr, aop_add);
+ break;
+ case DW_OP_bregx:
+ {
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ op_ptr = read_sleb128 (op_ptr, op_end, &offset);
+ access_register (expr, arch, reg);
+ 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;

-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;
- }
+ b = block_for_pc (expr->scope);

- 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;
+ 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);
+
+ 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ 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 axs_lvalue_memory:
+ case DW_OP_abs:
+ /* Sign extend the operand. */
+ ax_ext (expr, 8 * addr_size);
+ 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, 8 * addr_size);
+ ax_simple (expr, aop_bit_not);
+ break;
+
+ case DW_OP_plus_uconst:
+ op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+ 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ /* 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ /* No need for a second swap here. */
+ ax_simple (expr, aop_equal);
+ break;
+
+ case DW_OP_lt:
+ /* Sign extend the operands. */
+ ax_ext (expr, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_simple (expr, aop_less_signed);
+ break;
+
+ case DW_OP_gt:
+ /* Sign extend the operands. */
+ ax_ext (expr, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ /* 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, 8 * addr_size);
+ ax_simple (expr, aop_swap);
+ ax_ext (expr, 8 * addr_size);
+ /* 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, 8 * addr_size);
+ 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:
+ {
+ ULONGEST size;
+
+ 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 (bits_collected + 8 * size > 8 * sizeof (LONGEST))
+ error (_("Expression pieces exceed word size"));
+
+ unimplemented (op);
+ }
+ break;
+
+ case DW_OP_bit_piece:
{
- extern int trace_kludge; /* Ugh. */
+ ULONGEST size, offset;

- gdb_assert (fragments[frag].bytes == 4);
- if (trace_kludge)
- ax_trace_quick (ax, 4);
- ax_simple (ax, aop_ref32);
+ if (op_ptr - 1 == previous_piece)
+ error (_("Cannot translate empty pieces to agent expressions"));
+ previous_piece = op_ptr - 1;
+
+ /* Record the piece. */
+ op_ptr = read_uleb128 (op_ptr, op_end, &size);
+ op_ptr = read_uleb128 (op_ptr, op_end, &offset);
+
+ if (bits_collected + size > 8 * sizeof (LONGEST))
+ error (_("Expression pieces exceed word size"));
+
+ unimplemented (op);
}
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);
}

\f
@@ -1813,9 +2152,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 +2297,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) \
{ \