public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* RFC: implement DW_OP_bit_piece
@ 2010-05-18 23:43 Tom Tromey
  2010-05-19 14:16 ` Stan Shebs
  2010-05-20 21:07 ` RFC: implement DW_OP_bit_piece Jan Kratochvil
  0 siblings, 2 replies; 36+ messages in thread
From: Tom Tromey @ 2010-05-18 23:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

I plan to check this in, but first I would appreciate comments on the
implementation.

This patch implements DW_OP_bit_piece.  This is needed now that Jakub
has pushed in gcc patches to generate it when SRA optimization is
performed.

The basic idea is simple: in read_pieced_value and write_pieced_value,
do all operations by bits and not bytes.  The implementation is a big
mess because we can have nonzero bit offsets for both the source and
destination buffers.

We do take care to optimize for the byte-aligned case.  We could go a
little further and lazily create the cleanup we need, but I elected not
to do that, on the grounds that it is a premature optimization.

This revealed one gdb bug, which I will report.  It is kfail'd in the
test suite; I will update that with the bug number.

Built and regtested on x86-64 (compile farm).
New test included.

I haven't yet tried this on a big-endian box.  I will do that tomorrow.

Tom

2010-05-18  Tom Tromey  <tromey@redhat.com>

	* dwarf2loc.c (extract_bits_primitive): New function.
	(extract_bits): Likewise.
	(insert_bits): Likewise.
	(copy_bitwise): Likewise.
	(read_pieced_value): Do all operations in bits.
	(write_pieced_value): Likewise.
	* dwarf2expr.h (struct dwarf_expr_piece) <location>: Shrink size.
	<offset, bit_piece>: New fields.
	* dwarf2expr.c (add_piece): New arguments bit_piece, offset.
	Always use xrealloc to resize piece array.
	(execute_stack_op) <DW_OP_reg0>: Handle DW_OP_bit_piece.
	<DW_OP_piece>: Update.
	<DW_OP_bit_piece>: New case.

2010-05-18  Tom Tromey  <tromey@redhat.com>

	* gdb.dwarf2/pieces.exp (pieces_test_f3): New proc.
	Call it.
	* gdb.dwarf2/pieces.S: Update.
	* gdb.dwarf2/pieces.c (struct B): Remove initial field.

diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 482c293..c288caa 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -151,23 +151,27 @@ dwarf_expr_stack_empty_p (struct dwarf_expr_context *ctx)
 
 /* Add a new piece to CTX's piece list.  */
 static void
-add_piece (struct dwarf_expr_context *ctx, ULONGEST size)
+add_piece (struct dwarf_expr_context *ctx, ULONGEST size, int bit_piece,
+	   ULONGEST offset)
 {
   struct dwarf_expr_piece *p;
 
+  if (bit_piece && offset >= ctx->addr_size)
+    error (_("DWARF reader does not support DW_OP_bit_piece offset greater "
+	     "than address size."));
+
   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));
+  ctx->pieces = xrealloc (ctx->pieces,
+			  (ctx->num_pieces
+			   * sizeof (struct dwarf_expr_piece)));
 
   p = &ctx->pieces[ctx->num_pieces - 1];
   p->location = ctx->location;
+  p->bit_piece = bit_piece;
   p->size = size;
+  p->offset = offset;
+
   if (p->location == DWARF_VALUE_LITERAL)
     {
       p->v.literal.data = ctx->data;
@@ -496,9 +500,11 @@ execute_stack_op (struct dwarf_expr_context *ctx,
 	case DW_OP_reg31:
 	  if (op_ptr != op_end 
 	      && *op_ptr != DW_OP_piece
+	      && *op_ptr != DW_OP_bit_piece
 	      && *op_ptr != DW_OP_GNU_uninit)
 	    error (_("DWARF-2 expression error: DW_OP_reg operations must be "
-		   "used either alone or in conjuction with DW_OP_piece."));
+		     "used either alone or in conjuction with DW_OP_piece "
+		     "or DW_OP_bit_piece."));
 
 	  result = op - DW_OP_reg0;
 	  ctx->location = DWARF_VALUE_REGISTER;
@@ -866,7 +872,7 @@ execute_stack_op (struct dwarf_expr_context *ctx,
 
             /* Record the piece.  */
             op_ptr = read_uleb128 (op_ptr, op_end, &size);
-	    add_piece (ctx, size);
+	    add_piece (ctx, size, 0, 0);
 
             /* Pop off the address/regnum, and reset the location
 	       type.  */
@@ -877,6 +883,24 @@ execute_stack_op (struct dwarf_expr_context *ctx,
           }
           goto no_push;
 
+	case DW_OP_bit_piece:
+	  {
+	    ULONGEST size, offset;
+
+            /* Record the piece.  */
+	    op_ptr = read_uleb128 (op_ptr, op_end, &size);
+	    op_ptr = read_uleb128 (op_ptr, op_end, &offset);
+	    add_piece (ctx, size, 1, offset);
+
+            /* Pop off the address/regnum, and reset the location
+	       type.  */
+	    if (ctx->location != DWARF_VALUE_LITERAL
+		&& ctx->location != DWARF_VALUE_OPTIMIZED_OUT)
+	      dwarf_expr_pop (ctx);
+            ctx->location = DWARF_VALUE_MEMORY;
+	  }
+	  goto no_push;
+
 	case DW_OP_GNU_uninit:
 	  if (op_ptr != op_end)
 	    error (_("DWARF-2 expression error: DW_OP_GNU_uninit must always "
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index f24f193..3361ef1 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -155,10 +155,16 @@ struct dwarf_expr_context
 };
 
 
-/* A piece of an object, as recorded by DW_OP_piece.  */
+/* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece.  */
 struct dwarf_expr_piece
 {
-  enum dwarf_value_location location;
+  ENUM_BITFIELD (dwarf_value_location) location : 8;
+
+  /* The piece offset, in bits.  This is only valid for bit pieces.  */
+  unsigned int offset : 8;
+
+  /* Nonzero if this piece came from DW_OP_bit_piece.  */
+  unsigned int bit_piece : 1;
 
   union
   {
@@ -181,7 +187,8 @@ struct dwarf_expr_piece
     } literal;
   } v;
 
-  /* The length of the piece, in bytes.  */
+  /* The length of the piece.  This is measured in bytes for ordinary
+     pieces, and in bits for bit pieces.  */
   ULONGEST size;
 };
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 2900f22..ee2df33 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -257,52 +257,254 @@ allocate_piece_closure (int n_pieces, struct dwarf_expr_piece *pieces,
   return c;
 }
 
+/* The lowest-level function to extract bits from a byte buffer.
+   SOURCE is the buffer.  It is updated if we read to the end of a
+   byte.
+   SOURCE_OFFSET_BITS is the offset of the first bit to read.  It is
+   updated to reflect the number of bits actually read.
+   NBITS is the number of bits we want to read.  This function may
+   read fewer bits.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.
+   RESULT is set to the extracted bits.
+   The function returns the number of bits actually read.  */
+
+static int
+extract_bits_primitive (const gdb_byte **source,
+			unsigned int *source_offset_bits,
+			int nbits, int bits_big_endian,
+			unsigned int *result)
+{
+  unsigned int avail, mask, datum;
+
+  gdb_assert (*source_offset_bits < 8);
+
+  avail = 8 - *source_offset_bits;
+  if (avail > nbits)
+    avail = nbits;
+  mask = (1 << avail) - 1;
+
+  datum = **source;
+  if (bits_big_endian)
+    datum >>= 8 - *source_offset_bits;
+  else
+    datum >>= *source_offset_bits;
+  datum &= mask;
+  nbits -= avail;
+  *source_offset_bits += avail;
+  if (*source_offset_bits >= 8)
+    {
+      *source_offset_bits -= 8;
+      ++*source;
+    }
+
+  *result = datum;
+  return avail;
+}
+
+/* Extract some bits from a source buffer and move forward in the
+   buffer.
+   
+   SOURCE is the source buffer.  It is updated as bytes are read.
+   SOURCE_OFFSET_BITS is the offset into SOURCE.  It is updated as
+   bits are read.
+   NBITS is the number of bits to read.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.
+   
+   This function returns the bits that were read.  */
+
+static unsigned int
+extract_bits (const gdb_byte **source, unsigned int *source_offset_bits,
+	      int nbits, int bits_big_endian)
+{
+  unsigned int datum, bits_read;
+
+  bits_read = extract_bits_primitive (source, source_offset_bits, nbits,
+				      bits_big_endian, &datum);
+  if (bits_read < nbits)
+    {
+      unsigned int more;
+      nbits -= bits_read;
+      if (bits_big_endian)
+	datum <<= nbits;
+      extract_bits_primitive (source, source_offset_bits, nbits,
+			      bits_big_endian, &more);
+      datum |= more;
+    }
+
+  return datum;
+}
+
+/* Write some bits into a buffer and move forward in the buffer.
+   
+   DATUM is the bits to write.  The low-order bits of DATUM are used.
+   DEST is the destination buffer.  It is updated as bytes are
+   written.
+   DEST_OFFSET_BITS is the bit offset in DEST at which writing is
+   done.
+   NBITS is the number of valid bits in DATUM.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.  */
+
+static void
+insert_bits (unsigned int datum,
+	     gdb_byte *dest, unsigned int dest_offset_bits,
+	     int nbits, int bits_big_endian)
+{
+  unsigned int mask;
+
+  gdb_assert (dest_offset_bits > 0 && dest_offset_bits < 8);
+
+  mask = (1 << nbits) - 1;
+  if (bits_big_endian)
+    {
+      datum <<= 8 - dest_offset_bits;
+      mask <<= 8 - dest_offset_bits;
+    }
+  else
+    {
+      datum <<= dest_offset_bits;
+      mask <<= dest_offset_bits;
+    }
+
+  gdb_assert ((datum & ~mask) == 0);
+
+  *dest = (*dest & ~mask) | datum;
+}
+
+/* Copy bits from a source to a destination.
+   
+   DEST is where the bits should be written.
+   DEST_OFFSET_BITS is the bit offset into DEST.
+   SOURCE is the source of bits.
+   SOURCE_OFFSET_BITS is the bit offset into SOURCE.
+   BIT_COUNT is the number of bits to copy.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.  */
+
+static void
+copy_bitwise (gdb_byte *dest, unsigned int dest_offset_bits,
+	      const gdb_byte *source, unsigned int source_offset_bits,
+	      unsigned int bit_count,
+	      int bits_big_endian)
+{
+  unsigned int dest_avail;
+  int datum;
+
+  /* Reduce everything to byte-size pieces.  */
+  dest += dest_offset_bits / 8;
+  dest_offset_bits %= 8;
+  source += source_offset_bits / 8;
+  source_offset_bits %= 8;
+
+  dest_avail = 8 - dest_offset_bits % 8;
+
+  /* See if we can fill the first destination byte.  */
+  if (dest_avail < bit_count)
+    {
+      datum = extract_bits (&source, &source_offset_bits, dest_avail,
+			    bits_big_endian);
+      insert_bits (datum, dest, dest_offset_bits, dest_avail, bits_big_endian);
+      ++dest;
+      dest_offset_bits = 0;
+      bit_count -= dest_avail;
+    }
+
+  /* Now, either DEST_OFFSET_BITS is byte-aligned, or we have fewer
+     than 8 bits remaining.  */
+  gdb_assert (dest_offset_bits % 8 == 0 || bit_count < 8);
+  for (; bit_count >= 8; bit_count -= 8)
+    {
+      datum = extract_bits (&source, &source_offset_bits, 8, bits_big_endian);
+      *dest++ = (gdb_byte) datum;
+    }
+
+  /* Finally, we may have a few leftover bits.  */
+  gdb_assert (bit_count <= 8 - dest_offset_bits % 8);
+  if (bit_count > 0)
+    {
+      datum = extract_bits (&source, &source_offset_bits, bit_count,
+			    bits_big_endian);
+      insert_bits (datum, dest, dest_offset_bits, bit_count, bits_big_endian);
+    }
+}
+
 static void
 read_pieced_value (struct value *v)
 {
   int i;
   long offset = 0;
-  ULONGEST bytes_to_skip;
+  ULONGEST bits_to_skip;
   gdb_byte *contents;
   struct piece_closure *c = (struct piece_closure *) value_computed_closure (v);
   struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (v));
   size_t type_len;
+  size_t buffer_size = 0;
+  char *buffer = NULL;
+  struct cleanup *cleanup;
+  int bits_big_endian
+    = gdbarch_bits_big_endian (get_type_arch (value_type (v)));
 
   if (value_type (v) != value_enclosing_type (v))
     internal_error (__FILE__, __LINE__,
 		    _("Should not be able to create a lazy value with "
 		      "an enclosing type"));
 
+  cleanup = make_cleanup (free_current_contents, &buffer);
+
   contents = value_contents_raw (v);
-  bytes_to_skip = value_offset (v);
-  type_len = TYPE_LENGTH (value_type (v));
+  bits_to_skip = 8 * value_offset (v);
+  type_len = 8 * TYPE_LENGTH (value_type (v));
+
   for (i = 0; i < c->n_pieces && offset < type_len; i++)
     {
       struct dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size;
-      long dest_offset, source_offset;
-
-      if (bytes_to_skip > 0 && bytes_to_skip >= p->size)
+      size_t this_size, this_size_bits;
+      long dest_offset_bits, source_offset_bits, source_offset;
+      char *dest_buffer;
+
+      /* Compute size, source, and destination offsets for copying, in
+	 bits.  */
+      this_size_bits = p->size;
+      if (! p->bit_piece)
+	this_size_bits *= 8;
+      if (bits_to_skip > 0 && bits_to_skip >= this_size_bits)
 	{
-	  bytes_to_skip -= p->size;
+	  bits_to_skip -= this_size_bits;
 	  continue;
 	}
-      this_size = p->size;
-      if (this_size > type_len - offset)
-	this_size = type_len - offset;
-      if (bytes_to_skip > 0)
+      if (this_size_bits > type_len - offset)
+	this_size_bits = type_len - offset;
+      if (bits_to_skip > 0)
+	{
+	  dest_offset_bits = 0;
+	  source_offset_bits = bits_to_skip;
+	  this_size_bits -= bits_to_skip;
+	  bits_to_skip = 0;
+	}
+      else
 	{
-	  dest_offset = 0;
-	  source_offset = bytes_to_skip;
-	  this_size -= bytes_to_skip;
-	  bytes_to_skip = 0;
+	  dest_offset_bits = offset;
+	  source_offset_bits = 0;
 	}
+
+      /* If source and destinations both have a byte offset of zero,
+	 then we can optimize and copy directly from the source to the
+	 destination.  Otherwise, we allocate a temporary intermediate
+	 buffer and then copy bitwise from this buffer to the
+	 destination buffer.  */
+      this_size = (this_size_bits + source_offset_bits % 8 + 7) / 8;
+      source_offset = source_offset_bits / 8;
+      if (dest_offset_bits % 8 == 0 && source_offset_bits % 8 == 0)
+	dest_buffer = contents + dest_offset_bits / 8;
       else
 	{
-	  dest_offset = offset;
-	  source_offset = 0;
+	  if (buffer_size < this_size)
+	    {
+	      buffer_size = this_size;
+	      buffer = xrealloc (buffer, buffer_size);
+	    }
+	  dest_buffer = buffer;
 	}
 
+      /* Copy from the source to DEST_BUFFER.  */
       switch (p->location)
 	{
 	case DWARF_VALUE_REGISTER:
@@ -320,7 +522,7 @@ read_pieced_value (struct value *v)
 	    if (gdb_regnum != -1)
 	      {
 		get_frame_register_bytes (frame, gdb_regnum, reg_offset, 
-					  this_size, contents + dest_offset);
+					  this_size, dest_buffer);
 	      }
 	    else
 	      {
@@ -333,10 +535,10 @@ read_pieced_value (struct value *v)
 	case DWARF_VALUE_MEMORY:
 	  if (p->v.expr.in_stack_memory)
 	    read_stack (p->v.expr.value + source_offset,
-			contents + dest_offset, this_size);
+			dest_buffer, this_size);
 	  else
 	    read_memory (p->v.expr.value + source_offset,
-			 contents + dest_offset, this_size);
+			 dest_buffer, this_size);
 	  break;
 
 	case DWARF_VALUE_STACK:
@@ -352,7 +554,7 @@ read_pieced_value (struct value *v)
 		/* Nothing.  */
 	      }
 	    else if (source_offset == 0)
-	      store_unsigned_integer (contents + dest_offset, n,
+	      store_unsigned_integer (dest_buffer, n,
 				      gdbarch_byte_order (gdbarch),
 				      p->v.expr.value);
 	    else
@@ -362,7 +564,7 @@ read_pieced_value (struct value *v)
 		store_unsigned_integer (bytes, n + source_offset,
 					gdbarch_byte_order (gdbarch),
 					p->v.expr.value);
-		memcpy (contents + dest_offset, bytes + source_offset, n);
+		memcpy (dest_buffer, bytes + source_offset, n);
 	      }
 	  }
 	  break;
@@ -375,8 +577,7 @@ read_pieced_value (struct value *v)
 		   ? p->v.literal.length - source_offset
 		   : 0);
 	    if (n != 0)
-	      memcpy (contents + dest_offset,
-		      p->v.literal.data + source_offset, n);
+	      memcpy (dest_buffer, p->v.literal.data + source_offset, n);
 	  }
 	  break;
 
@@ -384,17 +585,41 @@ read_pieced_value (struct value *v)
 	  /* We just leave the bits empty for now.  This is not ideal
 	     but gdb currently does not have a nice way to represent
 	     optimized-out pieces.  */
-	  warning (_("bytes %ld-%ld in computed object were optimized out; "
+	  warning (_("bits %ld-%ld in computed object were optimized out; "
 		     "replacing with zeroes"),
 		   offset,
-		   offset + (long) this_size);
+		   offset + (long) this_size_bits);
 	  break;
 
 	default:
 	  internal_error (__FILE__, __LINE__, _("invalid location type"));
 	}
-      offset += this_size;
+
+      /* If we used a temporary buffer, then copy bitwise from the
+	 temporary buffer to the destination.  */
+      if (dest_offset_bits % 8 != 0 || source_offset_bits % 8 != 0)
+	copy_bitwise (contents, dest_offset_bits,
+		      buffer, source_offset_bits % 8,
+		      this_size_bits, bits_big_endian);
+      else if (this_size_bits % 8 != 0)
+	{
+	  /* The request size was not an even number of bytes, so mask
+	     off the extra bits.  */
+	  unsigned int extra_bits = 8 - this_size_bits % 8;
+	  unsigned int mask = (1 << extra_bits) - 1;
+	  gdb_byte *last_byte;
+
+	  if (!bits_big_endian)
+	    mask <<= 8 - extra_bits;
+
+	  last_byte = contents + (offset + this_size_bits) / 8;
+	  *last_byte &= ~mask;
+	}
+
+      offset += this_size_bits;
     }
+
+  do_cleanups (cleanup);
 }
 
 static void
@@ -402,11 +627,16 @@ write_pieced_value (struct value *to, struct value *from)
 {
   int i;
   long offset = 0;
-  ULONGEST bytes_to_skip;
+  ULONGEST bits_to_skip;
   const gdb_byte *contents;
   struct piece_closure *c = (struct piece_closure *) value_computed_closure (to);
   struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (to));
   size_t type_len;
+  size_t buffer_size = 0;
+  char *buffer = NULL;
+  struct cleanup *cleanup;
+  int bits_big_endian
+    = gdbarch_bits_big_endian (get_type_arch (value_type (to)));
 
   if (frame == NULL)
     {
@@ -414,34 +644,60 @@ write_pieced_value (struct value *to, struct value *from)
       return;
     }
 
+  cleanup = make_cleanup (free_current_contents, &buffer);
+
   contents = value_contents (from);
-  bytes_to_skip = value_offset (to);
-  type_len = TYPE_LENGTH (value_type (to));
+  bits_to_skip = 8 * value_offset (to);
+  type_len = 8 * TYPE_LENGTH (value_type (to));
   for (i = 0; i < c->n_pieces && offset < type_len; i++)
     {
       struct dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size;
-      long dest_offset, source_offset;
+      size_t this_size_bits, this_size;
+      long dest_offset_bits, source_offset_bits, dest_offset, source_offset;
+      int need_bitwise;
+      const gdb_byte *source_buffer;
 
-      if (bytes_to_skip > 0 && bytes_to_skip >= p->size)
+      this_size_bits = p->size;
+      if (! p->bit_piece)
+	this_size_bits *= 8;
+
+      if (bits_to_skip > 0 && bits_to_skip >= this_size_bits)
 	{
-	  bytes_to_skip -= p->size;
+	  bits_to_skip -= this_size_bits;
 	  continue;
 	}
-      this_size = p->size;
-      if (this_size > type_len - offset)
-	this_size = type_len - offset;
-      if (bytes_to_skip > 0)
+      if (this_size_bits > type_len - offset)
+	this_size_bits = type_len - offset;
+      if (bits_to_skip > 0)
 	{
-	  dest_offset = bytes_to_skip;
-	  source_offset = 0;
-	  this_size -= bytes_to_skip;
-	  bytes_to_skip = 0;
+	  dest_offset_bits = bits_to_skip;
+	  source_offset_bits = 0;
+	  this_size_bits -= bits_to_skip;
+	  bits_to_skip = 0;
 	}
       else
 	{
-	  dest_offset = 0;
-	  source_offset = offset;
+	  dest_offset_bits = 0;
+	  source_offset_bits = offset;
+	}
+
+      this_size = (this_size_bits + source_offset_bits % 8 + 7) / 8;
+      source_offset = source_offset_bits / 8;
+      dest_offset = dest_offset_bits / 8;
+      if (dest_offset_bits % 8 == 0 && source_offset_bits % 8 == 0)
+	{
+	  source_buffer = contents + source_offset;
+	  need_bitwise = 0;
+	}
+      else
+	{
+	  if (buffer_size < this_size)
+	    {
+	      buffer_size = this_size;
+	      buffer = xrealloc (buffer, buffer_size);
+	    }
+	  source_buffer = buffer;
+	  need_bitwise = 1;
 	}
 
       switch (p->location)
@@ -459,8 +715,18 @@ write_pieced_value (struct value *to, struct value *from)
 
 	    if (gdb_regnum != -1)
 	      {
+		if (need_bitwise)
+		  {
+		    get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+					      this_size, buffer);
+		    copy_bitwise (buffer, dest_offset_bits,
+				  contents, source_offset_bits,
+				  this_size_bits,
+				  bits_big_endian);
+		  }
+
 		put_frame_register_bytes (frame, gdb_regnum, reg_offset, 
-					  this_size, contents + source_offset);
+					  this_size, source_buffer);
 	      }
 	    else
 	      {
@@ -470,14 +736,27 @@ write_pieced_value (struct value *to, struct value *from)
 	  }
 	  break;
 	case DWARF_VALUE_MEMORY:
