Based on a patch from Daniel Berlin (dberlin@dberlin.org).

* symtab.h: Add opaque declarations of struct axs_value and
	struct agent_expr.
	(enum address_class): Add LOC_COMPUTED and LOC_COMPUTED_ARG.
	(struct location_funcs): New type.
	(struct symbol): Add "loc" to aux_value.
	(SYMBOL_LOCATION_BATON, SYMBOL_LOCATION_FUNCS): New macros.
	* dwarf2read.c: Include "dwarf2expr.h".
	(dwarf2_symbol_mark_computed): New function.
	(read_func_scope): Use it.
	(var_decode_location): New function.
	(new_symbol): Use it.
	* dwarf2expr.c, dwarf2expr.h, dwarf2loc.c, dwarf2loc.h: New files.

	* Makefile.in (SFILES): Add dwarf2loc.c and dwarf2expr.c.
	(dwarf2expr_h, dwarf2loc_h): New variables.
	(COMMON_OBS): Add dwarf2expr.o and dwarf2loc.o.
	(dwarf2expr.o, dwarf2loc.o): New rules.
	(dwarf2read.o): Add $(dwarf2expr_h) and $(dwarf2loc_h).
	* buildsym.c (finish_block): Handle LOC_COMPUTED and
	LOC_COMPUTED_ARG.
	* findvar.c (symbol_read_needs_frame, read_var_value): Likewise.
	* m2-exp.y (yylex): Likewise.
	* printcmd.c (address_info, print_frame_args): Likewise.
	* stack.c (print_block_frame_locals, print_frame_arg_vars): Likewise.
	* symmisc.c (print_symbol, print_partial_symbols): Likewise.
	* ada-lang.c (ada_resolve_subexp, symtab_for_sym)
	(ada_add_block_symbols, fill_in_ada_prototype): Likewise.
	* symtab.c (lookup_block_symbol): Likewise.
This commit is contained in:
Daniel Jacobowitz 2003-02-21 15:24:18 +00:00
parent 4cf623b60b
commit 4c2df51b5a
16 changed files with 1379 additions and 103 deletions

View file

@ -1,3 +1,35 @@
2003-02-21 Daniel Jacobowitz <drow@mvista.com>
Based on a patch from Daniel Berlin (dberlin@dberlin.org).
* symtab.h: Add opaque declarations of struct axs_value and
struct agent_expr.
(enum address_class): Add LOC_COMPUTED and LOC_COMPUTED_ARG.
(struct location_funcs): New type.
(struct symbol): Add "loc" to aux_value.
(SYMBOL_LOCATION_BATON, SYMBOL_LOCATION_FUNCS): New macros.
* dwarf2read.c: Include "dwarf2expr.h".
(dwarf2_symbol_mark_computed): New function.
(read_func_scope): Use it.
(var_decode_location): New function.
(new_symbol): Use it.
* dwarf2expr.c, dwarf2expr.h, dwarf2loc.c, dwarf2loc.h: New files.
* Makefile.in (SFILES): Add dwarf2loc.c and dwarf2expr.c.
(dwarf2expr_h, dwarf2loc_h): New variables.
(COMMON_OBS): Add dwarf2expr.o and dwarf2loc.o.
(dwarf2expr.o, dwarf2loc.o): New rules.
(dwarf2read.o): Add $(dwarf2expr_h) and $(dwarf2loc_h).
* buildsym.c (finish_block): Handle LOC_COMPUTED and
LOC_COMPUTED_ARG.
* findvar.c (symbol_read_needs_frame, read_var_value): Likewise.
* m2-exp.y (yylex): Likewise.
* printcmd.c (address_info, print_frame_args): Likewise.
* stack.c (print_block_frame_locals, print_frame_arg_vars): Likewise.
* symmisc.c (print_symbol, print_partial_symbols): Likewise.
* ada-lang.c (ada_resolve_subexp, symtab_for_sym)
(ada_add_block_symbols, fill_in_ada_prototype): Likewise.
* symtab.c (lookup_block_symbol): Likewise.
2003-02-20 Adam Fedor <fedor@gnu.org>
* symtab.h: Remove objc_specific struct

View file

@ -513,7 +513,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
complaints.c completer.c corefile.c \
cp-abi.c cp-support.c cp-valprint.c \
dbxread.c demangle.c disasm.c doublest.c \
dummy-frame.c dwarfread.c dwarf2read.c \
dummy-frame.c dwarfread.c dwarf2expr.c dwarf2loc.c dwarf2read.c \
elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \
f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \
frame-unwind.c \
@ -628,6 +628,8 @@ doublest_h = doublest.h $(floatformat_h)
dst_h = dst.h
dummy_frame_h = dummy-frame.h
dwarf2cfi_h = dwarf2cfi.h
dwarf2expr_h = dwarf2expr.h
dwarf2loc_h = dwarf2loc.h
environ_h = environ.h
event_loop_h = event-loop.h
event_top_h = event-top.h
@ -837,6 +839,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \
dbxread.o coffread.o coff-pe-read.o elfread.o \
dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
dwarf2expr.o dwarf2loc.o \
c-lang.o f-lang.o \
ui-out.o cli-out.o \
varobj.o wrapper.o \
@ -1632,11 +1635,16 @@ dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \
dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \
$(objfiles_h) $(target_h) $(elf_dwarf2_h) $(inferior_h) \
$(regcache_h) $(dwarf2cfi_h) $(gdb_assert_h)
dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \
$(gdbcore_h) $(dwarf2expr_h)
dwarf2loc.o: dwarf2loc.c $(defs_h) $(ui_out_h) $(value_h) $(frame_h) \
$(gdbcore_h) $(target_h) $(inferior_h) $(dwarf2expr_h) \
$(dwarf2loc_h) $(gdb_string_h)
dwarf2read.o: dwarf2read.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
$(symfile_h) $(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) \
$(demangle_h) $(expression_h) $(filenames_h) $(macrotab_h) \
$(language_h) $(complaints_h) $(bcache_h) $(gdb_string_h) \
$(gdb_assert_h)
$(language_h) $(complaints_h) $(bcache_h) $(dwarf2expr_h) \
$(dwarf2loc_h) $(gdb_string_h) $(gdb_assert_h)
dwarfread.o: dwarfread.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(symfile_h) \
$(objfiles_h) $(elf_dwarf_h) $(buildsym_h) $(demangle_h) \
$(expression_h) $(language_h) $(complaints_h) $(gdb_string_h)

