This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Add support for tracking/evaluating dwarf2 location expressions


This patch adds a place in the symbol structure to store the dwarf2
location (an upcoming dwarf2read huge rewrite patch uses it), an
evaluation maachine to findvar.c, and has read_var_value use the dwarf2
location if it's available.

NOte that in struct d2_location, in the symtab.h patch, that framlocdesc
cannot be unioned with locdesc, because the symbol providing the frame
location description  usually has it's own real location.

Currently, because GDB makes no use of the frame unwind info, etc, I
evaluate the frame pointer location expression for whatever is providing
it for the thing we are trying to evaluate, rather than rely what GDB
tells us the frame pointer is.

Yes, it's currently pointless to do this,  it's just future proofing, and
what we are supposed to do, anyway.

This patch will have no effect whatosever without the dwarf2read.c
rewrite, but it won't break anything, neither, so i sepereated it out and
am submitting it now.
--Dan
2001-03-30  Daniel Berlin  <dberlin@redhat.com>

	* symtab.h (address_class): Add LOC_DWARF2_EXPRESSION.
	(struct symbol): Add struct d2_location to store dwarf2
	location expressions.
	(SYMBOL_DWARF2_LOCATION, SYMBOL_DWARF2_FRAME_LOCATION): New macros.

	* findvar.c (read_leb128): New function, read leb128 data from a
	buffer.
	(evaluate_dwarf2_locdesc): New function, evaluate a given
	dwarf2 location description.
	(read_var_value): Use the dwarf2 location expression if it's available.

Index: findvar.c
===================================================================
RCS file: /cvs/src/src/gdb/findvar.c,v
retrieving revision 1.19
diff -c -3 -p -w -B -b -r1.19 findvar.c
*** findvar.c	2001/03/06 08:21:07	1.19
--- findvar.c	2001/03/30 18:17:34
***************
*** 31,36 ****
--- 31,37 ----
  #include "gdb_string.h"
  #include "floatformat.h"
  #include "symfile.h"		/* for overlay functions */
