* dwarf2expr.h (struct dwarf_expr_context): New members
authorJim Blandy <jimb@codesourcery.com>
Tue, 24 Aug 2004 21:01:49 +0000 (21:01 +0000)
committerJim Blandy <jimb@codesourcery.com>
Tue, 24 Aug 2004 21:01:49 +0000 (21:01 +0000)
'num_pieces' and 'pieces', for returning the result of an
expression that uses DW_OP_piece.
(struct dwarf_expr_piece): New struct type.
* dwarf2expr.c (new_dwarf_expr_context): Initialize num_pieces and
pieces.
(free_dwarf_expr_context): Free pieces, if any.
(add_piece): New function.
(execute_stack_op): Implement DW_OP_piece.
* dwarf2loc.c (dwarf2_evaluate_loc_desc): If the result of the
expression is a list of pieces, print an error message.
(dwarf2_loc_desc_needs_frame): If the expression yields
pieces, and any piece is in a register, then we need a frame.

gdb/ChangeLog
gdb/dwarf2expr.c
gdb/dwarf2expr.h
gdb/dwarf2loc.c

index 219ed9a..66c08d2 100644 (file)
@@ -1,5 +1,19 @@
 2004-08-24  Jim Blandy  <jimb@redhat.com>
 
+       * dwarf2expr.h (struct dwarf_expr_context): New members
+       'num_pieces' and 'pieces', for returning the result of an
+       expression that uses DW_OP_piece.
+       (struct dwarf_expr_piece): New struct type.
+       * dwarf2expr.c (new_dwarf_expr_context): Initialize num_pieces and
+       pieces.
+       (free_dwarf_expr_context): Free pieces, if any.
+       (add_piece): New function.
+       (execute_stack_op): Implement DW_OP_piece.
+       * dwarf2loc.c (dwarf2_evaluate_loc_desc): If the result of the
+       expression is a list of pieces, print an error message.
+        (dwarf2_loc_desc_needs_frame): If the expression yields
+        pieces, and any piece is in a register, then we need a frame.
+
        * dwarf2loc.c (dwarf2_evaluate_loc_desc): Wait to fetch the top of
        the stack until we've decided what sort of result the evaluation
        has produced.  Use separate variables, with more specific names.
index 294afa0..a60e5a9 100644 (file)
@@ -42,6 +42,8 @@ new_dwarf_expr_context (void)
   retval->stack_len = 0;
   retval->stack_allocated = 10;
   retval->stack = xmalloc (retval->stack_allocated * sizeof (CORE_ADDR));
+  retval->num_pieces = 0;
+  retval->pieces = 0;
   return retval;
 }
 
@@ -51,6 +53,7 @@ void
 free_dwarf_expr_context (struct dwarf_expr_context *ctx)
 {
   xfree (ctx->stack);
+  xfree (ctx->pieces);
   xfree (ctx);
 }
 
@@ -100,6 +103,29 @@ dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n)
 
 }
 
+/* Add a new piece to CTX's piece list.  */
+static void
+add_piece (struct dwarf_expr_context *ctx,
+           int in_reg, CORE_ADDR value, ULONGEST size)
+{
+  struct dwarf_expr_piece *p;
+
+  ctx->num_pieces++;
+
+  if (ctx->pieces)
+    ctx->pieces = xrealloc (ctx->pieces,
+                            (ctx->num_pieces
+                             * sizeof (struct dwarf_expr_piece)));
+  else
+    ctx->pieces = xmalloc (ctx->num_pieces
+                           * sizeof (struct dwarf_expr_piece));
+
+  p = &ctx->pieces[ctx->num_pieces - 1];
+  p->in_reg = in_reg;
+  p->value = value;
+  p->size = size;
+}
+
 /* Evaluate the expression at ADDR (LEN bytes long) using the context
    CTX.  */
 
@@ -661,6 +687,22 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
        case DW_OP_nop:
          goto no_push;
 