+	  if (need_bitwise)
+	    {
+	      /* Only the first and last bytes can possibly have any
+		 bits reused.  */
+	      read_memory (p->v.expr.value + dest_offset, buffer, 1);
+	      read_memory (p->v.expr.value + dest_offset + this_size - 1,
+			   buffer + this_size - 1, 1);
+	      copy_bitwise (buffer, dest_offset_bits,
+			    contents, source_offset_bits,
+			    this_size_bits,
+			    bits_big_endian);
+	    }
+
 	  write_memory (p->v.expr.value + dest_offset,
-			contents + source_offset, this_size);
+			source_buffer, this_size);
 	  break;
 	default:
 	  set_value_optimized_out (to, 1);
 	  return;
 	}
-      offset += this_size;
+      offset += this_size_bits;
     }
 }
 
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.S b/gdb/testsuite/gdb.dwarf2/pieces.S
index 0ecdbb0..f08b53d 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.S
+++ b/gdb/testsuite/gdb.dwarf2/pieces.S
@@ -989,23 +989,18 @@ main:
 .LLST6:
 	.long	.LVL13-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL14-.Ltext0	# Location list end address (*.LLST6)
-	.value	0xa	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x8	# Location expression size
 	.byte	0x34	# DW_OP_lit4
 	.byte	0x9f	# DW_OP_stack_value
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x93	# DW_OP_piece
-	.uleb128 0x2
-	.long	.LVL14-.Ltext0	# Location list begin address (*.LLST6)
-	.long	.LVL15-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x15	# Location expression size
 	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
+	.uleb128 0x14
 	.uleb128 0
+	.long	.LVL14-.Ltext0	# Location list begin address (*.LLST6)
+	.long	.LVL15-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x11	# Location expression size
 	.byte	0x34	# DW_OP_lit4
 	.byte	0x9f	# DW_OP_stack_value
 	.byte	0x9d	# DW_OP_bit_piece
@@ -1021,15 +1016,11 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL15-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL16-1-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x14	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x10	# Location expression size
 	.byte	0x52	# DW_OP_reg2
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
@@ -1044,15 +1035,11 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL16-1-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL17-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x14	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x10	# Location expression size
 	.byte	0x56	# DW_OP_reg6
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
@@ -1067,14 +1054,14 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL17-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LFE3-.Ltext0	# Location list end address (*.LLST6)
 	.value	0xf	# Location expression size
-	.byte	0x93	# DW_OP_piece
-	.uleb128 0x2
+	.byte	0x9d	# DW_OP_bit_piece
+	.uleb128 0xc
+	.uleb128 0
 	.byte	0x91	# DW_OP_fbreg
 	.sleb128 0
 	.byte	0x94	# DW_OP_deref_size
@@ -1085,9 +1072,8 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	0	# Location list terminator begin (*.LLST6)
 	.long	0	# Location list terminator end (*.LLST6)
 .LLST7:
@@ -1356,7 +1342,7 @@ main:
 	.long	0x48	# DW_AT_type
 	.byte	0x4	# DW_AT_byte_size
 	.byte	0xc	# DW_AT_bit_size
-	.byte	0x10	# DW_AT_bit_offset
+	.byte	0x14	# DW_AT_bit_offset
 	.byte	0x2	# DW_AT_data_member_location
 	.byte	0x23	# DW_OP_plus_uconst
 	.uleb128 0
@@ -1367,7 +1353,7 @@ main:
 	.long	0x48	# DW_AT_type
 	.byte	0x4	# DW_AT_byte_size
 	.byte	0xc	# DW_AT_bit_size
-	.byte	0x4	# DW_AT_bit_offset
+	.byte	0x8	# DW_AT_bit_offset
 	.byte	0x2	# DW_AT_data_member_location
 	.byte	0x23	# DW_OP_plus_uconst
 	.uleb128 0
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.c b/gdb/testsuite/gdb.dwarf2/pieces.c
index 04ea8a2..29879f5 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.c
+++ b/gdb/testsuite/gdb.dwarf2/pieces.c
@@ -21,7 +21,7 @@
    However, it is used to extract breakpoint line numbers.  */
 
 struct A { int i; int j; };
-struct B { int : 4; int i : 12; int j : 12; int : 4; };
+struct B { int i : 12; int j : 12; int : 4; };
 struct C { int i; int j; int q; };
 
 __attribute__((noinline)) void
