diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 54 | ||||
-rw-r--r-- | gdb/block.c | 34 | ||||
-rw-r--r-- | gdb/block.h | 3 | ||||
-rw-r--r-- | gdb/defs.h | 8 | ||||
-rw-r--r-- | gdb/dwarf2-frame.c | 3 | ||||
-rw-r--r-- | gdb/dwarf2expr.c | 82 | ||||
-rw-r--r-- | gdb/dwarf2expr.h | 13 | ||||
-rw-r--r-- | gdb/dwarf2loc.c | 287 | ||||
-rw-r--r-- | gdb/dwarf2loc.h | 3 | ||||
-rw-r--r-- | gdb/dwarf2read.c | 229 | ||||
-rw-r--r-- | gdb/exceptions.h | 3 | ||||
-rw-r--r-- | gdb/gdb-gdb.py | 2 | ||||
-rw-r--r-- | gdb/gdbtypes.h | 67 | ||||
-rw-r--r-- | gdb/python/py-type.c | 17 | ||||
-rw-r--r-- | gdb/symtab.h | 3 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/Makefile.in | 4 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-entry-value.cc | 42 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-entry-value.exp | 47 | ||||
-rw-r--r-- | gdb/utils.c | 39 |
20 files changed, 921 insertions, 26 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b97d44d..a663756 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,59 @@ 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. * gdb-gdb.py (StructMainTypePrettyPrinter): Change TYPE_SPECIFIC_CALLING_CONVENTION to TYPE_SPECIFIC_FUNC. Move diff --git a/gdb/block.c b/gdb/block.c index 776ae53..c165bc2 100644 --- a/gdb/block.c +++ b/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. */ diff --git a/gdb/block.h b/gdb/block.h index 923013c..1742f24 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -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 */ diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 232b223..cd62529 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -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 diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index c296607..2eb9d08 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -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) { diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 9bd7268..8518f37 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -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 */ diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index b0881db..980e9ab 100644 --- a/gdb/dwarf2loc.c +++ b/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); +} diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index a0ea031..9efe196 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -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. */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index c8b3f11..a139b96 100644 --- a/gdb/dwarf2read.c +++ b/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); diff --git a/gdb/exceptions.h b/gdb/exceptions.h index 9e306e4..1aa457a 100644 --- a/gdb/exceptions.h +++ b/gdb/exceptions.h @@ -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 }; diff --git a/gdb/gdb-gdb.py b/gdb/gdb-gdb.py index ae1d742..d948244 100644 --- a/gdb/gdb-gdb.py +++ b/gdb/gdb-gdb.py @@ -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): diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index e78aa0d..523cd80 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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) diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index c7fd25b..44a2038 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -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); diff --git a/gdb/symtab.h b/gdb/symtab.h index 41a0fd6..fe8880f 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -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 diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d21d922..52e544e 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,12 @@ 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. * gdb.dwarf2/implptr-64bit.S: New file. * gdb.dwarf2/implptr-64bit.exp: New file. diff --git a/gdb/testsuite/gdb.arch/Makefile.in b/gdb/testsuite/gdb.arch/Makefile.in index a86edaf..619f78d 100644 --- a/gdb/testsuite/gdb.arch/Makefile.in +++ b/gdb/testsuite/gdb.arch/Makefile.in @@ -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: diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.cc b/gdb/testsuite/gdb.arch/amd64-entry-value.cc new file mode 100644 index 0000000..b492231 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc @@ -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; +} diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.exp b/gdb/testsuite/gdb.arch/amd64-entry-value.exp new file mode 100644 index 0000000..e73254b --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp @@ -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" diff --git a/gdb/utils.c b/gdb/utils.c index 21682d0..08c08c6 100644 --- a/gdb/utils.c +++ b/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) { |