diff options
-rw-r--r-- | gdb/ChangeLog | 18 | ||||
-rw-r--r-- | gdb/dwarf2-frame.c | 27 | ||||
-rw-r--r-- | gdb/dwarf2-frame.h | 4 | ||||
-rw-r--r-- | gdb/dwarf2expr.c | 4 | ||||
-rw-r--r-- | gdb/dwarf2expr.h | 3 | ||||
-rw-r--r-- | gdb/dwarf2loc.c | 23 | ||||
-rw-r--r-- | gdb/frame.c | 11 | ||||
-rw-r--r-- | gdb/frame.h | 6 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/callframecfa.S | 309 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/callframecfa.exp | 55 |
11 files changed, 465 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6c199cb..a538f1a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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". diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 427f58f..f9ca067 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -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); +} const struct objfile_data *dwarf2_frame_objfile_data; diff --git a/gdb/dwarf2-frame.h b/gdb/dwarf2-frame.h index b203661..dd03d59 100644 --- a/gdb/dwarf2-frame.h +++ b/gdb/dwarf2-frame.h @@ -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 */ diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 2721065..6401e72 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -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 diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 2306e49..6b3a068 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -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); diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index b6c9b11..dc150a7 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -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); diff --git a/gdb/frame.c b/gdb/frame.c index 67e0607..67ef967 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -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. */ diff --git a/gdb/frame.h b/gdb/frame.h index febef5c..611c6d3 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -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) */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8cce673..0a2c704 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -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 index 0000000..6d0421a --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/callframecfa.S @@ -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 index 0000000..00d67fc --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/callframecfa.exp @@ -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" +} |