@@ -89,7 +89,7 @@ __attribute__((noinline)) int
 f6 (int k)
 {
   int z = 23;
-  struct C a = { k, k, z};
+  struct C a = { k, k, z };
   asm ("" : "+r" (a.i));
   a.j++;
   bar (a.i);
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.exp b/gdb/testsuite/gdb.dwarf2/pieces.exp
index c7608cd..020fecd 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.exp
+++ b/gdb/testsuite/gdb.dwarf2/pieces.exp
@@ -67,15 +67,30 @@ proc pieces_test_f2 {} {
     gdb_test "print a\[1\]" " = 14" "print a\[1\] in pieces:f2"
 }
 
+# Function f3 tests DW_OP_bit_piece.
+proc pieces_test_f3 {} {
+    global csrcfile
+    set line [gdb_get_line_number "f3 breakpoint" $csrcfile]
+    gdb_test "break pieces.c:$line" "Breakpoint 4.*" \
+       "set f3 breakpoint for pieces"
+    gdb_continue_to_breakpoint "continue to f3 breakpoint for pieces"
+    gdb_test "print a.i" " = 4" "print a.i in pieces:f3"
+    gdb_test "print a.j" " = 14" "print a.j in pieces:f3"
+    setup_kfail "no bug yet" *-*-*
+    # Right now gdb says "value optimized out" here, but that is wrong.
+    gdb_test "print a.i = 7" " = 7" "set a.i in pieces:f3"
+    gdb_test "print a.i" " = 7" "print new a.i in pieces:f3"
+}
+
 # Function f6 tests for an empty DW_OP_piece.
 proc pieces_test_f6 {} {
     global csrcfile
     set line [gdb_get_line_number "f6 breakpoint" $csrcfile]
-    gdb_test "break pieces.c:$line" "Breakpoint 4.*" \
+    gdb_test "break pieces.c:$line" "Breakpoint 5.*" \
        "set f6 breakpoint for pieces"
     gdb_continue_to_breakpoint "continue to f6 breakpoint for pieces"
     gdb_test "print a" \
-	"warning: bytes .* in computed object were.* = {i = 7, j = 8, q = 0}" \
+	"warning: bits .* in computed object were.* = {i = 7, j = 8, q = 0}" \
 	"print a with optimized out piece"
     # Note: no warning for this case.
     gdb_test_multiple "print a.i" \
@@ -91,4 +106,5 @@ proc pieces_test_f6 {} {
 
 pieces_test_f1
 pieces_test_f2
+pieces_test_f3
 pieces_test_f6

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-18 23:43 RFC: implement DW_OP_bit_piece Tom Tromey
@ 2010-05-19 14:16 ` Stan Shebs
  2010-05-19 23:35   ` Tom Tromey
  2010-05-20 21:07 ` RFC: implement DW_OP_bit_piece Jan Kratochvil
  1 sibling, 1 reply; 36+ messages in thread
From: Stan Shebs @ 2010-05-19 14:16 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, Jan Kratochvil

Tom Tromey wrote:
> I plan to check this in, but first I would appreciate comments on the
> implementation.
>
> This patch implements DW_OP_bit_piece.  This is needed now that Jakub
> has pushed in gcc patches to generate it when SRA optimization is
> performed.
>   

Your code looks reasonable, but you're missing two, uh, pieces :-)  - 
the dwarf2_tracepoint_var_ref code to compile to bytecodes, and 
human-readable description in locexpr_describe_location_1.

(Yes it's onerous, but we did want to revive tracepoints, right?)

Stan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-19 14:16 ` Stan Shebs
@ 2010-05-19 23:35   ` Tom Tromey
  2010-05-20  3:29     ` Stan Shebs
                       ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Tom Tromey @ 2010-05-19 23:35 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

>>>>> "Stan" == Stan Shebs <stan@codesourcery.com> writes:

Stan> Your code looks reasonable, but you're missing two, uh, pieces :-)  - 

Thanks.

Stan> the dwarf2_tracepoint_var_ref code to compile to bytecodes, and
Stan> human-readable description in locexpr_describe_location_1.

Stan> (Yes it's onerous, but we did want to revive tracepoints, right?)

I will update locexpr_describe_location_1.

I am less sanguine about updating the tracepoint code, I suppose because
it is pretty new and yet doesn't implement even what was already in gdb
when it went in:

	  if (bytes != 4)
	    error (_("DW_OP_piece %s not supported in location for \"%s\"."),
		   pulongest (bytes), SYMBOL_PRINT_NAME (symbol));

I did dig around in the code a little, and it turns out I'm also not
clear on all the details I would need to implement the support.

I don't really see how DWARF expressions can work with the current
setup.  Maybe just some subset can -- but then I would like to
understand how the subset is chosen, I guess so I can argue against
choosing DW_OP_bit_piece ;-).  Ok, seriously...

For instance, I don't understand how a DWARF expression involving a
conditional could work.  You could compile DWARF to AX, including the
condition.  But then I think you'd have to circumvent the DWARF
expression when re-evaluating the expression at "replay" time (I don't
know the real name of the mode, sorry).

GCC is already emitting nontrivial DWARF.  It can emit some stack ops
(look at the MOD case in dwarf2out.c).  It can emit pieces and stack and
literal values.  And, I think it can emit TLS references.  So this is
not just hypothetical, today's expression translation is already
insufficient for today's GCC.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-19 23:35   ` Tom Tromey
@ 2010-05-20  3:29     ` Stan Shebs
  2010-05-20  5:10       ` Tom Tromey
  2010-05-20 19:53     ` RFC: implement DW_OP_bit_piece Tom Tromey
  2010-05-21 20:16     ` Tom Tromey
  2 siblings, 1 reply; 36+ messages in thread
From: Stan Shebs @ 2010-05-20  3:29 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Stan Shebs, gdb-patches, Jan Kratochvil

Tom Tromey wrote:
> I am less sanguine about updating the tracepoint code, I suppose because
> it is pretty new and yet doesn't implement even what was already in gdb
> when it went in:
>
> 	  if (bytes != 4)
> 	    error (_("DW_OP_piece %s not supported in location for \"%s\"."),
> 		   pulongest (bytes), SYMBOL_PRINT_NAME (symbol));
>   

Touche'  :-)

> I did dig around in the code a little, and it turns out I'm also not
> clear on all the details I would need to implement the support.
>
> I don't really see how DWARF expressions can work with the current
> setup.  Maybe just some subset can -- but then I would like to
> understand how the subset is chosen, I guess so I can argue against
> choosing DW_OP_bit_piece ;-).  Ok, seriously...
>
> For instance, I don't understand how a DWARF expression involving a
> conditional could work.  You could compile DWARF to AX, including the
> condition.  But then I think you'd have to circumvent the DWARF
> expression when re-evaluating the expression at "replay" time (I don't
> know the real name of the mode, sorry).
>
>   

In theory, evaluation of the expression while examining a trace frame 
will just work, because the DWARF condition will evaluate to the same 
value as it would have when looking at the live state.

> GCC is already emitting nontrivial DWARF.  It can emit some stack ops
> (look at the MOD case in dwarf2out.c).  It can emit pieces and stack and
> literal values.  And, I think it can emit TLS references.  So this is
> not just hypothetical, today's expression translation is already
> insufficient for today's GCC.
>   

We've been special-casing things in the ax code as they've come along in 
real compiler output - your mention of bit pieces got my attention 
because it sounded like tracepoint test cases could start regressing if 
someone updated their GCC.

But yeah, this is the kind of thing that gets us to start muttering 
again about the common compilation / evaluation pathway idea.  
CodeSourcery's tracepoint work has already been decided for this year, 
and the closest related task is going to be some better handling of 
partially-collected values.  But now is a good time to start thinking 
about what we should do in 2011; I can see things getting to the point 
where the common pathway is the easiest strategy for coping with 
ever-more-complex debug info from GCC.

Stan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-20  3:29     ` Stan Shebs
@ 2010-05-20  5:10       ` Tom Tromey
  2010-05-20  7:12         ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-20  5:10 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

>>>>> "Stan" == Stan Shebs <stan@codesourcery.com> writes:

Stan> In theory, evaluation of the expression while examining a trace frame
Stan> will just work, because the DWARF condition will evaluate to the same
Stan> value as it would have when looking at the live state.

My understanding is that tracepoint collection happens without GDB's
intervention.  I think this implies that either the conditions must be
uploaded, or the AX code must over-collect data along all branches of
the DWARF expression.

Stan> But yeah, this is the kind of thing that gets us to start muttering
Stan> again about the common compilation / evaluation pathway idea.

Yeah.  ISTR some other justifications for a big expression evaluator
rewrite -- async function calls or something like that.

But it seems like this can probably be done without that.  Though, I
haven't looked enough at ax.h to know whether it can represent all of
DWARF... which reminds me, how much trouble is it to add to AX?  Is it
versioned so we can detect old remotes?

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-20  5:10       ` Tom Tromey
@ 2010-05-20  7:12         ` Tom Tromey
  2010-05-26 22:41           ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-20  7:12 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

Tom> But it seems like this can probably be done without that.  Though, I
Tom> haven't looked enough at ax.h to know whether it can represent all of
Tom> DWARF... which reminds me, how much trouble is it to add to AX?  Is it
Tom> versioned so we can detect old remotes?

I looked a little.

I didn't see explicit versioning in the agent expressions but I gather
from remote.c that we could add a new remote feature and query it.

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

DW_OP_implicit_value can be arbitrarily wide.  It seems strange to even
want to upload a constant, but this could be used as part of a bigger
expression.  However in practice it is probably ok.

Some stack ops are missing: DW_OP_pick, DW_OP_rot, DW_OP_over.
I think 'over' is emitted by gcc, but maybe we could recognize the
particular bytecode sequence and generate a signed modulus directly.
(Yuck.)

DW_OP_call_frame_cfa seems to require some gyrations, I didn't trace all
the way down to see if it is reasonably possible.

DW_OP_GNU_push_tls_address.  Maybe possible, but I don't know enough.

DW_OP_piece and DW_OP_bit_piece.  These are problems in some contexts,
but not others.  A few cases I've considered:

* As the terminus of a trace expression they ought to be ok.  This means
  a simple expression, like a variable, which is made of pieces.  In
  this case I think we can probably trace the various parts and discard
  each result until the final one.

* They might be ok as part of an aggregate which is then "sliced" at a
  constant offset.  So, something like "struct.field" or "array[5]".
  However, I think they are not ok, or at least difficult to compile, if
  the expression is something like "array[i]".  Even the possible case
  here will probably lead to ridiculous bytecode in some cases.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-19 23:35   ` Tom Tromey
  2010-05-20  3:29     ` Stan Shebs
@ 2010-05-20 19:53     ` Tom Tromey
  2010-05-20 20:30       ` Jan Kratochvil
  2010-05-21 20:16     ` Tom Tromey
  2 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-20 19:53 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

Tom> I will update locexpr_describe_location_1.

I looked at this a bit.  The existing code only supports a subset of
DWARF expressions.  I hacked at it a little and I can get this:

(gdb) info addr a
Symbol "a" is multi-location (range 0x8048440-0x8048448, a variable with complex or multiple locations (DWARF2); range 0x8048448-0x804844b, a variable with complex or multiple locations (DWARF2); range 0x804844b-0x804845b, a variable in $edx [12-bit piece at offset 0], and a variable at frame base reg $ebp offset 8+0Corrupted DWARF2 expression for "a".


... but I think this is pretty ugly (not to mention the "Corrupted" bit
at the end there... I haven't investigated it).

I think it would be more useful to just disassemble complicated DWARF
expressions.  We could just push in Jan's patch to do this.  Comments?

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-20 19:53     ` RFC: implement DW_OP_bit_piece Tom Tromey
@ 2010-05-20 20:30       ` Jan Kratochvil
  0 siblings, 0 replies; 36+ messages in thread
From: Jan Kratochvil @ 2010-05-20 20:30 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Stan Shebs, gdb-patches

On Thu, 20 May 2010 21:44:46 +0200, Tom Tromey wrote:
> I think it would be more useful to just disassemble complicated DWARF
> expressions.  We could just push in Jan's patch to do this.  Comments?

There was no straight patch read, more an idea it should get integrated with
existing binutils readelf and bfd/:
	[rfc] Decode "is a variable with complex or multiple locations" (PR 8399)
	http://sourceware.org/ml/gdb-patches/2009-09/msg00649.html


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-18 23:43 RFC: implement DW_OP_bit_piece Tom Tromey
  2010-05-19 14:16 ` Stan Shebs
@ 2010-05-20 21:07 ` Jan Kratochvil
  2010-05-21 17:57   ` Tom Tromey
  1 sibling, 1 reply; 36+ messages in thread
From: Jan Kratochvil @ 2010-05-20 21:07 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On Wed, 19 May 2010 01:27:33 +0200, Tom Tromey wrote:
> We do take care to optimize for the byte-aligned case.

FYI I am strongly against this decision.  This creates (a) more complicated
code to maintain (b) less used and more dense to debug codepath (the bits one)
and (c) I doubt current hardware and current `gcc -O2' code will ever notice
a difference - GDB has much more serious performance issues (symbols reading,
lookup) than evaluation of any specific values.


> --- a/gdb/dwarf2expr.c
> +++ b/gdb/dwarf2expr.c
> +/* The lowest-level function to extract bits from a byte buffer.
> +   SOURCE is the buffer.  It is updated if we read to the end of a
> +   byte.
> +   SOURCE_OFFSET_BITS is the offset of the first bit to read.  It is
> +   updated to reflect the number of bits actually read.
> +   NBITS is the number of bits we want to read.  This function may
> +   read fewer bits.
> +   BITS_BIG_ENDIAN is taken directly from gdbarch.
> +   RESULT is set to the extracted bits.
> +   The function returns the number of bits actually read.  */
> +
> +static int
> +extract_bits_primitive (const gdb_byte **source,
> +			unsigned int *source_offset_bits,
> +			int nbits, int bits_big_endian,
> +			unsigned int *result)

IMHO either NBITS should be also updated by the number of bits read or SOURCE
and SOURCE_OFFSET_BITS should be updated togetierh with NBITS by the caller.
This is a bit mix of both styles.  But this function is not used much so it
does not matter much. 


> +{
> +  unsigned int avail, mask, datum;
> +
> +  gdb_assert (*source_offset_bits < 8);
> +
> +  avail = 8 - *source_offset_bits;
> +  if (avail > nbits)
> +    avail = nbits;

NBITS is no longer used anywhere, AVAIL is used instead.  Therefore this
function ignores the caller's wish of NBITS.  I would see here more:
	if (avail < nbits)
	  nbits = avail;
	And use NBITS instead of AVAIL everywhere later...


> +  mask = (1 << avail) - 1;
> +
> +  datum = **source;
> +  if (bits_big_endian)
> +    datum >>= 8 - *source_offset_bits;

Assuming NBITS contains here the caller's wished read width (possible lowered
by the remaining bits available in current byte):

It should be rather:
	datum >>= 8 - (*source_offset_bits + nbits);

source_offset_bits = 2
nbits = 3
mask = 7
 b0   b1   b2   b3   b4   b5   b6   b7  = big endian bits numbering
 128  64   32   16    8    4    2    1  = value represented by this bit
drop drop WANT WANT WANT drop drop drop

Your expression
	datum >>= 6;
	datum &= 7;
	 ??   b0   b1
	 ??   128  64
	zero drop drop
Suggested expression
	datum >>= 3;
	datum &= 7;
	 b2   b3   b4
	 32   16    8
	WANT WANT WANT


> +  else
> +    datum >>= *source_offset_bits;
> +  datum &= mask;


> +  nbits -= avail;

NBITS is updated but its value is then never used anywhere later.


> +  *source_offset_bits += avail;
> +  if (*source_offset_bits >= 8)
> +    {
> +      *source_offset_bits -= 8;
> +      ++*source;
> +    }
> +
> +  *result = datum;
> +  return avail;
> +}
> +
> +/* Extract some bits from a source buffer and move forward in the
> +   buffer.
> +   
> +   SOURCE is the source buffer.  It is updated as bytes are read.
> +   SOURCE_OFFSET_BITS is the offset into SOURCE.  It is updated as
> +   bits are read.
> +   NBITS is the number of bits to read.
> +   BITS_BIG_ENDIAN is taken directly from gdbarch.
> +   
> +   This function returns the bits that were read.  */
> +
> +static unsigned int
> +extract_bits (const gdb_byte **source, unsigned int *source_offset_bits,
> +	      int nbits, int bits_big_endian)
> +{
> +  unsigned int datum, bits_read;
> +
> +  bits_read = extract_bits_primitive (source, source_offset_bits, nbits,
> +				      bits_big_endian, &datum);
> +  if (bits_read < nbits)
> +    {
> +      unsigned int more;

Missing declarations empty line separator.

> +      nbits -= bits_read;
> +      if (bits_big_endian)
> +	datum <<= nbits;
> +      extract_bits_primitive (source, source_offset_bits, nbits,
> +			      bits_big_endian, &more);

> +      datum |= more;

For (bits_big_endian == 0) MORE needs to be <<= NBITS.

extract_bits_primitive() always returns RESULT fit in the lowest-order bits.
Two |= without any << have to mangle both RESULTs each over the other.


> +    }
> +
> +  return datum;
> +}

If this function is passed NBITS >= 17 it does not assert-fail and it returns
only incomplete 9..16 bits of it.  Should there be some
	while (bits_read < nbits)
(and associated adjustments) instead?

And this function needs to distinguish both the bits endianity and the bytes
endianity.  Out of big-byte-endian machines there are both big-bits-endian and
little-bits-endian ones:
	http://en.wikipedia.org/wiki/Bit_numbering#Usage
OTOH there is currently no GDB target using set_gdbarch_bits_big_endian,
therefore all the GDB targets are little-bits-endian.  This seems to be wrong.

http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf
does not contain any Figures so I rather used:
http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.7.pdf
where on Figure 3-11 it seems that:
ppc64    big-byte-endian is      big-bits-endian
ppc64 little-byte-endian is also big-bits-endian - this seems weird to me.

It is the same for ppc32:
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
Figure 3-15 and Figure 3-16



> +
> +/* Write some bits into a buffer and move forward in the buffer.
> +   
> +   DATUM is the bits to write.  The low-order bits of DATUM are used.
> +   DEST is the destination buffer.  It is updated as bytes are
> +   written.
> +   DEST_OFFSET_BITS is the bit offset in DEST at which writing is
> +   done.
> +   NBITS is the number of valid bits in DATUM.
> +   BITS_BIG_ENDIAN is taken directly from gdbarch.  */
> +
> +static void
> +insert_bits (unsigned int datum,
> +	     gdb_byte *dest, unsigned int dest_offset_bits,
> +	     int nbits, int bits_big_endian)
> +{
> +  unsigned int mask;
> +
> +  gdb_assert (dest_offset_bits > 0 && dest_offset_bits < 8);

I would rather see for the ">" part:
	gdb_assert (dest_offset_bits >= 0);
as for dest_offset_bits = 0, source_offset_bits != 0 satisfying
> +      if (dest_offset_bits % 8 != 0 || source_offset_bits % 8 != 0)
it can IMO happen, and in general this function can support it.
Also if the bits and bytes variants of code would be merged we would need it.

and for the "<" part:
	gdb_assert (dest_offset_bits + nbits <= 8);
as this function handles only write to single byte.


> +
> +  mask = (1 << nbits) - 1;
> +  if (bits_big_endian)
> +    {
> +      datum <<= 8 - dest_offset_bits;
> +      mask <<= 8 - dest_offset_bits;

Again I would rather see:
	datum <<= 8 - (dest_offset_bits + nbits);
	mask <<= 8 - (dest_offset_bits + nbits);

For:
bits_big_endian = 1
dest_offset_bits = 1
nbits = 3
mask = 7
 b0   b1   b2   b3   b4   b5   b6   b7  = big endian bits numbering
 128  64   32   16    8    4    2    1  = value represented by this bit
  0    0    0    0    0    1    1    1

former expression:
mask <<= 7
mask = 128
  1    0    0    0    0    0    0    0

suggested expression:
mask <= 4
  0    1    1    1    0    0    0    0


> +    }
> +  else
> +    {
> +      datum <<= dest_offset_bits;
> +      mask <<= dest_offset_bits;
> +    }
> +
> +  gdb_assert ((datum & ~mask) == 0);
> +
> +  *dest = (*dest & ~mask) | datum;
> +}


> +static void
> +copy_bitwise (gdb_byte *dest, unsigned int dest_offset_bits,
> +	      const gdb_byte *source, unsigned int source_offset_bits,
> +	      unsigned int bit_count,
> +	      int bits_big_endian)

Seems OK to me.


>  read_pieced_value (struct value *v)
+
> @@ -402,11 +627,16 @@ write_pieced_value (struct value *to, struct value *from)

Not reviewed, the patches no longer apply to HEAD and also this part may or
may not be changed a lot depending on the discussions above.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-20 21:07 ` RFC: implement DW_OP_bit_piece Jan Kratochvil
@ 2010-05-21 17:57   ` Tom Tromey
  2010-05-25 18:19     ` performance talk [Re: RFC: implement DW_OP_bit_piece] Jan Kratochvil
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-21 17:57 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Tom> We do take care to optimize for the byte-aligned case.

Jan> FYI I am strongly against this decision.  This creates (a) more
Jan> complicated code to maintain (b) less used and more dense to debug
Jan> codepath (the bits one) and (c) I doubt current hardware and
Jan> current `gcc -O2' code will ever notice a difference

Ok.  I will change this and make all the other changes you recommend.

Jan> GDB has much more serious performance issues (symbols reading,
Jan> lookup) than evaluation of any specific values.

If you know of specific bad cases, I'm very interested in that.
I think we understand the symbol reading problem pretty well now, but
other stuff could at least use bug reports.

Jan> And this function needs to distinguish both the bits endianity and
Jan> the bytes endianity.  Out of big-byte-endian machines there are
Jan> both big-bits-endian and little-bits-endian ones:
Jan> 	http://en.wikipedia.org/wiki/Bit_numbering#Usage
Jan> OTOH there is currently no GDB target using set_gdbarch_bits_big_endian,
Jan> therefore all the GDB targets are little-bits-endian.  This seems
Jan> to be wrong.

As we discussed on irc, gdb is actually mostly ok here -- the default is
set properly in gdbarch.c:

  gdbarch->bits_big_endian = (gdbarch->byte_order == BFD_ENDIAN_BIG);

There may be some architecture where this is wrong -- Jakub mentioned
some ARM part? -- but naturally that is outside the scope of this patch.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-19 23:35   ` Tom Tromey
  2010-05-20  3:29     ` Stan Shebs
  2010-05-20 19:53     ` RFC: implement DW_OP_bit_piece Tom Tromey
@ 2010-05-21 20:16     ` Tom Tromey
  2010-05-21 21:16       ` Stan Shebs
  2 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-21 20:16 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

Stan> the dwarf2_tracepoint_var_ref code to compile to bytecodes, and
Stan> human-readable description in locexpr_describe_location_1.

Stan> (Yes it's onerous, but we did want to revive tracepoints, right?)

Tom> I will update locexpr_describe_location_1.

I am actually just going to commit what I have, because it definitely
improves the situation, and then work on the remaining pieces as
separate patches.  I did not see a clean way to make
locexpr_describe_location_1 nicer, so I am going to rewrite it as
discussed elsewhere in the thread.

Here is the latest patch, which addresses Jan's review and also fixes a
bug that neither of us caught earlier.

Tom

2010-05-21  Tom Tromey  <tromey@redhat.com>

	* dwarf2loc.c (extract_bits_primitive): New function.
	(extract_bits): Likewise.
	(insert_bits): Likewise.
	(copy_bitwise): Likewise.
	(read_pieced_value): Do all operations in bits.
	(write_pieced_value): Likewise.
	* dwarf2expr.h (struct dwarf_expr_piece) <offset>: New field.
	* dwarf2expr.c (add_piece): New arguments bit_piece, offset.
	Always use xrealloc to resize piece array.
	(execute_stack_op) <DW_OP_reg0>: Handle DW_OP_bit_piece.
	<DW_OP_piece>: Update.
	<DW_OP_bit_piece>: New case.

2010-05-18  Tom Tromey  <tromey@redhat.com>

	* gdb.dwarf2/pieces.exp (pieces_test_f3): New proc.
	Call it.
	* gdb.dwarf2/pieces.S: Update.
	* gdb.dwarf2/pieces.c (struct B): Remove initial field.

diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 482c293..2a4151d 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -151,23 +151,21 @@ dwarf_expr_stack_empty_p (struct dwarf_expr_context *ctx)
 
 /* Add a new piece to CTX's piece list.  */
 static void
-add_piece (struct dwarf_expr_context *ctx, ULONGEST size)
+add_piece (struct dwarf_expr_context *ctx, ULONGEST size, ULONGEST offset)
 {
   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));
+  ctx->pieces = xrealloc (ctx->pieces,
+			  (ctx->num_pieces
+			   * sizeof (struct dwarf_expr_piece)));
 
   p = &ctx->pieces[ctx->num_pieces - 1];
   p->location = ctx->location;
   p->size = size;
+  p->offset = offset;
+
   if (p->location == DWARF_VALUE_LITERAL)
     {
       p->v.literal.data = ctx->data;
@@ -496,9 +494,11 @@ execute_stack_op (struct dwarf_expr_context *ctx,
 	case DW_OP_reg31:
 	  if (op_ptr != op_end 
 	      && *op_ptr != DW_OP_piece
+	      && *op_ptr != DW_OP_bit_piece
 	      && *op_ptr != DW_OP_GNU_uninit)
 	    error (_("DWARF-2 expression error: DW_OP_reg operations must be "
-		   "used either alone or in conjuction with DW_OP_piece."));
+		     "used either alone or in conjuction with DW_OP_piece "
+		     "or DW_OP_bit_piece."));
 
 	  result = op - DW_OP_reg0;
 	  ctx->location = DWARF_VALUE_REGISTER;
@@ -866,7 +866,7 @@ execute_stack_op (struct dwarf_expr_context *ctx,
 
             /* Record the piece.  */
             op_ptr = read_uleb128 (op_ptr, op_end, &size);
-	    add_piece (ctx, size);
+	    add_piece (ctx, 8 * size, 0);
 
             /* Pop off the address/regnum, and reset the location
 	       type.  */
@@ -877,6 +877,24 @@ execute_stack_op (struct dwarf_expr_context *ctx,
           }
           goto no_push;
 
+	case DW_OP_bit_piece:
+	  {
+	    ULONGEST size, offset;
+
+            /* Record the piece.  */
+	    op_ptr = read_uleb128 (op_ptr, op_end, &size);
+	    op_ptr = read_uleb128 (op_ptr, op_end, &offset);
+	    add_piece (ctx, size, offset);
+
+            /* Pop off the address/regnum, and reset the location
+	       type.  */
+	    if (ctx->location != DWARF_VALUE_LITERAL
+		&& ctx->location != DWARF_VALUE_OPTIMIZED_OUT)
+	      dwarf_expr_pop (ctx);
+            ctx->location = DWARF_VALUE_MEMORY;
+	  }
+	  goto no_push;
+
 	case DW_OP_GNU_uninit:
 	  if (op_ptr != op_end)
 	    error (_("DWARF-2 expression error: DW_OP_GNU_uninit must always "
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index f24f193..487d4f7 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -155,7 +155,7 @@ struct dwarf_expr_context
 };
 
 
-/* A piece of an object, as recorded by DW_OP_piece.  */
+/* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece.  */
 struct dwarf_expr_piece
 {
   enum dwarf_value_location location;
@@ -181,8 +181,10 @@ struct dwarf_expr_piece
     } literal;
   } v;
 
-  /* The length of the piece, in bytes.  */
+  /* The length of the piece, in bits.  */
   ULONGEST size;
+  /* The piece offset, in bits.  */
+  ULONGEST offset;
 };
 
 struct dwarf_expr_context *new_dwarf_expr_context (void);
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 2900f22..298e53c 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -257,52 +257,245 @@ allocate_piece_closure (int n_pieces, struct dwarf_expr_piece *pieces,
   return c;
 }
 
+/* The lowest-level function to extract bits from a byte buffer.
+   SOURCE is the buffer.  It is updated if we read to the end of a
+   byte.
+   SOURCE_OFFSET_BITS is the offset of the first bit to read.  It is
+   updated to reflect the number of bits actually read.
+   NBITS is the number of bits we want to read.  It is updated to
+   reflect the number of bits actually read.  This function may read
+   fewer bits.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.
+   This function returns the extracted bits.  */
+
+static unsigned int
+extract_bits_primitive (const gdb_byte **source,
+			unsigned int *source_offset_bits,
+			int *nbits, int bits_big_endian)
+{
+  unsigned int avail, mask, datum;
+
+  gdb_assert (*source_offset_bits < 8);
+
+  avail = 8 - *source_offset_bits;
+  if (avail > *nbits)
+    avail = *nbits;
+
+  mask = (1 << avail) - 1;
+  datum = **source;
+  if (bits_big_endian)
+    datum >>= 8 - (*source_offset_bits + *nbits);
+  else
+    datum >>= *source_offset_bits;
+  datum &= mask;
+
+  *nbits -= avail;
+  *source_offset_bits += avail;
+  if (*source_offset_bits >= 8)
+    {
+      *source_offset_bits -= 8;
+      ++*source;
+    }
+
+  return datum;
+}
+
+/* Extract some bits from a source buffer and move forward in the
+   buffer.
+   
+   SOURCE is the source buffer.  It is updated as bytes are read.
+   SOURCE_OFFSET_BITS is the offset into SOURCE.  It is updated as
+   bits are read.
+   NBITS is the number of bits to read.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.
+   
+   This function returns the bits that were read.  */
+
+static unsigned int
+extract_bits (const gdb_byte **source, unsigned int *source_offset_bits,
+	      int nbits, int bits_big_endian)
+{
+  unsigned int datum;
+
+  gdb_assert (nbits > 0 && nbits <= 8);
+
+  datum = extract_bits_primitive (source, source_offset_bits, &nbits,
+				  bits_big_endian);
+  if (nbits > 0)
+    {
+      unsigned int more;
+
+      more = extract_bits_primitive (source, source_offset_bits, &nbits,
+				     bits_big_endian);
+      if (bits_big_endian)
+	datum <<= nbits;
+      else
+	more <<= nbits;
+      datum |= more;
+    }
+
+  return datum;
+}
+
+/* Write some bits into a buffer and move forward in the buffer.
+   
+   DATUM is the bits to write.  The low-order bits of DATUM are used.
+   DEST is the destination buffer.  It is updated as bytes are
+   written.
+   DEST_OFFSET_BITS is the bit offset in DEST at which writing is
+   done.
+   NBITS is the number of valid bits in DATUM.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.  */
+
+static void
+insert_bits (unsigned int datum,
+	     gdb_byte *dest, unsigned int dest_offset_bits,
+	     int nbits, int bits_big_endian)
+{
+  unsigned int mask;
+
+  gdb_assert (dest_offset_bits >= 0 && dest_offset_bits + nbits <= 8);
+
+  mask = (1 << nbits) - 1;
+  if (bits_big_endian)
+    {
+      datum <<= 8 - (dest_offset_bits + nbits);
+      mask <<= 8 - (dest_offset_bits + nbits);
+    }
+  else
+    {
+      datum <<= dest_offset_bits;
+      mask <<= dest_offset_bits;
+    }
+
+  gdb_assert ((datum & ~mask) == 0);
+
+  *dest = (*dest & ~mask) | datum;
+}
+
+/* Copy bits from a source to a destination.
+   
+   DEST is where the bits should be written.
+   DEST_OFFSET_BITS is the bit offset into DEST.
+   SOURCE is the source of bits.
+   SOURCE_OFFSET_BITS is the bit offset into SOURCE.
+   BIT_COUNT is the number of bits to copy.
+   BITS_BIG_ENDIAN is taken directly from gdbarch.  */
+
+static void
+copy_bitwise (gdb_byte *dest, unsigned int dest_offset_bits,
+	      const gdb_byte *source, unsigned int source_offset_bits,
+	      unsigned int bit_count,
+	      int bits_big_endian)
+{
+  unsigned int dest_avail;
+  int datum;
+
+  /* Reduce everything to byte-size pieces.  */
+  dest += dest_offset_bits / 8;
+  dest_offset_bits %= 8;
+  source += source_offset_bits / 8;
+  source_offset_bits %= 8;
+
+  dest_avail = 8 - dest_offset_bits % 8;
+
+  /* See if we can fill the first destination byte.  */
+  if (dest_avail < bit_count)
+    {
+      datum = extract_bits (&source, &source_offset_bits, dest_avail,
+			    bits_big_endian);
+      insert_bits (datum, dest, dest_offset_bits, dest_avail, bits_big_endian);
+      ++dest;
+      dest_offset_bits = 0;
+      bit_count -= dest_avail;
+    }
+
+  /* Now, either DEST_OFFSET_BITS is byte-aligned, or we have fewer
+     than 8 bits remaining.  */
+  gdb_assert (dest_offset_bits % 8 == 0 || bit_count < 8);
+  for (; bit_count >= 8; bit_count -= 8)
+    {
+      datum = extract_bits (&source, &source_offset_bits, 8, bits_big_endian);
+      *dest++ = (gdb_byte) datum;
+    }
+
+  /* Finally, we may have a few leftover bits.  */
+  gdb_assert (bit_count <= 8 - dest_offset_bits % 8);
+  if (bit_count > 0)
+    {
+      datum = extract_bits (&source, &source_offset_bits, bit_count,
+			    bits_big_endian);
+      insert_bits (datum, dest, dest_offset_bits, bit_count, bits_big_endian);
+    }
+}
+
 static void
 read_pieced_value (struct value *v)
 {
   int i;
   long offset = 0;
-  ULONGEST bytes_to_skip;
+  ULONGEST bits_to_skip;
   gdb_byte *contents;
   struct piece_closure *c = (struct piece_closure *) value_computed_closure (v);
   struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (v));
   size_t type_len;
+  size_t buffer_size = 0;
+  char *buffer = NULL;
+  struct cleanup *cleanup;
+  int bits_big_endian
+    = gdbarch_bits_big_endian (get_type_arch (value_type (v)));
 
   if (value_type (v) != value_enclosing_type (v))
     internal_error (__FILE__, __LINE__,
 		    _("Should not be able to create a lazy value with "
 		      "an enclosing type"));
 
+  cleanup = make_cleanup (free_current_contents, &buffer);
+
   contents = value_contents_raw (v);
-  bytes_to_skip = value_offset (v);
-  type_len = TYPE_LENGTH (value_type (v));
+  bits_to_skip = 8 * value_offset (v);
+  type_len = 8 * TYPE_LENGTH (value_type (v));
+
   for (i = 0; i < c->n_pieces && offset < type_len; i++)
     {
       struct dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size;
-      long dest_offset, source_offset;
-
-      if (bytes_to_skip > 0 && bytes_to_skip >= p->size)
+      size_t this_size, this_size_bits;
+      long dest_offset_bits, source_offset_bits, source_offset;
+      gdb_byte *intermediate_buffer;
+
+      /* Compute size, source, and destination offsets for copying, in
+	 bits.  */
+      this_size_bits = p->size;
+      if (bits_to_skip > 0 && bits_to_skip >= this_size_bits)
 	{
-	  bytes_to_skip -= p->size;
+	  bits_to_skip -= this_size_bits;
 	  continue;
 	}
-      this_size = p->size;
-      if (this_size > type_len - offset)
-	this_size = type_len - offset;
-      if (bytes_to_skip > 0)
+      if (this_size_bits > type_len - offset)
+	this_size_bits = type_len - offset;
+      if (bits_to_skip > 0)
 	{
-	  dest_offset = 0;
-	  source_offset = bytes_to_skip;
-	  this_size -= bytes_to_skip;
-	  bytes_to_skip = 0;
+	  dest_offset_bits = 0;
+	  source_offset_bits = bits_to_skip;
+	  this_size_bits -= bits_to_skip;
+	  bits_to_skip = 0;
 	}
       else
 	{
-	  dest_offset = offset;
-	  source_offset = 0;
+	  dest_offset_bits = offset;
+	  source_offset_bits = 0;
+	}
+
+      this_size = (this_size_bits + source_offset_bits % 8 + 7) / 8;
+      source_offset = source_offset_bits / 8;
+      if (buffer_size < this_size)
+	{
+	  buffer_size = this_size;
+	  buffer = xrealloc (buffer, buffer_size);
 	}
+      intermediate_buffer = buffer;
 
+      /* Copy from the source to DEST_BUFFER.  */
       switch (p->location)
 	{
 	case DWARF_VALUE_REGISTER:
@@ -314,13 +507,18 @@ read_pieced_value (struct value *v)
 
 	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
 		&& this_size < register_size (arch, gdb_regnum))
-	      /* Big-endian, and we want less than full size.  */
-	      reg_offset = register_size (arch, gdb_regnum) - this_size;
+	      {
+		/* Big-endian, and we want less than full size.  */
+		reg_offset = register_size (arch, gdb_regnum) - this_size;
+		/* We want the lower-order THIS_SIZE_BITS of the bytes
+		   we extract from the register.  */
+		source_offset_bits += 8 * this_size - this_size_bits;
+	      }
 
 	    if (gdb_regnum != -1)
 	      {
 		get_frame_register_bytes (frame, gdb_regnum, reg_offset, 
-					  this_size, contents + dest_offset);
+					  this_size, buffer);
 	      }
 	    else
 	      {
@@ -332,11 +530,9 @@ read_pieced_value (struct value *v)
 
 	case DWARF_VALUE_MEMORY:
 	  if (p->v.expr.in_stack_memory)
-	    read_stack (p->v.expr.value + source_offset,
-			contents + dest_offset, this_size);
+	    read_stack (p->v.expr.value + source_offset, buffer, this_size);
 	  else
-	    read_memory (p->v.expr.value + source_offset,
-			 contents + dest_offset, this_size);
+	    read_memory (p->v.expr.value + source_offset, buffer, this_size);
 	  break;
 
 	case DWARF_VALUE_STACK:
@@ -352,7 +548,7 @@ read_pieced_value (struct value *v)
 		/* Nothing.  */
 	      }
 	    else if (source_offset == 0)
-	      store_unsigned_integer (contents + dest_offset, n,
+	      store_unsigned_integer (buffer, n,
 				      gdbarch_byte_order (gdbarch),
 				      p->v.expr.value);
 	    else
@@ -362,7 +558,7 @@ read_pieced_value (struct value *v)
 		store_unsigned_integer (bytes, n + source_offset,
 					gdbarch_byte_order (gdbarch),
 					p->v.expr.value);
-		memcpy (contents + dest_offset, bytes + source_offset, n);
+		memcpy (buffer, bytes + source_offset, n);
 	      }
 	  }
 	  break;
@@ -375,8 +571,7 @@ read_pieced_value (struct value *v)
 		   ? p->v.literal.length - source_offset
 		   : 0);
 	    if (n != 0)
