This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 02/12] entryval#2: Basic parameter values recovery


Hi,

[patch 02/12] entryval: Basic parameter values recovery
http://sourceware.org/ml/gdb-patches/2011-07/msg00432.html

This patch reads in the DWARF info for entry values and recovers the current
values from it.

It uses entry values internally, user cannot yet access them directly.


Thanks,
Jan


gdb/
2011-09-12  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Implement basic support for DW_TAG_GNU_call_site.
	* block.c: Include gdbtypes.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 (dwarf_expr_ctx_funcs): New forward declaration.
	(call_site_to_target_addr, dwarf_expr_reg_to_entry_parameter)
	(dwarf_expr_push_dwarf_reg_entry_value): New functions.
	(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.
	* 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/
2011-09-13  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.

--- a/gdb/block.c
+++ b/gdb/block.c
@@ -25,6 +25,7 @@
 #include "gdb_obstack.h"
 #include "cp-support.h"
 #include "addrmap.h"
+#include "gdbtypes.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 +161,29 @@ blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section,
   return 0;
 }
 
+/* Return call_site for specified PC.  PC must match exactly, it must be the
+   next instruction after call (or after tail call jump).  Return NULL if it
+   cannot be found.  */
+
+struct call_site *
+call_site_for_pc (CORE_ADDR pc)
+{
+  struct symtab *symtab;
+  void **slot;
+
+  /* -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)
+    return NULL;
+
+  slot = htab_find_slot (symtab->call_site_htab, &pc, NO_INSERT);
+  if (slot == NULL)
+    return NULL;
+
+  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.  */
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -142,6 +142,8 @@ extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR,
 						    struct block **,
                                                     struct symtab *);
 
+extern struct call_site *call_site_for_pc (CORE_ADDR pc);
+
 extern struct block *block_for_pc (CORE_ADDR);
 
 extern struct block *block_for_pc_sect (CORE_ADDR, struct obj_section *);
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -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 */
--- 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
--- 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.  */
 
@@ -1187,11 +1224,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:
 	  {
@@ -1336,6 +1389,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)
 {
--- 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.  */
 
@@ -263,5 +272,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 */
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -47,6 +47,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,
@@ -301,6 +303,223 @@ dwarf_expr_get_base_type (struct dwarf_expr_context *ctx, size_t die_offset)
   return dwarf2_get_die_type (die_offset, debaton->per_cu);
 }
 
+/* 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 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)
+	  throw_error (NO_ENTRY_VALUE_ERROR,
+		       _("DW_AT_GNU_call_site_target is not specified"));
+	if (caller_frame == NULL)
+	  throw_error (NO_ENTRY_VALUE_ERROR,
+		       _("DW_AT_GNU_call_site_target DWARF block resolving "
+			 "requires known frame which is currently not "
+			 "available"));
+	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)
+	  throw_error (NO_ENTRY_VALUE_ERROR,
+		       _("Cannot find function \"%s\" for a call site target"),
+		       physname);
+	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 (caller_pc);
+  if (call_site == NULL)
+    {
+      struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (caller_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, caller_pc),
+		   msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym));
+    }
+
+  target_addr = call_site_to_target_addr (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.  */
@@ -1095,7 +1314,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
@@ -1148,6 +1368,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 (info_verbose)
+	    exception_print (gdb_stdout, ex);
+	  do_cleanups (old_chain);
+	  return allocate_optimized_out_value (type);
+	}
       else
 	throw_exception (ex);
     }
@@ -1375,6 +1602,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 =
@@ -1386,7 +1624,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)
--- 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 *);
 
@@ -4785,6 +4790,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)
@@ -4823,6 +4830,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:
@@ -6117,6 +6127,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'.  */
@@ -6316,7 +6528,8 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
     return 0;
 
   *lowpc = low;
-  *highpc = high;
+  if (highpc)
+    *highpc = high;
   return ret;
 }
 
@@ -12666,6 +12879,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>";
     }
@@ -16330,14 +16545,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
@@ -16394,7 +16601,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
@@ -16404,7 +16611,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);
--- 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
 };
--- 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):
--- 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)
--- 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
 {
@@ -822,6 +823,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);
--- 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
--- 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:
--- /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;
+}
--- /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"
--- 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)
 {


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