View file

@ -2172,6 +2172,8 @@ ada_resolve_subexp (struct expression **expp, int *pos, int deprocedure_p,
case LOC_LOCAL_ARG:
case LOC_BASEREG:
case LOC_BASEREG_ARG:
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
goto FoundNonType;
default:
break;
@ -3466,6 +3468,8 @@ symtab_for_sym (struct symbol *sym)
case LOC_LOCAL_ARG:
case LOC_BASEREG:
case LOC_BASEREG_ARG:
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
for (j = FIRST_LOCAL_BLOCK;
j < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); j += 1)
{
@ -3970,6 +3974,7 @@ ada_add_block_symbols (struct block *block, const char *name,
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
arg_sym = sym;
break;
case LOC_UNRESOLVED:
@ -4033,6 +4038,7 @@ ada_add_block_symbols (struct block *block, const char *name,
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
arg_sym = sym;
break;
case LOC_UNRESOLVED:
@ -4117,6 +4123,7 @@ ada_add_block_symbols (struct block *block, const char *name,
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
arg_sym = sym;
break;
case LOC_UNRESOLVED:
@ -4201,6 +4208,7 @@ fill_in_ada_prototype (struct symbol *func)
case LOC_REGPARM:
case LOC_LOCAL_ARG:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
TYPE_FIELD_BITPOS (ftype, nargs) = nargs;
TYPE_FIELD_BITSIZE (ftype, nargs) = 0;
TYPE_FIELD_STATIC_KIND (ftype, nargs) = 0;

View file

@ -309,6 +309,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
nparams++;
break;
case LOC_UNDEF:
@ -324,6 +325,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}
@ -345,6 +347,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_LOCAL_ARG:
case LOC_COMPUTED_ARG:
TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym);
TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
iparams++;
@ -362,6 +365,7 @@ finish_block (struct symbol *symbol, struct pending **listhead,
case LOC_BASEREG:
case LOC_UNRESOLVED:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
default:
break;
}

687
gdb/dwarf2expr.c Normal file
View file

@ -0,0 +1,687 @@
/* Dwarf2 Expression Evaluator
Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Daniel Berlin (dan@dberlin.org)
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "value.h"
#include "gdbcore.h"
#include "elf/dwarf2.h"
#include "dwarf2expr.h"
/* Local prototypes. */
static void execute_stack_op (struct dwarf_expr_context *,
unsigned char *, unsigned char *);
/* Create a new context for the expression evaluator. */
struct dwarf_expr_context *
new_dwarf_expr_context ()
{
struct dwarf_expr_context *retval;
retval = xcalloc (1, sizeof (struct dwarf_expr_context));
retval->stack_len = 10;
retval->stack = xmalloc (10 * sizeof (CORE_ADDR));
return retval;
}
/* Release the memory allocated to CTX. */
void
free_dwarf_expr_context (struct dwarf_expr_context *ctx)
{
xfree (ctx->stack);
xfree (ctx);
}
/* Expand the memory allocated to CTX's stack to contain at least
NEED more elements than are currently used. */
static void
dwarf_expr_grow_stack (struct dwarf_expr_context *ctx, size_t need)
{
if (ctx->stack_len + need > ctx->stack_allocated)
{
size_t templen = ctx->stack_len * 2;
while (templen < (ctx->stack_len + need))
templen *= 2;
ctx->stack = xrealloc (ctx->stack,
templen * sizeof (CORE_ADDR));
ctx->stack_allocated = templen;
}
}
/* Push VALUE onto CTX's stack. */
void
dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value)
{
dwarf_expr_grow_stack (ctx, 1);
ctx->stack[ctx->stack_len++] = value;
}
/* Pop the top item off of CTX's stack. */
void
dwarf_expr_pop (struct dwarf_expr_context *ctx)
{
if (ctx->stack_len <= 0)
error ("dwarf expression stack underflow");
ctx->stack_len--;
}
/* Retrieve the N'th item on CTX's stack. */
CORE_ADDR
dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n)
{
if (ctx->stack_len < n)
error ("Asked for position %d of stack, stack only has %d elements on it\n",
n, ctx->stack_len);
return ctx->stack[ctx->stack_len - (1 + n)];
}
/* Evaluate the expression at ADDR (LEN bytes long) using the context
CTX. */
void
dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr,
size_t len)
{
execute_stack_op (ctx, addr, addr + len);
}
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. Verify that it doesn't extend
past BUF_END. */
static unsigned char *
read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r)
{
unsigned shift = 0;
ULONGEST result = 0;
unsigned char byte;
while (1)
{
if (buf >= buf_end)
error ("read_uleb128: Corrupted DWARF expression.");
byte = *buf++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*r = result;
return buf;
}
/* Decode the signed LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. Verify that it doesn't extend
past BUF_END. */
static unsigned char *
read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r)
{
unsigned shift = 0;
LONGEST result = 0;
unsigned char byte;
while (1)
{
if (buf >= buf_end)
error ("read_sleb128: Corrupted DWARF expression.");
byte = *buf++;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
}
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= -(1 << shift);
*r = result;
return buf;
}
/* Read an address from BUF, and verify that it doesn't extend past
BUF_END. The address is returned, and *BYTES_READ is set to the
number of bytes read from BUF. */
static CORE_ADDR
read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read)
{
CORE_ADDR result;
if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT)
error ("read_address: Corrupted DWARF expression.");
*bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
return result;
}
/* Return the type of an address, for unsigned arithmetic. */
static struct type *
unsigned_address_type (void)
{
switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_uint16;
case 4:
return builtin_type_uint32;
case 8:
return builtin_type_uint64;
default:
internal_error (__FILE__, __LINE__,
"Unsupported address size.\n");
}
}
/* Return the type of an address, for signed arithmetic. */
static struct type *
signed_address_type (void)
{
switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_int16;
case 4:
return builtin_type_int32;
case 8:
return builtin_type_int64;
default:
internal_error (__FILE__, __LINE__,
"Unsupported address size.\n");
}
}
/* The engine for the expression evaluator. Using the context in CTX,
evaluate the expression between OP_PTR and OP_END. */
static void
execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
unsigned char *op_end)
{
while (op_ptr < op_end)
{
enum dwarf_location_atom op = *op_ptr++;
CORE_ADDR result, memaddr;
ULONGEST uoffset, reg;
LONGEST offset;
int bytes_read;
enum lval_type expr_lval;
ctx->in_reg = 0;
switch (op)
{
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:
result = op - DW_OP_lit0;
break;
case DW_OP_addr:
result = read_address (op_ptr, op_end, &bytes_read);
op_ptr += bytes_read;
break;
case DW_OP_const1u:
result = extract_unsigned_integer (op_ptr, 1);
op_ptr += 1;
break;
case DW_OP_const1s:
result = extract_signed_integer (op_ptr, 1);
op_ptr += 1;
break;
case DW_OP_const2u:
result = extract_unsigned_integer (op_ptr, 2);
op_ptr += 2;
break;
case DW_OP_const2s:
result = extract_signed_integer (op_ptr, 2);
op_ptr += 2;
break;
case DW_OP_const4u:
result = extract_unsigned_integer (op_ptr, 4);
op_ptr += 4;
break;
case DW_OP_const4s:
result = extract_signed_integer (op_ptr, 4);
op_ptr += 4;
break;
case DW_OP_const8u:
result = extract_unsigned_integer (op_ptr, 8);
op_ptr += 8;
break;
case DW_OP_const8s:
result = extract_signed_integer (op_ptr, 8);
op_ptr += 8;
break;
case DW_OP_constu:
op_ptr = read_uleb128 (op_ptr, op_end, &uoffset);
result = uoffset;
break;
case DW_OP_consts:
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
result = offset;
break;
/* 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:
/* NOTE: in the presence of DW_OP_piece this check is incorrect. */
if (op_ptr != op_end)
error ("DWARF-2 expression error: DW_OP_reg operations must be "
"used alone.");
/* FIXME drow/2003-02-21: This call to read_reg could be pushed
into the evaluator's caller by changing the semantics for in_reg.
Then we wouldn't need to return an lval_type and a memaddr. */
result = (ctx->read_reg) (ctx->baton, op - DW_OP_reg0, &expr_lval,
&memaddr);
if (expr_lval == lval_register)
{
ctx->regnum = op - DW_OP_reg0;
ctx->in_reg = 1;
}
else
result = memaddr;
break;
case DW_OP_regx:
op_ptr = read_uleb128 (op_ptr, op_end, &reg);
if (op_ptr != op_end)
error ("DWARF-2 expression error: DW_OP_reg operations must be "
"used alone.");
result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr);
if (expr_lval == lval_register)
{
ctx->regnum = reg;
ctx->in_reg = 1;
}
else
result = memaddr;
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:
{
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0,
&expr_lval, &memaddr);
result += offset;
}
break;
case DW_OP_bregx:
{
op_ptr = read_uleb128 (op_ptr, op_end, &reg);
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr);
result += offset;
}
break;
case DW_OP_fbreg:
{
unsigned char *datastart;
size_t datalen;
unsigned int before_stack_len;
op_ptr = read_sleb128 (op_ptr, op_end, &offset);
/* Rather than create a whole new context, we simply
record the stack length before execution, then reset it
afterwards, effectively erasing whatever the recursive
call put there. */
before_stack_len = ctx->stack_len;
(ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
dwarf_expr_eval (ctx, datastart, datalen);
result = dwarf_expr_fetch (ctx, 0);
if (! ctx->in_reg)
{
char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
int bytes_read;
(ctx->read_mem) (ctx->baton, buf, result,
TARGET_ADDR_BIT / TARGET_CHAR_BIT);
result = read_address (buf,
buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
&bytes_read);
}
result = result + offset;
ctx->stack_len = before_stack_len;
ctx->in_reg = 0;
}
break;
case DW_OP_dup:
result = dwarf_expr_fetch (ctx, 0);
break;
case DW_OP_drop:
dwarf_expr_pop (ctx);
goto no_push;
case DW_OP_pick:
offset = *op_ptr++;
result = dwarf_expr_fetch (ctx, offset);
break;
case DW_OP_over:
result = dwarf_expr_fetch (ctx, 1);
break;
case DW_OP_rot:
{
CORE_ADDR t1, t2, t3;
if (ctx->stack_len < 3)
error ("Not enough elements for DW_OP_rot. Need 3, have %d\n",
ctx->stack_len);
t1 = ctx->stack[ctx->stack_len - 1];
t2 = ctx->stack[ctx->stack_len - 2];
t3 = ctx->stack[ctx->stack_len - 3];
ctx->stack[ctx->stack_len - 1] = t2;
ctx->stack[ctx->stack_len - 2] = t3;
ctx->stack[ctx->stack_len - 3] = t1;
goto no_push;
}
case DW_OP_deref:
case DW_OP_deref_size:
case DW_OP_abs:
case DW_OP_neg:
case DW_OP_not:
case DW_OP_plus_uconst:
/* Unary operations. */
result = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
switch (op)
{
case DW_OP_deref:
{
char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
int bytes_read;
(ctx->read_mem) (ctx->baton, buf, result,
TARGET_ADDR_BIT / TARGET_CHAR_BIT);
result = read_address (buf,
buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
&bytes_read);
}
break;
case DW_OP_deref_size:
{
char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
int bytes_read;
(ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
result = read_address (buf,
buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
&bytes_read);
}
break;
case DW_OP_abs:
if ((signed int) result < 0)
result = -result;
break;
case DW_OP_neg:
result = -result;
break;
case DW_OP_not:
result = ~result;
break;
case DW_OP_plus_uconst:
op_ptr = read_uleb128 (op_ptr, op_end, &reg);
result += reg;
break;
}
break;
case DW_OP_and:
case DW_OP_div:
case DW_OP_minus:
case DW_OP_mod:
case DW_OP_mul:
case DW_OP_or:
case DW_OP_plus:
case DW_OP_shl:
case DW_OP_shr:
case DW_OP_shra:
case DW_OP_xor:
case DW_OP_le:
case DW_OP_ge:
case DW_OP_eq:
case DW_OP_lt:
case DW_OP_gt:
case DW_OP_ne:
{
/* Binary operations. Use the value engine to do computations in
the right width. */
CORE_ADDR first, second;
enum exp_opcode binop;
struct value *val1, *val2;
second = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
first = dwarf_expr_fetch (ctx, 1);
dwarf_expr_pop (ctx);
val1 = value_from_longest (unsigned_address_type (), first);
val2 = value_from_longest (unsigned_address_type (), second);
switch (op)
{
case DW_OP_and:
binop = BINOP_BITWISE_AND;
break;
case DW_OP_div:
binop = BINOP_DIV;
case DW_OP_minus:
binop = BINOP_SUB;
break;
case DW_OP_mod:
binop = BINOP_MOD;
break;
case DW_OP_mul:
binop = BINOP_MUL;
break;
case DW_OP_or:
binop = BINOP_BITWISE_IOR;
break;
case DW_OP_plus:
binop = BINOP_ADD;
break;
case DW_OP_shl:
binop = BINOP_LSH;
break;
case DW_OP_shr:
binop = BINOP_RSH;
case DW_OP_shra:
binop = BINOP_RSH;
val1 = value_from_longest (signed_address_type (), first);
break;
case DW_OP_xor:
binop = BINOP_BITWISE_XOR;
break;
case DW_OP_le:
binop = BINOP_LEQ;
break;
case DW_OP_ge:
binop = BINOP_GEQ;
break;
case DW_OP_eq:
binop = BINOP_EQUAL;
break;
case DW_OP_lt:
binop = BINOP_LESS;
break;
case DW_OP_gt:
binop = BINOP_GTR;
break;
case DW_OP_ne:
binop = BINOP_NOTEQUAL;
break;
default:
internal_error (__FILE__, __LINE__,
"Can't be reached.");
}
result = value_as_long (value_binop (val1, val2, binop));
}
break;
case DW_OP_GNU_push_tls_address:
result = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);
result = (ctx->get_tls_address) (ctx->baton, result);
break;
case DW_OP_skip:
offset = extract_signed_integer (op_ptr, 2);
op_ptr += 2;
op_ptr += offset;
goto no_push;
case DW_OP_bra:
offset = extract_signed_integer (op_ptr, 2);
op_ptr += 2;
if (dwarf_expr_fetch (ctx, 0) != 0)
op_ptr += offset;
dwarf_expr_pop (ctx);
goto no_push;
case DW_OP_nop:
goto no_push;
default:
error ("Unhandled dwarf expression opcode");
}
/* Most things push a result value. */
dwarf_expr_push (ctx, result);
no_push:;
}
}

