mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-24 12:39:59 +00:00
gdb/
Implement basic support for DW_TAG_GNU_call_site. * block.c: Include gdbtypes.h and exceptions.h. (call_site_for_pc): New function. * block.h (call_site_for_pc): New declaration. * defs.h: Include hashtab.h. (make_cleanup_htab_delete, core_addr_hash, core_addr_eq): New declarations. * dwarf2-frame.c (dwarf2_frame_ctx_funcs): Install ctx_no_push_dwarf_reg_entry_value. * dwarf2expr.c (read_uleb128, read_sleb128): Support R as NULL. (dwarf_block_to_dwarf_reg): New function. (execute_stack_op) <DW_OP_GNU_entry_value>: Implement it. (ctx_no_push_dwarf_reg_entry_value): New function. * dwarf2expr.h (struct dwarf_expr_context_funcs): New field push_dwarf_reg_entry_value. (ctx_no_push_dwarf_reg_entry_value, dwarf_block_to_dwarf_reg): New declarations. * dwarf2loc.c: Include gdbcmd.h. (dwarf_expr_ctx_funcs): New forward declaration. (entry_values_debug, show_entry_values_debug, call_site_to_target_addr) (dwarf_expr_reg_to_entry_parameter) (dwarf_expr_push_dwarf_reg_entry_value): New. (dwarf_expr_ctx_funcs): Install dwarf_expr_push_dwarf_reg_entry_value. (dwarf2_evaluate_loc_desc_full): Handle NO_ENTRY_VALUE_ERROR. (needs_dwarf_reg_entry_value): New function. (needs_frame_ctx_funcs): Install it. (_initialize_dwarf2loc): New function. * dwarf2loc.h (entry_values_debug): New declaration. * dwarf2read.c (struct dwarf2_cu): New field call_site_htab. (read_call_site_scope): New forward declaration. (process_full_comp_unit): Copy call_site_htab. (process_die): Support DW_TAG_GNU_call_site. (read_call_site_scope): New function. (dwarf2_get_pc_bounds): Support NULL HIGHPC. (dwarf_tag_name): Support DW_TAG_GNU_call_site. (cleanup_htab): Delete. (write_psymtabs_to_index): Use make_cleanup_htab_delete instead of it. * exceptions.h (enum errors): New NO_ENTRY_VALUE_ERROR. * gdb-gdb.py (StructMainTypePrettyPrinter): Support FIELD_LOC_KIND_DWARF_BLOCK. * gdbtypes.h (enum field_loc_kind): New entry FIELD_LOC_KIND_DWARF_BLOCK. (struct main_type): New loc entry dwarf_block. (struct call_site, FIELD_DWARF_BLOCK, SET_FIELD_DWARF_BLOCK) (TYPE_FIELD_DWARF_BLOCK): New. * python/py-type.c: Include dwarf2loc.h. (check_types_equal): Support FIELD_LOC_KIND_DWARF_BLOCK. New internal_error call on unknown FIELD_LOC_KIND. * symtab.h (struct symtab): New field call_site_htab. * utils.c (do_htab_delete_cleanup, make_cleanup_htab_delete) (core_addr_hash, core_addr_eq): New functions. gdb/testsuite/ Implement basic support for DW_TAG_GNU_call_site. * gdb.arch/Makefile.in (EXECUTABLES): Add amd64-entry-value. * gdb.arch/amd64-entry-value.cc: New file. * gdb.arch/amd64-entry-value.exp: New file.
This commit is contained in:
parent
b6cdc2c1b5
commit
8e3b41a906
@ -1,3 +1,57 @@
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Implement basic support for DW_TAG_GNU_call_site.
|
||||
* block.c: Include gdbtypes.h and exceptions.h.
|
||||
(call_site_for_pc): New function.
|
||||
* block.h (call_site_for_pc): New declaration.
|
||||
* defs.h: Include hashtab.h.
|
||||
(make_cleanup_htab_delete, core_addr_hash, core_addr_eq): New
|
||||
declarations.
|
||||
* dwarf2-frame.c (dwarf2_frame_ctx_funcs): Install
|
||||
ctx_no_push_dwarf_reg_entry_value.
|
||||
* dwarf2expr.c (read_uleb128, read_sleb128): Support R as NULL.
|
||||
(dwarf_block_to_dwarf_reg): New function.
|
||||
(execute_stack_op) <DW_OP_GNU_entry_value>: Implement it.
|
||||
(ctx_no_push_dwarf_reg_entry_value): New function.
|
||||
* dwarf2expr.h (struct dwarf_expr_context_funcs): New field
|
||||
push_dwarf_reg_entry_value.
|
||||
(ctx_no_push_dwarf_reg_entry_value, dwarf_block_to_dwarf_reg): New
|
||||
declarations.
|
||||
* dwarf2loc.c: Include gdbcmd.h.
|
||||
(dwarf_expr_ctx_funcs): New forward declaration.
|
||||
(entry_values_debug, show_entry_values_debug, call_site_to_target_addr)
|
||||
(dwarf_expr_reg_to_entry_parameter)
|
||||
(dwarf_expr_push_dwarf_reg_entry_value): New.
|
||||
(dwarf_expr_ctx_funcs): Install dwarf_expr_push_dwarf_reg_entry_value.
|
||||
(dwarf2_evaluate_loc_desc_full): Handle NO_ENTRY_VALUE_ERROR.
|
||||
(needs_dwarf_reg_entry_value): New function.
|
||||
(needs_frame_ctx_funcs): Install it.
|
||||
(_initialize_dwarf2loc): New function.
|
||||
* dwarf2loc.h (entry_values_debug): New declaration.
|
||||
* dwarf2read.c (struct dwarf2_cu): New field call_site_htab.
|
||||
(read_call_site_scope): New forward declaration.
|
||||
(process_full_comp_unit): Copy call_site_htab.
|
||||
(process_die): Support DW_TAG_GNU_call_site.
|
||||
(read_call_site_scope): New function.
|
||||
(dwarf2_get_pc_bounds): Support NULL HIGHPC.
|
||||
(dwarf_tag_name): Support DW_TAG_GNU_call_site.
|
||||
(cleanup_htab): Delete.
|
||||
(write_psymtabs_to_index): Use make_cleanup_htab_delete instead of it.
|
||||
* exceptions.h (enum errors): New NO_ENTRY_VALUE_ERROR.
|
||||
* gdb-gdb.py (StructMainTypePrettyPrinter): Support
|
||||
FIELD_LOC_KIND_DWARF_BLOCK.
|
||||
* gdbtypes.h (enum field_loc_kind): New entry
|
||||
FIELD_LOC_KIND_DWARF_BLOCK.
|
||||
(struct main_type): New loc entry dwarf_block.
|
||||
(struct call_site, FIELD_DWARF_BLOCK, SET_FIELD_DWARF_BLOCK)
|
||||
(TYPE_FIELD_DWARF_BLOCK): New.
|
||||
* python/py-type.c: Include dwarf2loc.h.
|
||||
(check_types_equal): Support FIELD_LOC_KIND_DWARF_BLOCK. New
|
||||
internal_error call on unknown FIELD_LOC_KIND.
|
||||
* symtab.h (struct symtab): New field call_site_htab.
|
||||
* utils.c (do_htab_delete_cleanup, make_cleanup_htab_delete)
|
||||
(core_addr_hash, core_addr_eq): New functions.
|
||||
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Code reshuffle.
|
||||
|
34
gdb/block.c
34
gdb/block.c
@ -25,6 +25,8 @@
|
||||
#include "gdb_obstack.h"
|
||||
#include "cp-support.h"
|
||||
#include "addrmap.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
/* This is used by struct block to store namespace-related info for
|
||||
C++ files, namely using declarations and the current namespace in
|
||||
@ -160,6 +162,38 @@ blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return call_site for specified PC in GDBARCH. PC must match exactly, it
|
||||
must be the next instruction after call (or after tail call jump). Throw
|
||||
NO_ENTRY_VALUE_ERROR otherwise. This function never returns NULL. */
|
||||
|
||||
struct call_site *
|
||||
call_site_for_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
{
|
||||
struct symtab *symtab;
|
||||
void **slot = NULL;
|
||||
|
||||
/* -1 as tail call PC can be already after the compilation unit range. */
|
||||
symtab = find_pc_symtab (pc - 1);
|
||||
|
||||
if (symtab != NULL && symtab->call_site_htab != NULL)
|
||||
slot = htab_find_slot (symtab->call_site_htab, &pc, NO_INSERT);
|
||||
|
||||
if (slot == NULL)
|
||||
{
|
||||
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (pc);
|
||||
|
||||
/* DW_TAG_gnu_call_site will be missing just if GCC could not determine
|
||||
the call target. */
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("DW_OP_GNU_entry_value resolving cannot find "
|
||||
"DW_TAG_GNU_call_site %s in %s"),
|
||||
paddress (gdbarch, pc),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
}
|
||||
|
||||
return *slot;
|
||||
}
|
||||
|
||||
/* Return the blockvector immediately containing the innermost lexical block
|
||||
containing the specified pc value, or 0 if there is none.
|
||||
Backward compatibility, no section. */
|
||||
|
@ -142,6 +142,9 @@ extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR,
|
||||
struct block **,
|
||||
struct symtab *);
|
||||
|
||||
extern struct call_site *call_site_for_pc (struct gdbarch *gdbarch,
|
||||
CORE_ADDR pc);
|
||||
|
||||
extern struct block *block_for_pc (CORE_ADDR);
|
||||
|
||||
extern struct block *block_for_pc_sect (CORE_ADDR, struct obj_section *);
|
||||
|
@ -93,6 +93,7 @@
|
||||
#include <stdarg.h> /* For va_list. */
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
/* Rather than duplicate all the logic in BFD for figuring out what
|
||||
types to use (which can be pretty complicated), symply define them
|
||||
@ -376,6 +377,8 @@ extern struct cleanup *make_final_cleanup (make_cleanup_ftype *, void *);
|
||||
extern struct cleanup *make_my_cleanup (struct cleanup **,
|
||||
make_cleanup_ftype *, void *);
|
||||
|
||||
extern struct cleanup *make_cleanup_htab_delete (htab_t htab);
|
||||
|
||||
extern struct cleanup *make_my_cleanup2 (struct cleanup **,
|
||||
make_cleanup_ftype *, void *,
|
||||
void (*free_arg) (void *));
|
||||
@ -550,6 +553,11 @@ extern const char *paddress (struct gdbarch *gdbarch, CORE_ADDR addr);
|
||||
extern const char *print_core_address (struct gdbarch *gdbarch,
|
||||
CORE_ADDR address);
|
||||
|
||||
/* Callback hash_f and eq_f for htab_create_alloc or htab_create_alloc_ex. */
|
||||
|
||||
extern hashval_t core_addr_hash (const void *ap);
|
||||
extern int core_addr_eq (const void *ap, const void *bp);
|
||||
|
||||
/* %d for LONGEST */
|
||||
extern char *plongest (LONGEST l);
|
||||
/* %u for ULONGEST */
|
||||
|
@ -353,7 +353,8 @@ static const struct dwarf_expr_context_funcs dwarf2_frame_ctx_funcs =
|
||||
ctx_no_get_frame_pc,
|
||||
ctx_no_get_tls_address,
|
||||
ctx_no_dwarf_call,
|
||||
ctx_no_get_base_type
|
||||
ctx_no_get_base_type,
|
||||
ctx_no_push_dwarf_reg_entry_value
|
||||
};
|
||||
|
||||
static CORE_ADDR
|
||||
|
@ -371,7 +371,7 @@ dwarf_expr_eval (struct dwarf_expr_context *ctx, const gdb_byte *addr,
|
||||
|
||||
/* 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. */
|
||||
past BUF_END. R can be NULL, the constant is then only skipped. */
|
||||
|
||||
const gdb_byte *
|
||||
read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, ULONGEST * r)
|
||||
@ -391,13 +391,14 @@ read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, ULONGEST * r)
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
*r = result;
|
||||
if (r)
|
||||
*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. */
|
||||
past BUF_END. R can be NULL, the constant is then only skipped. */
|
||||
|
||||
const gdb_byte *
|
||||
read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, LONGEST * r)
|
||||
@ -420,7 +421,8 @@ read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, LONGEST * r)
|
||||
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
|
||||
result |= -(((LONGEST) 1) << shift);
|
||||
|
||||
*r = result;
|
||||
if (r)
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -481,6 +483,41 @@ dwarf_get_base_type (struct dwarf_expr_context *ctx, ULONGEST die, int size)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_reg* return the
|
||||
DWARF register number. Otherwise return -1. */
|
||||
|
||||
int
|
||||
dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
|
||||
{
|
||||
ULONGEST dwarf_reg;
|
||||
|
||||
if (buf_end <= buf)
|
||||
return -1;
|
||||
if (*buf >= DW_OP_reg0 && *buf <= DW_OP_reg31)
|
||||
{
|
||||
if (buf_end - buf != 1)
|
||||
return -1;
|
||||
return *buf - DW_OP_reg0;
|
||||
}
|
||||
|
||||
if (*buf == DW_OP_GNU_regval_type)
|
||||
{
|
||||
buf++;
|
||||
buf = read_uleb128 (buf, buf_end, &dwarf_reg);
|
||||
buf = read_uleb128 (buf, buf_end, NULL);
|
||||
}
|
||||
else if (*buf == DW_OP_regx)
|
||||
{
|
||||
buf++;
|
||||
buf = read_uleb128 (buf, buf_end, &dwarf_reg);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
if (buf != buf_end || (int) dwarf_reg != dwarf_reg)
|
||||
return -1;
|
||||
return dwarf_reg;
|
||||
}
|
||||
|
||||
/* The engine for the expression evaluator. Using the context in CTX,
|
||||
evaluate the expression between OP_PTR and OP_END. */
|
||||
|
||||
@ -1191,11 +1228,27 @@ execute_stack_op (struct dwarf_expr_context *ctx,
|
||||
goto no_push;
|
||||
|
||||
case DW_OP_GNU_entry_value:
|
||||
/* This operation is not yet supported by GDB. */
|
||||
ctx->location = DWARF_VALUE_OPTIMIZED_OUT;
|
||||
ctx->stack_len = 0;
|
||||
ctx->num_pieces = 0;
|
||||
goto abort_expression;
|
||||
{
|
||||
ULONGEST len;
|
||||
int dwarf_reg;
|
||||
CORE_ADDR deref_size;
|
||||
|
||||
op_ptr = read_uleb128 (op_ptr, op_end, &len);
|
||||
if (op_ptr + len > op_end)
|
||||
error (_("DW_OP_GNU_entry_value: too few bytes available."));
|
||||
|
||||
dwarf_reg = dwarf_block_to_dwarf_reg (op_ptr, op_ptr + len);
|
||||
if (dwarf_reg != -1)
|
||||
{
|
||||
op_ptr += len;
|
||||
ctx->funcs->push_dwarf_reg_entry_value (ctx, dwarf_reg,
|
||||
0 /* unused */);
|
||||
goto no_push;
|
||||
}
|
||||
|
||||
error (_("DWARF-2 expression error: DW_OP_GNU_entry_value is "
|
||||
"supported only for single DW_OP_reg*"));
|
||||
}
|
||||
|
||||
case DW_OP_GNU_const_type:
|
||||
{
|
||||
@ -1340,6 +1393,17 @@ ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die)
|
||||
error (_("Support for typed DWARF is not supported in this context"));
|
||||
}
|
||||
|
||||
/* Stub dwarf_expr_context_funcs.push_dwarf_block_entry_value
|
||||
implementation. */
|
||||
|
||||
void
|
||||
ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
|
||||
int dwarf_reg, CORE_ADDR fb_offset)
|
||||
{
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("Support for DW_OP_GNU_entry_value is unimplemented"));
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_dwarf2expr (void)
|
||||
{
|
||||
|
@ -62,6 +62,15 @@ struct dwarf_expr_context_funcs
|
||||
meaningful to substitute a stub type of the correct size. */
|
||||
struct type *(*get_base_type) (struct dwarf_expr_context *ctx, size_t die);
|
||||
|
||||
/* Push on DWARF stack an entry evaluated for DW_TAG_GNU_call_site's
|
||||
DWARF_REG/FB_OFFSET at the caller of specified BATON. If DWARF register
|
||||
number DWARF_REG specifying the push_dwarf_reg_entry_value parameter is
|
||||
not -1 FB_OFFSET is ignored. Otherwise FB_OFFSET specifies stack
|
||||
parameter offset against caller's stack pointer (which equals the callee's
|
||||
frame base). */
|
||||
void (*push_dwarf_reg_entry_value) (struct dwarf_expr_context *ctx,
|
||||
int dwarf_reg, CORE_ADDR fb_offset);
|
||||
|
||||
#if 0
|
||||
/* Not yet implemented. */
|
||||
|
||||
@ -267,5 +276,9 @@ CORE_ADDR ctx_no_get_frame_pc (void *baton);
|
||||
CORE_ADDR ctx_no_get_tls_address (void *baton, CORE_ADDR offset);
|
||||
void ctx_no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset);
|
||||
struct type *ctx_no_get_base_type (struct dwarf_expr_context *ctx, size_t die);
|
||||
void ctx_no_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
|
||||
int dwarf_reg, CORE_ADDR fb_offset);
|
||||
|
||||
int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
|
||||
|
||||
#endif /* dwarf2expr.h */
|
||||
|
287
gdb/dwarf2loc.c
287
gdb/dwarf2loc.c
@ -33,6 +33,7 @@
|
||||
#include "objfiles.h"
|
||||
#include "exceptions.h"
|
||||
#include "block.h"
|
||||
#include "gdbcmd.h"
|
||||
|
||||
#include "dwarf2.h"
|
||||
#include "dwarf2expr.h"
|
||||
@ -47,6 +48,8 @@ extern int dwarf2_always_disassemble;
|
||||
static void dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
|
||||
const gdb_byte **start, size_t *length);
|
||||
|
||||
static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs;
|
||||
|
||||
static struct value *dwarf2_evaluate_loc_desc_full (struct type *type,
|
||||
struct frame_info *frame,
|
||||
const gdb_byte *data,
|
||||
@ -296,6 +299,249 @@ dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, size_t die_offset)
|
||||
return dwarf2_get_die_type (die_offset, debaton->per_cu);
|
||||
}
|
||||
|
||||
/* See dwarf2loc.h. */
|
||||
|
||||
int entry_values_debug = 0;
|
||||
|
||||
/* Helper to set entry_values_debug. */
|
||||
|
||||
static void
|
||||
show_entry_values_debug (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
{
|
||||
fprintf_filtered (file,
|
||||
_("Entry values and tail call frames debugging is %s.\n"),
|
||||
value);
|
||||
}
|
||||
|
||||
/* Find DW_TAG_GNU_call_site's DW_AT_GNU_call_site_target address.
|
||||
CALLER_FRAME (for registers) can be NULL if it is not known. This function
|
||||
always returns valid address or it throws NO_ENTRY_VALUE_ERROR. */
|
||||
|
||||
static CORE_ADDR
|
||||
call_site_to_target_addr (struct gdbarch *call_site_gdbarch,
|
||||
struct call_site *call_site,
|
||||
struct frame_info *caller_frame)
|
||||
{
|
||||
switch (FIELD_LOC_KIND (call_site->target))
|
||||
{
|
||||
case FIELD_LOC_KIND_DWARF_BLOCK:
|
||||
{
|
||||
struct dwarf2_locexpr_baton *dwarf_block;
|
||||
struct value *val;
|
||||
struct type *caller_core_addr_type;
|
||||
struct gdbarch *caller_arch;
|
||||
|
||||
dwarf_block = FIELD_DWARF_BLOCK (call_site->target);
|
||||
if (dwarf_block == NULL)
|
||||
{
|
||||
struct minimal_symbol *msym;
|
||||
|
||||
msym = lookup_minimal_symbol_by_pc (call_site->pc - 1);
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("DW_AT_GNU_call_site_target is not specified "
|
||||
"at %s in %s"),
|
||||
paddress (call_site_gdbarch, call_site->pc),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
|
||||
}
|
||||
if (caller_frame == NULL)
|
||||
{
|
||||
struct minimal_symbol *msym;
|
||||
|
||||
msym = lookup_minimal_symbol_by_pc (call_site->pc - 1);
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("DW_AT_GNU_call_site_target DWARF block resolving "
|
||||
"requires known frame which is currently not "
|
||||
"available at %s in %s"),
|
||||
paddress (call_site_gdbarch, call_site->pc),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
|
||||
}
|
||||
caller_arch = get_frame_arch (caller_frame);
|
||||
caller_core_addr_type = builtin_type (caller_arch)->builtin_func_ptr;
|
||||
val = dwarf2_evaluate_loc_desc (caller_core_addr_type, caller_frame,
|
||||
dwarf_block->data, dwarf_block->size,
|
||||
dwarf_block->per_cu);
|
||||
/* DW_AT_GNU_call_site_target is a DWARF expression, not a DWARF
|
||||
location. */
|
||||
if (VALUE_LVAL (val) == lval_memory)
|
||||
return value_address (val);
|
||||
else
|
||||
return value_as_address (val);
|
||||
}
|
||||
|
||||
case FIELD_LOC_KIND_PHYSNAME:
|
||||
{
|
||||
const char *physname;
|
||||
struct minimal_symbol *msym;
|
||||
|
||||
physname = FIELD_STATIC_PHYSNAME (call_site->target);
|
||||
msym = lookup_minimal_symbol_text (physname, NULL);
|
||||
if (msym == NULL)
|
||||
{
|
||||
msym = lookup_minimal_symbol_by_pc (call_site->pc - 1);
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("Cannot find function \"%s\" for a call site target "
|
||||
"at %s in %s"),
|
||||
physname, paddress (call_site_gdbarch, call_site->pc),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
|
||||
}
|
||||
return SYMBOL_VALUE_ADDRESS (msym);
|
||||
}
|
||||
|
||||
case FIELD_LOC_KIND_PHYSADDR:
|
||||
return FIELD_STATIC_PHYSADDR (call_site->target);
|
||||
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__, _("invalid call site target kind"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch call_site_parameter from caller matching the parameters. FRAME is for
|
||||
callee. See DWARF_REG and FB_OFFSET description at struct
|
||||
dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
|
||||
|
||||
Function always returns non-NULL, it throws NO_ENTRY_VALUE_ERROR
|
||||
otherwise. */
|
||||
|
||||
static struct call_site_parameter *
|
||||
dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg,
|
||||
CORE_ADDR fb_offset,
|
||||
struct dwarf2_per_cu_data **per_cu_return)
|
||||
{
|
||||
CORE_ADDR func_addr = get_frame_func (frame);
|
||||
CORE_ADDR caller_pc;
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
struct frame_info *caller_frame = get_prev_frame (frame);
|
||||
struct call_site *call_site;
|
||||
int iparams;
|
||||
struct value *val;
|
||||
struct dwarf2_locexpr_baton *dwarf_block;
|
||||
struct call_site_parameter *parameter;
|
||||
CORE_ADDR target_addr;
|
||||
|
||||
if (gdbarch != frame_unwind_arch (frame))
|
||||
{
|
||||
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr);
|
||||
struct gdbarch *caller_gdbarch = frame_unwind_arch (frame);
|
||||
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("DW_OP_GNU_entry_value resolving callee gdbarch %s "
|
||||
"(of %s (%s)) does not match caller gdbarch %s"),
|
||||
gdbarch_bfd_arch_info (gdbarch)->printable_name,
|
||||
paddress (gdbarch, func_addr),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym),
|
||||
gdbarch_bfd_arch_info (caller_gdbarch)->printable_name);
|
||||
}
|
||||
|
||||
if (caller_frame == NULL)
|
||||
{
|
||||
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr);
|
||||
|
||||
throw_error (NO_ENTRY_VALUE_ERROR, _("DW_OP_GNU_entry_value resolving "
|
||||
"requires caller of %s (%s)"),
|
||||
paddress (gdbarch, func_addr),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
}
|
||||
caller_pc = get_frame_pc (caller_frame);
|
||||
call_site = call_site_for_pc (gdbarch, caller_pc);
|
||||
|
||||
target_addr = call_site_to_target_addr (gdbarch, call_site, caller_frame);
|
||||
if (target_addr != func_addr)
|
||||
{
|
||||
struct minimal_symbol *target_msym, *func_msym;
|
||||
|
||||
target_msym = lookup_minimal_symbol_by_pc (target_addr);
|
||||
func_msym = lookup_minimal_symbol_by_pc (func_addr);
|
||||
throw_error (NO_ENTRY_VALUE_ERROR,
|
||||
_("DW_OP_GNU_entry_value resolving expects callee %s at %s "
|
||||
"but the called frame is for %s at %s"),
|
||||
(target_msym == NULL ? "???"
|
||||
: SYMBOL_PRINT_NAME (target_msym)),
|
||||
paddress (gdbarch, target_addr),
|
||||
func_msym == NULL ? "???" : SYMBOL_PRINT_NAME (func_msym),
|
||||
paddress (gdbarch, func_addr));
|
||||
}
|
||||
|
||||
for (iparams = 0; iparams < call_site->parameter_count; iparams++)
|
||||
{
|
||||
parameter = &call_site->parameter[iparams];
|
||||
if (parameter->dwarf_reg == -1 && dwarf_reg == -1)
|
||||
{
|
||||
if (parameter->fb_offset == fb_offset)
|
||||
break;
|
||||
}
|
||||
else if (parameter->dwarf_reg == dwarf_reg)
|
||||
break;
|
||||
}
|
||||
if (iparams == call_site->parameter_count)
|
||||
{
|
||||
struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (caller_pc);
|
||||
|
||||
/* DW_TAG_GNU_call_site_parameter will be missing just if GCC could not
|
||||
determine its value. */
|
||||
throw_error (NO_ENTRY_VALUE_ERROR, _("Cannot find matching parameter "
|
||||
"at DW_TAG_GNU_call_site %s at %s"),
|
||||
paddress (gdbarch, caller_pc),
|
||||
msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
|
||||
}
|
||||
|
||||
*per_cu_return = call_site->per_cu;
|
||||
return parameter;
|
||||
}
|
||||
|
||||
/* Execute call_site_parameter's DWARF block for caller of the CTX's frame.
|
||||
CTX must be of dwarf_expr_ctx_funcs kind. See DWARF_REG and FB_OFFSET
|
||||
description at struct dwarf_expr_context_funcs->push_dwarf_reg_entry_value.
|
||||
|
||||
The CTX caller can be from a different CU - per_cu_dwarf_call implementation
|
||||
can be more simple as it does not support cross-CU DWARF executions. */
|
||||
|
||||
static void
|
||||
dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
|
||||
int dwarf_reg, CORE_ADDR fb_offset)
|
||||
{
|
||||
struct dwarf_expr_baton *debaton;
|
||||
struct frame_info *frame, *caller_frame;
|
||||
struct dwarf2_per_cu_data *caller_per_cu;
|
||||
struct dwarf_expr_baton baton_local;
|
||||
struct dwarf_expr_context saved_ctx;
|
||||
struct call_site_parameter *parameter;
|
||||
const gdb_byte *data_src;
|
||||
size_t size;
|
||||
|
||||
gdb_assert (ctx->funcs == &dwarf_expr_ctx_funcs);
|
||||
debaton = ctx->baton;
|
||||
frame = debaton->frame;
|
||||
caller_frame = get_prev_frame (frame);
|
||||
|
||||
parameter = dwarf_expr_reg_to_entry_parameter (frame, dwarf_reg, fb_offset,
|
||||
&caller_per_cu);
|
||||
data_src = parameter->value;
|
||||
size = parameter->value_size;
|
||||
|
||||
baton_local.frame = caller_frame;
|
||||
baton_local.per_cu = caller_per_cu;
|
||||
|
||||
saved_ctx.gdbarch = ctx->gdbarch;
|
||||
saved_ctx.addr_size = ctx->addr_size;
|
||||
saved_ctx.offset = ctx->offset;
|
||||
saved_ctx.baton = ctx->baton;
|
||||
ctx->gdbarch = get_objfile_arch (dwarf2_per_cu_objfile (baton_local.per_cu));
|
||||
ctx->addr_size = dwarf2_per_cu_addr_size (baton_local.per_cu);
|
||||
ctx->offset = dwarf2_per_cu_text_offset (baton_local.per_cu);
|
||||
ctx->baton = &baton_local;
|
||||
|
||||
dwarf_expr_eval (ctx, data_src, size);
|
||||
|
||||
ctx->gdbarch = saved_ctx.gdbarch;
|
||||
ctx->addr_size = saved_ctx.addr_size;
|
||||
ctx->offset = saved_ctx.offset;
|
||||
ctx->baton = saved_ctx.baton;
|
||||
}
|
||||
|
||||
struct piece_closure
|
||||
{
|
||||
/* Reference count. */
|
||||
@ -1082,7 +1328,8 @@ static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs =
|
||||
dwarf_expr_frame_pc,
|
||||
dwarf_expr_tls_address,
|
||||
dwarf_expr_dwarf_call,
|
||||
dwarf_expr_get_base_type
|
||||
dwarf_expr_get_base_type,
|
||||
dwarf_expr_push_dwarf_reg_entry_value
|
||||
};
|
||||
|
||||
/* Evaluate a location description, starting at DATA and with length
|
||||
@ -1136,6 +1383,13 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
|
||||
mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type));
|
||||
return retval;
|
||||
}
|
||||
else if (ex.error == NO_ENTRY_VALUE_ERROR)
|
||||
{
|
||||
if (entry_values_debug)
|
||||
exception_print (gdb_stdout, ex);
|
||||
do_cleanups (old_chain);
|
||||
return allocate_optimized_out_value (type);
|
||||
}
|
||||
else
|
||||
throw_exception (ex);
|
||||
}
|
||||
@ -1363,6 +1617,17 @@ needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
|
||||
ctx->funcs->get_frame_pc, ctx->baton);
|
||||
}
|
||||
|
||||
/* DW_OP_GNU_entry_value accesses require a caller, therefore a frame. */
|
||||
|
||||
static void
|
||||
needs_dwarf_reg_entry_value (struct dwarf_expr_context *ctx,
|
||||
int dwarf_reg, CORE_ADDR fb_offset)
|
||||
{
|
||||
struct needs_frame_baton *nf_baton = ctx->baton;
|
||||
|
||||
nf_baton->needs_frame = 1;
|
||||
}
|
||||
|
||||
/* Virtual method table for dwarf2_loc_desc_needs_frame below. */
|
||||
|
||||
static const struct dwarf_expr_context_funcs needs_frame_ctx_funcs =
|
||||
@ -1374,7 +1639,8 @@ static const struct dwarf_expr_context_funcs needs_frame_ctx_funcs =
|
||||
needs_frame_frame_cfa, /* get_frame_pc */
|
||||
needs_frame_tls_address,
|
||||
needs_frame_dwarf_call,
|
||||
NULL /* get_base_type */
|
||||
NULL, /* get_base_type */
|
||||
needs_dwarf_reg_entry_value
|
||||
};
|
||||
|
||||
/* Return non-zero iff the location expression at DATA (length SIZE)
|
||||
@ -2981,3 +3247,20 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = {
|
||||
loclist_describe_location,
|
||||
loclist_tracepoint_var_ref
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_dwarf2loc (void)
|
||||
{
|
||||
add_setshow_zinteger_cmd ("entry-values", class_maintenance,
|
||||
&entry_values_debug,
|
||||
_("Set entry values and tail call frames "
|
||||
"debugging."),
|
||||
_("Show entry values and tail call frames "
|
||||
"debugging."),
|
||||
_("When non-zero, the process of determining "
|
||||
"parameter values from function entry point "
|
||||
"and tail call frames will be printed."),
|
||||
NULL,
|
||||
show_entry_values_debug,
|
||||
&setdebuglist, &showdebuglist);
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ struct axs_value;
|
||||
/* This header is private to the DWARF-2 reader. It is shared between
|
||||
dwarf2read.c and dwarf2loc.c. */
|
||||
|
||||
/* `set debug entry-values' setting. */
|
||||
extern int entry_values_debug;
|
||||
|
||||
/* Return the OBJFILE associated with the compilation unit CU. If CU
|
||||
came from a separate debuginfo file, then the master objfile is
|
||||
returned. */
|
||||
|
229
gdb/dwarf2read.c
229
gdb/dwarf2read.c
@ -407,6 +407,9 @@ struct dwarf2_cu
|
||||
after all type information has been read. */
|
||||
VEC (delayed_method_info) *method_list;
|
||||
|
||||
/* To be copied to symtab->call_site_htab. */
|
||||
htab_t call_site_htab;
|
||||
|
||||
/* Mark used when releasing cached dies. */
|
||||
unsigned int mark : 1;
|
||||
|
||||
@ -1079,6 +1082,8 @@ static void read_func_scope (struct die_info *, struct dwarf2_cu *);
|
||||
|
||||
static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *);
|
||||
|
||||
static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu);
|
||||
|
||||
static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
|
||||
struct dwarf2_cu *, struct partial_symtab *);
|
||||
|
||||
@ -4799,6 +4804,8 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu)
|
||||
|
||||
if (gcc_4_minor >= 5)
|
||||
symtab->epilogue_unwind_valid = 1;
|
||||
|
||||
symtab->call_site_htab = cu->call_site_htab;
|
||||
}
|
||||
|
||||
if (dwarf2_per_objfile->using_index)
|
||||
@ -4837,6 +4844,9 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
|
||||
case DW_TAG_catch_block:
|
||||
read_lexical_block_scope (die, cu);
|
||||
break;
|
||||
case DW_TAG_GNU_call_site:
|
||||
read_call_site_scope (die, cu);
|
||||
break;
|
||||
case DW_TAG_class_type:
|
||||
case DW_TAG_interface_type:
|
||||
case DW_TAG_structure_type:
|
||||
@ -6131,6 +6141,208 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
|
||||
using_directives = new->using_directives;
|
||||
}
|
||||
|
||||
/* Read in DW_TAG_GNU_call_site and insert it to CU->call_site_htab. */
|
||||
|
||||
static void
|
||||
read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
|
||||
{
|
||||
struct objfile *objfile = cu->objfile;
|
||||
struct gdbarch *gdbarch = get_objfile_arch (objfile);
|
||||
CORE_ADDR pc, baseaddr;
|
||||
struct attribute *attr;
|
||||
struct call_site *call_site, call_site_local;
|
||||
void **slot;
|
||||
int nparams;
|
||||
struct die_info *child_die;
|
||||
|
||||
baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
|
||||
|
||||
attr = dwarf2_attr (die, DW_AT_low_pc, cu);
|
||||
if (!attr)
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("missing DW_AT_low_pc for DW_TAG_GNU_call_site "
|
||||
"DIE 0x%x [in module %s]"),
|
||||
die->offset, cu->objfile->name);
|
||||
return;
|
||||
}
|
||||
pc = DW_ADDR (attr) + baseaddr;
|
||||
|
||||
if (cu->call_site_htab == NULL)
|
||||
cu->call_site_htab = htab_create_alloc_ex (16, core_addr_hash, core_addr_eq,
|
||||
NULL, &objfile->objfile_obstack,
|
||||
hashtab_obstack_allocate, NULL);
|
||||
call_site_local.pc = pc;
|
||||
slot = htab_find_slot (cu->call_site_htab, &call_site_local, INSERT);
|
||||
if (*slot != NULL)
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("Duplicate PC %s for DW_TAG_GNU_call_site "
|
||||
"DIE 0x%x [in module %s]"),
|
||||
paddress (gdbarch, pc), die->offset, cu->objfile->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Count parameters at the caller. */
|
||||
|
||||
nparams = 0;
|
||||
for (child_die = die->child; child_die && child_die->tag;
|
||||
child_die = sibling_die (child_die))
|
||||
{
|
||||
if (child_die->tag != DW_TAG_GNU_call_site_parameter)
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("Tag %d is not DW_TAG_GNU_call_site_parameter in "
|
||||
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
|
||||
child_die->tag, child_die->offset, cu->objfile->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
nparams++;
|
||||
}
|
||||
|
||||
call_site = obstack_alloc (&objfile->objfile_obstack,
|
||||
(sizeof (*call_site)
|
||||
+ (sizeof (*call_site->parameter)
|
||||
* (nparams - 1))));
|
||||
*slot = call_site;
|
||||
memset (call_site, 0, sizeof (*call_site) - sizeof (*call_site->parameter));
|
||||
call_site->pc = pc;
|
||||
|
||||
attr = dwarf2_attr (die, DW_AT_GNU_call_site_target, cu);
|
||||
if (attr == NULL)
|
||||
attr = dwarf2_attr (die, DW_AT_abstract_origin, cu);
|
||||
SET_FIELD_DWARF_BLOCK (call_site->target, NULL);
|
||||
if (!attr || (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0))
|
||||
/* Keep NULL DWARF_BLOCK. */;
|
||||
else if (attr_form_is_block (attr))
|
||||
{
|
||||
struct dwarf2_locexpr_baton *dlbaton;
|
||||
|
||||
dlbaton = obstack_alloc (&objfile->objfile_obstack, sizeof (*dlbaton));
|
||||
dlbaton->data = DW_BLOCK (attr)->data;
|
||||
dlbaton->size = DW_BLOCK (attr)->size;
|
||||
dlbaton->per_cu = cu->per_cu;
|
||||
|
||||
SET_FIELD_DWARF_BLOCK (call_site->target, dlbaton);
|
||||
}
|
||||
else if (is_ref_attr (attr))
|
||||
{
|
||||
struct objfile *objfile = cu->objfile;
|
||||
struct dwarf2_cu *target_cu = cu;
|
||||
struct die_info *target_die;
|
||||
|
||||
target_die = follow_die_ref_or_sig (die, attr, &target_cu);
|
||||
gdb_assert (target_cu->objfile == objfile);
|
||||
if (die_is_declaration (target_die, target_cu))
|
||||
{
|
||||
const char *target_physname;
|
||||
|
||||
target_physname = dwarf2_physname (NULL, target_die, target_cu);
|
||||
if (target_physname == NULL)
|
||||
complaint (&symfile_complaints,
|
||||
_("DW_AT_GNU_call_site_target target DIE has invalid "
|
||||
"physname, for referencing DIE 0x%x [in module %s]"),
|
||||
die->offset, cu->objfile->name);
|
||||
else
|
||||
SET_FIELD_PHYSNAME (call_site->target, (char *) target_physname);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE_ADDR lowpc;
|
||||
|
||||
/* DW_AT_entry_pc should be preferred. */
|
||||
if (!dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu, NULL))
|
||||
complaint (&symfile_complaints,
|
||||
_("DW_AT_GNU_call_site_target target DIE has invalid "
|
||||
"low pc, for referencing DIE 0x%x [in module %s]"),
|
||||
die->offset, cu->objfile->name);
|
||||
else
|
||||
SET_FIELD_PHYSADDR (call_site->target, lowpc + baseaddr);
|
||||
}
|
||||
}
|
||||
else
|
||||
complaint (&symfile_complaints,
|
||||
_("DW_TAG_GNU_call_site DW_AT_GNU_call_site_target is neither "
|
||||
"block nor reference, for DIE 0x%x [in module %s]"),
|
||||
die->offset, cu->objfile->name);
|
||||
|
||||
call_site->per_cu = cu->per_cu;
|
||||
|
||||
for (child_die = die->child;
|
||||
child_die && child_die->tag;
|
||||
child_die = sibling_die (child_die))
|
||||
{
|
||||
struct dwarf2_locexpr_baton *dlbaton;
|
||||
struct call_site_parameter *parameter;
|
||||
|
||||
if (child_die->tag != DW_TAG_GNU_call_site_parameter)
|
||||
{
|
||||
/* Already printed the complaint above. */
|
||||
continue;
|
||||
}
|
||||
|
||||
gdb_assert (call_site->parameter_count < nparams);
|
||||
parameter = &call_site->parameter[call_site->parameter_count];
|
||||
|
||||
/* DW_AT_location specifies the register number. Value of the data
|
||||
assumed for the register is contained in DW_AT_GNU_call_site_value. */
|
||||
|
||||
attr = dwarf2_attr (child_die, DW_AT_location, cu);
|
||||
if (!attr || !attr_form_is_block (attr))
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("No DW_FORM_block* DW_AT_location for "
|
||||
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
|
||||
child_die->offset, cu->objfile->name);
|
||||
continue;
|
||||
}
|
||||
parameter->dwarf_reg = dwarf_block_to_dwarf_reg (DW_BLOCK (attr)->data,
|
||||
&DW_BLOCK (attr)->data[DW_BLOCK (attr)->size]);
|
||||
if (parameter->dwarf_reg == -1)
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("Only single DW_OP_reg is supported "
|
||||
"for DW_FORM_block* DW_AT_location for "
|
||||
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
|
||||
child_die->offset, cu->objfile->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_value, cu);
|
||||
if (!attr_form_is_block (attr))
|
||||
{
|
||||
complaint (&symfile_complaints,
|
||||
_("No DW_FORM_block* DW_AT_GNU_call_site_value for "
|
||||
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
|
||||
child_die->offset, cu->objfile->name);
|
||||
continue;
|
||||
}
|
||||
parameter->value = DW_BLOCK (attr)->data;
|
||||
parameter->value_size = DW_BLOCK (attr)->size;
|
||||
|
||||
/* Parameters are not pre-cleared by memset above. */
|
||||
parameter->data_value = NULL;
|
||||
parameter->data_value_size = 0;
|
||||
call_site->parameter_count++;
|
||||
|
||||
attr = dwarf2_attr (child_die, DW_AT_GNU_call_site_data_value, cu);
|
||||
if (attr)
|
||||
{
|
||||
if (!attr_form_is_block (attr))
|
||||
complaint (&symfile_complaints,
|
||||
_("No DW_FORM_block* DW_AT_GNU_call_site_data_value for "
|
||||
"DW_TAG_GNU_call_site child DIE 0x%x [in module %s]"),
|
||||
child_die->offset, cu->objfile->name);
|
||||
else
|
||||
{
|
||||
parameter->data_value = DW_BLOCK (attr)->data;
|
||||
parameter->data_value_size = DW_BLOCK (attr)->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET.
|
||||
Return 1 if the attributes are present and valid, otherwise, return 0.
|
||||
If RANGES_PST is not NULL we should setup `objfile->psymtabs_addrmap'. */
|
||||
@ -6330,7 +6542,8 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
|
||||
return 0;
|
||||
|
||||
*lowpc = low;
|
||||
*highpc = high;
|
||||
if (highpc)
|
||||
*highpc = high;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -12741,6 +12954,8 @@ dwarf_tag_name (unsigned tag)
|
||||
return "DW_TAG_PGI_kanji_type";
|
||||
case DW_TAG_PGI_interface_block:
|
||||
return "DW_TAG_PGI_interface_block";
|
||||
case DW_TAG_GNU_call_site:
|
||||
return "DW_TAG_GNU_call_site";
|
||||
default:
|
||||
return "DW_TAG_<unknown>";
|
||||
}
|
||||
@ -16426,14 +16641,6 @@ write_one_signatured_type (void **slot, void *d)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A cleanup function for an htab_t. */
|
||||
|
||||
static void
|
||||
cleanup_htab (void *arg)
|
||||
{
|
||||
htab_delete (arg);
|
||||
}
|
||||
|
||||
/* Create an index file for OBJFILE in the directory DIR. */
|
||||
|
||||
static void
|
||||
@ -16490,7 +16697,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
|
||||
|
||||
psyms_seen = htab_create_alloc (100, htab_hash_pointer, htab_eq_pointer,
|
||||
NULL, xcalloc, xfree);
|
||||
make_cleanup (cleanup_htab, psyms_seen);
|
||||
make_cleanup_htab_delete (psyms_seen);
|
||||
|
||||
/* While we're scanning CU's create a table that maps a psymtab pointer
|
||||
(which is what addrmap records) to its index (which is what is recorded
|
||||
@ -16500,7 +16707,7 @@ write_psymtabs_to_index (struct objfile *objfile, const char *dir)
|
||||
hash_psymtab_cu_index,
|
||||
eq_psymtab_cu_index,
|
||||
NULL, xcalloc, xfree);
|
||||
make_cleanup (cleanup_htab, cu_index_htab);
|
||||
make_cleanup_htab_delete (cu_index_htab);
|
||||
psymtab_cu_index_map = (struct psymtab_cu_index_map *)
|
||||
xmalloc (sizeof (struct psymtab_cu_index_map)
|
||||
* dwarf2_per_objfile->n_comp_units);
|
||||
|
@ -85,6 +85,9 @@ enum errors {
|
||||
traceframe. */
|
||||
NOT_AVAILABLE_ERROR,
|
||||
|
||||
/* DW_OP_GNU_entry_value resolving failed. */
|
||||
NO_ENTRY_VALUE_ERROR,
|
||||
|
||||
/* Add more errors here. */
|
||||
NR_ERRORS
|
||||
};
|
||||
|
@ -158,6 +158,8 @@ class StructMainTypePrettyPrinter:
|
||||
return 'physaddr = 0x%x' % loc_val['physaddr']
|
||||
elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
|
||||
return 'physname = %s' % loc_val['physname']
|
||||
elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
|
||||
return 'dwarf_block = %s' % loc_val['dwarf_block']
|
||||
else:
|
||||
return 'loc = ??? (unsupported loc_kind value)'
|
||||
def struct_field_img(self, fieldno):
|
||||
|
@ -348,7 +348,8 @@ enum field_loc_kind
|
||||
{
|
||||
FIELD_LOC_KIND_BITPOS, /* bitpos */
|
||||
FIELD_LOC_KIND_PHYSADDR, /* physaddr */
|
||||
FIELD_LOC_KIND_PHYSNAME /* physname */
|
||||
FIELD_LOC_KIND_PHYSNAME, /* physname */
|
||||
FIELD_LOC_KIND_DWARF_BLOCK /* dwarf_block */
|
||||
};
|
||||
|
||||
/* A discriminant to determine which field in the main_type.type_specific
|
||||
@ -510,6 +511,12 @@ struct main_type
|
||||
|
||||
CORE_ADDR physaddr;
|
||||
const char *physname;
|
||||
|
||||
/* The field location can be computed by evaluating the following DWARF
|
||||
block. Its DATA is allocated on objfile_obstack - no CU load is
|
||||
needed to access it. */
|
||||
|
||||
struct dwarf2_locexpr_baton *dwarf_block;
|
||||
}
|
||||
loc;
|
||||
|
||||
@ -897,6 +904,59 @@ struct func_type
|
||||
unsigned calling_convention;
|
||||
};
|
||||
|
||||
/* A place where a function gets called from, represented by
|
||||
DW_TAG_GNU_call_site. It can be looked up from symtab->call_site_htab. */
|
||||
|
||||
struct call_site
|
||||
{
|
||||
/* Address of the first instruction after this call. It must be the first
|
||||
field as we overload core_addr_hash and core_addr_eq for it. */
|
||||
CORE_ADDR pc;
|
||||
|
||||
/* Describe DW_AT_GNU_call_site_target. Missing attribute uses
|
||||
FIELD_LOC_KIND_DWARF_BLOCK with FIELD_DWARF_BLOCK == NULL. */
|
||||
struct
|
||||
{
|
||||
union field_location loc;
|
||||
|
||||
/* Discriminant for union field_location. */
|
||||
ENUM_BITFIELD(field_loc_kind) loc_kind : 2;
|
||||
}
|
||||
target;
|
||||
|
||||
/* Size of the PARAMETER array. */
|
||||
unsigned parameter_count;
|
||||
|
||||
/* CU of the function where the call is located. It gets used for DWARF
|
||||
blocks execution in the parameter array below. */
|
||||
struct dwarf2_per_cu_data *per_cu;
|
||||
|
||||
/* Describe DW_TAG_GNU_call_site's DW_TAG_formal_parameter. */
|
||||
struct call_site_parameter
|
||||
{
|
||||
/* DW_TAG_formal_parameter's DW_AT_location's DW_OP_regX as DWARF
|
||||
register number, for register passed parameters. If -1 then use
|
||||
fb_offset. */
|
||||
int dwarf_reg;
|
||||
|
||||
/* Offset from the callee's frame base, for stack passed parameters.
|
||||
This equals offset from the caller's stack pointer. Valid only if
|
||||
DWARF_REGNUM is -1. */
|
||||
CORE_ADDR fb_offset;
|
||||
|
||||
/* DW_TAG_formal_parameter's DW_AT_GNU_call_site_value. It is never
|
||||
NULL. */
|
||||
const gdb_byte *value;
|
||||
size_t value_size;
|
||||
|
||||
/* DW_TAG_formal_parameter's DW_AT_GNU_call_site_data_value. It may be
|
||||
NULL if not provided by DWARF. */
|
||||
const gdb_byte *data_value;
|
||||
size_t data_value_size;
|
||||
}
|
||||
parameter[1];
|
||||
};
|
||||
|
||||
/* The default value of TYPE_CPLUS_SPECIFIC(T) points to the
|
||||
this shared static structure. */
|
||||
|
||||
@ -1019,6 +1079,7 @@ extern void allocate_gnat_aux_type (struct type *);
|
||||
#define FIELD_BITPOS(thisfld) ((thisfld).loc.bitpos)
|
||||
#define FIELD_STATIC_PHYSNAME(thisfld) ((thisfld).loc.physname)
|
||||
#define FIELD_STATIC_PHYSADDR(thisfld) ((thisfld).loc.physaddr)
|
||||
#define FIELD_DWARF_BLOCK(thisfld) ((thisfld).loc.dwarf_block)
|
||||
#define SET_FIELD_BITPOS(thisfld, bitpos) \
|
||||
(FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_BITPOS, \
|
||||
FIELD_BITPOS (thisfld) = (bitpos))
|
||||
@ -1028,6 +1089,9 @@ extern void allocate_gnat_aux_type (struct type *);
|
||||
#define SET_FIELD_PHYSADDR(thisfld, addr) \
|
||||
(FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_PHYSADDR, \
|
||||
FIELD_STATIC_PHYSADDR (thisfld) = (addr))
|
||||
#define SET_FIELD_DWARF_BLOCK(thisfld, addr) \
|
||||
(FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_DWARF_BLOCK, \
|
||||
FIELD_DWARF_BLOCK (thisfld) = (addr))
|
||||
#define FIELD_ARTIFICIAL(thisfld) ((thisfld).artificial)
|
||||
#define FIELD_BITSIZE(thisfld) ((thisfld).bitsize)
|
||||
|
||||
@ -1038,6 +1102,7 @@ extern void allocate_gnat_aux_type (struct type *);
|
||||
#define TYPE_FIELD_BITPOS(thistype, n) FIELD_BITPOS (TYPE_FIELD (thistype, n))
|
||||
#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) FIELD_STATIC_PHYSNAME (TYPE_FIELD (thistype, n))
|
||||
#define TYPE_FIELD_STATIC_PHYSADDR(thistype, n) FIELD_STATIC_PHYSADDR (TYPE_FIELD (thistype, n))
|
||||
#define TYPE_FIELD_DWARF_BLOCK(thistype, n) FIELD_DWARF_BLOCK (TYPE_FIELD (thistype, n))
|
||||
#define TYPE_FIELD_ARTIFICIAL(thistype, n) FIELD_ARTIFICIAL(TYPE_FIELD(thistype,n))
|
||||
#define TYPE_FIELD_BITSIZE(thistype, n) FIELD_BITSIZE(TYPE_FIELD(thistype,n))
|
||||
#define TYPE_FIELD_PACKED(thistype, n) (FIELD_BITSIZE(TYPE_FIELD(thistype,n))!=0)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "language.h"
|
||||
#include "vec.h"
|
||||
#include "bcache.h"
|
||||
#include "dwarf2loc.h"
|
||||
|
||||
typedef struct pyty_type_object
|
||||
{
|
||||
@ -900,6 +901,22 @@ check_types_equal (struct type *type1, struct type *type2,
|
||||
FIELD_STATIC_PHYSNAME (*field2)))
|
||||
return Py_NE;
|
||||
break;
|
||||
case FIELD_LOC_KIND_DWARF_BLOCK:
|
||||
{
|
||||
struct dwarf2_locexpr_baton *block1, *block2;
|
||||
|
||||
block1 = FIELD_DWARF_BLOCK (*field1);
|
||||
block2 = FIELD_DWARF_BLOCK (*field2);
|
||||
if (block1->per_cu != block2->per_cu
|
||||
|| block1->size != block2->size
|
||||
|| memcmp (block1->data, block2->data, block1->size) != 0)
|
||||
return Py_NE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__, _("Unsupported field kind "
|
||||
"%d by check_types_equal"),
|
||||
FIELD_LOC_KIND (*field1));
|
||||
}
|
||||
|
||||
entry.type1 = FIELD_TYPE (*field1);
|
||||
|
@ -831,6 +831,9 @@ struct symtab
|
||||
|
||||
struct objfile *objfile;
|
||||
|
||||
/* struct call_site entries for this compilation unit or NULL. */
|
||||
|
||||
htab_t call_site_htab;
|
||||
};
|
||||
|
||||
#define BLOCKVECTOR(symtab) (symtab)->blockvector
|
||||
|
@ -1,3 +1,10 @@
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Implement basic support for DW_TAG_GNU_call_site.
|
||||
* gdb.arch/Makefile.in (EXECUTABLES): Add amd64-entry-value.
|
||||
* gdb.arch/amd64-entry-value.cc: New file.
|
||||
* gdb.arch/amd64-entry-value.exp: New file.
|
||||
|
||||
2011-10-09 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Fix DW_OP_GNU_implicit_pointer for DWARF32 v3+ on 64-bit arches.
|
||||
|
@ -1,8 +1,8 @@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
EXECUTABLES = altivec-abi altivec-regs amd64-byte amd64-disp-step \
|
||||
amd64-dword amd64-i386-address amd64-word i386-bp_permanent \
|
||||
EXECUTABLES = altivec-abi altivec-regs amd64-byte amd64-disp-step amd64-dword \
|
||||
amd64-entry-value amd64-i386-address amd64-word i386-bp_permanent \
|
||||
i386-permbkpt i386-avx i386-signal i386-sse
|
||||
|
||||
all info install-info dvi install uninstall installcheck check:
|
||||
|
42
gdb/testsuite/gdb.arch/amd64-entry-value.cc
Normal file
42
gdb/testsuite/gdb.arch/amd64-entry-value.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2011 Free Software Foundation, Inc.
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
static volatile int v;
|
||||
|
||||
static void __attribute__((noinline, noclone))
|
||||
e (int i, double j)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
|
||||
static void __attribute__((noinline, noclone))
|
||||
d (int i, double j)
|
||||
{
|
||||
i++;
|
||||
j++;
|
||||
e (i, j);
|
||||
e (v, v);
|
||||
asm ("breakhere:");
|
||||
e (v, v);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
d (30, 30.5);
|
||||
return 0;
|
||||
}
|
47
gdb/testsuite/gdb.arch/amd64-entry-value.exp
Normal file
47
gdb/testsuite/gdb.arch/amd64-entry-value.exp
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set testfile amd64-entry-value
|
||||
set srcfile ${testfile}.s
|
||||
set opts {}
|
||||
|
||||
if [info exists COMPILE] {
|
||||
# make check RUNTESTFLAGS="gdb.arch/amd64-entry-value.exp COMPILE=1"
|
||||
set srcfile ${testfile}.cc
|
||||
lappend opts debug optimize=-O2
|
||||
} elseif { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
|
||||
verbose "Skipping amd64-entry-value."
|
||||
return
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_breakpoint "breakhere"
|
||||
|
||||
|
||||
# Test @entry values for register passed parameters.
|
||||
|
||||
gdb_continue_to_breakpoint "entry: breakhere"
|
||||
|
||||
gdb_test "bt" "^bt\r\n#0 +d *\\(i=31, j=31\\.5\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in main .*" \
|
||||
"entry: bt"
|
||||
gdb_test "p i" " = 31" "entry: p i"
|
||||
gdb_test "p j" { = 31\.5} "entry: p j"
|
39
gdb/utils.c
39
gdb/utils.c
@ -403,6 +403,24 @@ make_cleanup_unpush_target (struct target_ops *ops)
|
||||
return make_my_cleanup (&cleanup_chain, do_unpush_target, ops);
|
||||
}
|
||||
|
||||
/* Helper for make_cleanup_htab_delete compile time checking the types. */
|
||||
|
||||
static void
|
||||
do_htab_delete_cleanup (void *htab_voidp)
|
||||
{
|
||||
htab_t htab = htab_voidp;
|
||||
|
||||
htab_delete (htab);
|
||||
}
|
||||
|
||||
/* Return a new cleanup that deletes HTAB. */
|
||||
|
||||
struct cleanup *
|
||||
make_cleanup_htab_delete (htab_t htab)
|
||||
{
|
||||
return make_cleanup (do_htab_delete_cleanup, htab);
|
||||
}
|
||||
|
||||
struct restore_ui_file_closure
|
||||
{
|
||||
struct ui_file **variable;
|
||||
@ -2911,6 +2929,27 @@ print_core_address (struct gdbarch *gdbarch, CORE_ADDR address)
|
||||
return hex_string_custom (address, 16);
|
||||
}
|
||||
|
||||
/* Callback hash_f for htab_create_alloc or htab_create_alloc_ex. */
|
||||
|
||||
hashval_t
|
||||
core_addr_hash (const void *ap)
|
||||
{
|
||||
const CORE_ADDR *addrp = ap;
|
||||
|
||||
return *addrp;
|
||||
}
|
||||
|
||||
/* Callback eq_f for htab_create_alloc or htab_create_alloc_ex. */
|
||||
|
||||
int
|
||||
core_addr_eq (const void *ap, const void *bp)
|
||||
{
|
||||
const CORE_ADDR *addr_ap = ap;
|
||||
const CORE_ADDR *addr_bp = bp;
|
||||
|
||||
return *addr_ap == *addr_bp;
|
||||
}
|
||||
|
||||
static char *
|
||||
decimal2str (char *sign, ULONGEST addr, int width)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user