gdb
authorTom Tromey <tromey@redhat.com>
Wed, 2 Sep 2009 14:53:57 +0000 (14:53 +0000)
committerTom Tromey <tromey@redhat.com>
Wed, 2 Sep 2009 14:53:57 +0000 (14:53 +0000)
* frame.h (frame_unwinder_is): Declare.
* frame.c (frame_unwinder_is): New function.
* dwarf2loc.c: Include dwarf2-frame.h.
(dwarf_expr_frame_cfa): New function.
(dwarf2_evaluate_loc_desc): Use it.
(needs_frame_frame_cfa): New function.
(dwarf2_loc_desc_needs_frame): Use it.
* dwarf2expr.h (struct dwarf_expr_context) <get_frame_cfa>: New
field.
* dwarf2expr.c (execute_stack_op) <DW_OP_call_frame_cfa>: New
case.
* dwarf2-frame.h (dwarf2_frame_cfa): Declare.
* dwarf2-frame.c (no_get_frame_cfa): New function.
(execute_stack_op): Use it.
(dwarf2_frame_cfa): New function.
gdb/testsuite
* gdb.dwarf2/callframecfa.exp: New file.
* gdb.dwarf2/callframecfa.S: New file.

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

index 6c199cb..a538f1a 100644 (file)
@@ -1,3 +1,21 @@
+2009-09-02  Tom Tromey  <tromey@redhat.com>
+
+       * frame.h (frame_unwinder_is): Declare.
+       * frame.c (frame_unwinder_is): New function.
+       * dwarf2loc.c: Include dwarf2-frame.h.
+       (dwarf_expr_frame_cfa): New function.
+       (dwarf2_evaluate_loc_desc): Use it.
+       (needs_frame_frame_cfa): New function.
+       (dwarf2_loc_desc_needs_frame): Use it.
+       * dwarf2expr.h (struct dwarf_expr_context) <get_frame_cfa>: New
+       field.
+       * dwarf2expr.c (execute_stack_op) <DW_OP_call_frame_cfa>: New
+       case.
+       * dwarf2-frame.h (dwarf2_frame_cfa): Declare.
+       * dwarf2-frame.c (no_get_frame_cfa): New function.
+       (execute_stack_op): Use it.
+       (dwarf2_frame_cfa): New function.
+
 2009-09-02  Hui Zhu  <teawater@gmail.com>
 
        * record.c (record_resume): Change "signal" to "siggnal".
index 427f58f..f9ca067 100644 (file)
@@ -309,6 +309,15 @@ no_get_frame_base (void *baton, gdb_byte **start, size_t *length)
                  _("Support for DW_OP_fbreg is unimplemented"));
 }
 
+/* Helper function for execute_stack_op.  */
+
+static CORE_ADDR
+no_get_frame_cfa (void *baton)
+{
+  internal_error (__FILE__, __LINE__,
+                 _("Support for DW_OP_call_frame_cfa is unimplemented"));
+}
+
 static CORE_ADDR
 no_get_tls_address (void *baton, CORE_ADDR offset)
 {
@@ -363,6 +372,7 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size,
   ctx->read_reg = read_reg;
   ctx->read_mem = read_mem;
   ctx->get_frame_base = no_get_frame_base;
+  ctx->get_frame_cfa = no_get_frame_cfa;
   ctx->get_tls_address = no_get_tls_address;
 
   dwarf_expr_push (ctx, initial);
@@ -1250,6 +1260,23 @@ dwarf2_frame_base_sniffer (struct frame_info *this_frame)
 
   return NULL;
 }
+
+/* Compute the CFA for THIS_FRAME, but only if THIS_FRAME came from
+   the DWARF unwinder.  This is used to implement
+   DW_OP_call_frame_cfa.  */
+
+CORE_ADDR
+dwarf2_frame_cfa (struct frame_info *this_frame)
+{
+  while (get_frame_type (this_frame) == INLINE_FRAME)
+    this_frame = get_prev_frame (this_frame);
+  /* This restriction could be lifted if other unwinders are known to
+     compute the frame base in a way compatible with the DWARF
+     unwinder.  */
+  if (! frame_unwinder_is (this_frame, &dwarf2_frame_unwind))
+    error (_("can't compute CFA for this frame"));
+  return get_frame_base (this_frame);
+}
 \f
 const struct objfile_data *dwarf2_frame_objfile_data;
 
index b203661..dd03d59 100644 (file)
@@ -118,4 +118,8 @@ extern const struct frame_base *
 
 void dwarf2_frame_build_info (struct objfile *objfile);
 
+/* Compute the DWARF CFA for a frame.  */
+
+CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame);
+
 #endif /* dwarf2-frame.h */