+        case DW_OP_piece:
+          {
+            ULONGEST size;
+            CORE_ADDR addr_or_regnum;
+
+            /* Record the piece.  */
+            op_ptr = read_uleb128 (op_ptr, op_end, &size);
+            addr_or_regnum = dwarf_expr_fetch (ctx, 0);
+            add_piece (ctx, ctx->in_reg, addr_or_regnum, size);
+
+            /* Pop off the address/regnum, and clear the in_reg flag.  */
+            dwarf_expr_pop (ctx);
+            ctx->in_reg = 0;
+          }
+          goto no_push;
+
        default:
          error ("Unhandled dwarf expression opcode 0x%x", op);
        }
index 0a60edb..f22d085 100644 (file)
@@ -74,6 +74,49 @@ struct dwarf_expr_context
   /* Non-zero if the result is in a register.  The register number
      will be on the expression stack.  */
   int in_reg;
+
+  /* An array of pieces.  PIECES points to its first element;
+     NUM_PIECES is its length.
+
+     Each time DW_OP_piece is executed, we add a new element to the
+     end of this array, recording the current top of the stack, the
+     current in_reg flag, and the size given as the operand to
+     DW_OP_piece.  We then pop the top value from the stack, clear the
+     in_reg flag, and resume evaluation.
+
+     The Dwarf spec doesn't say whether DW_OP_piece pops the top value
+     from the stack.  We do, ensuring that clients of this interface
+     expecting to see a value left on the top of the stack (say, code
+     evaluating frame base expressions or CFA's specified with
+     DW_CFA_def_cfa_expression) will get an error if the expression
+     actually marks all the values it computes as pieces.
+
+     If an expression never uses DW_OP_piece, num_pieces will be zero.
+     (It would be nice to present these cases as expressions yielding
+     a single piece, with in_reg clear, so that callers need not
+     distinguish between the no-DW_OP_piece and one-DW_OP_piece cases.
+     But expressions with no DW_OP_piece operations have no value to
+     place in a piece's 'size' field; the size comes from the
+     surrounding data.  So the two cases need to be handled
+     separately.)  */
+  int num_pieces;
+  struct dwarf_expr_piece *pieces;
+};
+
+
+/* A piece of an object, as recorded by DW_OP_piece.  */
+struct dwarf_expr_piece
+{
+  /* If IN_REG is zero, then the piece is in memory, and VALUE is its address.
+     If IN_REG is non-zero, then the piece is in a register, and VALUE
+     is the register number.  */
+  int in_reg;
+
+  /* This piece's address or register number.  */
+  CORE_ADDR value;
+
+  /* The length of the piece, in bytes.  */
+  ULONGEST size;
 };
 
 struct dwarf_expr_context *new_dwarf_expr_context (void);
index 3e7cdd6..c281642 100644 (file)
@@ -205,6 +205,7 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
                          unsigned char *data, unsigned short size,
                          struct objfile *objfile)
 {
+  struct gdbarch *arch = get_frame_arch (frame);
   struct value *retval;
   struct dwarf_expr_baton baton;
   struct dwarf_expr_context *ctx;
@@ -227,8 +228,15 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
   ctx->get_tls_address = dwarf_expr_tls_address;
 
   dwarf_expr_eval (ctx, data, size);
-
-  if (ctx->in_reg)
+  if (ctx->num_pieces > 0)
+    {
+      /* We haven't implemented splicing together pieces from
+         arbitrary sources yet.  */
+      error ("The value of variable '%s' is distributed across several\n"
+             "locations, and GDB cannot access its value.\n",
+             SYMBOL_NATURAL_NAME (var));
+    }
+  else if (ctx->in_reg)
     {
       CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0);
       int gdb_regnum = DWARF2_REG_TO_REGNUM (dwarf_regnum);
@@ -323,6 +331,17 @@ dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size)
 
   in_reg = ctx->in_reg;
 
+  if (ctx->num_pieces > 0)
+    {
+      int i;
+
+      /* If the location has several pieces, and any of them are in
+         registers, then we will need a frame to fetch them from.  */
+      for (i = 0; i < ctx->num_pieces; i++)
+        if (ctx->pieces[i].in_reg)
+          in_reg = 1;
+    }
+
   free_dwarf_expr_context (ctx);
 
   return baton.needs_frame || in_reg;