+ #include "elf/dwarf2.h"
  #include "regcache.h"

  /* This is used to indicate that we don't know the format of the floating point
*************** symbol_read_needs_frame (struct symbol *
*** 501,507 ****
--- 502,807 ----
      }
    return 1;
  }
+ struct dwarf_block
+ {
+ 	unsigned int size;
+ 	unsigned char *data;
+ };
+ /* Read a LEB128 value from the buffer given by data */
+ static unsigned long int
+ read_leb128 (unsigned char *data, int *length_return, int sign)
+ {
+   unsigned long int result = 0;
+   unsigned int      num_read = 0;
+   int               shift = 0;
+   unsigned char     byte;
+
+   do
+     {
+       byte = * data ++;
+       num_read ++;
+
+       result |= (byte & 0x7f) << shift;
+
+       shift += 7;
+
+     }
+   while (byte & 0x80);
+
+   if (length_return != NULL)
+     *length_return = num_read;
+
+   if (sign && (shift < 32) && (byte & 0x40))
+     result |= -1 << shift;
+
+   return result;
+ }
+
+ /* Evaluate a dwarf2 location description, given in THEBLOCK, in the
+    context of frame FRAME. */
+ value_ptr
+ evaluate_dwarf2_locdesc (register struct symbol *var, struct frame_info *frame,
+ 			 struct dwarf_block *theblock, struct type *type)
+ {
+   int i;
+   int stacki;
+   unsigned char op;
+   unsigned int bytes_read;
+   value_ptr stack[64];
+
+   i=0;
+   stacki=0;
+   stack[stacki]=0;
+   bytes_read = 0;
+
+   /* Loop until we are done with the location expression we were asked
+      to evaluate */
+   while (i < theblock->size)
+     {
+       /* Get the opcode */
+       op = theblock->data[i++];
+
+       if (op >= DW_OP_reg0 && op <= DW_OP_reg31)
+ 	{
+ 	  /* Push value of register specified by opcode onto stack */
+ 	  stack[++stacki] = value_from_register (type, op - DW_OP_reg0, frame);
+ 	}
+       else if (op == DW_OP_regx)
+ 	{
+ 	  unsigned int unsnd;
+
+ 	  /* Get the register number operand */
+ 	  unsnd = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /* Push the value of that register onto the stack */
+ 	  stack[++stacki] = value_from_register (type, unsnd, frame);
+ 	}
+       else if (op >= DW_OP_breg0 && op <= DW_OP_breg31)
+ 	{
+ 	  unsigned int basereg = op - DW_OP_breg0;
+ 	  unsigned int basereg_addr;
+ 	  unsigned int addr;
+
+ 	  /* Allocate a buffer to store the register data */
+ 	  char *buf = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+
+ 	  /* Read the offset from the base register */
+ 	  basereg_addr = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /* Get the base register */
+ 	  get_saved_register (buf, NULL, NULL, frame, basereg, NULL);
+
+ 	  /* Extract the address from the base register */
+ 	  addr = extract_address (buf, REGISTER_RAW_SIZE (basereg));
+ 	  addr += basereg_addr;
+
+ 	  /* Push the value of *(basereg + offset) onto the stack */
+ 	  stack[++stacki] = value_ind (value_from_pointer (lookup_pointer_type (type), addr));
+ 	}
+       else if (op == DW_OP_bregx)
+ 	{
+
+ 	  unsigned int basereg;
+ 	  unsigned int addr;
+ 	  unsigned int basereg_addr;
+
+ 	  /* Allocate a buffer to store the register data */
+ 	  char *buf = (char*) alloca (MAX_REGISTER_RAW_SIZE);
+
+ 	  /* Read the base register */
+ 	  basereg = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /* Read the offset from the base register */
+ 	  basereg_addr = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /* Get the base register */
+ 	  get_saved_register (buf, NULL, NULL, frame, basereg, NULL);
+
+ 	  /* Extract address from the base register */
+ 	  addr = extract_address (buf, REGISTER_RAW_SIZE (basereg));
+ 	  addr += basereg_addr;
+
+ 	  /* Push the value of *(basereg + offset) onto the stack */
+ 	  stack[++stacki] = value_ind (value_from_pointer (lookup_pointer_type (type), addr));
+ 	}
+       else if (op == DW_OP_fbreg)
+ 	{
+ 	  value_ptr framepointer;
+ 	  unsigned int basereg_addr;
+ 	  struct symbol *framefunc;
+
+ 	  /* Get our current function's symbol, so we can get the
+ 	     frame location (we don't do this using gdb's frame, since
+ 	     it doesn't yet support dwarf2 frame unwinding, etc, and
+ 	     thus, the frame it says may not *really* be what we
+ 	     want) */
+ 	  framefunc = get_frame_function (frame);
+
+ 	  /* Read the offset from the frame pointer */
+ 	  basereg_addr = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i+= bytes_read;
+
+ 	  /* Make sure we have a valid frame function, and that it has
+ 	     a dwarf2 frame location for us */
+ 	  if (framefunc == NULL)
+ 	    error ("Cannot find function for frame, and therefore, can't figure out framepointer");
+ 	  if (SYMBOL_DWARF2_FRAME_LOC (framefunc) == NULL)
+ 	    error ("Frame base location for function is NULL, therefore, can't figure out framepointer");
+
+ 	  /* Recursively evaluate the location of the frame pointer */
+ 	  framepointer = evaluate_dwarf2_locdesc (var, frame, SYMBOL_DWARF2_FRAME_LOC (framefunc), builtin_type_CORE_ADDR);
+
+ 	  /* Add the offset */
+ 	  framepointer = value_add (framepointer, value_from_longest (builtin_type_CORE_ADDR, basereg_addr));
+
+ 	  /* Push the value of *(fp + offset) onto the stack */
+ 	  stack[++stacki] = value_ind (value_from_pointer (lookup_pointer_type (type), value_as_pointer (framepointer)));
+ 	}
+       else if (op == DW_OP_addr)
+ 	{
+ 	  unsigned int addr;
+ 	  /* Extract the address from the data */
+ 	  addr = extract_address (theblock->data + i, TYPE_LENGTH (builtin_type_ptr));
+ 	  i += TYPE_LENGTH (builtin_type_ptr);

+ 	  /* Push the value at *addr onto the stack */
+ 	  stack[++stacki] = value_ind (value_from_pointer (lookup_pointer_type (type), addr));
+ 	}
+       else if (op >= DW_OP_const1u && op <= DW_OP_const4s)
+ 	{
+ 	  unsigned int readsize;
+ 	  unsigned int sign=0;
+
+ 	  /* Determine the size to read, and whether it's signed or
+ 	     not */
+ 	  switch (op)
+ 	    {
+ 	    case DW_OP_const1s:
+ 	      sign = 1;
+ 	    case DW_OP_const1u:
+ 	      readsize = 1;
+ 	      break;
+ 	    case DW_OP_const2s:
+ 	      sign = 1;
+ 	    case DW_OP_const2u:
+ 	      readsize = 2;
+ 	      break;
+ 	    case DW_OP_const4s:
+ 	      sign = 1;
+ 	    case DW_OP_const4u:
+ 	      readsize = 4;
+ 	      break;
+ 	    default:
+ 	      error ("Unknown constant size while trying to evaluate dwarf2 expression");
+ 	    }
+ 	  if (sign)
+ 	    {
+ 	      LONGEST value;
+
+ 	      /* Extract the signed integer from the data */
+ 	      value = extract_signed_integer (theblock->data + i, readsize);
+
+ 	      /* FIXME: we have no builtin_type_LONGEST, so i can't use that here */
+ 	      stack[++stacki] = value_from_longest (builtin_type_long, value);
+ 	    }
+ 	  else
+ 	    {
+ 	      ULONGEST value;
+
+ 	      /* Extract the unsigned integer from the data */
+ 	      value = extract_unsigned_integer (theblock->data + i, readsize);
+
+ 	      /* FIXME: we have no builtin_type_ULONGEST, so i can't use that here */
+ 	      stack[++stacki] = value_from_longest (builtin_type_unsigned_long, value);
+ 	    }
+ 	  i += readsize;
+ 	}
+       else if (op == DW_OP_constu)
+ 	{
+ 	  unsigned int bytes_read;
+ 	  ULONGEST value;
+
+ 	  /* Read in the uleb128 value for the constant */
+ 	  value = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /*FIXME: we have no builtin_type_ULONGEST, so i can't use that here */
+ 	  stack[++stacki] = value_from_longest (builtin_type_unsigned_long, value);
+ 	}
+       else if (op == DW_OP_consts)
+ 	{
+ 	  unsigned int bytes_read;
+ 	  LONGEST value;
+
+ 	  /* Read in the sleb128 value for the constant */
+ 	  value = read_leb128 (theblock->data + i, &bytes_read, 1);
+ 	  i += bytes_read;
+
+ 	  /*FIXME: we have no builtin_type_LONGEST, so i can't use that here */
+ 	  stack[++stacki] = value_from_longest (builtin_type_long, value);
+ 	}
+       else if (op == DW_OP_plus)
+ 	{
+ 	  /* Add the value of the top of the stack, to the item at
+ 	     top-1, and pop top item */
+ 	  if (VALUE_LVAL (stack[stacki]) == lval_memory)
+ 	    VALUE_ADDRESS (stack[stacki - 1]) += value_as_long (stack[stacki]);
+ 	  else
+ 	    stack[stacki - 1] = value_add (stack[stacki - 1], stack[stacki]);
+ 	  stacki--;
+ 	}
+       else if (op == DW_OP_plus_uconst)
+ 	{
+ 	  unsigned int bytes_read;
+ 	  ULONGEST value;
+
+ 	  /* Read in uleb128 value for constant to add */
+ 	  value = read_leb128 (theblock->data + i, &bytes_read, 0);
+ 	  i += bytes_read;
+
+ 	  /* Add the constant to the value at the top of the stack */
+ 	  if (VALUE_LVAL (stack[stacki]) == lval_memory)
+ 	    VALUE_ADDRESS (stack[stacki]) += value;
+ 	  else
+ 	    stack[stacki] = value_add (stack[stacki], value_from_longest (builtin_type_unsigned_long, value));
+ 	}
+       else if (op == DW_OP_minus)
+ 	{
+ 	  /* Subtract the topofstack-1 value from the topofstack, put
+ 	     it in topofstack-1, and pop the top of the stack.
+
+ 	  I.E. if stack is
+ 	  10
+ 	  4
+ 	  then act like we popped both, and pushed 6 onto the stack.
+ 	  */
+
+ 	  if (VALUE_LVAL (stack[stacki]) == lval_memory)
+ 	    VALUE_ADDRESS (stack[stacki - 1]) = VALUE_ADDRESS (stack[stacki]) - value_as_long (stack[stacki - 1]);
+ 	  else
+ 	    stack[stacki - 1] = value_sub (stack[stacki], stack[stacki - 1]);
+ 	  stacki--;
+ 	}
+       else if (op == DW_OP_deref)
+ 	{
+ 	  /* Dereference the address at the top of the stack */
+ 	  stack[stacki] = value_ind (value_at (lookup_pointer_type (type),
+ 					       value_as_pointer (value_addr (stack[stacki])),
+ 					       VALUE_BFD_SECTION (stack[stacki])));
+ 	}
+       else
+ 	{
+ 	  break;
+ 	}
+     }
+   /* Return whatever the top of the stack is */
+   return stack[stacki];
+ }
+
  /* Given a struct symbol for a variable,
     and a stack frame id, read the value of the variable
     and return a (pointer to a) struct value containing the value.
*************** read_var_value (register struct symbol *
*** 524,530 ****

    if (frame == NULL)
      frame = selected_frame;
!
    switch (SYMBOL_CLASS (var))
      {
      case LOC_CONST:
--- 824,831 ----

    if (frame == NULL)
      frame = selected_frame;
!   if (SYMBOL_DWARF2_LOC (var) != NULL)
!     return evaluate_dwarf2_locdesc (var, frame, (struct dwarf_block *) SYMBOL_DWARF2_LOC (var), SYMBOL_TYPE (var));
    switch (SYMBOL_CLASS (var))
      {
      case LOC_CONST:
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.18
diff -c -3 -p -w -B -b -r1.18 symtab.h
*** symtab.h	2001/02/08 06:03:54	1.18
--- symtab.h	2001/03/30 18:17:35
*************** enum address_class
*** 653,660 ****
       * with a level of indirection.
       */