index 2721065..6401e72 100644 (file)
@@ -716,6 +716,10 @@ execute_stack_op (struct dwarf_expr_context *ctx,
          }
          break;
 
+       case DW_OP_call_frame_cfa:
+         result = (ctx->get_frame_cfa) (ctx->baton);
+         break;
+
        case DW_OP_GNU_push_tls_address:
          /* Variable is at a constant offset in the thread-local
          storage block into the objfile for the current thread and
index 2306e49..6b3a068 100644 (file)
@@ -55,6 +55,9 @@ struct dwarf_expr_context
      expression evaluation is complete.  */
   void (*get_frame_base) (void *baton, gdb_byte **start, size_t *length);
 
+  /* Return the CFA for the frame.  */
+  CORE_ADDR (*get_frame_cfa) (void *baton);
+
   /* Return the thread-local storage address for
      DW_OP_GNU_push_tls_address.  */
   CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset);
index b6c9b11..dc150a7 100644 (file)
@@ -36,6 +36,7 @@
 #include "dwarf2.h"
 #include "dwarf2expr.h"
 #include "dwarf2loc.h"
+#include "dwarf2-frame.h"
 
 #include "gdb_string.h"
 #include "gdb_assert.h"
@@ -194,6 +195,16 @@ dwarf_expr_frame_base (void *baton, gdb_byte **start, size_t * length)
           SYMBOL_NATURAL_NAME (framefunc));
 }
 
+/* Helper function for dwarf2_evaluate_loc_desc.  Computes the CFA for
+   the frame in BATON.  */
+
+static CORE_ADDR
+dwarf_expr_frame_cfa (void *baton)
+{
+  struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+  return dwarf2_frame_cfa (debaton->frame);
+}
+
 /* Using the objfile specified in BATON, find the address for the
    current thread's thread-local storage with offset OFFSET.  */
 static CORE_ADDR
@@ -237,6 +248,7 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
   ctx->read_reg = dwarf_expr_read_reg;
   ctx->read_mem = dwarf_expr_read_mem;
   ctx->get_frame_base = dwarf_expr_frame_base;
+  ctx->get_frame_cfa = dwarf_expr_frame_cfa;
   ctx->get_tls_address = dwarf_expr_tls_address;
 
   dwarf_expr_eval (ctx, data, size);
@@ -331,6 +343,16 @@ needs_frame_frame_base (void *baton, gdb_byte **start, size_t * length)
   nf_baton->needs_frame = 1;
 }
 
+/* CFA accesses require a frame.  */
+
+static CORE_ADDR
+needs_frame_frame_cfa (void *baton)
+{
+  struct needs_frame_baton *nf_baton = baton;
+  nf_baton->needs_frame = 1;
+  return 1;
+}
+
 /* Thread-local accesses do require a frame.  */
 static CORE_ADDR
 needs_frame_tls_address (void *baton, CORE_ADDR offset)
@@ -363,6 +385,7 @@ dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size,
   ctx->read_reg = needs_frame_read_reg;
   ctx->read_mem = needs_frame_read_mem;
   ctx->get_frame_base = needs_frame_frame_base;
+  ctx->get_frame_cfa = needs_frame_frame_cfa;
   ctx->get_tls_address = needs_frame_tls_address;
 
   dwarf_expr_eval (ctx, data, size);
index 67e0607..67ef967 100644 (file)
@@ -1843,6 +1843,17 @@ get_frame_args_address (struct frame_info *fi)
   return fi->base->this_args (fi, &fi->base_cache);
 }
 
+/* Return true if the frame unwinder for frame FI is UNWINDER; false
+   otherwise.  */
+
+int
+frame_unwinder_is (struct frame_info *fi, const struct frame_unwind *unwinder)
+{
+  if (fi->unwind == NULL)
+    fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
+  return fi->unwind == unwinder;
+}
+
 /* Level of the selected frame: 0 for innermost, 1 for its caller, ...
    or -1 for a NULL frame.  */
 
index febef5c..611c6d3 100644 (file)
@@ -696,4 +696,10 @@ extern struct frame_info *deprecated_safe_get_selected_frame (void);
 
 extern struct frame_info *create_new_frame (CORE_ADDR base, CORE_ADDR pc);
 
+/* Return true if the frame unwinder for frame FI is UNWINDER; false
+   otherwise.  */
+
+extern int frame_unwinder_is (struct frame_info *fi,
+                             const struct frame_unwind *unwinder);
+
 #endif /* !defined (FRAME_H)  */