97
gdb/dwarf2expr.h Normal file
View file

@ -0,0 +1,97 @@
/* Dwarf2 Expression Evaluator
Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Daniel Berlin (dan@dberlin.org)
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#if !defined (DWARF2EXPR_H)
#define DWARF2EXPR_H
/* The expression evaluator works with a dwarf_expr_context, describing
its current state and its callbacks. */
struct dwarf_expr_context
{
/* The stack of values, allocated with xmalloc. */
CORE_ADDR *stack;
/* The number of values currently pushed on the stack, and the
number of elements allocated to the stack. */
int stack_len, stack_allocated;
/* An opaque argument provided by the caller, which will be passed
to all of the callback functions. */
void *baton;
/* Return the value of register number REGNUM. LVALP will be set
to the kind of lval this register is (generally lval_register
for the current frame's registers or lval_memory for a register
saved to the stack). For lval_memory ADDRP will be set to the
saved location of the register. */
CORE_ADDR (*read_reg) (void *baton, int regnum, enum lval_type *lvalp,
CORE_ADDR *addrp);
/* Read LENGTH bytes at ADDR into BUF. */
void (*read_mem) (void *baton, char *buf, CORE_ADDR addr,
size_t length);
/* Return the location expression for the frame base attribute, in
START and LENGTH. The result must be live until the current
expression evaluation is complete. */
void (*get_frame_base) (void *baton, unsigned char **start,
size_t *length);
/* Return the thread-local storage address for
DW_OP_GNU_push_tls_address. */
CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset);
#if 0
/* Not yet implemented. */
/* Return the location expression for the dwarf expression
subroutine in the die at OFFSET in the current compilation unit.
The result must be live until the current expression evaluation
is complete. */
unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length);
/* Return the `object address' for DW_OP_push_object_address. */
CORE_ADDR (*get_object_address) (void *baton);
#endif
/* The current depth of dwarf expression recursion, via DW_OP_call*,
DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
depth we'll tolerate before raising an error. */
int recursion_depth, max_recursion_depth;
/* Non-zero if the result is in a register. The register number
will be in REGNUM, and the result will be the contents of the
register. */
int in_reg;
/* If the result is in a register, the register number. */
int regnum;
};
struct dwarf_expr_context *new_dwarf_expr_context ();
void free_dwarf_expr_context (struct dwarf_expr_context *ctx);
void dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value);
void dwarf_expr_pop (struct dwarf_expr_context *ctx);
void dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr,
size_t len);
CORE_ADDR dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n);
#endif