-	      memcpy (contents + dest_offset,
-		      p->v.literal.data + source_offset, n);
+	      intermediate_buffer = p->v.literal.data + source_offset;
 	  }
 	  break;
 
@@ -384,17 +579,25 @@ read_pieced_value (struct value *v)
 	  /* We just leave the bits empty for now.  This is not ideal
 	     but gdb currently does not have a nice way to represent
 	     optimized-out pieces.  */
-	  warning (_("bytes %ld-%ld in computed object were optimized out; "
+	  warning (_("bits %ld-%ld in computed object were optimized out; "
 		     "replacing with zeroes"),
 		   offset,
-		   offset + (long) this_size);
+		   offset + (long) this_size_bits);
 	  break;
 
 	default:
 	  internal_error (__FILE__, __LINE__, _("invalid location type"));
 	}
-      offset += this_size;
+
+      if (p->location != DWARF_VALUE_OPTIMIZED_OUT)
+	copy_bitwise (contents, dest_offset_bits,
+		      intermediate_buffer, source_offset_bits % 8,
+		      this_size_bits, bits_big_endian);
+
+      offset += this_size_bits;
     }
+
+  do_cleanups (cleanup);
 }
 
 static void
@@ -402,11 +605,16 @@ write_pieced_value (struct value *to, struct value *from)
 {
   int i;
   long offset = 0;
-  ULONGEST bytes_to_skip;
+  ULONGEST bits_to_skip;
   const gdb_byte *contents;
   struct piece_closure *c = (struct piece_closure *) value_computed_closure (to);
   struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (to));
   size_t type_len;
+  size_t buffer_size = 0;
+  char *buffer = NULL;
+  struct cleanup *cleanup;
+  int bits_big_endian
+    = gdbarch_bits_big_endian (get_type_arch (value_type (to)));
 
   if (frame == NULL)
     {
@@ -414,34 +622,57 @@ write_pieced_value (struct value *to, struct value *from)
       return;
     }
 
+  cleanup = make_cleanup (free_current_contents, &buffer);
+
   contents = value_contents (from);
-  bytes_to_skip = value_offset (to);
-  type_len = TYPE_LENGTH (value_type (to));
+  bits_to_skip = 8 * value_offset (to);
+  type_len = 8 * TYPE_LENGTH (value_type (to));
   for (i = 0; i < c->n_pieces && offset < type_len; i++)
     {
       struct dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size;
-      long dest_offset, source_offset;
+      size_t this_size_bits, this_size;
+      long dest_offset_bits, source_offset_bits, dest_offset, source_offset;
+      int need_bitwise;
+      const gdb_byte *source_buffer;
 
-      if (bytes_to_skip > 0 && bytes_to_skip >= p->size)
+      this_size_bits = p->size;
+      if (bits_to_skip > 0 && bits_to_skip >= this_size_bits)
 	{
-	  bytes_to_skip -= p->size;
+	  bits_to_skip -= this_size_bits;
 	  continue;
 	}
-      this_size = p->size;
-      if (this_size > type_len - offset)
-	this_size = type_len - offset;
-      if (bytes_to_skip > 0)
+      if (this_size_bits > type_len - offset)
+	this_size_bits = type_len - offset;
+      if (bits_to_skip > 0)
+	{
+	  dest_offset_bits = bits_to_skip;
+	  source_offset_bits = 0;
+	  this_size_bits -= bits_to_skip;
+	  bits_to_skip = 0;
+	}
+      else
+	{
+	  dest_offset_bits = 0;
+	  source_offset_bits = offset;
+	}
+
+      this_size = (this_size_bits + source_offset_bits % 8 + 7) / 8;
+      source_offset = source_offset_bits / 8;
+      dest_offset = dest_offset_bits / 8;
+      if (dest_offset_bits % 8 == 0 && source_offset_bits % 8 == 0)
 	{
-	  dest_offset = bytes_to_skip;
-	  source_offset = 0;
-	  this_size -= bytes_to_skip;
-	  bytes_to_skip = 0;
+	  source_buffer = contents + source_offset;
+	  need_bitwise = 0;
 	}
       else
 	{
-	  dest_offset = 0;
-	  source_offset = offset;
+	  if (buffer_size < this_size)
+	    {
+	      buffer_size = this_size;
+	      buffer = xrealloc (buffer, buffer_size);
+	    }
+	  source_buffer = buffer;
+	  need_bitwise = 1;
 	}
 
       switch (p->location)
@@ -459,8 +690,18 @@ write_pieced_value (struct value *to, struct value *from)
 
 	    if (gdb_regnum != -1)
 	      {
+		if (need_bitwise)
+		  {
+		    get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+					      this_size, buffer);
+		    copy_bitwise (buffer, dest_offset_bits,
+				  contents, source_offset_bits,
+				  this_size_bits,
+				  bits_big_endian);
+		  }
+
 		put_frame_register_bytes (frame, gdb_regnum, reg_offset, 
-					  this_size, contents + source_offset);
+					  this_size, source_buffer);
 	      }
 	    else
 	      {
@@ -470,15 +711,31 @@ write_pieced_value (struct value *to, struct value *from)
 	  }
 	  break;
 	case DWARF_VALUE_MEMORY:
+	  if (need_bitwise)
+	    {
+	      /* Only the first and last bytes can possibly have any
+		 bits reused.  */
+	      read_memory (p->v.expr.value + dest_offset, buffer, 1);
+	      read_memory (p->v.expr.value + dest_offset + this_size - 1,
+			   buffer + this_size - 1, 1);
+	      copy_bitwise (buffer, dest_offset_bits,
+			    contents, source_offset_bits,
+			    this_size_bits,
+			    bits_big_endian);
+	    }
+
 	  write_memory (p->v.expr.value + dest_offset,
-			contents + source_offset, this_size);
+			source_buffer, this_size);
 	  break;
 	default:
 	  set_value_optimized_out (to, 1);
-	  return;
+	  goto done;
 	}
-      offset += this_size;
+      offset += this_size_bits;
     }
+
+ done:
+  do_cleanups (cleanup);
 }
 
 static void *
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.S b/gdb/testsuite/gdb.dwarf2/pieces.S
index 0ecdbb0..f08b53d 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.S
+++ b/gdb/testsuite/gdb.dwarf2/pieces.S
@@ -989,23 +989,18 @@ main:
 .LLST6:
 	.long	.LVL13-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL14-.Ltext0	# Location list end address (*.LLST6)
-	.value	0xa	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x8	# Location expression size
 	.byte	0x34	# DW_OP_lit4
 	.byte	0x9f	# DW_OP_stack_value
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x93	# DW_OP_piece
-	.uleb128 0x2
-	.long	.LVL14-.Ltext0	# Location list begin address (*.LLST6)
-	.long	.LVL15-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x15	# Location expression size
 	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
+	.uleb128 0x14
 	.uleb128 0
+	.long	.LVL14-.Ltext0	# Location list begin address (*.LLST6)
+	.long	.LVL15-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x11	# Location expression size
 	.byte	0x34	# DW_OP_lit4
 	.byte	0x9f	# DW_OP_stack_value
 	.byte	0x9d	# DW_OP_bit_piece
@@ -1021,15 +1016,11 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL15-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL16-1-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x14	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x10	# Location expression size
 	.byte	0x52	# DW_OP_reg2
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
@@ -1044,15 +1035,11 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL16-1-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LVL17-.Ltext0	# Location list end address (*.LLST6)
-	.value	0x14	# Location expression size
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.value	0x10	# Location expression size
 	.byte	0x56	# DW_OP_reg6
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
@@ -1067,14 +1054,14 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	.LVL17-.Ltext0	# Location list begin address (*.LLST6)
 	.long	.LFE3-.Ltext0	# Location list end address (*.LLST6)
 	.value	0xf	# Location expression size
-	.byte	0x93	# DW_OP_piece
-	.uleb128 0x2
+	.byte	0x9d	# DW_OP_bit_piece
+	.uleb128 0xc
+	.uleb128 0
 	.byte	0x91	# DW_OP_fbreg
 	.sleb128 0
 	.byte	0x94	# DW_OP_deref_size
@@ -1085,9 +1072,8 @@ main:
 	.byte	0x9d	# DW_OP_bit_piece
 	.uleb128 0xc
 	.uleb128 0
-	.byte	0x9d	# DW_OP_bit_piece
-	.uleb128 0x4
-	.uleb128 0
+	.byte	0x93	# DW_OP_piece
+	.uleb128 0x1
 	.long	0	# Location list terminator begin (*.LLST6)
 	.long	0	# Location list terminator end (*.LLST6)
 .LLST7:
@@ -1356,7 +1342,7 @@ main:
 	.long	0x48	# DW_AT_type
 	.byte	0x4	# DW_AT_byte_size
 	.byte	0xc	# DW_AT_bit_size
-	.byte	0x10	# DW_AT_bit_offset
+	.byte	0x14	# DW_AT_bit_offset
 	.byte	0x2	# DW_AT_data_member_location
 	.byte	0x23	# DW_OP_plus_uconst
 	.uleb128 0
@@ -1367,7 +1353,7 @@ main:
 	.long	0x48	# DW_AT_type
 	.byte	0x4	# DW_AT_byte_size
 	.byte	0xc	# DW_AT_bit_size
-	.byte	0x4	# DW_AT_bit_offset
+	.byte	0x8	# DW_AT_bit_offset
 	.byte	0x2	# DW_AT_data_member_location
 	.byte	0x23	# DW_OP_plus_uconst
 	.uleb128 0
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.c b/gdb/testsuite/gdb.dwarf2/pieces.c
index 04ea8a2..29879f5 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.c
+++ b/gdb/testsuite/gdb.dwarf2/pieces.c
@@ -21,7 +21,7 @@
    However, it is used to extract breakpoint line numbers.  */
 
 struct A { int i; int j; };
-struct B { int : 4; int i : 12; int j : 12; int : 4; };
+struct B { int i : 12; int j : 12; int : 4; };
 struct C { int i; int j; int q; };
 
 __attribute__((noinline)) void
@@ -89,7 +89,7 @@ __attribute__((noinline)) int
 f6 (int k)
 {
   int z = 23;
-  struct C a = { k, k, z};
+  struct C a = { k, k, z };
   asm ("" : "+r" (a.i));
   a.j++;
   bar (a.i);
diff --git a/gdb/testsuite/gdb.dwarf2/pieces.exp b/gdb/testsuite/gdb.dwarf2/pieces.exp
index c7608cd..2e812b5 100644
--- a/gdb/testsuite/gdb.dwarf2/pieces.exp
+++ b/gdb/testsuite/gdb.dwarf2/pieces.exp
@@ -67,15 +67,30 @@ proc pieces_test_f2 {} {
     gdb_test "print a\[1\]" " = 14" "print a\[1\] in pieces:f2"
 }
 
+# Function f3 tests DW_OP_bit_piece.
+proc pieces_test_f3 {} {
+    global csrcfile
+    set line [gdb_get_line_number "f3 breakpoint" $csrcfile]
+    gdb_test "break pieces.c:$line" "Breakpoint 4.*" \
+       "set f3 breakpoint for pieces"
+    gdb_continue_to_breakpoint "continue to f3 breakpoint for pieces"
+    gdb_test "print a.i" " = 4" "print a.i in pieces:f3"
+    gdb_test "print a.j" " = 14" "print a.j in pieces:f3"
+    # Right now gdb says "value optimized out" here, but that is wrong.
+    setup_kfail "no bug yet" *-*-*
+    gdb_test "print a.i = 7" " = 7" "set a.i in pieces:f3"
+    gdb_test "print a.i" " = 7" "print new a.i in pieces:f3"
+}
+
 # Function f6 tests for an empty DW_OP_piece.
 proc pieces_test_f6 {} {
     global csrcfile
     set line [gdb_get_line_number "f6 breakpoint" $csrcfile]
-    gdb_test "break pieces.c:$line" "Breakpoint 4.*" \
+    gdb_test "break pieces.c:$line" "Breakpoint 5.*" \
        "set f6 breakpoint for pieces"
     gdb_continue_to_breakpoint "continue to f6 breakpoint for pieces"
     gdb_test "print a" \
-	"warning: bytes .* in computed object were.* = {i = 7, j = 8, q = 0}" \
+	"warning: bits .* in computed object were.* = {i = 7, j = 8, q = 0}" \
 	"print a with optimized out piece"
     # Note: no warning for this case.
     gdb_test_multiple "print a.i" \
@@ -91,4 +106,5 @@ proc pieces_test_f6 {} {
 
 pieces_test_f1
 pieces_test_f2
+pieces_test_f3
 pieces_test_f6

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-21 20:16     ` Tom Tromey
@ 2010-05-21 21:16       ` Stan Shebs
  2010-05-21 21:18         ` Tom Tromey
  2010-05-25 19:22         ` RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
  0 siblings, 2 replies; 36+ messages in thread
From: Stan Shebs @ 2010-05-21 21:16 UTC (permalink / raw)
  To: tromey; +Cc: Stan Shebs, gdb-patches, Jan Kratochvil

Tom Tromey wrote:
> Stan> the dwarf2_tracepoint_var_ref code to compile to bytecodes, and
> Stan> human-readable description in locexpr_describe_location_1.
>
> Stan> (Yes it's onerous, but we did want to revive tracepoints, right?)
>
> Tom> I will update locexpr_describe_location_1.
>
> I am actually just going to commit what I have, because it definitely
> improves the situation, and then work on the remaining pieces as
> separate patches.  I did not see a clean way to make
> locexpr_describe_location_1 nicer, so I am going to rewrite it as
> discussed elsewhere in the thread.
>   

Which rewrite is that?  I can see switching to opcode disassembly for 
heinously-complicated location expressions, but multiple pieces and 
reg/offset seem reasonable to describe verbally - if nothing else, it 
conveys to the user that a local has a nontrivial liveness range and 
lives in different places at different times, so the user needs to be 
cautious when a register or stack location seems to have a wrong value 
in it.

Stan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-21 21:16       ` Stan Shebs
@ 2010-05-21 21:18         ` Tom Tromey
  2010-05-25 19:22         ` RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
  1 sibling, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2010-05-21 21:18 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Stan Shebs, gdb-patches, Jan Kratochvil

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Stan> Which rewrite is that?  I can see switching to opcode disassembly for
Stan> heinously-complicated location expressions, but multiple pieces and
Stan> reg/offset seem reasonable to describe verbally - if nothing else, it
Stan> conveys to the user that a local has a nontrivial liveness range and
Stan> lives in different places at different times, so the user needs to be
Stan> cautious when a register or stack location seems to have a wrong value
Stan> in it.

Yeah.  What I was planning was something like: if a given piece is
simple to describe in plain English, do so; else, disassemble.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* performance talk  [Re: RFC: implement DW_OP_bit_piece]
  2010-05-21 17:57   ` Tom Tromey
@ 2010-05-25 18:19     ` Jan Kratochvil
  2010-05-25 22:23       ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Jan Kratochvil @ 2010-05-25 18:19 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On Fri, 21 May 2010 19:44:50 +0200, Tom Tromey wrote:
> Jan> GDB has much more serious performance issues (symbols reading,
> Jan> lookup) than evaluation of any specific values.
> 
> If you know of specific bad cases, I'm very interested in that.
> I think we understand the symbol reading problem pretty well now, but
> other stuff could at least use bug reports.

Checked now we were talking about `attach' being fast enough (~2s on OOo.org)
but I was testing it with `archer-tromey-delayed-symfile2'.  Then `bt full' is
still slow - tens of secs.  More than 3GB of RAM or SSD would help caching the
on-disk debuginfo files, though.  My box could be also declared as an
inappropriate for development of apps of the OOo.org size.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece)
  2010-05-21 21:16       ` Stan Shebs
  2010-05-21 21:18         ` Tom Tromey
@ 2010-05-25 19:22         ` Tom Tromey
  2010-05-25 19:27           ` Jan Kratochvil
  1 sibling, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-25 19:22 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Stan Shebs, gdb-patches, Jan Kratochvil

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Stan> Which rewrite is that?  I can see switching to opcode disassembly for
Stan> heinously-complicated location expressions, but multiple pieces and
Stan> reg/offset seem reasonable to describe verbally - if nothing else, it
Stan> conveys to the user that a local has a nontrivial liveness range and
Stan> lives in different places at different times, so the user needs to be
Stan> cautious when a register or stack location seems to have a wrong value
Stan> in it.

Here is what I came up with.  Let me know what you think.

With this patch, by default GDB still tries to describe a location in a
"human readable" form.  This is not always possible, though, and in
those cases it falls back to a disassembly form.  Additionally, it adds
a new parameter, "maint show dwarf2 always-disassemble", which can be
set if you prefer to always get disassembly.

Sample still-pretty output:

(gdb) info addr argc
Symbol "argc" is a variable at frame base reg $ebp offset 8+0.

(This is identical to the existing output.)


Here is existing gdb on a complicated expression.  Maybe not the ideal
example since it uses something not currently understood (but still ok,
because the new approach is much more complete and will only barf on
expressions that gdb cannot actually evaluate):

(gdb) info addr a
Symbol "a" is multi-location (range 0x8048440-0x8048448, a variable with complex or multiple locations (DWARF2)Corrupted DWARF2 expression for "a".

The new output.  This is pretty verbose, but I think this is a feature.

(gdb) info addr a
Symbol "a" is multi-location:
  Range 0x8048440-0x8048448: the constant 4 [12-bit piece, offset 0 bits], and an empty 20-bit piece
  Range 0x8048448-0x804844b: the constant 4 [12-bit piece, offset 0 bits], and a complex DWARF expression:
     1: DW_OP_fbreg 0
     3: DW_OP_deref_size 2
     5: DW_OP_plus_uconst 6
     7: DW_OP_stack_value
    [12-bit piece, offset 0 bits], and an empty 1-byte piece
  Range 0x804844b-0x804845b: a variable in $edx [12-bit piece, offset 0 bits], and a complex DWARF expression:
     1: DW_OP_fbreg 0
     3: DW_OP_deref_size 2
     5: DW_OP_plus_uconst 7
     7: DW_OP_stack_value
    [12-bit piece, offset 0 bits], and an empty 1-byte piece
  Range 0x804845b-0x804847d: a variable in $esi [12-bit piece, offset 0 bits], and a complex DWARF expression:
     1: DW_OP_fbreg 0
     3: DW_OP_deref_size 2
     5: DW_OP_plus_uconst 7
     7: DW_OP_stack_value
    [12-bit piece, offset 0 bits], and an empty 1-byte piece
  Range 0x804847d-0x8048481: an empty 12-bit piece, and a complex DWARF expression:
     1: DW_OP_fbreg 0
     3: DW_OP_deref_size 2
     5: DW_OP_plus_uconst 7
     7: DW_OP_stack_value
    [12-bit piece, offset 0 bits], and an empty 1-byte piece
.



Built and regression-tested on x86-64 (compile farm).
This includes a doc update.

Tom

2010-05-24  Tom Tromey  <tromey@redhat.com>

	* dwarf2read.c (dwarf_stack_op_name): No longer static.  Return
	type is const.  Add 'def' argument.  Add missing operators, remove
	unhandled ones.
	(decode_locdesc): Update.
	(dwarf2_always_disassemble): New global.
	(show_dwarf2_always_disassemble): New function.
	(_initialize_dwarf2_read): Add always-disassemble.
	* dwarf2loc.c (dwarf2_always_disassemble): Declare.
	(piece_end_p): New function.
	(locexpr_describe_location_piece): Replace 'size' argument with
	'end'.  Use piece_end_p.  Rewrite recognition of TLS.  Recognize
	some constants.  Remove errors.
	(disassemble_dwarf_expression): New function.
	(locexpr_describe_location_1): Use disassemble_dwarf_expression.
	(loclist_describe_location): Change output formatting.
	* dwarf2expr.h (dwarf_stack_op_name): Declare.

2010-05-24  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
	always-disassemble.

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e929481..741f423 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29862,6 +29862,20 @@ that symbol is described.  The type chain produced by this command is
 a recursive definition of the data type as stored in @value{GDBN}'s
 data structures, including its flags and contained types.
 
+@kindex maint set dwarf2 always-disassemble
+@kindex maint show dwarf2 always-disassemble
+@item maint set dwarf2 always-disassemble
+@item maint show dwarf2 always-disassemble
+Control the behavior of @code{info address} when using DWARF debugging
+information.
+
+The default is @code{off}, which means that @value{GDBN} should try to
+describe a variable's location in an easily readable format.  When
+@code{on}, @value{GDBN} will instead display the DWARF location
+expression in an assembly-like format.  Note that some locations are
+too complex for @value{GDBN} to describe simply; in this case you will
+always see the disassembly form.
+
 @kindex maint set dwarf2 max-cache-age
 @kindex maint show dwarf2 max-cache-age
 @item maint set dwarf2 max-cache-age
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index a0f4554..8ebbf87 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -208,4 +208,6 @@ const gdb_byte *read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
 CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
 			       const gdb_byte *buf_end, int addr_size);
 
+const char *dwarf_stack_op_name (unsigned int, int);
+
 #endif /* dwarf2expr.h */
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 481501b..48bb1aa 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -42,6 +42,8 @@
 #include "gdb_string.h"
 #include "gdb_assert.h"
 
+extern int dwarf2_always_disassemble;
+
 static void
 dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
 			 const gdb_byte **start, size_t *length);
@@ -1282,13 +1284,24 @@ locexpr_read_needs_frame (struct symbol *symbol)
 				      dlbaton->per_cu);
 }
 
