gdb/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 7 Jun 2010 19:55:33 +0000 (19:55 +0000)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 7 Jun 2010 19:55:33 +0000 (19:55 +0000)
Fix PR 10640.
* dwarf2-frame.c (no_dwarf_call): New function.
(execute_stack_op): Set CTX->DWARF_CALL.
* dwarf2expr.c (execute_stack_op) <DW_OP_call2, DW_OP_call4>: New.
* dwarf2expr.h (struct dwarf_expr_context) <dwarf_call>: New.
(struct dwarf_expr_context) <get_subr>: Remove the #if0-ed field.
* dwarf2loc.c (per_cu_dwarf_call, dwarf_expr_dwarf_call): New functions.
(dwarf2_evaluate_loc_desc): Initialize CTX->DWARF_CALL.
(needs_frame_dwarf_call): New function.
(dwarf2_loc_desc_needs_frame): Initialize CTX->DWARF_CALL.
* dwarf2read.c (follow_die_offset): Based on former follow_die_ref.
Update the comment.  Move variables die, offset and error call to ...
(follow_die_ref): ... a new function.
(dwarf2_fetch_die_location_block): New function.
* dwarf2loc.h (dwarf2_fetch_die_location_block): New prototype.

gdb/testsuite/
Test PR 10640.
* gdb.dwarf2/dw2-op-call.exp, gdb.dwarf2/dw2-op-call.S: New.

gdb/ChangeLog
gdb/dwarf2-frame.c
gdb/dwarf2expr.c
gdb/dwarf2expr.h
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/dwarf2read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw2-op-call.S [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/dw2-op-call.exp [new file with mode: 0644]

index 7113eb4db466de4a3776bda4c8a5be13fab6bc4c..955b848bb9e380fb834217289be227ebaaf9003a 100644 (file)
@@ -1,3 +1,21 @@
+2010-06-07  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       Fix PR 10640.
+       * dwarf2-frame.c (no_dwarf_call): New function.
+       (execute_stack_op): Set CTX->DWARF_CALL.
+       * dwarf2expr.c (execute_stack_op) <DW_OP_call2, DW_OP_call4>: New.
+       * dwarf2expr.h (struct dwarf_expr_context) <dwarf_call>: New.
+       (struct dwarf_expr_context) <get_subr>: Remove the #if0-ed field.
+       * dwarf2loc.c (per_cu_dwarf_call, dwarf_expr_dwarf_call): New functions.
+       (dwarf2_evaluate_loc_desc): Initialize CTX->DWARF_CALL.
+       (needs_frame_dwarf_call): New function.
+       (dwarf2_loc_desc_needs_frame): Initialize CTX->DWARF_CALL.
+       * dwarf2read.c (follow_die_offset): Based on former follow_die_ref.
+       Update the comment.  Move variables die, offset and error call to ...
+       (follow_die_ref): ... a new function.
+       (dwarf2_fetch_die_location_block): New function.
+       * dwarf2loc.h (dwarf2_fetch_die_location_block): New prototype.
+
 2010-06-07  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * dwarf2loc.c (struct dwarf_expr_baton) Replace objfile by per_cu.
index 2ac95b03f036b82e8bff1d0270f9da37479f1ce7..68793cd95c0dd7c18bd8e8412cb5217a4bbc8ed7 100644 (file)
@@ -328,6 +328,15 @@ no_get_tls_address (void *baton, CORE_ADDR offset)
                  _("Support for DW_OP_GNU_push_tls_address is unimplemented"));
 }
 
+/* Helper function for execute_stack_op.  */
+
+static void
+no_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
+{
+  internal_error (__FILE__, __LINE__,
+                 _("Support for DW_OP_call* is invalid in CFI"));
+}
+
 /* Execute the required actions for both the DW_CFA_restore and
 DW_CFA_restore_extended instructions.  */
 static void
@@ -378,6 +387,7 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
   ctx->get_frame_base = no_get_frame_base;
   ctx->get_frame_cfa = no_get_frame_cfa;
   ctx->get_tls_address = no_get_tls_address;
+  ctx->dwarf_call = no_dwarf_call;
 
   dwarf_expr_push (ctx, initial, initial_in_stack_memory);
   dwarf_expr_eval (ctx, exp, len);
index c145cf4558bd9b41e4084100615ac30da002eaab..4e5a0fc46cf3fda87ceeafaf4f5fa84b23c0cf8b 100644 (file)
@@ -911,6 +911,18 @@ execute_stack_op (struct dwarf_expr_context *ctx,
          ctx->initialized = 0;
          goto no_push;
 
+       case DW_OP_call2:
+         result = extract_unsigned_integer (op_ptr, 2, byte_order);
+         op_ptr += 2;
+         ctx->dwarf_call (ctx, result);
+         goto no_push;
+
+       case DW_OP_call4:
+         result = extract_unsigned_integer (op_ptr, 4, byte_order);
+         op_ptr += 4;
+         ctx->dwarf_call (ctx, result);
+         goto no_push;
+
        default:
          error (_("Unhandled dwarf expression opcode 0x%x"), op);
        }
index 8ebbf87cea1a10eea68fe5e33b1e0a84a3875e98..29f81a5aecddfbf45f40692886d7582e333ef57c 100644 (file)
@@ -97,15 +97,14 @@ struct dwarf_expr_context
      DW_OP_GNU_push_tls_address.  */
   CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset);
 
+  /* Execute DW_AT_location expression for the DWARF expression subroutine in
+     the DIE at DIE_OFFSET in the CU from CTX.  Do not touch STACK while it
+     being passed to and returned from the called DWARF subroutine.  */
+  void (*dwarf_call) (struct dwarf_expr_context *ctx, size_t die_offset);
+
 #if 0
   /* Not yet implemented.  */
 
-  /* Return the location expression for the dwarf expression
-     subroutine in the die at OFFSET in the current compilation unit.
-     The result must be live until the current expression evaluation
-     is complete.  */
-  unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length);
-
   /* Return the `object address' for DW_OP_push_object_address.  */
   CORE_ADDR (*get_object_address) (void *baton);
 #endif
index 9864c466a9ffad293882d167319f0e3333442dd2..8a9a34616ceb3c77d5a5ccf1c049c4f215f0f798 100644 (file)
@@ -232,6 +232,33 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset)
   return target_translate_tls_address (objfile, offset);
 }
 
+/* Call DWARF subroutine from DW_AT_location of DIE at DIE_OFFSET in current CU
+   (as is PER_CU).  State of the CTX is not affected by the call and return.  */
+
+static void
+per_cu_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset,
+                  struct dwarf2_per_cu_data *per_cu)
+{
+  struct dwarf2_locexpr_baton block;
+
+  block = dwarf2_fetch_die_location_block (die_offset, per_cu);
+
+  /* DW_OP_call_ref is currently not supported.  */
+  gdb_assert (block.per_cu == per_cu);
+
+  dwarf_expr_eval (ctx, block.data, block.size);
+}
+
+/* Helper interface of per_cu_dwarf_call for dwarf2_evaluate_loc_desc.  */
+
+static void
+dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
+{
+  struct dwarf_expr_baton *debaton = ctx->baton;
+
+  return per_cu_dwarf_call (ctx, die_offset, debaton->per_cu);
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -815,6 +842,7 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame,
   ctx->get_frame_base = dwarf_expr_frame_base;
   ctx->get_frame_cfa = dwarf_expr_frame_cfa;
   ctx->get_tls_address = dwarf_expr_tls_address;
+  ctx->dwarf_call = dwarf_expr_dwarf_call;
 
   dwarf_expr_eval (ctx, data, size);
   if (ctx->num_pieces > 0)
@@ -962,6 +990,16 @@ needs_frame_tls_address (void *baton, CORE_ADDR offset)
   return 1;
 }
 
+/* Helper interface of per_cu_dwarf_call for dwarf2_loc_desc_needs_frame.  */
+
+static void
+needs_frame_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset)
+{
+  struct needs_frame_baton *nf_baton = ctx->baton;
+
+  return per_cu_dwarf_call (ctx, die_offset, nf_baton->per_cu);
+}
+
 /* Return non-zero iff the location expression at DATA (length SIZE)
    requires a frame to evaluate.  */
 
@@ -988,6 +1026,7 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size,
   ctx->get_frame_base = needs_frame_frame_base;
   ctx->get_frame_cfa = needs_frame_frame_cfa;
   ctx->get_tls_address = needs_frame_tls_address;
+  ctx->dwarf_call = needs_frame_dwarf_call;
 
   dwarf_expr_eval (ctx, data, size);
 
index 4938241dcc09cb3c5fcc640ad7e486646ee12f23..3ff595e7b593d70efc02c6ab6be2039b56bbc36a 100644 (file)
@@ -37,6 +37,9 @@ CORE_ADDR dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu);
 /* Return the offset size given in the compilation unit header for CU.  */
 int dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *cu);
 
+struct dwarf2_locexpr_baton dwarf2_fetch_die_location_block
+  (unsigned int offset, struct dwarf2_per_cu_data *per_cu);
+
 /* The symbol location baton types used by the DWARF-2 reader (i.e.
    SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
    dwarf2_locexpr_baton" is for a symbol with a single location
index 6a6f1cb2b42167c8a8cd9043d137ace5c6885d22..05fbd0936ca260fd2095a225dec4d69a365c06a7 100644 (file)
@@ -10736,30 +10736,25 @@ follow_die_ref_or_sig (struct die_info *src_die, struct attribute *attr,
   return die;
 }
 
-/* Follow reference attribute ATTR of SRC_DIE.
-   On entry *REF_CU is the CU of SRC_DIE.
+/* Follow reference OFFSET.
+   On entry *REF_CU is the CU of source DIE referencing OFFSET.
    On exit *REF_CU is the CU of the result.  */
 
 static struct die_info *