287
gdb/dwarf2loc.c Normal file
View file

@ -0,0 +1,287 @@
/* DWARF 2 location expression support for GDB.
Copyright 2003 Free Software Foundation, Inc.
Contributed by Daniel Jacobowitz, MontaVista Software, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "ui-out.h"
#include "value.h"
#include "frame.h"
#include "gdbcore.h"
#include "target.h"
#include "inferior.h"
#include "elf/dwarf2.h"
#include "dwarf2expr.h"
#include "dwarf2loc.h"
#include "gdb_string.h"
#ifndef DWARF2_REG_TO_REGNUM
#define DWARF2_REG_TO_REGNUM(REG) (REG)
#endif
/* This is the baton used when performing dwarf2 expression
evaluation. */
struct dwarf_expr_baton
{
struct frame_info *frame;
struct objfile *objfile;
};
/* Helper functions for dwarf2_evaluate_loc_desc. */
/* Using the frame specified in BATON, read register REGNUM. The lval
type will be returned in LVALP, and for lval_memory the register
save address will be returned in ADDRP. */
static CORE_ADDR
dwarf_expr_read_reg (void *baton, int regnum, enum lval_type *lvalp,
CORE_ADDR *addrp)
{
CORE_ADDR result;
struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
char *buf = (char *) alloca (MAX_REGISTER_RAW_SIZE);
int optimized, realnum;
frame_register (debaton->frame, DWARF2_REG_TO_REGNUM (regnum),
&optimized, lvalp, addrp, &realnum, buf);
result = extract_address (buf, REGISTER_RAW_SIZE (regnum));
return result;
}
/* Read memory at ADDR (length LEN) into BUF. */
static void
dwarf_expr_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len)
{
read_memory (addr, buf, len);
}
/* Using the frame specified in BATON, find the location expression
describing the frame base. Return a pointer to it in START and
its length in LENGTH. */
static void
dwarf_expr_frame_base (void *baton, unsigned char **start, size_t * length)
{
struct symbol *framefunc;
struct dwarf2_locexpr_baton *symbaton;
struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
framefunc = get_frame_function (debaton->frame);
symbaton = SYMBOL_LOCATION_BATON (framefunc);
*start = symbaton->data;
*length = symbaton->size;
}
/* Using the objfile specified in BATON, find the address for the
current thread's thread-local storage with offset OFFSET. */
static CORE_ADDR
dwarf_expr_tls_address (void *baton, CORE_ADDR offset)
{
struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
CORE_ADDR addr;
if (target_get_thread_local_address_p ())
addr = target_get_thread_local_address (inferior_ptid,
debaton->objfile,
offset);
else
error ("Cannot find thread-local variables on this target");
return addr;
}
/* Evaluate a location description, starting at DATA and with length
SIZE, to find the current location of variable VAR in the context
of FRAME. */
static struct value *
dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
unsigned char *data, unsigned short size,
struct objfile *objfile)
{
CORE_ADDR result;
struct value *retval;
struct dwarf_expr_baton baton;
struct dwarf_expr_context *ctx;
baton.frame = frame;
baton.objfile = objfile;
ctx = new_dwarf_expr_context ();
ctx->baton = &baton;
ctx->read_reg = dwarf_expr_read_reg;
ctx->read_mem = dwarf_expr_read_mem;
ctx->get_frame_base = dwarf_expr_frame_base;
ctx->get_tls_address = dwarf_expr_tls_address;
dwarf_expr_eval (ctx, data, size);
retval = allocate_value (SYMBOL_TYPE (var));
VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var);
if (ctx->in_reg)
{
store_unsigned_integer (VALUE_CONTENTS_RAW (retval),
TYPE_LENGTH (SYMBOL_TYPE (var)),
dwarf_expr_fetch (ctx, 0));
VALUE_LVAL (retval) = lval_register;
VALUE_REGNO (retval) = ctx->regnum;
}
else
{
result = dwarf_expr_fetch (ctx, 0);
VALUE_LVAL (retval) = lval_memory;
VALUE_LAZY (retval) = 1;
VALUE_ADDRESS (retval) = result;
}
free_dwarf_expr_context (ctx);
return retval;
}
/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
struct needs_frame_baton
{
int needs_frame;
};
/* Reads from registers do require a frame. */
static CORE_ADDR
needs_frame_read_reg (void *baton, int regnum, enum lval_type *lvalp,
CORE_ADDR *addrp)
{
struct needs_frame_baton *nf_baton = baton;
nf_baton->needs_frame = 1;
return 1;
}
/* Reads from memory do not require a frame. */
static void
needs_frame_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len)
{
memset (buf, 0, len);
}
/* Frame-relative accesses do require a frame. */
static void
needs_frame_frame_base (void *baton, unsigned char **start, size_t * length)
{
static char lit0 = DW_OP_lit0;
struct needs_frame_baton *nf_baton = baton;
*start = &lit0;
*length = 1;
nf_baton->needs_frame = 1;
}
/* Thread-local accesses do require a frame. */
static CORE_ADDR
needs_frame_tls_address (void *baton, CORE_ADDR offset)
{
struct needs_frame_baton *nf_baton = baton;
nf_baton->needs_frame = 1;
return 1;
}
/* Return non-zero iff the location expression at DATA (length SIZE)
requires a frame to evaluate. */
static int
dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size)
{
struct needs_frame_baton baton;
struct dwarf_expr_context *ctx;
baton.needs_frame = 0;
ctx = new_dwarf_expr_context ();
ctx->baton = &baton;
ctx->read_reg = needs_frame_read_reg;
ctx->read_mem = needs_frame_read_mem;
ctx->get_frame_base = needs_frame_frame_base;
ctx->get_tls_address = needs_frame_tls_address;
dwarf_expr_eval (ctx, data, size);
free_dwarf_expr_context (ctx);
return baton.needs_frame;
}
/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
evaluator to calculate the location. */
static struct value *
locexpr_read_variable (struct symbol *symbol, struct frame_info *frame)
{
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
struct value *val;
val = dwarf2_evaluate_loc_desc (symbol, frame, dlbaton->data, dlbaton->size,
dlbaton->objfile);
return val;
}
/* Return non-zero iff we need a frame to evaluate SYMBOL. */
static int
locexpr_read_needs_frame (struct symbol *symbol)
{
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size);
}
/* Print a natural-language description of SYMBOL to STREAM. */
static int
locexpr_describe_location (struct symbol *symbol, struct ui_file *stream)
{
/* FIXME: be more extensive. */
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
if (dlbaton->size == 1
&& dlbaton->data[0] >= DW_OP_reg0
&& dlbaton->data[0] <= DW_OP_reg31)
{
int regno = DWARF2_REG_TO_REGNUM (dlbaton->data[0] - DW_OP_reg0);
fprintf_filtered (stream,
"a variable in register %s", REGISTER_NAME (regno));
return 1;
}
fprintf_filtered (stream,
"a variable with complex or multiple locations (DWARF2)");
return 1;
}
/* The set of location functions used with the DWARF-2 expression
evaluator. */
struct location_funcs dwarf2_locexpr_funcs = {
locexpr_read_variable,
locexpr_read_needs_frame,
locexpr_describe_location,
NULL
};