-/* Describe a single piece of a location, returning an updated
-   position in the bytecode sequence.  */
+/* Return true if DATA points to the end of a piece.  END is one past
+   the last byte in the expression.  */
+
+static int
+piece_end_p (const gdb_byte *data, const gdb_byte *end)
+{
+  return data == end || data[0] == DW_OP_piece || data[0] == DW_OP_bit_piece;
+}
+
+/* Nicely describe a single piece of a location, returning an updated
+   position in the bytecode sequence.  This function cannot recognize
+   all locations; if a location is not recognized, it simply returns
+   DATA.  */
 
 static const gdb_byte *
 locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 				 CORE_ADDR addr, struct objfile *objfile,
-				 const gdb_byte *data, int size,
+				 const gdb_byte *data, const gdb_byte *end,
 				 unsigned int addr_size)
 {
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
@@ -1305,7 +1318,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
     {
       ULONGEST reg;
 
-      data = read_uleb128 (data + 1, data + size, &reg);
+      data = read_uleb128 (data + 1, end, &reg);
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
       fprintf_filtered (stream, _("a variable in $%s"),
 			gdbarch_register_name (gdbarch, regno));
@@ -1316,10 +1329,15 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
       struct symbol *framefunc;
       int frame_reg = 0;
       LONGEST frame_offset;
-      const gdb_byte *base_data;
+      const gdb_byte *base_data, *new_data;
       size_t base_size;
       LONGEST base_offset = 0;
 
+      new_data = read_sleb128 (data + 1, end, &frame_offset);
+      if (!piece_end_p (new_data, end))
+	return data;
+      data = new_data;
+
       b = block_for_pc (addr);
 
       if (!b)
@@ -1363,19 +1381,18 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
 
-      data = read_sleb128 (data + 1, data + size, &frame_offset);
-
       fprintf_filtered (stream, _("a variable at frame base reg $%s offset %s+%s"),
 			gdbarch_register_name (gdbarch, regno),
 			plongest (base_offset), plongest (frame_offset));
     }
-  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
+  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31
+	   && piece_end_p (data, end))
     {
       LONGEST offset;
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_breg0);
 
-      data = read_sleb128 (data + 1, data + size, &offset);
+      data = read_sleb128 (data + 1, end, &offset);
 
       fprintf_filtered (stream,
 			_("a variable at offset %s from base reg $%s"),
@@ -1395,13 +1412,14 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
      The operand represents the offset at which the variable is within
      the thread local storage.  */
 
-  else if (size > 1
-	   && data[size - 1] == DW_OP_GNU_push_tls_address
-	   && data[0] == DW_OP_addr)
+  else if (data + 1 + addr_size < end
+	   && data[0] == DW_OP_addr
+	   && data[1 + addr_size] == DW_OP_GNU_push_tls_address
+	   && piece_end_p (data + 2 + addr_size, end))
     {
       CORE_ADDR offset = dwarf2_read_address (gdbarch,
 					      data + 1,
-					      data + size - 1,
+					      end,
 					      addr_size);
 
       fprintf_filtered (stream, 
@@ -1411,9 +1429,221 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       data += 1 + addr_size + 1;
     }
-  else
-    fprintf_filtered (stream,
-		      _("a variable with complex or multiple locations (DWARF2)"));
+  else if (data[0] >= DW_OP_lit0
+	   && data[0] <= DW_OP_lit31
+	   && data + 1 < end
+	   && data[1] == DW_OP_stack_value)
+    {
+      fprintf_filtered (stream, _("the constant %d"), data[0] - DW_OP_lit0);
+      data += 2;
+    }
+
+  return data;
+}
+
+/* Disassemble an expression, stopping at the end of a piece or at the
+   end of the expression.  Returns a pointer to the next unread byte
+   in the input expression.  If ALL is nonzero, then this function
+   will keep going until it reaches the end of the expression.  */
+
+static const gdb_byte *
+disassemble_dwarf_expression (struct ui_file *stream,
+			      struct gdbarch *arch, unsigned int addr_size,
+			      const gdb_byte *data, const gdb_byte *end,
+			      int all)
+{
+  const gdb_byte *start = data;
+
+  fprintf_filtered (stream, _("a complex DWARF expression:\n"));
+
+  while (data < end
+	 && (all
+	     || (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece)))
+    {
+      enum dwarf_location_atom op = *data++;
+      CORE_ADDR addr;
+      ULONGEST ul;
+      LONGEST l;
+      const char *name;
+
+      name = dwarf_stack_op_name (op, 0);
+
+      if (!name)
+	error (_("Unrecognized DWARF opcode 0x%02x at %ld"),
+	       op, (long) (data - start));
+      fprintf_filtered (stream, "  % 4ld: %s", (long) (data - start), name);
+
+      switch (op)
+	{
+	case DW_OP_addr:
+	  addr = dwarf2_read_address (arch, data, end, addr_size);
+	  data += addr_size;
+	  fprintf_filtered (stream, " %s", paddress (arch, addr));
+	  break;
+
+	case DW_OP_const1u:
+	  ul = extract_unsigned_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const1s:
+	  l = extract_signed_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const2u:
+	  ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const2s:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const4u:
+	  ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const4s:
+	  l = extract_signed_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const8u:
+	  ul = extract_unsigned_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const8s:
+	  l = extract_signed_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_constu:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_consts:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+
+	case DW_OP_regx:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_implicit_value:
+	  data = read_uleb128 (data, end, &ul);
+	  data += ul;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	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:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_bregx:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_sleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " register %s offset %s",
+			      pulongest (ul), pulongest (offset));
+	  }
+	  break;
+
+	case DW_OP_fbreg:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_pick:
+	  fprintf_filtered (stream, " %d", *data);
+	  ++data;
+	  break;
+
+	case DW_OP_deref_size:
+	  {
+	    int addr_size = *data++;
+
+	    fprintf_filtered (stream, " %d", addr_size);
+	  }
+	  break;
+
+	case DW_OP_plus_uconst:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_skip:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " to %ld",
+			    (long) (data + l - start));
+	  break;
+
+	case DW_OP_bra:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %ld",
+			    (long) (data + l - start));
+	  break;
+
+        case DW_OP_piece:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s (bytes)", pulongest (ul));
+	  break;
+
+	case DW_OP_bit_piece:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_uleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " size %s offset %s (bits)",
+			      pulongest (ul), pulongest (offset));
+	  }
+	  break;
+	}
+
+      fprintf_filtered (stream, "\n");
+    }
 
   return data;
 }
@@ -1428,37 +1658,74 @@ locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
 			     struct objfile *objfile, unsigned int addr_size)
 {
   const gdb_byte *end = data + size;
-  int piece_done = 0, first_piece = 1, bad = 0;
+  int first_piece = 1, bad = 0;
 
-  /* A multi-piece description consists of multiple sequences of bytes
-     each followed by DW_OP_piece + length of piece.  */
   while (data < end)
     {
-      if (!piece_done)
-	{
-	  if (first_piece)
-	    first_piece = 0;
-	  else
-	    fprintf_filtered (stream, _(", and "));
+      const gdb_byte *here = data;
+      int disassemble = 1;
+
+      if (first_piece)
+	first_piece = 0;
+      else
+	fprintf_filtered (stream, _(", and "));
 
+      if (!dwarf2_always_disassemble)
+	{
 	  data = locexpr_describe_location_piece (symbol, stream, addr, objfile,
-						  data, size, addr_size);
-	  piece_done = 1;
+						  data, end, addr_size);
+	  /* If we printed anything, or if we have an empty piece,
+	     then don't disassemble.  */
+	  if (data != here
+	      || data[0] == DW_OP_piece
+	      || data[0] == DW_OP_bit_piece)
+	    disassemble = 0;
 	}
-      else if (data[0] == DW_OP_piece)
+      if (disassemble)
+	data = disassemble_dwarf_expression (stream, get_objfile_arch (objfile),
+					     addr_size, data, end,
+					     dwarf2_always_disassemble);
+
+      if (data < end)
 	{
-	  ULONGEST bytes;
+	  int empty = data == here;
 	      
-	  data = read_uleb128 (data + 1, end, &bytes);
+	  if (disassemble)
+	    fprintf_filtered (stream, "   ");
+	  if (data[0] == DW_OP_piece)
+	    {
+	      ULONGEST bytes;
 
-	  fprintf_filtered (stream, _(" [%s-byte piece]"), pulongest (bytes));
+	      data = read_uleb128 (data + 1, end, &bytes);
 
-	  piece_done = 0;
-	}
-      else
-	{
-	  bad = 1;
-	  break;
+	      if (empty)
+		fprintf_filtered (stream, _("an empty %s-byte piece"),
+				  pulongest (bytes));
+	      else
+		fprintf_filtered (stream, _(" [%s-byte piece]"),
+				  pulongest (bytes));
+	    }
+	  else if (data[0] == DW_OP_bit_piece)
+	    {
+	      ULONGEST bits, offset;
+
+	      data = read_uleb128 (data + 1, end, &bits);
+	      data = read_uleb128 (data, end, &offset);
+
+	      if (empty)
+		fprintf_filtered (stream,
+				  _("an empty %s-bit piece"),
+				  pulongest (bits));
+	      else
+		fprintf_filtered (stream,
+				  _(" [%s-bit piece, offset %s bits]"),
+				  pulongest (bits), pulongest (offset));
+	    }
+	  else
+	    {
+	      bad = 1;
+	      break;
+	    }
 	}
     }
 
@@ -1572,7 +1839,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   loc_ptr = dlbaton->data;
   buf_end = dlbaton->data + dlbaton->size;
 
-  fprintf_filtered (stream, _("multi-location ("));
+  fprintf_filtered (stream, _("multi-location:\n"));
 
   /* Iterate through locations until we run out.  */
   while (1)
@@ -1589,7 +1856,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 	{
 	  base_address = dwarf2_read_address (gdbarch,
 					      loc_ptr, buf_end, addr_size);
-	  fprintf_filtered (stream, _("[base address %s]"),
+	  fprintf_filtered (stream, _("  Base address %s"),
 			    paddress (gdbarch, base_address));
 	  loc_ptr += addr_size;
 	  continue;
@@ -1600,11 +1867,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 
       /* An end-of-list entry.  */
       if (low == 0 && high == 0)
-	{
-	  /* Indicate the end of the list, for readability.  */
-	  fprintf_filtered (stream, _(")"));
-	  return;
-	}
+	break;
 
       /* Otherwise, a location expression entry.  */
       low += base_address;
@@ -1613,21 +1876,17 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
       length = extract_unsigned_integer (loc_ptr, 2, byte_order);
       loc_ptr += 2;
 
-      /* Separate the different locations with a semicolon.  */
-      if (first)
-	first = 0;
-      else
-	fprintf_filtered (stream, _("; "));
-
       /* (It would improve readability to print only the minimum
 	 necessary digits of the second number of the range.)  */
-      fprintf_filtered (stream, _("range %s-%s, "),
+      fprintf_filtered (stream, _("  Range %s-%s: "),
 			paddress (gdbarch, low), paddress (gdbarch, high));
 
       /* Now describe this particular location.  */
       locexpr_describe_location_1 (symbol, low, stream, loc_ptr, length,
 				   objfile, addr_size);
 
+      fprintf_filtered (stream, "\n");
+
       loc_ptr += length;
     }
 }
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 129d6c1..8d74fb4 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1002,8 +1002,6 @@ static char *dwarf_attr_name (unsigned int);
 
 static char *dwarf_form_name (unsigned int);
 
-static char *dwarf_stack_op_name (unsigned int);
-
 static char *dwarf_bool_name (unsigned int);
 
 static char *dwarf_type_encoding_name (unsigned int);
@@ -9848,8 +9846,8 @@ dwarf_form_name (unsigned form)
 
 /* Convert a DWARF stack opcode into its string name.  */
 
-static char *
-dwarf_stack_op_name (unsigned op)
+const char *
+dwarf_stack_op_name (unsigned op, int def)
 {
   switch (op)
     {
@@ -10152,32 +10150,24 @@ dwarf_stack_op_name (unsigned op)
       return "DW_OP_call4";
     case DW_OP_call_ref:
       return "DW_OP_call_ref";
-    /* GNU extensions.  */
     case DW_OP_form_tls_address:
       return "DW_OP_form_tls_address";
     case DW_OP_call_frame_cfa:
       return "DW_OP_call_frame_cfa";
     case DW_OP_bit_piece:
       return "DW_OP_bit_piece";
+    /* DWARF 4 extensions.  */
+    case DW_OP_implicit_value:
+      return "DW_OP_implicit_value";
+    case DW_OP_stack_value:
+      return "DW_OP_stack_value";
+    /* GNU extensions.  */
     case DW_OP_GNU_push_tls_address:
       return "DW_OP_GNU_push_tls_address";
     case DW_OP_GNU_uninit:
       return "DW_OP_GNU_uninit";
-    /* HP extensions. */ 
-    case DW_OP_HP_is_value:
-      return "DW_OP_HP_is_value";
-    case DW_OP_HP_fltconst4:
-      return "DW_OP_HP_fltconst4";
-    case DW_OP_HP_fltconst8:
-      return "DW_OP_HP_fltconst8";
-    case DW_OP_HP_mod_range:
-      return "DW_OP_HP_mod_range";
-    case DW_OP_HP_unmod_range:
-      return "DW_OP_HP_unmod_range";
-    case DW_OP_HP_tls:
-      return "DW_OP_HP_tls";
     default:
-      return "OP_<unknown>";
+      return def ? "OP_<unknown>" : NULL;
     }
 }
 
@@ -11018,7 +11008,7 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)
 
 	default:
 	  complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
-		     dwarf_stack_op_name (op));
+		     dwarf_stack_op_name (op, 1));
 	  return (stack[stacki]);
 	}
     }
@@ -12199,6 +12189,17 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
   munmap_section_buffer (&data->eh_frame);
 }
 
+int dwarf2_always_disassemble;
+
+static void
+show_dwarf2_always_disassemble (struct ui_file *file, int from_tty,
+				struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Whether to always disassemble DWARF expressions is %s.\n"),
+		    value);
+}
+
 void _initialize_dwarf2_read (void);
 
 void
@@ -12231,6 +12232,18 @@ caching, which can slow down startup."),
 			    &set_dwarf2_cmdlist,
 			    &show_dwarf2_cmdlist);
 
+  add_setshow_boolean_cmd ("always-disassemble", class_obscure,
+			   &dwarf2_always_disassemble, _("\
+Set whether `info address' always disassembles DWARF expressions."), _("\
+Show whether `info address' always disassembles DWARF expressions."), _("\
+When enabled, DWARF expressions are always printed in an assembly-like\n\
+syntax.  When disabled, expressions will be printed in a more\n\
+conversational style, when possible."),
+			   NULL,
+			   show_dwarf2_always_disassemble,
+			   &set_dwarf2_cmdlist,
+			   &show_dwarf2_cmdlist);
+
   add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
 Set debugging of the dwarf2 DIE reader."), _("\
 Show debugging of the dwarf2 DIE reader."), _("\

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece)
  2010-05-25 19:22         ` RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
@ 2010-05-25 19:27           ` Jan Kratochvil
  2010-05-25 20:25             ` RFC: DWARF expression disassembly Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Jan Kratochvil @ 2010-05-25 19:27 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Stan Shebs, gdb-patches

On Tue, 25 May 2010 21:16:34 +0200, Tom Tromey wrote:
> This is not always possible, though, and in
> those cases it falls back to a disassembly form.  Additionally, it adds
> a new parameter, "maint show dwarf2 always-disassemble", which can be
> set if you prefer to always get disassembly.

I have to ask why have you duplicated
binutils/dwarf.c:decode_location_expression().

Asking primarily because I miss the register names decording in readelf.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-05-25 19:27           ` Jan Kratochvil
@ 2010-05-25 20:25             ` Tom Tromey
  2010-05-25 20:52               ` Jan Kratochvil
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-25 20:25 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Stan Shebs, gdb-patches

>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:

Jan> On Tue, 25 May 2010 21:16:34 +0200, Tom Tromey wrote:
>> This is not always possible, though, and in
>> those cases it falls back to a disassembly form.  Additionally, it adds
>> a new parameter, "maint show dwarf2 always-disassemble", which can be
>> set if you prefer to always get disassembly.

Jan> I have to ask why have you duplicated
Jan> binutils/dwarf.c:decode_location_expression().

I did think about this, and I have a few reasons.

First, it really isn't that much code.  (The code in gdb is actually
much shorter, since we already have a table of opcode names.)