-follow_die_ref (struct die_info *src_die, struct attribute *attr,
-               struct dwarf2_cu **ref_cu)
+follow_die_offset (unsigned int offset, struct dwarf2_cu **ref_cu)
 {
-  struct die_info *die;
-  unsigned int offset;
   struct die_info temp_die;
   struct dwarf2_cu *target_cu, *cu = *ref_cu;
 
   gdb_assert (cu->per_cu != NULL);
 
-  offset = dwarf2_get_ref_die_offset (attr);
-
   if (cu->per_cu->from_debug_types)
     {
       /* .debug_types CUs cannot reference anything outside their CU.
         If they need to, they have to reference a signatured type via
         DW_FORM_sig8.  */
       if (! offset_in_cu_p (&cu->header, offset))
-       goto not_found;
+       return NULL;
       target_cu = cu;
     }
   else if (! offset_in_cu_p (&cu->header, offset))
@@ -10779,15 +10774,67 @@ follow_die_ref (struct die_info *src_die, struct attribute *attr,
 
   *ref_cu = target_cu;
   temp_die.offset = offset;
-  die = htab_find_with_hash (target_cu->die_hash, &temp_die, offset);
-  if (die)
-    return die;
+  return htab_find_with_hash (target_cu->die_hash, &temp_die, offset);
+}
 
- not_found:
+/* Follow reference attribute ATTR of SRC_DIE.
+   On entry *REF_CU is the CU of SRC_DIE.
+   On exit *REF_CU is the CU of the result.  */
 
-  error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE "
-        "at 0x%x [in module %s]"),
-        offset, src_die->offset, cu->objfile->name);
+static struct die_info *
+follow_die_ref (struct die_info *src_die, struct attribute *attr,
+               struct dwarf2_cu **ref_cu)
+{
+  unsigned int offset = dwarf2_get_ref_die_offset (attr);
+  struct dwarf2_cu *cu = *ref_cu;
+  struct die_info *die;
+
+  die = follow_die_offset (offset, ref_cu);
+  if (!die)
+    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE "
+          "at 0x%x [in module %s]"),
+          offset, src_die->offset, cu->objfile->name);
+
+  return die;
+}
+
+/* Return DWARF block and its CU referenced by OFFSET at PER_CU.  Returned
+   value is intended for DW_OP_call*.  */
+
+struct dwarf2_locexpr_baton
+dwarf2_fetch_die_location_block (unsigned int offset,
+                                struct dwarf2_per_cu_data *per_cu)
+{
+  struct dwarf2_cu *cu = per_cu->cu;
+  struct die_info *die;
+  struct attribute *attr;
+  struct dwarf2_locexpr_baton retval;
+
+  die = follow_die_offset (offset, &cu);
+  if (!die)
+    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
+          offset, per_cu->cu->objfile->name);
+
+  attr = dwarf2_attr (die, DW_AT_location, cu);
+  if (!attr)
+    {
+      /* DWARF: "If there is no such attribute, then there is no effect.".  */
+
+      retval.data = NULL;
+      retval.size = 0;
+    }
+  else
+    {
+      if (!attr_form_is_block (attr))
+       error (_("Dwarf Error: DIE at 0x%x referenced in module %s "
+                "is neither DW_FORM_block* nor DW_FORM_exprloc"),
+              offset, per_cu->cu->objfile->name);
+
+      retval.data = DW_BLOCK (attr)->data;
+      retval.size = DW_BLOCK (attr)->size;
+    }
+  retval.per_cu = cu->per_cu;
+  return retval;
 }
 
 /* Follow the signature attribute ATTR in SRC_DIE.
index 291175b3a1e3cae0f31bdc75a35d594a03bae9e7..5ec90066b2cc8044416cc785c198a9888dcc1c35 100644 (file)
@@ -1,3 +1,8 @@
+2010-06-07  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       Test PR 10640.
+       * gdb.dwarf2/dw2-op-call.exp, gdb.dwarf2/dw2-op-call.S: New.
+
 2010-06-07  Sami Wagiaalla  <swagiaal@redhat.com>
 
        * gdb.cp/koenig.exp: Test for ADL operators.
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-call.S b/gdb/testsuite/gdb.dwarf2/dw2-op-call.S
new file mode 100644 (file)
index 0000000..068e224
--- /dev/null
@@ -0,0 +1,119 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 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/>.  */
+
+/* Test DW_OP_call2 and DW_OP_call4, PR gdb/10640.  */
+
+       .section .data
+array1:        .2byte  1
+array2:        .2byte  2
+array3:        .2byte  3
+
+       .section .debug_info
+.Lcu1_begin:
+       /* CU header */
+       .4byte  .Lcu1_end - .Lcu1_start         /* Length of Compilation Unit */
+.Lcu1_start:
+       .2byte  2                               /* DWARF Version */
+       .4byte  .Labbrev1_begin                 /* Offset into abbrev section */
+       .byte   4                               /* Pointer size */
+
+       /* CU die */
+       .uleb128 1                              /* Abbrev: DW_TAG_compile_unit */
+       .ascii  "file1.txt\0"                   /* DW_AT_name */
+       .ascii  "GNU C 3.3.3\0"                 /* DW_AT_producer */
+       .byte   2                               /* DW_LANG_C (C) */
+
+.L2byte_type:
+       .uleb128        2                       /* Abbrev: DW_TAG_base_type */
+       .ascii          "2byte\0"               /* DW_AT_name */
+       .byte           2                       /* DW_AT_byte_size */
+       .byte           7                       /* DW_AT_encoding: DW_ATE_unsigned */
+
+.Larray1:
+       .uleb128        3                       /* Abbrev: DW_TAG_variable */
+       .ascii          "array1\0"              /* DW_AT_name */
+       .4byte          .L2byte_type-.Lcu1_begin        /* DW_AT_type */
+       .byte           2f - 1f                 /* DW_AT_location */
+1:     .byte           3                       /*   DW_OP_addr */
+       .4byte          array                   /*     <addr> */
+2:
+
+       .uleb128        3                       /* Abbrev: DW_TAG_variable */
+       .ascii          "array2\0"              /* DW_AT_name */
+       .4byte          .L2byte_type-.Lcu1_begin        /* DW_AT_type */
+       .byte           2f - 1f                 /* DW_AT_location */
+1:     .byte           0x98                    /*   DW_OP_call2 */
+       .2byte          .Larray1-.Lcu1_begin    /*     <current CU offset> */
+       .byte           0x23                    /*   DW_OP_plus_uconst */
+       .uleb128        array2-array1           /*     <uconst> */
+2:
+
+       .uleb128        3                       /* Abbrev: DW_TAG_variable */
+       .ascii          "array3\0"              /* DW_AT_name */
+       .4byte          .L2byte_type-.Lcu1_begin        /* DW_AT_type */
+       .byte           2f - 1f                 /* DW_AT_location */
+1:     .byte           0x99                    /*   DW_OP_call4 */
+       .4byte          .Larray1-.Lcu1_begin    /*     <current CU offset> */
+       .byte           0x23                    /*   DW_OP_plus_uconst */
+       .uleb128        array3-array1           /*     <uconst> */
+2:
+
+       .byte           0                       /* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+       .section .debug_abbrev
+.Labbrev1_begin:
+       .uleb128        1                       /* Abbrev code */
+       .uleb128        0x11                    /* DW_TAG_compile_unit */
+       .byte           1                       /* has_children */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0x25                    /* DW_AT_producer */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0x13                    /* DW_AT_language */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .uleb128        2                       /* Abbrev code */
+       .uleb128        0x24                    /* DW_TAG_base_type */
+       .byte           0                       /* has_children */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0xb                     /* DW_AT_byte_size */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .uleb128        0x3e                    /* DW_AT_encoding */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .uleb128        3                       /* Abbrev code */
+       .uleb128        0x34                    /* DW_TAG_variable */
+       .byte           0                       /* has_children */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0x49                    /* DW_AT_type */
+       .uleb128        0x13                    /* DW_FORM_ref4 */
+       .uleb128        0x2                     /* DW_AT_location */
+       .uleb128        0xa                     /* DW_FORM_block1 */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
new file mode 100644 (file)
index 0000000..5b5fefd
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright 2009 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/>.
+
+# Test DW_OP_call2 and DW_OP_call4, PR gdb/10640.
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+    && ![istarget *-*-gnu*]
+    && ![istarget *-*-elf*]
+    && ![istarget *-*-openbsd*]
+    && ![istarget arm-*-eabi*]
+    && ![istarget powerpc-*-eabi*]} {
+    return 0  
+}
+
+set testfile "dw2-op-call"
+set srcfile ${testfile}.S
+set executable ${testfile}.x
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${executable}" object {nodebug}] != "" } {
+    return -1
+}
+
+clean_restart $executable
+
+gdb_test "p array1" " = 1"
+gdb_test "p array2" " = 2" "array2 using DW_OP_call2"
+gdb_test "p array3" " = 3" "array3 using DW_OP_call4"