39
gdb/dwarf2loc.h Normal file
View file

@ -0,0 +1,39 @@
/* Dwarf2 location expression support for GDB.
Copyright 2003 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#if !defined (DWARF2LOC_H)
#define DWARF2LOC_H
/* This header is private to the DWARF-2 reader. It is shared between
dwarf2read.c and dwarf2loc.c. */
/* The symbol location baton type used by the DWARF-2 reader (i.e.
SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol). */
struct dwarf2_locexpr_baton
{
unsigned char *data;
unsigned short size;
struct objfile *objfile;
};
extern struct location_funcs dwarf2_locexpr_funcs;
#endif

View file

@ -38,10 +38,12 @@
#include "expression.h"
#include "filenames.h" /* for DOSish file names */
#include "macrotab.h"
#include "language.h"
#include "complaints.h"
#include "bcache.h"
#include "dwarf2expr.h"
#include "dwarf2loc.h"
#include <fcntl.h>
#include "gdb_string.h"
#include "gdb_assert.h"
@ -905,6 +907,11 @@ static void dwarf_decode_macros (struct line_header *, unsigned int,
static int attr_form_is_block (struct attribute *);
static void
dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
const struct comp_unit_head *,
struct objfile *objfile);
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
@ -1998,6 +2005,13 @@ read_func_scope (struct die_info *die, struct objfile *objfile,
new = push_context (0, lowpc);
new->name = new_symbol (die, die->type, objfile, cu_header);
/* If there was a location expression for DW_AT_frame_base above,
record it. We still need to decode it above because not all
symbols use location expressions exclusively. */
if (attr)
dwarf2_symbol_mark_computed (attr, new->name, cu_header, objfile);
list_in_scope = &local_symbols;
if (die->has_children)
@ -4930,6 +4944,61 @@ dwarf2_start_subfile (char *filename, char *dirname)
start_subfile (filename, dirname);
}
static void
var_decode_location (struct attribute *attr, struct symbol *sym,
struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
/* NOTE drow/2003-01-30: There used to be a comment and some special
code here to turn a symbol with DW_AT_external and a
SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was
necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux
with some versions of binutils) where shared libraries could have
relocations against symbols in their debug information - the
minimal symbol would have the right address, but the debug info
would not. It's no longer necessary, because we will explicitly
apply relocations when we read in the debug information now. */
/* A DW_AT_location attribute with no contents indicates that a
variable has been optimized away. */
if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0)
{
SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
return;
}
/* Handle one degenerate form of location expression specially, to
preserve GDB's previous behavior when section offsets are
specified. If this is just a DW_OP_addr then mark this symbol
as LOC_STATIC. */
if (attr_form_is_block (attr)
&& DW_BLOCK (attr)->size == 1 + cu_header->addr_size
&& DW_BLOCK (attr)->data[0] == DW_OP_addr)
{
int dummy;
SYMBOL_VALUE_ADDRESS (sym) =
read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu_header,
&dummy);
fixup_symbol_section (sym, objfile);
SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets,
SYMBOL_SECTION (sym));
SYMBOL_CLASS (sym) = LOC_STATIC;
return;
}
/* NOTE drow/2002-01-30: It might be worthwhile to have a static
expression evaluator, and use LOC_COMPUTED only when necessary
(i.e. when the value of a register or memory location is
referenced, or a thread-local block, etc.). Then again, it might
not be worthwhile. I'm assuming that it isn't unless performance
or memory numbers show me otherwise. */
dwarf2_symbol_mark_computed (attr, sym, cu_header, objfile);
SYMBOL_CLASS (sym) = LOC_COMPUTED;
}
/* Given a pointer to a DWARF information entry, figure out if we need
to make a symbol table entry for it, and if so, create a new entry
and return a pointer to it.
@ -5018,106 +5087,12 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile,
attr = dwarf_attr (die, DW_AT_location);
if (attr)
{
var_decode_location (attr, sym, objfile, cu_header);
attr2 = dwarf_attr (die, DW_AT_external);
if (attr2 && (DW_UNSND (attr2) != 0))
{
/* Support the .debug_loc offsets */
if (attr_form_is_block (attr))
{
SYMBOL_VALUE_ADDRESS (sym) =
decode_locdesc (DW_BLOCK (attr), objfile, cu_header);
}
else if (attr->form == DW_FORM_data4
|| attr->form == DW_FORM_data8)
{
dwarf2_complex_location_expr_complaint ();
}
else
{
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
"external variable");
}
add_symbol_to_list (sym, &global_symbols);
if (is_thread_local)
{
/* SYMBOL_VALUE_ADDRESS contains at this point the
offset of the variable within the thread local
storage. */
SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC;
SYMBOL_OBJFILE (sym) = objfile;
}
/* In shared libraries the address of the variable
in the location descriptor might still be relocatable,
so its value could be zero.
Enter the symbol as a LOC_UNRESOLVED symbol, if its
value is zero, the address of the variable will then
be determined from the minimal symbol table whenever
the variable is referenced. */
else if (SYMBOL_VALUE_ADDRESS (sym))
{
fixup_symbol_section (sym, objfile);
SYMBOL_VALUE_ADDRESS (sym) +=
ANOFFSET (objfile->section_offsets,
SYMBOL_SECTION (sym));
SYMBOL_CLASS (sym) = LOC_STATIC;
}
else
SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
}
add_symbol_to_list (sym, &global_symbols);
else
{
/* Support the .debug_loc offsets */
if (attr_form_is_block (attr))
{
SYMBOL_VALUE (sym) = addr =
decode_locdesc (DW_BLOCK (attr), objfile, cu_header);
}
else if (attr->form == DW_FORM_data4
|| attr->form == DW_FORM_data8)
{
dwarf2_complex_location_expr_complaint ();
}
else
{
dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
"external variable");
addr = 0;
}
add_symbol_to_list (sym, list_in_scope);
if (optimized_out)
{
SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
}
else if (isreg)
{
SYMBOL_CLASS (sym) = LOC_REGISTER;
SYMBOL_VALUE (sym) =
DWARF2_REG_TO_REGNUM (SYMBOL_VALUE (sym));
}
else if (offreg)
{
SYMBOL_CLASS (sym) = LOC_BASEREG;
SYMBOL_BASEREG (sym) = DWARF2_REG_TO_REGNUM (basereg);
}
else if (islocal)
{
SYMBOL_CLASS (sym) = LOC_LOCAL;
}
else if (is_thread_local)
{
SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC;
SYMBOL_OBJFILE (sym) = objfile;
}
else
{
fixup_symbol_section (sym, objfile);
SYMBOL_VALUE_ADDRESS (sym) =
addr + ANOFFSET (objfile->section_offsets,
SYMBOL_SECTION (sym));
SYMBOL_CLASS (sym) = LOC_STATIC;
}
}
add_symbol_to_list (sym, list_in_scope);
}
else
{
@ -7347,3 +7322,32 @@ attr_form_is_block (struct attribute *attr)
|| attr->form == DW_FORM_block4
|| attr->form == DW_FORM_block);
}
static void
dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
const struct comp_unit_head *cu_header,
struct objfile *objfile)
{
struct dwarf2_locexpr_baton *baton;
/* When support for location lists is added, this will go away. */
if (!attr_form_is_block (attr))
{
dwarf2_complex_location_expr_complaint ();
return;
}
baton = obstack_alloc (&objfile->symbol_obstack,
sizeof (struct dwarf2_locexpr_baton));
baton->objfile = objfile;
/* Note that we're just copying the block's data pointer here, not
the actual data. We're still pointing into the dwarf_info_buffer
for SYM's objfile; right now we never release that buffer, but
when we do clean up properly this may need to change. */
baton->size = DW_BLOCK (attr)->size;
baton->data = DW_BLOCK (attr)->data;
SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
SYMBOL_LOCATION_BATON (sym) = baton;
}

