gdb/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Sun, 9 Oct 2011 19:21:39 +0000 (19:21 +0000)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Sun, 9 Oct 2011 19:21:39 +0000 (19:21 +0000)
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.

20 files changed:
gdb/ChangeLog
gdb/block.c
gdb/block.h
gdb/defs.h
gdb/dwarf2-frame.c
gdb/dwarf2expr.c
gdb/dwarf2expr.h
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/dwarf2read.c
gdb/exceptions.h
gdb/gdb-gdb.py
gdb/gdbtypes.h
gdb/python/py-type.c
gdb/symtab.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/Makefile.in
gdb/testsuite/gdb.arch/amd64-entry-value.cc [new file with mode: 0644]
gdb/testsuite/gdb.arch/amd64-entry-value.exp [new file with mode: 0644]
gdb/utils.c

index b97d44ddc8dfc5a1b88b380e2ccd4c20d0cd1007..a6637561806345c88b2f2239817d0a12123e4b89 100644 (file)
@@ -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.
index 776ae53f5aa51a80449b02ecdb2bbc91bbb09a64..c165bc2fc65f4a4697d710b62395bb5ec47902b6 100644 (file)
@@ -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.  */
index 923013ca38ae406e56e42c3e77c05003d64a178a..1742f249db0b0c14bd0470649f2addd697900b58 100644 (file)
@@ -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 *);
index d8129b873ca59d8db92ab5b72f1d66b492eb762a..4b60d6bcff71571a1f9065c0dd6172908944b41c 100644 (file)
@@ -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 */
index 232b223dbeca2e2ec200fb472c2d14e9aa04a324..cd62529c7842baf428421d526fb2598adfcc1027 100644 (file)
@@ -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
index c29660703859ffdbc76a057c75eb50b6fc3e3579..2eb9d08cdcc4da38a00bf4762505557382fd4793 100644 (file)
@@ -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;
 }
 \f
@@ -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)
 {
index 9bd7268971caf0767d2989ff7b888ef94a8c4412..8518f3787434f7ad641b39f14593b7730a50b401 100644 (file)
@@ -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 */
index b0881dbc29dc20beb16d47f6e609cccb13cd5452..980e9ab68c682543ee1651025355f38e0583e5d7 100644 (file)
@@ -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);
+}
index a0ea031e8dd098b095a35a0bfb4de262dfa268eb..9efe1962105049768f6ed6b16325ebc198d7dcf2 100644 (file)
@@ -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.  */
index c8b3f11cfa27678048568a2211ed79db4560b3d8..a139b96bbf6adf761559cd47e8ce05ddbd170377 100644 (file)
@@ -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);
index 9e306e4d381485de051cb09eb57ceda2264f1150..1aa457a3a8183ecdbe5b8b5d3fa97548daf8750c 100644 (file)
@@ -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
 };
index ae1d742fa9b869f24881ee0aea7ece6c178ca91d..d9482442fb1c98570bad335f0b15d7028921e5a3 100644 (file)
@@ -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):
index e78aa0d54a90bf0c2dba729d04e18c2248e30124..523cd8007b5a64d843d2b4f94c9a7916986d70ea 100644 (file)
@@ -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)
index c7fd25b8cb861abc07ca8c46ef17be28c2c748b3..44a20386e5bf1df60eebbd4908efcb8a9f5e7dc6 100644 (file)
@@ -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);
index 41a0fd6bb1edd9f7779efa4fb9471a6f38eb5d1f..fe8880fffaf6e978849215e5ce3842444f72a23e 100644 (file)
@@ -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
index d21d922247b4d976834fc2c914e3e5cac40c7d3c..52e544ec9f575c9aef6c597c335c49619180fc7e 100644 (file)
@@ -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.
index a86edaf475165ea5eade07d69f450bed19a14f99..619f78db2f4172b6f2e1825284cf5827165c7dc9 100644 (file)
@@ -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 (file)
index 0000000..b492231
--- /dev/null
@@ -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 (file)
index 0000000..e73254b
--- /dev/null
@@ -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"
index 21682d0e8e527ff8caffb9c27fb8732cc532be75..08c08c637de82f19a5b1d0bc3a9712391e4fda65 100644 (file)
@@ -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)
 {