Second, we want some specialized behavior: different piece handling,
some output formatting details, and the fact that we want to only handle
operations that gdb itself handles.  (This latter may be a mistake;
maybe we want to decode DW_OP_call* even though we can't evaluate them.)

Jan> Asking primarily because I miss the register names decording in readelf.

I don't see that in the code or the output.  I see raw numbers like:

(DW_OP_reg3; DW_OP_piece: 4; DW_OP_fbreg: 0; DW_OP_deref; DW_OP_plus_uconst: 6; DW_OP_stack_value; DW_OP_piece: 4)

I can add decoding if you want.  Maybe some other details need fixing
too; if you agree with this general approach, feel free to list all the
issues you run across and I will fix them up.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-05-25 20:25             ` RFC: DWARF expression disassembly Tom Tromey
@ 2010-05-25 20:52               ` Jan Kratochvil
  2010-05-25 22:03                 ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Jan Kratochvil @ 2010-05-25 20:52 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Stan Shebs, gdb-patches

On Tue, 25 May 2010 22:17:08 +0200, Tom Tromey wrote:
> Jan> Asking primarily because I miss the register names decording in readelf.

I meant in the current output of readelf I miss it does not decode the
register names.


> I don't see that in the code or the output.  I see raw numbers like:
> 
> (DW_OP_reg3; DW_OP_piece: 4; DW_OP_fbreg: 0; DW_OP_deref; DW_OP_plus_uconst: 6; DW_OP_stack_value; DW_OP_piece: 4)

Yes, I agree.


> I can add decoding if you want.

Apparently I cannot express personal experience with the GDB output but
I believe I will also miss it there.  It is simpler to do in GDB.


> Maybe some other details need fixing
> too; if you agree with this general approach, feel free to list all the
> issues you run across and I will fix them up.

I cannot align myself with this separate implementation as I miss more the
register names in readelf than the address decoding in GDB.  I understand I am
free to submit a binutils patch for it.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-05-25 20:52               ` Jan Kratochvil
@ 2010-05-25 22:03                 ` Tom Tromey
  2010-05-26 17:21                   ` Eli Zaretskii
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-25 22:03 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Stan Shebs, gdb-patches

>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:

Jan> On Tue, 25 May 2010 22:17:08 +0200, Tom Tromey wrote:
Jan> Asking primarily because I miss the register names decording in readelf.

Jan> I meant in the current output of readelf I miss it does not decode the
Jan> register names.

Oh, sorry.  I took the completely opposite meaning from what you said.

Here is an updated version of the patch that adds register name decoding
and also handles DW_OP_call*, even though gdb cannot evaluate those.

Tom

2010-05-25  Tom Tromey  <tromey@redhat.com>

	* dwarf2loc.h (dwarf2_per_cu_data): Declare.
	* dwarf2read.c (dwarf_stack_op_name): No longer static.  Return
	type is const.  Add 'def' argument.  Add missing operators, remove
	unhandled ones.
	(decode_locdesc): Update.
	(dwarf2_always_disassemble): New global.
	(show_dwarf2_always_disassemble): New function.
	(_initialize_dwarf2_read): Add always-disassemble.
	(dwarf2_per_cu_offset_size): New function.
	* dwarf2loc.c (dwarf2_always_disassemble): Declare.
	(piece_end_p): New function.
	(locexpr_describe_location_piece): Replace 'size' argument with
	'end'.  Use piece_end_p.  Rewrite recognition of TLS.  Recognize
	some constants.  Remove errors.
	(disassemble_dwarf_expression): New function.
	(locexpr_describe_location_1): Use disassemble_dwarf_expression.
	Add 'offset_size' argument.
	(loclist_describe_location): Change output formatting.
	* dwarf2expr.h (dwarf_stack_op_name): Declare.

b/gdb/doc/ChangeLog:
2010-05-24  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
	always-disassemble.

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e929481..741f423 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29862,6 +29862,20 @@ that symbol is described.  The type chain produced by this command is
 a recursive definition of the data type as stored in @value{GDBN}'s
 data structures, including its flags and contained types.
 
+@kindex maint set dwarf2 always-disassemble
+@kindex maint show dwarf2 always-disassemble
+@item maint set dwarf2 always-disassemble
+@item maint show dwarf2 always-disassemble
+Control the behavior of @code{info address} when using DWARF debugging
+information.
+
+The default is @code{off}, which means that @value{GDBN} should try to
+describe a variable's location in an easily readable format.  When
+@code{on}, @value{GDBN} will instead display the DWARF location
+expression in an assembly-like format.  Note that some locations are
+too complex for @value{GDBN} to describe simply; in this case you will
+always see the disassembly form.
+
 @kindex maint set dwarf2 max-cache-age
 @kindex maint show dwarf2 max-cache-age
 @item maint set dwarf2 max-cache-age
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index a0f4554..8ebbf87 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -208,4 +208,6 @@ const gdb_byte *read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
 CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
 			       const gdb_byte *buf_end, int addr_size);
 
+const char *dwarf_stack_op_name (unsigned int, int);
+
 #endif /* dwarf2expr.h */
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 481501b..228d076 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -42,6 +42,8 @@
 #include "gdb_string.h"
 #include "gdb_assert.h"
 
+extern int dwarf2_always_disassemble;
+
 static void
 dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
 			 const gdb_byte **start, size_t *length);
@@ -1282,13 +1284,24 @@ locexpr_read_needs_frame (struct symbol *symbol)
 				      dlbaton->per_cu);
 }
 
-/* Describe a single piece of a location, returning an updated
-   position in the bytecode sequence.  */
+/* Return true if DATA points to the end of a piece.  END is one past
+   the last byte in the expression.  */
+
+static int
+piece_end_p (const gdb_byte *data, const gdb_byte *end)
+{
+  return data == end || data[0] == DW_OP_piece || data[0] == DW_OP_bit_piece;
+}
+
+/* Nicely describe a single piece of a location, returning an updated
+   position in the bytecode sequence.  This function cannot recognize
+   all locations; if a location is not recognized, it simply returns
+   DATA.  */
 
 static const gdb_byte *
 locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 				 CORE_ADDR addr, struct objfile *objfile,
-				 const gdb_byte *data, int size,
+				 const gdb_byte *data, const gdb_byte *end,
 				 unsigned int addr_size)
 {
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
@@ -1305,7 +1318,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
     {
       ULONGEST reg;
 
-      data = read_uleb128 (data + 1, data + size, &reg);
+      data = read_uleb128 (data + 1, end, &reg);
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
       fprintf_filtered (stream, _("a variable in $%s"),
 			gdbarch_register_name (gdbarch, regno));
@@ -1316,10 +1329,15 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
       struct symbol *framefunc;
       int frame_reg = 0;
       LONGEST frame_offset;
-      const gdb_byte *base_data;
+      const gdb_byte *base_data, *new_data;
       size_t base_size;
       LONGEST base_offset = 0;
 
+      new_data = read_sleb128 (data + 1, end, &frame_offset);
+      if (!piece_end_p (new_data, end))
+	return data;
+      data = new_data;
+
       b = block_for_pc (addr);
 
       if (!b)
@@ -1363,19 +1381,18 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
 
-      data = read_sleb128 (data + 1, data + size, &frame_offset);
-
       fprintf_filtered (stream, _("a variable at frame base reg $%s offset %s+%s"),
 			gdbarch_register_name (gdbarch, regno),
 			plongest (base_offset), plongest (frame_offset));
     }
-  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
+  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31
+	   && piece_end_p (data, end))
     {
       LONGEST offset;
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_breg0);
 
-      data = read_sleb128 (data + 1, data + size, &offset);
+      data = read_sleb128 (data + 1, end, &offset);
 
       fprintf_filtered (stream,
 			_("a variable at offset %s from base reg $%s"),
@@ -1395,13 +1412,14 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
      The operand represents the offset at which the variable is within
      the thread local storage.  */
 
-  else if (size > 1
-	   && data[size - 1] == DW_OP_GNU_push_tls_address
-	   && data[0] == DW_OP_addr)
+  else if (data + 1 + addr_size < end
+	   && data[0] == DW_OP_addr
+	   && data[1 + addr_size] == DW_OP_GNU_push_tls_address
+	   && piece_end_p (data + 2 + addr_size, end))
     {
       CORE_ADDR offset = dwarf2_read_address (gdbarch,
 					      data + 1,
-					      data + size - 1,
+					      end,
 					      addr_size);
 
       fprintf_filtered (stream, 
@@ -1411,9 +1429,275 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       data += 1 + addr_size + 1;
     }
-  else
-    fprintf_filtered (stream,
-		      _("a variable with complex or multiple locations (DWARF2)"));
+  else if (data[0] >= DW_OP_lit0
+	   && data[0] <= DW_OP_lit31
+	   && data + 1 < end
+	   && data[1] == DW_OP_stack_value)
+    {
+      fprintf_filtered (stream, _("the constant %d"), data[0] - DW_OP_lit0);
+      data += 2;
+    }
+
+  return data;
+}
+
+/* Disassemble an expression, stopping at the end of a piece or at the
+   end of the expression.  Returns a pointer to the next unread byte
+   in the input expression.  If ALL is nonzero, then this function
+   will keep going until it reaches the end of the expression.  */
+
+static const gdb_byte *
+disassemble_dwarf_expression (struct ui_file *stream,
+			      struct gdbarch *arch, unsigned int addr_size,
+			      int offset_size,
+			      const gdb_byte *data, const gdb_byte *end,
+			      int all)
+{
+  const gdb_byte *start = data;
+
+  fprintf_filtered (stream, _("a complex DWARF expression:\n"));
+
+  while (data < end
+	 && (all
+	     || (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece)))
+    {
+      enum dwarf_location_atom op = *data++;
+      CORE_ADDR addr;
+      ULONGEST ul;
+      LONGEST l;
+      const char *name;
+
+      name = dwarf_stack_op_name (op, 0);
+
+      if (!name)
+	error (_("Unrecognized DWARF opcode 0x%02x at %ld"),
+	       op, (long) (data - start));
+      fprintf_filtered (stream, "  % 4ld: %s", (long) (data - start), name);
+
+      switch (op)
+	{
+	case DW_OP_addr:
+	  addr = dwarf2_read_address (arch, data, end, addr_size);
+	  data += addr_size;
+	  fprintf_filtered (stream, " %s", paddress (arch, addr));
+	  break;
+
+	case DW_OP_const1u:
+	  ul = extract_unsigned_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const1s:
+	  l = extract_signed_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const2u:
+	  ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const2s:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const4u:
+	  ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const4s:
+	  l = extract_signed_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const8u:
+	  ul = extract_unsigned_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const8s:
+	  l = extract_signed_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_constu:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_consts:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+
+	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:
+	  fprintf_filtered (stream, " [$%s]",
+			    gdbarch_register_name (arch, op - DW_OP_reg0));
+	  break;
+
+	case DW_OP_regx:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+			    gdbarch_register_name (arch, (int) ul));
+	  break;
+
+	case DW_OP_implicit_value:
+	  data = read_uleb128 (data, end, &ul);
+	  data += ul;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	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:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+			    gdbarch_register_name (arch, op - DW_OP_breg0));
+	  break;
+
+	case DW_OP_bregx:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_sleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " register %s [$%s] offset %s",
+			      pulongest (ul),
+			      gdbarch_register_name (arch, (int) ul),
+			      pulongest (offset));
+	  }
+	  break;
+
+	case DW_OP_fbreg:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_xderef_size:
+	case DW_OP_deref_size:
+	case DW_OP_pick:
+	  fprintf_filtered (stream, " %d", *data);
+	  ++data;
+	  break;
+
+	case DW_OP_plus_uconst:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_skip:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " to %ld",
+			    (long) (data + l - start));
+	  break;
+
+	case DW_OP_bra:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %ld",
+			    (long) (data + l - start));
+	  break;
+
+	case DW_OP_call2:
+	  ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, 2));
+	  break;
+
+	case DW_OP_call4:
+	  ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, 4));
+	  break;
+
+	case DW_OP_call_ref:
+	  ul = extract_unsigned_integer (data, offset_size,
+					 gdbarch_byte_order (arch));
+	  data += offset_size;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
+	  break;
+
+        case DW_OP_piece:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s (bytes)", pulongest (ul));
+	  break;
+
+	case DW_OP_bit_piece:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_uleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " size %s offset %s (bits)",
+			      pulongest (ul), pulongest (offset));
+	  }
+	  break;
+	}
+
+      fprintf_filtered (stream, "\n");
+    }
 
   return data;
 }
@@ -1425,40 +1709,78 @@ static void
 locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
 			     struct ui_file *stream,
 			     const gdb_byte *data, int size,
-			     struct objfile *objfile, unsigned int addr_size)
+			     struct objfile *objfile, unsigned int addr_size,
+			     int offset_size)
 {
   const gdb_byte *end = data + size;
-  int piece_done = 0, first_piece = 1, bad = 0;
+  int first_piece = 1, bad = 0;
 
-  /* A multi-piece description consists of multiple sequences of bytes
-     each followed by DW_OP_piece + length of piece.  */
   while (data < end)
     {
-      if (!piece_done)
-	{
-	  if (first_piece)
-	    first_piece = 0;
-	  else
-	    fprintf_filtered (stream, _(", and "));
+      const gdb_byte *here = data;
+      int disassemble = 1;
+
+      if (first_piece)
+	first_piece = 0;
+      else
+	fprintf_filtered (stream, _(", and "));
 
+      if (!dwarf2_always_disassemble)
+	{
 	  data = locexpr_describe_location_piece (symbol, stream, addr, objfile,
-						  data, size, addr_size);
-	  piece_done = 1;
+						  data, end, addr_size);
+	  /* If we printed anything, or if we have an empty piece,
+	     then don't disassemble.  */
+	  if (data != here
+	      || data[0] == DW_OP_piece
+	      || data[0] == DW_OP_bit_piece)
+	    disassemble = 0;
 	}
-      else if (data[0] == DW_OP_piece)
+      if (disassemble)
+	data = disassemble_dwarf_expression (stream, get_objfile_arch (objfile),
+					     addr_size, offset_size, data, end,
+					     dwarf2_always_disassemble);
+
+      if (data < end)
 	{
-	  ULONGEST bytes;
+	  int empty = data == here;
 	      
-	  data = read_uleb128 (data + 1, end, &bytes);
+	  if (disassemble)
+	    fprintf_filtered (stream, "   ");
+	  if (data[0] == DW_OP_piece)
+	    {
+	      ULONGEST bytes;
 
-	  fprintf_filtered (stream, _(" [%s-byte piece]"), pulongest (bytes));
+	      data = read_uleb128 (data + 1, end, &bytes);
 
-	  piece_done = 0;
-	}
-      else
-	{
-	  bad = 1;
-	  break;
+	      if (empty)
+		fprintf_filtered (stream, _("an empty %s-byte piece"),
+				  pulongest (bytes));
+	      else
+		fprintf_filtered (stream, _(" [%s-byte piece]"),
+				  pulongest (bytes));
+	    }
+	  else if (data[0] == DW_OP_bit_piece)
+	    {
+	      ULONGEST bits, offset;
+
+	      data = read_uleb128 (data + 1, end, &bits);
+	      data = read_uleb128 (data, end, &offset);
+
+	      if (empty)
+		fprintf_filtered (stream,
+				  _("an empty %s-bit piece"),
+				  pulongest (bits));
+	      else
+		fprintf_filtered (stream,
+				  _(" [%s-bit piece, offset %s bits]"),
+				  pulongest (bits), pulongest (offset));
+	    }
+	  else
+	    {
+	      bad = 1;
+	      break;
+	    }
 	}
     }
 
@@ -1477,9 +1799,10 @@ locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
   struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu);
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+  int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
 
   locexpr_describe_location_1 (symbol, addr, stream, dlbaton->data, dlbaton->size,
-			       objfile, addr_size);
+			       objfile, addr_size, offset_size);
 }
 
 /* Describe the location of SYMBOL as an agent value in VALUE, generating
@@ -1563,6 +1886,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+  int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
   CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
   /* Adjust base_address for relocatable objects.  */
   CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets,
@@ -1572,7 +1896,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   loc_ptr = dlbaton->data;
   buf_end = dlbaton->data + dlbaton->size;
 
-  fprintf_filtered (stream, _("multi-location ("));
+  fprintf_filtered (stream, _("multi-location:\n"));
 
   /* Iterate through locations until we run out.  */
   while (1)
@@ -1589,7 +1913,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 	{
 	  base_address = dwarf2_read_address (gdbarch,
 					      loc_ptr, buf_end, addr_size);
-	  fprintf_filtered (stream, _("[base address %s]"),
+	  fprintf_filtered (stream, _("  Base address %s"),
 			    paddress (gdbarch, base_address));
 	  loc_ptr += addr_size;
 	  continue;
@@ -1600,11 +1924,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 
       /* An end-of-list entry.  */
       if (low == 0 && high == 0)
-	{
-	  /* Indicate the end of the list, for readability.  */
-	  fprintf_filtered (stream, _(")"));
-	  return;
-	}
+	break;
 
       /* Otherwise, a location expression entry.  */
       low += base_address;
@@ -1613,20 +1933,16 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
       length = extract_unsigned_integer (loc_ptr, 2, byte_order);
       loc_ptr += 2;
 
-      /* Separate the different locations with a semicolon.  */
-      if (first)
-	first = 0;
-      else
-	fprintf_filtered (stream, _("; "));
-
       /* (It would improve readability to print only the minimum
 	 necessary digits of the second number of the range.)  */
-      fprintf_filtered (stream, _("range %s-%s, "),
+      fprintf_filtered (stream, _("  Range %s-%s: "),
 			paddress (gdbarch, low), paddress (gdbarch, high));
 
       /* Now describe this particular location.  */
       locexpr_describe_location_1 (symbol, low, stream, loc_ptr, length,
-				   objfile, addr_size);
+				   objfile, addr_size, offset_size);
+
+      fprintf_filtered (stream, "\n");
 
       loc_ptr += length;
     }
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index fa0bd11..fd5f49d 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -34,6 +34,9 @@ struct objfile *dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *cu);
 /* Return the address size given in the compilation unit header for CU.  */
 CORE_ADDR dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu);
 
+/* Return the offset size given in the compilation unit header for CU.  */
+int dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *cu);
+
 /* The symbol location baton types used by the DWARF-2 reader (i.e.
    SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
    dwarf2_locexpr_baton" is for a symbol with a single location
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 129d6c1..7d7eb6c 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1002,8 +1002,6 @@ static char *dwarf_attr_name (unsigned int);
 
 static char *dwarf_form_name (unsigned int);
 
-static char *dwarf_stack_op_name (unsigned int);
-
 static char *dwarf_bool_name (unsigned int);
 
 static char *dwarf_type_encoding_name (unsigned int);
@@ -9848,8 +9846,8 @@ dwarf_form_name (unsigned form)
 
 /* Convert a DWARF stack opcode into its string name.  */
 
-static char *
-dwarf_stack_op_name (unsigned op)
+const char *
+dwarf_stack_op_name (unsigned op, int def)
 {
   switch (op)
     {
@@ -10152,32 +10150,24 @@ dwarf_stack_op_name (unsigned op)
       return "DW_OP_call4";
     case DW_OP_call_ref:
       return "DW_OP_call_ref";
-    /* GNU extensions.  */
     case DW_OP_form_tls_address:
       return "DW_OP_form_tls_address";
     case DW_OP_call_frame_cfa:
       return "DW_OP_call_frame_cfa";
     case DW_OP_bit_piece:
       return "DW_OP_bit_piece";
+    /* DWARF 4 extensions.  */
+    case DW_OP_implicit_value:
+      return "DW_OP_implicit_value";
+    case DW_OP_stack_value:
+      return "DW_OP_stack_value";
+    /* GNU extensions.  */
     case DW_OP_GNU_push_tls_address:
       return "DW_OP_GNU_push_tls_address";
     case DW_OP_GNU_uninit:
       return "DW_OP_GNU_uninit";
-    /* HP extensions. */ 
-    case DW_OP_HP_is_value:
-      return "DW_OP_HP_is_value";
-    case DW_OP_HP_fltconst4:
-      return "DW_OP_HP_fltconst4";
-    case DW_OP_HP_fltconst8:
-      return "DW_OP_HP_fltconst8";
-    case DW_OP_HP_mod_range:
-      return "DW_OP_HP_mod_range";
-    case DW_OP_HP_unmod_range:
-      return "DW_OP_HP_unmod_range";
-    case DW_OP_HP_tls:
-      return "DW_OP_HP_tls";
     default:
-      return "OP_<unknown>";
+      return def ? "OP_<unknown>" : NULL;
     }
 }
 
@@ -11018,7 +11008,7 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)
 
 	default:
 	  complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
-		     dwarf_stack_op_name (op));
+		     dwarf_stack_op_name (op, 1));
 	  return (stack[stacki]);
 	}
     }
@@ -11745,6 +11735,28 @@ dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *per_cu)
     }
 }
 
+/* Return the offset size given in the compilation unit header for CU.  */
+
+int
+dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu)
+{
+  if (per_cu->cu)
+    return per_cu->cu->header.offset_size;
+  else
+    {
+      /* If the CU is not currently read in, we re-read its header.  */
+      struct objfile *objfile = per_cu->psymtab->objfile;
+      struct dwarf2_per_objfile *per_objfile
+	= objfile_data (objfile, dwarf2_objfile_data_key);
+      gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset;
+      struct comp_unit_head cu_header;
+
+      memset (&cu_header, 0, sizeof cu_header);
+      read_comp_unit_head (&cu_header, info_ptr, objfile->obfd);
+      return cu_header.offset_size;
+    }
+}
+
 /* Locate the .debug_info compilation unit from CU's objfile which contains
    the DIE at OFFSET.  Raises an error on failure.  */
 
@@ -12199,6 +12211,17 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
   munmap_section_buffer (&data->eh_frame);
 }
 
+int dwarf2_always_disassemble;
+
+static void
+show_dwarf2_always_disassemble (struct ui_file *file, int from_tty,
+				struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Whether to always disassemble DWARF expressions is %s.\n"),
+		    value);
+}
+
 void _initialize_dwarf2_read (void);
 
 void
@@ -12231,6 +12254,18 @@ caching, which can slow down startup."),
 			    &set_dwarf2_cmdlist,
 			    &show_dwarf2_cmdlist);
 
+  add_setshow_boolean_cmd ("always-disassemble", class_obscure,
+			   &dwarf2_always_disassemble, _("\
+Set whether `info address' always disassembles DWARF expressions."), _("\
+Show whether `info address' always disassembles DWARF expressions."), _("\
+When enabled, DWARF expressions are always printed in an assembly-like\n\
+syntax.  When disabled, expressions will be printed in a more\n\
+conversational style, when possible."),
+			   NULL,
+			   show_dwarf2_always_disassemble,
+			   &set_dwarf2_cmdlist,
+			   &show_dwarf2_cmdlist);
+
   add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
 Set debugging of the dwarf2 DIE reader."), _("\
 Show debugging of the dwarf2 DIE reader."), _("\

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: performance talk  [Re: RFC: implement DW_OP_bit_piece]
  2010-05-25 18:19     ` performance talk [Re: RFC: implement DW_OP_bit_piece] Jan Kratochvil
@ 2010-05-25 22:23       ` Tom Tromey
  0 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2010-05-25 22:23 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:

Tom> If you know of specific bad cases, I'm very interested in that.
Tom> I think we understand the symbol reading problem pretty well now, but
Tom> other stuff could at least use bug reports.

Jan> Checked now we were talking about `attach' being fast enough (~2s
Jan> on OOo.org) but I was testing it with
Jan> `archer-tromey-delayed-symfile2'.  Then `bt full' is still slow -
Jan> tens of secs.

Yeah, this is known.  See below.

At this point I'm much more interested in performance problems elsewhere
in gdb.  This particular one is, while not "solved", at least very well
explored.  A solution is on the horizon...

Here's a dump of the status:

This particular branch uses the aranges section to lazily read DWARF.
This makes "attach" very fast, because we don't hit the disk very much.

However, "bt" and "bt full" are still quite slow.  If you want the bt
output for OO.o you can actually see it pause for a noticeable amount of
time at one particular point.

What is happening here is that at this point we need some particular
piece of debuginfo (I think a type, but I am not sure I looked into the
details).  Since we don't have any sort of by-name index, we have to
read psymtabs and then search.

The fix for this is to add a by-name map.  You might think we could use
debug_pubnames and debug_pubtypes, but those are broken beyond repair
for various reasons: historical gcc bugs make them unreliable, they
don't mention everything gdb needs, they aren't canonicalized, and
what's worse, it turns out that actually reading them in is too slow.

This is where the mmap()able debug index comes in.  This approach yields
good attach times *and* good backtrace times, at the cost of having to
build a separate index per objfile.  If you want to try this, it is all
on archer-tromey-optional-psymtab.  I can tell you how to make the index
files if you do this.

What makes this fast is that the by-name index means we can just read
the CUs we care about.  Reading any particular CU is fast enough that we
don't need anything smarter.

I am planning to propose this as an F14 feature: make index files for
all the debuginfo, and at the same time drop .debug_pub* (to save some
space).  I figured I would delay submission to FSF gdb until we get this
underway; my view is that this is more of a "distro" feature (creating
the index files is just as slow as simply starting gdb) and there is no
point in pushing it if the distro isn't interested.


Another idea I implemented is to read psymtabs in the background.  This
works pretty well: gdb starts some worker threads and reads in psymtabs
starting with the largest one (the smaller the debuginfo, the less
likely you are to notice the pause).

I haven't submitted this for two reasons.

First, it is not quite complete.  It has a questionable BFD hack, and I
haven't yet made the complaint() system threadsafe.

