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:
parent
4cf623b60b
commit
4c2df51b5a
16 changed files with 1379 additions and 103 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
687
gdb/dwarf2expr.c
Normal 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, ®);
|
||||
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, ®);
|
||||
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, ®);
|
||||
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
97
gdb/dwarf2expr.h
Normal 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
287
gdb/dwarf2loc.c
Normal 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
39
gdb/dwarf2loc.h
Normal 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
|
200
gdb/dwarf2read.c
200
gdb/dwarf2read.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
72
gdb/symtab.h
72
gdb/symtab.h
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue