+
+/* Given the location of a piece, issue bytecodes that will access it. */
+
+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"));
+ }
+}
+
+static void
+dwarf2_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ gdb_byte *data, int size)
+{
+ 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;
+ }
+
+ 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;
+ break;
+ }
+ }
+
+ if (bad || data > end)
+ error (_("Corrupted DWARF expression for \"%s\"."),
+ SYMBOL_PRINT_NAME (symbol));
+
+ /* If single expression, no pieces, convert to external format. */
+ if (length == 0)
+ {
+ dwarf2_tracepoint_var_access (ax, value, &fragments[0]);
+ return;
+ }
+
+ if (length != TYPE_LENGTH (value->type))
+ error (_("Inconsistent piece information for \"%s\"."),
+ SYMBOL_PRINT_NAME (symbol));
+
+ /* Emit bytecodes to assemble the pieces into a single stack entry. */
+
+ 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);
+ }
+
+ dwarf2_tracepoint_var_access (ax, value, &fragments[frag]);
+
+ switch (value->kind)
+ {
+ case axs_lvalue_register:
+ ax_reg (ax, value->u.reg);
+ break;
+
+ case axs_lvalue_memory:
+ {
+ extern int trace_kludge; /* Ugh. */
+
+ gdb_assert (fragments[frag].bytes == 4);
+ if (trace_kludge)
+ ax_trace_quick (ax, 4);
+ ax_simple (ax, aop_ref32);
+ }
+ break;
+ }
+
+ if (!first)
+ {
+ /* or the new fragment into the previous */
+ ax_zero_ext (ax, 32);
+ ax_simple (ax, aop_bit_or);
+ }
+ first = 0;
+ }
+ value->kind = axs_rvalue;
+}
+