Second, I assume it will be contentious and/or too ugly.  It uses
__thread in various spots and it changes cp-name-parser.y to depend on
bison (by making it a pure parser), not to mention that threads are
widely hated.

I'd be happy to revisit this if people are interested.  Note that it is
not as good as the index approach.


These two approaches are actually complementary.  We could put them both
in.

Finally, one or both of these branches has a little optimization so that
if you "gdb -readnow", we don't create psymtabs at all.  This could go
in now; I just haven't bothered since I think -readnow is only ever
actually used to locate psymtab expansion bugs.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-05-25 22:03                 ` Tom Tromey
@ 2010-05-26 17:21                   ` Eli Zaretskii
  2010-06-01 18:36                     ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Eli Zaretskii @ 2010-05-26 17:21 UTC (permalink / raw)
  To: Tom Tromey; +Cc: jan.kratochvil, stan, gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: Stan Shebs <stan@codesourcery.com>, gdb-patches@sourceware.org
> Date: Tue, 25 May 2010 15:43:04 -0600
> 
> b/gdb/doc/ChangeLog:
> 2010-05-24  Tom Tromey  <tromey@redhat.com>
> 
> 	* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
> 	always-disassemble.

Thanks.  This part is okay, but I have a suggestion: it might help to
have an example of the assembly-like format when this option is ON,
and perhaps also explain how to interpret it, or point to some
document that could be used for that.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: implement DW_OP_bit_piece
  2010-05-20  7:12         ` Tom Tromey
@ 2010-05-26 22:41           ` Tom Tromey
  2010-06-03 20:12             ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-05-26 22:41 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

>>>>> "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)			  \
 {									  \

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-05-26 17:21                   ` Eli Zaretskii
@ 2010-06-01 18:36                     ` Tom Tromey
  2010-06-01 18:40                       ` Eli Zaretskii
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-06-01 18:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: jan.kratochvil, stan, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

Eli> Thanks.  This part is okay, but I have a suggestion: it might help to
Eli> have an example of the assembly-like format when this option is ON,
Eli> and perhaps also explain how to interpret it, or point to some
Eli> document that could be used for that.

Here is an updated patch that includes this.
Let me know what you think.

Tom

2010-05-25  Tom Tromey  <tromey@redhat.com>

	* dwarf2loc.h (dwarf2_per_cu_data): Declare.
	* dwarf2read.c (dwarf_stack_op_name): No longer static.  Return
	type is const.  Add 'def' argument.  Add missing operators, remove
	unhandled ones.
	(decode_locdesc): Update.
	(dwarf2_always_disassemble): New global.
	(show_dwarf2_always_disassemble): New function.
	(_initialize_dwarf2_read): Add always-disassemble.
	(dwarf2_per_cu_offset_size): New function.
	* dwarf2loc.c (dwarf2_always_disassemble): Declare.
	(piece_end_p): New function.
	(locexpr_describe_location_piece): Replace 'size' argument with
	'end'.  Use piece_end_p.  Rewrite recognition of TLS.  Recognize
	some constants.  Remove errors.
	(disassemble_dwarf_expression): New function.
	(locexpr_describe_location_1): Use disassemble_dwarf_expression.
	Add 'offset_size' argument.
	(loclist_describe_location): Change output formatting.
	* dwarf2expr.h (dwarf_stack_op_name): Declare.

2010-05-24  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Maintenance Commands): Document maint set dwarf2
	always-disassemble.

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e929481..47ff45b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29862,6 +29862,31 @@ that symbol is described.  The type chain produced by this command is
 a recursive definition of the data type as stored in @value{GDBN}'s
 data structures, including its flags and contained types.
 
+@kindex maint set dwarf2 always-disassemble
+@kindex maint show dwarf2 always-disassemble
+@item maint set dwarf2 always-disassemble
+@item maint show dwarf2 always-disassemble
+Control the behavior of @code{info address} when using DWARF debugging
+information.
+
+The default is @code{off}, which means that @value{GDBN} should try to
+describe a variable's location in an easily readable format.  When
+@code{on}, @value{GDBN} will instead display the DWARF location
+expression in an assembly-like format.  Note that some locations are
+too complex for @value{GDBN} to describe simply; in this case you will
+always see the disassembly form.
+
+Here is an example of the resulting disassembly:
+
+@smallexample
+(gdb) info addr argc
+Symbol "argc" is a complex DWARF expression:
+     1: DW_OP_fbreg 0
+@end smallexample
+
+For more information on these expressions, see
+@uref{http://www.dwarfstd.org/, the DWARF standard}.
+
 @kindex maint set dwarf2 max-cache-age
 @kindex maint show dwarf2 max-cache-age
 @item maint set dwarf2 max-cache-age
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index a0f4554..8ebbf87 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -208,4 +208,6 @@ const gdb_byte *read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
 CORE_ADDR dwarf2_read_address (struct gdbarch *gdbarch, const gdb_byte *buf,
 			       const gdb_byte *buf_end, int addr_size);
 
+const char *dwarf_stack_op_name (unsigned int, int);
+
 #endif /* dwarf2expr.h */
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 481501b..228d076 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -42,6 +42,8 @@
 #include "gdb_string.h"
 #include "gdb_assert.h"
 
+extern int dwarf2_always_disassemble;
+
 static void
 dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
 			 const gdb_byte **start, size_t *length);
@@ -1282,13 +1284,24 @@ locexpr_read_needs_frame (struct symbol *symbol)
 				      dlbaton->per_cu);
 }
 
-/* Describe a single piece of a location, returning an updated
-   position in the bytecode sequence.  */
+/* Return true if DATA points to the end of a piece.  END is one past
+   the last byte in the expression.  */
+
+static int
+piece_end_p (const gdb_byte *data, const gdb_byte *end)
+{
+  return data == end || data[0] == DW_OP_piece || data[0] == DW_OP_bit_piece;
+}
+
+/* Nicely describe a single piece of a location, returning an updated
+   position in the bytecode sequence.  This function cannot recognize
+   all locations; if a location is not recognized, it simply returns
+   DATA.  */
 
 static const gdb_byte *
 locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 				 CORE_ADDR addr, struct objfile *objfile,
-				 const gdb_byte *data, int size,
+				 const gdb_byte *data, const gdb_byte *end,
 				 unsigned int addr_size)
 {
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
@@ -1305,7 +1318,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
     {
       ULONGEST reg;
 
-      data = read_uleb128 (data + 1, data + size, &reg);
+      data = read_uleb128 (data + 1, end, &reg);
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
       fprintf_filtered (stream, _("a variable in $%s"),
 			gdbarch_register_name (gdbarch, regno));
@@ -1316,10 +1329,15 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
       struct symbol *framefunc;
       int frame_reg = 0;
       LONGEST frame_offset;
-      const gdb_byte *base_data;
+      const gdb_byte *base_data, *new_data;
       size_t base_size;
       LONGEST base_offset = 0;
 
+      new_data = read_sleb128 (data + 1, end, &frame_offset);
+      if (!piece_end_p (new_data, end))
+	return data;
+      data = new_data;
+
       b = block_for_pc (addr);
 
       if (!b)
@@ -1363,19 +1381,18 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, frame_reg);
 
-      data = read_sleb128 (data + 1, data + size, &frame_offset);
-
       fprintf_filtered (stream, _("a variable at frame base reg $%s offset %s+%s"),
 			gdbarch_register_name (gdbarch, regno),
 			plongest (base_offset), plongest (frame_offset));
     }
-  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31)
+  else if (data[0] >= DW_OP_breg0 && data[0] <= DW_OP_breg31
+	   && piece_end_p (data, end))
     {
       LONGEST offset;
 
       regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, data[0] - DW_OP_breg0);
 
-      data = read_sleb128 (data + 1, data + size, &offset);
+      data = read_sleb128 (data + 1, end, &offset);
 
       fprintf_filtered (stream,
 			_("a variable at offset %s from base reg $%s"),
@@ -1395,13 +1412,14 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
      The operand represents the offset at which the variable is within
      the thread local storage.  */
 
-  else if (size > 1
-	   && data[size - 1] == DW_OP_GNU_push_tls_address
-	   && data[0] == DW_OP_addr)
+  else if (data + 1 + addr_size < end
+	   && data[0] == DW_OP_addr
+	   && data[1 + addr_size] == DW_OP_GNU_push_tls_address
+	   && piece_end_p (data + 2 + addr_size, end))
     {
       CORE_ADDR offset = dwarf2_read_address (gdbarch,
 					      data + 1,
-					      data + size - 1,
+					      end,
 					      addr_size);
 
       fprintf_filtered (stream, 
@@ -1411,9 +1429,275 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 
       data += 1 + addr_size + 1;
     }
-  else
-    fprintf_filtered (stream,
-		      _("a variable with complex or multiple locations (DWARF2)"));
+  else if (data[0] >= DW_OP_lit0
+	   && data[0] <= DW_OP_lit31
+	   && data + 1 < end
+	   && data[1] == DW_OP_stack_value)
+    {
+      fprintf_filtered (stream, _("the constant %d"), data[0] - DW_OP_lit0);
+      data += 2;
+    }
+
+  return data;
+}
+
+/* Disassemble an expression, stopping at the end of a piece or at the
+   end of the expression.  Returns a pointer to the next unread byte
+   in the input expression.  If ALL is nonzero, then this function
+   will keep going until it reaches the end of the expression.  */
+
+static const gdb_byte *
+disassemble_dwarf_expression (struct ui_file *stream,
+			      struct gdbarch *arch, unsigned int addr_size,
+			      int offset_size,
+			      const gdb_byte *data, const gdb_byte *end,
+			      int all)
+{
+  const gdb_byte *start = data;
+
+  fprintf_filtered (stream, _("a complex DWARF expression:\n"));
+
+  while (data < end
+	 && (all
+	     || (data[0] != DW_OP_piece && data[0] != DW_OP_bit_piece)))
+    {
+      enum dwarf_location_atom op = *data++;
+      CORE_ADDR addr;
+      ULONGEST ul;
+      LONGEST l;
+      const char *name;
+
+      name = dwarf_stack_op_name (op, 0);
+
+      if (!name)
+	error (_("Unrecognized DWARF opcode 0x%02x at %ld"),
+	       op, (long) (data - start));
+      fprintf_filtered (stream, "  % 4ld: %s", (long) (data - start), name);
+
+      switch (op)
+	{
+	case DW_OP_addr:
+	  addr = dwarf2_read_address (arch, data, end, addr_size);
+	  data += addr_size;
+	  fprintf_filtered (stream, " %s", paddress (arch, addr));
+	  break;
+
+	case DW_OP_const1u:
+	  ul = extract_unsigned_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const1s:
+	  l = extract_signed_integer (data, 1, gdbarch_byte_order (arch));
+	  data += 1;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const2u:
+	  ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const2s:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const4u:
+	  ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const4s:
+	  l = extract_signed_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_const8u:
+	  ul = extract_unsigned_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_const8s:
+	  l = extract_signed_integer (data, 8, gdbarch_byte_order (arch));
+	  data += 8;
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+	case DW_OP_constu:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+	case DW_OP_consts:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", plongest (l));
+	  break;
+
+	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:
+	  fprintf_filtered (stream, " [$%s]",
+			    gdbarch_register_name (arch, op - DW_OP_reg0));
+	  break;
+
+	case DW_OP_regx:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+			    gdbarch_register_name (arch, (int) ul));
+	  break;
+
+	case DW_OP_implicit_value:
+	  data = read_uleb128 (data, end, &ul);
+	  data += ul;
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	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:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s [$%s]", pulongest (ul),
+			    gdbarch_register_name (arch, op - DW_OP_breg0));
+	  break;
+
+	case DW_OP_bregx:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_sleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " register %s [$%s] offset %s",
+			      pulongest (ul),
+			      gdbarch_register_name (arch, (int) ul),
+			      pulongest (offset));
+	  }
+	  break;
+
+	case DW_OP_fbreg:
+	  data = read_sleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_xderef_size:
+	case DW_OP_deref_size:
+	case DW_OP_pick:
+	  fprintf_filtered (stream, " %d", *data);
+	  ++data;
+	  break;
+
+	case DW_OP_plus_uconst:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
+
+	case DW_OP_skip:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " to %ld",
+			    (long) (data + l - start));
+	  break;
+
+	case DW_OP_bra:
+	  l = extract_signed_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " %ld",
+			    (long) (data + l - start));
+	  break;
+
+	case DW_OP_call2:
+	  ul = extract_unsigned_integer (data, 2, gdbarch_byte_order (arch));
+	  data += 2;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, 2));
+	  break;
+
+	case DW_OP_call4:
+	  ul = extract_unsigned_integer (data, 4, gdbarch_byte_order (arch));
+	  data += 4;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, 4));
+	  break;
+
+	case DW_OP_call_ref:
+	  ul = extract_unsigned_integer (data, offset_size,
+					 gdbarch_byte_order (arch));
+	  data += offset_size;
+	  fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
+	  break;
+
+        case DW_OP_piece:
+	  data = read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s (bytes)", pulongest (ul));
+	  break;
+
+	case DW_OP_bit_piece:
+	  {
+	    ULONGEST offset;
+
+	    data = read_uleb128 (data, end, &ul);
+	    data = read_uleb128 (data, end, &offset);
+	    fprintf_filtered (stream, " size %s offset %s (bits)",
+			      pulongest (ul), pulongest (offset));
+	  }
+	  break;
+	}
+
+      fprintf_filtered (stream, "\n");
+    }
 
   return data;
 }
@@ -1425,40 +1709,78 @@ static void
 locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
 			     struct ui_file *stream,
 			     const gdb_byte *data, int size,
-			     struct objfile *objfile, unsigned int addr_size)
+			     struct objfile *objfile, unsigned int addr_size,
+			     int offset_size)
 {
   const gdb_byte *end = data + size;
-  int piece_done = 0, first_piece = 1, bad = 0;
+  int first_piece = 1, bad = 0;
 
-  /* A multi-piece description consists of multiple sequences of bytes
-     each followed by DW_OP_piece + length of piece.  */
   while (data < end)
     {
-      if (!piece_done)
-	{
-	  if (first_piece)
-	    first_piece = 0;
-	  else
-	    fprintf_filtered (stream, _(", and "));
+      const gdb_byte *here = data;
+      int disassemble = 1;
+
+      if (first_piece)
+	first_piece = 0;
+      else
+	fprintf_filtered (stream, _(", and "));
 
+      if (!dwarf2_always_disassemble)
+	{
 	  data = locexpr_describe_location_piece (symbol, stream, addr, objfile,
-						  data, size, addr_size);
-	  piece_done = 1;
+						  data, end, addr_size);
+	  /* If we printed anything, or if we have an empty piece,
+	     then don't disassemble.  */
+	  if (data != here
+	      || data[0] == DW_OP_piece
+	      || data[0] == DW_OP_bit_piece)
+	    disassemble = 0;
 	}
-      else if (data[0] == DW_OP_piece)
+      if (disassemble)
+	data = disassemble_dwarf_expression (stream, get_objfile_arch (objfile),
+					     addr_size, offset_size, data, end,
+					     dwarf2_always_disassemble);
+
+      if (data < end)
 	{
-	  ULONGEST bytes;
+	  int empty = data == here;
 	      
-	  data = read_uleb128 (data + 1, end, &bytes);
+	  if (disassemble)
+	    fprintf_filtered (stream, "   ");
+	  if (data[0] == DW_OP_piece)
+	    {
+	      ULONGEST bytes;
 
-	  fprintf_filtered (stream, _(" [%s-byte piece]"), pulongest (bytes));
+	      data = read_uleb128 (data + 1, end, &bytes);
 
-	  piece_done = 0;
-	}
-      else
-	{
-	  bad = 1;
-	  break;
+	      if (empty)
+		fprintf_filtered (stream, _("an empty %s-byte piece"),
+				  pulongest (bytes));
+	      else
+		fprintf_filtered (stream, _(" [%s-byte piece]"),
+				  pulongest (bytes));
+	    }
+	  else if (data[0] == DW_OP_bit_piece)
+	    {
+	      ULONGEST bits, offset;
+
+	      data = read_uleb128 (data + 1, end, &bits);
+	      data = read_uleb128 (data, end, &offset);
+
+	      if (empty)
+		fprintf_filtered (stream,
+				  _("an empty %s-bit piece"),
+				  pulongest (bits));
+	      else
+		fprintf_filtered (stream,
+				  _(" [%s-bit piece, offset %s bits]"),
+				  pulongest (bits), pulongest (offset));
+	    }
+	  else
+	    {
+	      bad = 1;
+	      break;
+	    }
 	}
     }
 
@@ -1477,9 +1799,10 @@ locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
   struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu);
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+  int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
 
   locexpr_describe_location_1 (symbol, addr, stream, dlbaton->data, dlbaton->size,
-			       objfile, addr_size);
+			       objfile, addr_size, offset_size);
 }
 
 /* Describe the location of SYMBOL as an agent value in VALUE, generating
@@ -1563,6 +1886,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   struct gdbarch *gdbarch = get_objfile_arch (objfile);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
+  int offset_size = dwarf2_per_cu_offset_size (dlbaton->per_cu);
   CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
   /* Adjust base_address for relocatable objects.  */
   CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets,
@@ -1572,7 +1896,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   loc_ptr = dlbaton->data;
   buf_end = dlbaton->data + dlbaton->size;
 
-  fprintf_filtered (stream, _("multi-location ("));
+  fprintf_filtered (stream, _("multi-location:\n"));
 
   /* Iterate through locations until we run out.  */
   while (1)
@@ -1589,7 +1913,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 	{
 	  base_address = dwarf2_read_address (gdbarch,
 					      loc_ptr, buf_end, addr_size);
-	  fprintf_filtered (stream, _("[base address %s]"),
+	  fprintf_filtered (stream, _("  Base address %s"),
 			    paddress (gdbarch, base_address));
 	  loc_ptr += addr_size;
 	  continue;
@@ -1600,11 +1924,7 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 
       /* An end-of-list entry.  */
       if (low == 0 && high == 0)
-	{
-	  /* Indicate the end of the list, for readability.  */
-	  fprintf_filtered (stream, _(")"));
-	  return;
-	}
+	break;
 
       /* Otherwise, a location expression entry.  */
       low += base_address;
@@ -1613,20 +1933,16 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
       length = extract_unsigned_integer (loc_ptr, 2, byte_order);
       loc_ptr += 2;
 
-      /* Separate the different locations with a semicolon.  */
-      if (first)
-	first = 0;
-      else
-	fprintf_filtered (stream, _("; "));
-
       /* (It would improve readability to print only the minimum
 	 necessary digits of the second number of the range.)  */
-      fprintf_filtered (stream, _("range %s-%s, "),
+      fprintf_filtered (stream, _("  Range %s-%s: "),
 			paddress (gdbarch, low), paddress (gdbarch, high));
 
       /* Now describe this particular location.  */
       locexpr_describe_location_1 (symbol, low, stream, loc_ptr, length,
-				   objfile, addr_size);
+				   objfile, addr_size, offset_size);
+
+      fprintf_filtered (stream, "\n");
 
       loc_ptr += length;
     }
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index fa0bd11..fd5f49d 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -34,6 +34,9 @@ struct objfile *dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *cu);
 /* Return the address size given in the compilation unit header for CU.  */
 CORE_ADDR dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu);
 
+/* Return the offset size given in the compilation unit header for CU.  */
+int dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *cu);
+
 /* The symbol location baton types used by the DWARF-2 reader (i.e.
    SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
    dwarf2_locexpr_baton" is for a symbol with a single location
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 129d6c1..7d7eb6c 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -1002,8 +1002,6 @@ static char *dwarf_attr_name (unsigned int);
 
 static char *dwarf_form_name (unsigned int);
 
-static char *dwarf_stack_op_name (unsigned int);
-
 static char *dwarf_bool_name (unsigned int);
 
 static char *dwarf_type_encoding_name (unsigned int);
@@ -9848,8 +9846,8 @@ dwarf_form_name (unsigned form)
 
 /* Convert a DWARF stack opcode into its string name.  */
 
-static char *
-dwarf_stack_op_name (unsigned op)
+const char *
+dwarf_stack_op_name (unsigned op, int def)
 {
   switch (op)
     {
@@ -10152,32 +10150,24 @@ dwarf_stack_op_name (unsigned op)
       return "DW_OP_call4";
     case DW_OP_call_ref:
       return "DW_OP_call_ref";
-    /* GNU extensions.  */
     case DW_OP_form_tls_address:
       return "DW_OP_form_tls_address";
     case DW_OP_call_frame_cfa:
       return "DW_OP_call_frame_cfa";
     case DW_OP_bit_piece:
       return "DW_OP_bit_piece";
+    /* DWARF 4 extensions.  */
+    case DW_OP_implicit_value:
+      return "DW_OP_implicit_value";
+    case DW_OP_stack_value:
+      return "DW_OP_stack_value";
+    /* GNU extensions.  */
     case DW_OP_GNU_push_tls_address:
       return "DW_OP_GNU_push_tls_address";
     case DW_OP_GNU_uninit:
       return "DW_OP_GNU_uninit";
-    /* HP extensions. */ 
-    case DW_OP_HP_is_value:
-      return "DW_OP_HP_is_value";
-    case DW_OP_HP_fltconst4:
-      return "DW_OP_HP_fltconst4";
-    case DW_OP_HP_fltconst8:
-      return "DW_OP_HP_fltconst8";
-    case DW_OP_HP_mod_range:
-      return "DW_OP_HP_mod_range";
-    case DW_OP_HP_unmod_range:
-      return "DW_OP_HP_unmod_range";
-    case DW_OP_HP_tls:
-      return "DW_OP_HP_tls";
     default:
-      return "OP_<unknown>";
+      return def ? "OP_<unknown>" : NULL;
     }
 }
 
@@ -11018,7 +11008,7 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu)
 
 	default:
 	  complaint (&symfile_complaints, _("unsupported stack op: '%s'"),
-		     dwarf_stack_op_name (op));
+		     dwarf_stack_op_name (op, 1));
 	  return (stack[stacki]);
 	}
     }
@@ -11745,6 +11735,28 @@ dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *per_cu)
     }
 }
 
+/* Return the offset size given in the compilation unit header for CU.  */
+
+int
+dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu)
+{
+  if (per_cu->cu)
+    return per_cu->cu->header.offset_size;
+  else
+    {
+      /* If the CU is not currently read in, we re-read its header.  */
+      struct objfile *objfile = per_cu->psymtab->objfile;
+      struct dwarf2_per_objfile *per_objfile
+	= objfile_data (objfile, dwarf2_objfile_data_key);
+      gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset;
+      struct comp_unit_head cu_header;
+
+      memset (&cu_header, 0, sizeof cu_header);
+      read_comp_unit_head (&cu_header, info_ptr, objfile->obfd);
+      return cu_header.offset_size;
+    }
+}
+
 /* Locate the .debug_info compilation unit from CU's objfile which contains
    the DIE at OFFSET.  Raises an error on failure.  */
 
@@ -12199,6 +12211,17 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
   munmap_section_buffer (&data->eh_frame);
 }
 
+int dwarf2_always_disassemble;
+
+static void
+show_dwarf2_always_disassemble (struct ui_file *file, int from_tty,
+				struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Whether to always disassemble DWARF expressions is %s.\n"),
+		    value);
+}
+
 void _initialize_dwarf2_read (void);
 
 void
@@ -12231,6 +12254,18 @@ caching, which can slow down startup."),
 			    &set_dwarf2_cmdlist,
 			    &show_dwarf2_cmdlist);
 
+  add_setshow_boolean_cmd ("always-disassemble", class_obscure,
+			   &dwarf2_always_disassemble, _("\
+Set whether `info address' always disassembles DWARF expressions."), _("\
+Show whether `info address' always disassembles DWARF expressions."), _("\
+When enabled, DWARF expressions are always printed in an assembly-like\n\
+syntax.  When disabled, expressions will be printed in a more\n\
+conversational style, when possible."),
+			   NULL,
+			   show_dwarf2_always_disassemble,
+			   &set_dwarf2_cmdlist,
+			   &show_dwarf2_cmdlist);
+
   add_setshow_zinteger_cmd ("dwarf2-die", no_class, &dwarf2_die_debug, _("\
 Set debugging of the dwarf2 DIE reader."), _("\
 Show debugging of the dwarf2 DIE reader."), _("\

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-06-01 18:36                     ` Tom Tromey
@ 2010-06-01 18:40                       ` Eli Zaretskii
  2010-06-02 19:32                         ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Eli Zaretskii @ 2010-06-01 18:40 UTC (permalink / raw)
  To: Tom Tromey; +Cc: jan.kratochvil, stan, gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: jan.kratochvil@redhat.com, stan@codesourcery.com,
>         gdb-patches@sourceware.org
> Date: Tue, 01 Jun 2010 12:35:31 -0600
> 
> >>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
> 
> Eli> Thanks.  This part is okay, but I have a suggestion: it might help to
> Eli> have an example of the assembly-like format when this option is ON,
> Eli> and perhaps also explain how to interpret it, or point to some
> Eli> document that could be used for that.
> 
> Here is an updated patch that includes this.
> Let me know what you think.

Thank you, this is fine.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFC: DWARF expression disassembly
  2010-06-01 18:40                       ` Eli Zaretskii
@ 2010-06-02 19:32                         ` Tom Tromey
  0 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2010-06-02 19:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: jan.kratochvil, stan, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

Tom> Here is an updated patch that includes this.
Tom> Let me know what you think.

Eli> Thank you, this is fine.

Thanks.  I am going to commit it shortly.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)
  2010-05-26 22:41           ` Tom Tromey
@ 2010-06-03 20:12             ` Tom Tromey
  2010-06-08 20:45               ` RFA: rewrite dwarf->ax translator Tom Tromey
                                 ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Tom Tromey @ 2010-06-03 20:12 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

>>>>> "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, &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..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, &reg);
-      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, &reg);
+	  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, &reg);
+	    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, &reg);
+	  /* 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);
 }
 
 \f
@@ -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)			  \
 {									  \

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator
  2010-06-03 20:12             ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
@ 2010-06-08 20:45               ` Tom Tromey
  2010-06-11 15:20                 ` Tom Tromey
  2010-06-08 20:52               ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Pedro Alves
  2010-07-01 12:43               ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Pedro Alves
  2 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-06-08 20:45 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

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

Tom> Here is a new version of my patch to rewrite the DWARF->AX translator.

Here's yet another new version -- I rebased and added support for
DW_OP_call{2,4}, to follow Jan's change.

Tom


b/gdb/ChangeLog:
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 4e5a0fc..0dc0aaf 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 29f81a5..727e557 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -209,4 +209,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 8a9a346..ce5d485 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -1048,266 +1048,746 @@ 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, &reg);
-      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 dwarf2_per_cu_data *per_cu)
+{
+  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, &reg);
+	  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, &reg);
+	    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, per_cu);
+
+	    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 DW_OP_plus_uconst:
+	  op_ptr = read_uleb128 (op_ptr, op_end, &reg);
+	  /* 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 axs_lvalue_memory:
+	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);
 
-	    gdb_assert (fragments[frag].bytes == 4);
-	    if (trace_kludge)
-	      ax_trace_quick (ax, 4);
-	    ax_simple (ax, aop_ref32);
+	    if (bits_collected + size > 8 * sizeof (LONGEST))
+	      error (_("Expression pieces exceed word size"));
+
+	    /* 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);
+
+	case DW_OP_call2:
+	case DW_OP_call4:
+	  {
+	    struct dwarf2_locexpr_baton block;
+	    int size = (op == DW_OP_call2 ? 2 : 4);
+
+	    uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
+	    op_ptr += size;
+
+	    block = dwarf2_fetch_die_location_block (uoffset, per_cu);
+
+	    /* DW_OP_call_ref is currently not supported.  */
+	    gdb_assert (block.per_cu == per_cu);
+
+	    compile_dwarf_to_ax (expr, loc, arch, addr_size,
+				 block.data, block.data + block.size,
+				 per_cu);
+	  }
+	  break;
+
+	case DW_OP_call_ref:
+	  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
@@ -1864,9 +2344,11 @@ 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,
+		       dlbaton->per_cu);
 }
 
 /* The set of location functions used with the DWARF-2 expression
@@ -2008,10 +2490,12 @@ 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,
+		       dlbaton->per_cu);
 }
 
 /* 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)			  \
 {									  \

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)
  2010-06-03 20:12             ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
  2010-06-08 20:45               ` RFA: rewrite dwarf->ax translator Tom Tromey
@ 2010-06-08 20:52               ` Pedro Alves
  2010-06-08 21:21                 ` RFA: rewrite dwarf->ax translator Tom Tromey
  2010-07-01 12:43               ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Pedro Alves
  2 siblings, 1 reply; 36+ messages in thread
From: Pedro Alves @ 2010-06-08 20:52 UTC (permalink / raw)
  To: gdb-patches, Tom Tromey; +Cc: Stan Shebs, Jan Kratochvil

On Thursday 03 June 2010 21:12:13, Tom Tromey wrote:
> Built and regtested on x86-64 (compile farm).

I'm not sure whether testing natively actually exercises anything regarding
bytecode generation.  The gdb.trace/ tests are mostly skipped in that
case.  Did you try testing this against a x86|x86-64 gdbserver?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator
  2010-06-08 20:52               ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Pedro Alves
@ 2010-06-08 21:21                 ` Tom Tromey
  2010-06-08 22:48                   ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-06-08 21:21 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Stan Shebs, Jan Kratochvil

>>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:

Pedro> On Thursday 03 June 2010 21:12:13, Tom Tromey wrote:
>> Built and regtested on x86-64 (compile farm).

Pedro> I'm not sure whether testing natively actually exercises anything
Pedro> regarding bytecode generation.  The gdb.trace/ tests are mostly
Pedro> skipped in that case.  Did you try testing this against a
Pedro> x86|x86-64 gdbserver?

No.  I will do that.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator
  2010-06-08 21:21                 ` RFA: rewrite dwarf->ax translator Tom Tromey
@ 2010-06-08 22:48                   ` Tom Tromey
  2010-06-09 14:04                     ` Pedro Alves
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-06-08 22:48 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Stan Shebs, Jan Kratochvil

>>> Built and regtested on x86-64 (compile farm).

Pedro> I'm not sure whether testing natively actually exercises anything
Pedro> regarding bytecode generation.  The gdb.trace/ tests are mostly
Pedro> skipped in that case.  Did you try testing this against a
Pedro> x86|x86-64 gdbserver?

Tom> No.  I will do that.

The results look good to me.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator
  2010-06-08 22:48                   ` Tom Tromey
@ 2010-06-09 14:04                     ` Pedro Alves
  0 siblings, 0 replies; 36+ messages in thread
From: Pedro Alves @ 2010-06-09 14:04 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, Stan Shebs, Jan Kratochvil

On Tuesday 08 June 2010 23:48:18, Tom Tromey wrote:
> >>> Built and regtested on x86-64 (compile farm).
> 
> Pedro> I'm not sure whether testing natively actually exercises anything
> Pedro> regarding bytecode generation.  The gdb.trace/ tests are mostly
> Pedro> skipped in that case.  Did you try testing this against a
> Pedro> x86|x86-64 gdbserver?
> 
> Tom> No.  I will do that.
> 
> The results look good to me.

Thanks.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: RFA: rewrite dwarf->ax translator
  2010-06-08 20:45               ` RFA: rewrite dwarf->ax translator Tom Tromey
@ 2010-06-11 15:20                 ` Tom Tromey
  0 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2010-06-11 15:20 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches, Jan Kratochvil

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

Tom> Here's yet another new version -- I rebased and added support for
Tom> DW_OP_call{2,4}, to follow Jan's change.

I am checking this in.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece))
  2010-06-03 20:12             ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
  2010-06-08 20:45               ` RFA: rewrite dwarf->ax translator Tom Tromey
  2010-06-08 20:52               ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Pedro Alves
@ 2010-07-01 12:43               ` Pedro Alves
  2010-07-01 15:25                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator Tom Tromey
  2010-07-01 15:34                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Jan Kratochvil
  2 siblings, 2 replies; 36+ messages in thread