index 8cce673..0a2c704 100644 (file)
@@ -1,3 +1,8 @@
+2009-09-02  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.dwarf2/callframecfa.exp: New file.
+       * gdb.dwarf2/callframecfa.S: New file.
+
 2009-09-01  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * gdb.base/solib-overlap.exp, gdb.base/solib-overlap-lib.c,
diff --git a/gdb/testsuite/gdb.dwarf2/callframecfa.S b/gdb/testsuite/gdb.dwarf2/callframecfa.S
new file mode 100644 (file)
index 0000000..6d0421a
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+   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/>.
+ */
+
+/* This was compiled from a trivial program just to test the
+   DW_OP_call_frame_cfa operator:
+
+    int func (int arg) {
+      return arg + 23;
+    }
+
+    int main(int argc, char *argv[]) {
+      func (77);
+    }
+*/
+
+       .file   "q.c"
+       .section        .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+       .section        .debug_info,"",@progbits
+.Ldebug_info0:
+       .section        .debug_line,"",@progbits
+.Ldebug_line0:
+       .text
+.Ltext0:
+.globl func
+       .type   func, @function
+func:
+.LFB0:
+       .file 1 "q.c"
+       .loc 1 2 0
+       .cfi_startproc
+       pushl   %ebp
+       .cfi_def_cfa_offset 8
+       movl    %esp, %ebp
+       .cfi_offset 5, -8
+       .cfi_def_cfa_register 5
+       .loc 1 3 0
+       movl    8(%ebp), %eax
+       addl    $23, %eax
+       .loc 1 4 0
+       popl    %ebp
+       .cfi_restore 5
+       .cfi_def_cfa 4, 4
+       ret
+       .cfi_endproc
+.LFE0:
+       .size   func, .-func
+.globl _start
+       .type   _start, @function
+_start:
+.LFB1:
+       .loc 1 6 0
+       .cfi_startproc
+       pushl   %ebp
+       .cfi_def_cfa_offset 8
+       movl    %esp, %ebp
+       .cfi_offset 5, -8
+       .cfi_def_cfa_register 5
+       subl    $4, %esp
+       .loc 1 7 0
+       movl    $77, (%esp)
+       call    func
+       .loc 1 8 0
+       leave
+       .cfi_restore 5
+       .cfi_def_cfa 4, 4
+       ret
+       .cfi_endproc
+.LFE1:
+       .size   _start, .-_start
+.Letext0:
+       .section        .debug_info
+       .long   0x9e
+       .value  0x3
+       .long   .Ldebug_abbrev0
+       .byte   0x4
+       .uleb128 0x1
+       .long   .LASF5
+       .byte   0x1
+       .string "q.c"
+       .long   .LASF6
+       .long   .Ltext0
+       .long   .Letext0
+       .long   .Ldebug_line0
+       .uleb128 0x2
+       .byte   0x1
+       .long   .LASF0
+       .byte   0x1
+       .byte   0x1
+       .byte   0x1
+       .long   0x4f
+       .long   .LFB0
+       .long   .LFE0
+       .byte   0x1
+       .byte   0x9c
+       .long   0x4f
+       .uleb128 0x3
+       .string "arg"
+       .byte   0x1
+       .byte   0x1
+       .long   0x4f
+       .byte   0x2
+       .byte   0x91
+       .sleb128 0
+       .byte   0x0
+       .uleb128 0x4
+       .byte   0x4
+       .byte   0x5
+       .string "int"
+       .uleb128 0x2
+       .byte   0x1
+       .long   .LASF1
+       .byte   0x1
+       .byte   0x6
+       .byte   0x1
+       .long   0x4f
+       .long   .LFB1
+       .long   .LFE1
+       .byte   0x1
+       .byte   0x9c
+       .long   0x8e
+       .uleb128 0x5
+       .long   .LASF2
+       .byte   0x1
+       .byte   0x6
+       .long   0x4f
+       .byte   0x2
+       .byte   0x91
+       .sleb128 0
+       .uleb128 0x5
+       .long   .LASF3
+       .byte   0x1
+       .byte   0x6
+       .long   0x8e
+       .byte   0x2
+       .byte   0x91
+       .sleb128 4
+       .byte   0x0
+       .uleb128 0x6
+       .byte   0x4
+       .long   0x94
+       .uleb128 0x6
+       .byte   0x4
+       .long   0x9a
+       .uleb128 0x7
+       .byte   0x1
+       .byte   0x6
+       .long   .LASF4
+       .byte   0x0
+       .section        .debug_abbrev
+       .uleb128 0x1
+       .uleb128 0x11
+       .byte   0x1
+       .uleb128 0x25
+       .uleb128 0xe
+       .uleb128 0x13
+       .uleb128 0xb
+       .uleb128 0x3
+       .uleb128 0x8
+       .uleb128 0x1b
+       .uleb128 0xe
+       .uleb128 0x11
+       .uleb128 0x1
+       .uleb128 0x12
+       .uleb128 0x1
+       .uleb128 0x10
+       .uleb128 0x6
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x2
+       .uleb128 0x2e
+       .byte   0x1
+       .uleb128 0x3f
+       .uleb128 0xc
+       .uleb128 0x3
+       .uleb128 0xe
+       .uleb128 0x3a
+       .uleb128 0xb
+       .uleb128 0x3b
+       .uleb128 0xb
+       .uleb128 0x27
+       .uleb128 0xc
+       .uleb128 0x49
+       .uleb128 0x13
+       .uleb128 0x11
+       .uleb128 0x1
+       .uleb128 0x12
+       .uleb128 0x1
+       .uleb128 0x40
+       .uleb128 0xa
+       .uleb128 0x1
+       .uleb128 0x13
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x3
+       .uleb128 0x5
+       .byte   0x0
+       .uleb128 0x3
+       .uleb128 0x8
+       .uleb128 0x3a
+       .uleb128 0xb
+       .uleb128 0x3b
+       .uleb128 0xb
+       .uleb128 0x49
+       .uleb128 0x13
+       .uleb128 0x2
+       .uleb128 0xa
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x4
+       .uleb128 0x24
+       .byte   0x0
+       .uleb128 0xb
+       .uleb128 0xb
+       .uleb128 0x3e
+       .uleb128 0xb
+       .uleb128 0x3
+       .uleb128 0x8
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x5
+       .uleb128 0x5
+       .byte   0x0
+       .uleb128 0x3
+       .uleb128 0xe
+       .uleb128 0x3a
+       .uleb128 0xb
+       .uleb128 0x3b
+       .uleb128 0xb
+       .uleb128 0x49
+       .uleb128 0x13
+       .uleb128 0x2
+       .uleb128 0xa
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x6
+       .uleb128 0xf
+       .byte   0x0
+       .uleb128 0xb
+       .uleb128 0xb
+       .uleb128 0x49
+       .uleb128 0x13
+       .byte   0x0
+       .byte   0x0
+       .uleb128 0x7
+       .uleb128 0x24
+       .byte   0x0
+       .uleb128 0xb
+       .uleb128 0xb
+       .uleb128 0x3e
+       .uleb128 0xb
+       .uleb128 0x3
+       .uleb128 0xe
+       .byte   0x0
+       .byte   0x0
+       .byte   0x0
+       .section        .debug_pubnames,"",@progbits
+       .long   0x20
+       .value  0x2
+       .long   .Ldebug_info0
+       .long   0xa2
+       .long   0x25
+       .string "func"
+       .long   0x56
+       .string "main"
+       .long   0x0
+       .section        .debug_aranges,"",@progbits
+       .long   0x1c
+       .value  0x2
+       .long   .Ldebug_info0
+       .byte   0x4
+       .byte   0x0
+       .value  0x0
+       .value  0x0
+       .long   .Ltext0
+       .long   .Letext0-.Ltext0
+       .long   0x0
+       .long   0x0
+       .section        .debug_str,"MS",@progbits,1
+.LASF5:
+       .string "GNU C 4.5.0 20090810 (experimental) [trunk revision 150633]"
+.LASF2:
+       .string "argc"
+.LASF6:
+       .string "/tmp"
+.LASF0:
+       .string "func"
+.LASF3:
+       .string "argv"
+.LASF1:
+       .string "main"
+.LASF4:
+       .string "char"
+       .ident  "GCC: (GNU) 4.5.0 20090810 (experimental) [trunk revision 150633]"
+       .section        .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.dwarf2/callframecfa.exp b/gdb/testsuite/gdb.dwarf2/callframecfa.exp
new file mode 100644 (file)
index 0000000..00d67fc
--- /dev/null
@@ -0,0 +1,55 @@
+# 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_call_frame_cfa.
+
+# 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  
+}
+# This test can only be run on x86 targets.
+if {![istarget i?86-*]} {
+    return 0  
+}
+
+set testfile "callframecfa"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+       [list {additional_flags=-nostdlib}]] != "" } {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "break *func" "Breakpoint 1.*" "set breakpoint for call-frame-cfa"
+gdb_test "run" "" "run for call-frame-cfa"
+gdb_test "display arg" "arg = 77" "set display for call-frame-cfa"
+
+# We know how many instructions are in the function.  Note that we
+# can't handle the "ret" instruction due to the epilogue unwinder.
+for {set i 1} {$i < 5} {incr i} {
+    gdb_test "si" "arg = 77" "step $i for call-frame-cfa"
+}