View file

@ -384,6 +384,14 @@ symbol_read_needs_frame (struct symbol *sym)
{
/* All cases listed explicitly so that gcc -Wall will detect it if
we failed to consider one. */
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
{
struct location_funcs *symfuncs = SYMBOL_LOCATION_FUNCS (sym);
return (symfuncs->read_needs_frame) (sym);
}
break;
case LOC_REGISTER:
case LOC_ARG:
case LOC_REF_ARG:
@ -605,6 +613,18 @@ addresses have not been bound by the dynamic loader. Try again when executable i
}
break;
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
{
struct location_funcs *funcs = SYMBOL_LOCATION_FUNCS (var);
if (frame == 0 && (funcs->read_needs_frame) (var))
return 0;
return (funcs->read_variable) (var, frame);
}
break;
case LOC_UNRESOLVED:
{
struct minimal_symbol *msym;

View file

@ -1041,6 +1041,8 @@ yylex ()
case LOC_CONST:
case LOC_CONST_BYTES:
case LOC_OPTIMIZED_OUT:
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
return NAME;
case LOC_TYPEDEF:

View file

@ -1149,6 +1149,11 @@ address_info (char *exp, int from_tty)
}
break;
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
(SYMBOL_LOCATION_FUNCS (sym)->describe_location) (sym, gdb_stdout);
break;
case LOC_REGISTER:
printf_filtered ("a variable in register %s", REGISTER_NAME (val));
break;
@ -1814,6 +1819,7 @@ print_frame_args (struct symbol *func, struct frame_info *fi, int num,
case LOC_REGPARM_ADDR:
case LOC_LOCAL_ARG:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
break;
/* Other types of symbols we just skip over. */

View file

@ -1083,6 +1083,7 @@ print_block_frame_locals (struct block *b, register struct frame_info *fi,
case LOC_REGISTER:
case LOC_STATIC:
case LOC_BASEREG:
case LOC_COMPUTED:
values_printed = 1;
for (j = 0; j < num_tabs; j++)
fputs_filtered ("\t", stream);
@ -1309,6 +1310,7 @@ print_frame_arg_vars (register struct frame_info *fi,
case LOC_REGPARM:
case LOC_REGPARM_ADDR:
case LOC_BASEREG_ARG:
case LOC_COMPUTED_ARG:
values_printed = 1;
fputs_filtered (SYMBOL_PRINT_NAME (sym), stream);
fputs_filtered (" = ", stream);

View file

@ -752,6 +752,11 @@ print_symbol (void *args)
SYMBOL_BFD_SECTION (symbol)));
break;
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
fprintf_filtered (outfile, "computed at runtime");
break;
case LOC_UNRESOLVED:
fprintf_filtered (outfile, "unresolved");
break;
@ -903,6 +908,10 @@ print_partial_symbols (struct partial_symbol **p, int count, char *what,
case LOC_OPTIMIZED_OUT:
fputs_filtered ("optimized out", outfile);
break;
case LOC_COMPUTED:
case LOC_COMPUTED_ARG:
fputs_filtered ("computed at runtime", outfile);
break;
default:
fputs_filtered ("<invalid location>", outfile);
break;

View file

@ -1739,7 +1739,8 @@ lookup_block_symbol (register const struct block *block, const char *name,
SYMBOL_CLASS (sym) != LOC_REF_ARG &&
SYMBOL_CLASS (sym) != LOC_REGPARM &&
SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR &&
SYMBOL_CLASS (sym) != LOC_BASEREG_ARG)
SYMBOL_CLASS (sym) != LOC_BASEREG_ARG &&
SYMBOL_CLASS (sym) != LOC_COMPUTED_ARG)
{
break;
}

View file

@ -30,6 +30,8 @@ struct obstack;
struct objfile;
struct block;
struct blockvector;
struct axs_value;
struct agent_expr;
/* Don't do this; it means that if some .o's are compiled with GNU C
and some are not (easy to do accidentally the way we configure
@ -474,7 +476,58 @@ enum address_class
* with a level of indirection.
*/
LOC_INDIRECT
LOC_INDIRECT,
/* The variable's address is computed by a set of location
functions (see "struct location_funcs" below). */
LOC_COMPUTED,
/* Same as LOC_COMPUTED, but for function arguments. */
LOC_COMPUTED_ARG
};
/* A structure of function pointers describing the location of a
variable, structure member, or structure base class.
These functions' BATON arguments are generic data pointers, holding
whatever data the functions need --- the code which provides this
structure also provides the actual contents of the baton, and
decides its form. However, there may be other rules about where
the baton data must be allocated; whoever is pointing to this
`struct location_funcs' object will know the rules. For example,
when a symbol S's location is LOC_COMPUTED, then
SYMBOL_LOCATION_FUNCS(S) is pointing to a location_funcs structure,
and SYMBOL_LOCATION_BATON(S) is the baton, which must be allocated
on the same obstack as the symbol itself. */
struct location_funcs
{
/* Return the value of the variable SYMBOL, relative to the stack
frame FRAME. If the variable has been optimized out, return
zero.
Iff `read_needs_frame (SYMBOL)' is zero, then FRAME may be zero. */
struct value *(*read_variable) (struct symbol * symbol,
struct frame_info * frame);
/* Return non-zero if we need a frame to find the value of the SYMBOL. */
int (*read_needs_frame) (struct symbol * symbol);
/* Write to STREAM a natural-language description of the location of
SYMBOL. */
int (*describe_location) (struct symbol * symbol, struct ui_file * stream);
/* Tracepoint support. Append bytecodes to the tracepoint agent
expression AX that push the address of the object SYMBOL. Set
VALUE appropriately. Note --- for objects in registers, this
needn't emit any code; as long as it sets VALUE properly, then
the caller will generate the right code in the process of
treating this as an lvalue or rvalue. */
void (*tracepoint_var_ref) (struct symbol * symbol, struct agent_expr * ax,
struct axs_value * value);
};
/* Linked list of symbol's live ranges. */
@ -536,6 +589,21 @@ struct symbol
variable declared with the `__thread' storage class), we may
need to know which object file it's in. */
struct objfile *objfile;
/* For a LOC_COMPUTED or LOC_COMPUTED_ARG symbol, this is the
baton and location_funcs structure to find its location. For a
LOC_BLOCK symbol for a function in a compilation unit compiled
with DWARF 2 information, this is information used internally
by the DWARF 2 code --- specifically, the location expression
for the frame base for this function. */
/* FIXME drow/2003-02-21: For the LOC_BLOCK case, it might be better
to add a magic symbol to the block containing this information,
or to have a generic debug info annotation slot for symbols. */
struct
{
void *baton;
struct location_funcs *funcs;
} loc;
}
aux_value;
@ -560,6 +628,8 @@ struct symbol
#define SYMBOL_OBJFILE(symbol) (symbol)->aux_value.objfile
#define SYMBOL_ALIASES(symbol) (symbol)->aliases
#define SYMBOL_RANGES(symbol) (symbol)->ranges
#define SYMBOL_LOCATION_BATON(symbol) (symbol)->aux_value.loc.baton
#define SYMBOL_LOCATION_FUNCS(symbol) (symbol)->aux_value.loc.funcs
/* A partial_symbol records the name, namespace, and address class of
symbols whose types we have not parsed yet. For functions, it also