From: Pedro Alves @ 2010-07-01 12:43 UTC (permalink / raw)
  To: gdb-patches, Tom Tromey; +Cc: Stan Shebs, Jan Kratochvil

Hi Tom,

After the rewrite, I'm seeing this:

 (gdb) p m
 $1 = <value optimized out>
 (gdb) maint agent m
  ../../src/gdb/utils.c:1363: internal-error: virtual memory exhausted: can't allocate 562945039736192 bytes.
 A problem internal to GDB has been detected,
 further debugging may prove unreliable.
 Quit this debugging session? (y or n) 


#0  internal_error (file=0x7531ac "../../src/gdb/utils.c", line=1363, 
    string=0x753568 "virtual memory exhausted: can't allocate %ld bytes.") at ../../src/gdb/utils.c:1162
#1  0x0000000000417464 in nomem (size=562949953380224) at ../../src/gdb/utils.c:1363
#2  0x00000000004174c3 in xmalloc (size=562949953380224) at ../../src/gdb/utils.c:1394
#3  0x00000000005b1ac7 in compile_dwarf_to_ax (expr=0xebd020, loc=0x7fffffffd9b0, arch=0xcc9a20, addr_size=8, 
    op_ptr=0x0, op_end=0x7fffffffd7e0 " \320\353", per_cu=0xcada90) at ../../src/gdb/dwarf2loc.c:1220
#4  0x00000000005b4b78 in loclist_tracepoint_var_ref (symbol=0xd22c30, gdbarch=0xcc9a20, ax=0xebd020, 
    value=0x7fffffffd9b0) at ../../src/gdb/dwarf2loc.c:2572
#5  0x000000000048be46 in gen_var_ref (gdbarch=0xcc9a20, ax=0xebd020, value=0x7fffffffd9b0, var=0xd22c30)
    at ../../src/gdb/ax-gdb.c:713
#6  0x000000000048e570 in gen_expr (exp=0xed5280, pc=0x7fffffffd9c8, ax=0xebd020, value=0x7fffffffd9b0)
    at ../../src/gdb/ax-gdb.c:1962
#7  0x000000000048f92a in gen_trace_for_expr (scope=4197499, expr=0xed5280) at ../../src/gdb/ax-gdb.c:2387
#8  0x000000000048fabc in agent_command (exp=0xb4821c "m", from_tty=1) at ../../src/gdb/ax-gdb.c:2456

The xmalloc in question is this:

 offsets = xmalloc ((op_end - op_ptr) * sizeof (int));

`op_end' and `op_ptr' are `data' and `data + size' in loclist_tracepoint_var_ref:

  data = find_location_expression (dlbaton, &size, ax->scope);

  compile_dwarf_to_ax (ax, value, gdbarch, addr_size, data, data + size,
		       dlbaton->per_cu);

where:

 (top-gdb) p data
 $1 = (const gdb_byte *) 0x0
 (top-gdb) p size
 $2 = 140737488345056
 (top-gdb) p /x 
 $3 = 0x7fffffffd7e0

whoops.

On Thursday 03 June 2010 21:12:13, Tom Tromey wrote:

> 	(dwarf2_tracepoint_var_ref): Likewise.
> 	(locexpr_tracepoint_var_ref): Use compile_dwarf_to_ax.
> 	(loclist_tracepoint_var_ref): Likewise.

> -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)
> -{
(...)
> -      
> -  if (!data || size == 0)
> -    {
> -      value->optimized_out = 1;
> -      return;
> -    }

Apparently, this bit was lost with the rewrite.

(...)

> @@ -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);
>  }

This patch fixes it for me.  Is this the correct approach, or maybe there
was intent to handle this differently?

-- 
Pedro Alves

2010-07-01  Pedro Alves  <pedro@codesourcery.com>

	* dwarf2loc.c (locexpr_tracepoint_var_ref)
	(loclist_tracepoint_var_ref): Handle optimized out values.

---
 gdb/dwarf2loc.c |   17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

Index: src/gdb/dwarf2loc.c
===================================================================
--- src.orig/gdb/dwarf2loc.c	2010-07-01 12:19:35.000000000 +0100
+++ src/gdb/dwarf2loc.c	2010-07-01 13:32:38.000000000 +0100
@@ -2416,9 +2416,12 @@ locexpr_tracepoint_var_ref (struct symbo
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
 
-  compile_dwarf_to_ax (ax, value, gdbarch, addr_size,
-		       dlbaton->data, dlbaton->data + dlbaton->size,
-		       dlbaton->per_cu);
+  if (dlbaton->data == NULL || dlbaton->size == 0)
+    value->optimized_out = 1;
+  else
+    compile_dwarf_to_ax (ax, value, gdbarch, addr_size,
+			 dlbaton->data, dlbaton->data + dlbaton->size,
+			 dlbaton->per_cu);
 }
 
 /* The set of location functions used with the DWARF-2 expression
@@ -2568,9 +2571,11 @@ loclist_tracepoint_var_ref (struct symbo
   unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
 
   data = find_location_expression (dlbaton, &size, ax->scope);
-
-  compile_dwarf_to_ax (ax, value, gdbarch, addr_size, data, data + size,
-		       dlbaton->per_cu);
+  if (data == NULL || size == 0)
+    value->optimized_out = 1;
+  else
+    compile_dwarf_to_ax (ax, value, gdbarch, addr_size, data, data + size,
+			 dlbaton->per_cu);
 }
 
 /* The set of location functions used with the DWARF-2 expression

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator
  2010-07-01 12:43               ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Pedro Alves
@ 2010-07-01 15:25                 ` Tom Tromey
  2010-07-01 15:57                   ` Pedro Alves
  2010-07-01 15:34                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Jan Kratochvil
  1 sibling, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2010-07-01 15:25 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Stan Shebs, Jan Kratochvil

>>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:

>> -  if (!data || size == 0)
>> -    {
>> -      value->optimized_out = 1;
>> -      return;
>> -    }

Pedro> Apparently, this bit was lost with the rewrite.

Oops, sorry about that.

Pedro> This patch fixes it for me.  Is this the correct approach, or
Pedro> maybe there was intent to handle this differently?

It looks good to me.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece))
  2010-07-01 12:43               ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Pedro Alves
  2010-07-01 15:25                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator Tom Tromey
@ 2010-07-01 15:34                 ` Jan Kratochvil
  1 sibling, 0 replies; 36+ messages in thread
From: Jan Kratochvil @ 2010-07-01 15:34 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Tom Tromey, Stan Shebs

On Thu, 01 Jul 2010 14:42:59 +0200, Pedro Alves wrote:
> +  if (dlbaton->data == NULL || dlbaton->size == 0)

If SIZE != 0 then DATA must be != NULL otherwise GDB would crash elsewhere.

dwarf2_evaluate_loc_desc is already using this easier to read conditional:
  if (size == 0)
which means:
  if (dlbaton->size == 0)


Thanks,
Jan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator
  2010-07-01 15:25                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator Tom Tromey
@ 2010-07-01 15:57                   ` Pedro Alves
  0 siblings, 0 replies; 36+ messages in thread
From: Pedro Alves @ 2010-07-01 15:57 UTC (permalink / raw)
  To: tromey; +Cc: gdb-patches, Stan Shebs, Jan Kratochvil

On Thursday 01 July 2010 16:24:58, Tom Tromey wrote:
> >>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:
> 
> >> -  if (!data || size == 0)
> >> -    {
> >> -      value->optimized_out = 1;
> >> -      return;
> >> -    }
> 
> Pedro> Apparently, this bit was lost with the rewrite.
> 
> Oops, sorry about that.
> 
> Pedro> This patch fixes it for me.  Is this the correct approach, or
> Pedro> maybe there was intent to handle this differently?
> 
> It looks good to me.

Thanks, I've applied it.

On Thursday 01 July 2010 16:33:50, Jan Kratochvil wrote:
> On Thu, 01 Jul 2010 14:42:59 +0200, Pedro Alves wrote:
> > +  if (dlbaton->data == NULL || dlbaton->size == 0)
> 
> If SIZE != 0 then DATA must be != NULL otherwise GDB would crash elsewhere.

Maybe in the case, I'm not sure.  In the loclist case, it can be
seen that SIZE is undefined when DATA is NULL (see the internal error
example I posted before), so checking on SIZE isn't sufficient then.
I was prefering having both cases handled with the same condition,
and I used the same condition we were using before the rewrite.

> dwarf2_evaluate_loc_desc is already using this easier to read conditional:
>   if (size == 0)
> which means:
>   if (dlbaton->size == 0)

... while loclist_read_variable itself checks for data == NULL.  That
didn't seem that consistent and easier to read.

(Feel free to clean this up.  I'm disappearing for two weeks soon,
and I really should be focusing on other stuff.  I've applied it
as is, mainly to avoid branching 7.2 with the regression.)

Thanks,
-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2010-07-01 15:57 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-18 23:43 RFC: implement DW_OP_bit_piece Tom Tromey
2010-05-19 14:16 ` Stan Shebs
2010-05-19 23:35   ` Tom Tromey
2010-05-20  3:29     ` Stan Shebs
2010-05-20  5:10       ` Tom Tromey
2010-05-20  7:12         ` Tom Tromey
2010-05-26 22:41           ` Tom Tromey
2010-06-03 20:12             ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
2010-06-08 20:45               ` RFA: rewrite dwarf->ax translator Tom Tromey
2010-06-11 15:20                 ` Tom Tromey
2010-06-08 20:52               ` RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece) Pedro Alves
2010-06-08 21:21                 ` RFA: rewrite dwarf->ax translator Tom Tromey
2010-06-08 22:48                   ` Tom Tromey
2010-06-09 14:04                     ` Pedro Alves
2010-07-01 12:43               ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Pedro Alves
2010-07-01 15:25                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator Tom Tromey
2010-07-01 15:57                   ` Pedro Alves
2010-07-01 15:34                 ` collecting optimized out variables regression (Re: RFA: rewrite dwarf->ax translator (Was: RFC: implement DW_OP_bit_piece)) Jan Kratochvil
2010-05-20 19:53     ` RFC: implement DW_OP_bit_piece Tom Tromey
2010-05-20 20:30       ` Jan Kratochvil
2010-05-21 20:16     ` Tom Tromey
2010-05-21 21:16       ` Stan Shebs
2010-05-21 21:18         ` Tom Tromey
2010-05-25 19:22         ` RFC: DWARF expression disassembly (Was: RFC: implement DW_OP_bit_piece) Tom Tromey
2010-05-25 19:27           ` Jan Kratochvil
2010-05-25 20:25             ` RFC: DWARF expression disassembly Tom Tromey
2010-05-25 20:52               ` Jan Kratochvil
2010-05-25 22:03                 ` Tom Tromey
2010-05-26 17:21                   ` Eli Zaretskii
2010-06-01 18:36                     ` Tom Tromey
2010-06-01 18:40                       ` Eli Zaretskii
2010-06-02 19:32                         ` Tom Tromey
2010-05-20 21:07 ` RFC: implement DW_OP_bit_piece Jan Kratochvil
2010-05-21 17:57   ` Tom Tromey
2010-05-25 18:19     ` performance talk [Re: RFC: implement DW_OP_bit_piece] Jan Kratochvil
2010-05-25 22:23       ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).