!     LOC_INDIRECT

    };

  /* Linked list of symbol's live ranges. */
--- 653,663 ----
       * with a level of indirection.
       */

!     LOC_INDIRECT,

+     /* Location is a dwarf2 expression */
+     LOC_DWARF2_EXPRESSION
+
    };

  /* Linked list of symbol's live ranges. */
*************** struct symbol
*** 712,717 ****
--- 715,725 ----
  	short basereg;
        }
      aux_value;
+     struct
+     {
+ 	    void *locdesc;
+ 	    void *framelocdesc;
+     } d2_location;


      /* Link to a list of aliases for this symbol.
*************** struct symbol
*** 729,734 ****
--- 737,744 ----
  #define SYMBOL_TYPE(symbol)		(symbol)->type
  #define SYMBOL_LINE(symbol)		(symbol)->line
  #define SYMBOL_BASEREG(symbol)		(symbol)->aux_value.basereg
+ #define SYMBOL_DWARF2_LOC(symbol)  	(symbol)->d2_location.locdesc
+ #define SYMBOL_DWARF2_FRAME_LOC(symbol) (symbol)->d2_location.framelocdesc
  #define SYMBOL_ALIASES(symbol)		(symbol)->aliases
  #define SYMBOL_RANGES(symbol)		(symbol)->ranges



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]