* 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.
+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".
_("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)
{
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);
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;
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 */
}
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
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);
#include "dwarf2.h"
#include "dwarf2expr.h"
#include "dwarf2loc.h"
+#include "dwarf2-frame.h"
#include "gdb_string.h"
#include "gdb_assert.h"
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
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);
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)
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);
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. */
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) */
+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,
--- /dev/null
+/*
+ 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
--- /dev/null
+# 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"
+}