From 782d47dfbdfde099cccd06a944e843368cccda76 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 6 Dec 2013 19:48:00 +0000 Subject: [PATCH] Fix "info frame" in the outermost frame. Doing "info frame" in the outermost frame, when that was indicated by the next frame saying the unwound PC is undefined/not saved, results in error and incomplete output: (gdb) bt #0 thread_function0 (arg=0x0) at threads.c:63 #1 0x00000034cf407d14 in start_thread (arg=0x7ffff7fcb700) at pthread_create.c:309 #2 0x000000323d4f168d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 (gdb) frame 2 #2 0x000000323d4f168d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 115 call *%rax (gdb) info frame Stack level 2, frame at 0x0: rip = 0x323d4f168d in clone (../sysdeps/unix/sysv/linux/x86_64/clone.S:115); saved rip Register 16 was not saved (gdb) Not saved register values are treated as optimized out values internally throughout. stack.c:frame_info is handing unvailable values, but not optimized out ones. The patch deletes the frame_unwind_caller_pc_if_available wrapper function and instead lets errors propagate to frame_info (it's only user). As frame_unwind_pc now needs to be able to handle and cache two different error scenarios, the prev_pc.p variable is replaced with an enumeration. (FWIW, I looked into making gdbarch_unwind_pc or a variant return struct value's instead, but it results in lots of boxing and unboxing for no real gain -- e.g., the mips and arm implementations need to do computation on the unboxed PC value. Might as well throw an error on first attempt to get at invalid contents.) After the patch, we get: (gdb) info frame Stack level 2, frame at 0x0: rip = 0x323d4f168d in clone (../sysdeps/unix/sysv/linux/x86_64/clone.S:115); saved rip = Outermost frame: outermost caller of frame at 0x7ffff7fcafc0 source language asm. Arglist at 0x7ffff7fcafb8, args: Locals at 0x7ffff7fcafb8, Previous frame's sp is 0x7ffff7fcafc8 (gdb) A new test is added. It's based off dw2-reg-undefined.exp, and tweaked to mark the return address (rip) of "stop_frame" as undefined. Tested on x86_64 Fedora 17. gdb/ 2013-12-06 Pedro Alves * frame.c (enum cached_copy_status): New enum. (struct frame_info) : Change type to enum cached_copy_status. (fprint_frame): Handle not saved and unavailable prev_pc values. (frame_unwind_pc_if_available): Delete and merge contents into ... (frame_unwind_pc): ... here. Handle OPTIMIZED_OUT_ERROR. Adjust to use enum cached_copy_status. (frame_unwind_caller_pc_if_available): Delete. (create_new_frame): Adjust. * frame.h (frame_unwind_caller_pc_if_available): Delete declaration. * stack.c (frame_info): Use frame_unwind_caller_pc instead of frame_unwind_caller_pc_if_available, and handle NOT_AVAILABLE_ERROR and OPTIMIZED_OUT_ERROR errors. * valprint.c (val_print_optimized_out): Use val_print_not_saved. (val_print_not_saved): New function. * valprint.h (val_print_not_saved): Declare. gdb/testsuite/ 2013-12-06 Pedro Alves * gdb.dwarf2/dw2-undefined-ret-addr.S: New file. * gdb.dwarf2/dw2-undefined-ret-addr.c: New file. * gdb.dwarf2/dw2-undefined-ret-addr.exp: New file. --- gdb/ChangeLog | 20 + gdb/frame.c | 108 ++-- gdb/frame.h | 8 - gdb/stack.c | 27 +- gdb/testsuite/ChangeLog | 6 + .../gdb.dwarf2/dw2-undefined-ret-addr.S | 508 ++++++++++++++++++ .../gdb.dwarf2/dw2-undefined-ret-addr.c | 36 ++ .../gdb.dwarf2/dw2-undefined-ret-addr.exp | 58 ++ gdb/valprint.c | 8 +- gdb/valprint.h | 3 + 10 files changed, 723 insertions(+), 59 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.S create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.c create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 911131410a..474839254d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2013-12-06 Pedro Alves + + * frame.c (enum cached_copy_status): New enum. + (struct frame_info) : Change type to enum + cached_copy_status. + (fprint_frame): Handle not saved and unavailable prev_pc values. + (frame_unwind_pc_if_available): Delete and merge contents into ... + (frame_unwind_pc): ... here. Handle OPTIMIZED_OUT_ERROR. Adjust + to use enum cached_copy_status. + (frame_unwind_caller_pc_if_available): Delete. + (create_new_frame): Adjust. + * frame.h (frame_unwind_caller_pc_if_available): Delete + declaration. + * stack.c (frame_info): Use frame_unwind_caller_pc instead of + frame_unwind_caller_pc_if_available, and handle + NOT_AVAILABLE_ERROR and OPTIMIZED_OUT_ERROR errors. + * valprint.c (val_print_optimized_out): Use val_print_not_saved. + (val_print_not_saved): New function. + * valprint.h (val_print_not_saved): Declare. + 2013-12-06 Andrew Burgess Pedro Alves diff --git a/gdb/frame.c b/gdb/frame.c index 0ba1d4dfb4..6a8b5ae58b 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -50,6 +50,23 @@ static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame); static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame); static const char *frame_stop_reason_symbol_string (enum unwind_stop_reason reason); +/* Status of some values cached in the frame_info object. */ + +enum cached_copy_status +{ + /* Value is unknown. */ + CC_UNKNOWN, + + /* We have a value. */ + CC_VALUE, + + /* Value was not saved. */ + CC_NOT_SAVED, + + /* Value is unavailable. */ + CC_UNAVAILABLE +}; + /* We keep a cache of stack frames, each of which is a "struct frame_info". The innermost one gets allocated (in wait_for_inferior) each time the inferior stops; current_frame @@ -96,7 +113,7 @@ struct frame_info /* Cached copy of the previous frame's resume address. */ struct { - int p; + enum cached_copy_status status; CORE_ADDR value; } prev_pc; @@ -366,10 +383,15 @@ fprint_frame (struct ui_file *file, struct frame_info *fi) fprintf_unfiltered (file, ""); fprintf_unfiltered (file, ","); fprintf_unfiltered (file, "pc="); - if (fi->next != NULL && fi->next->prev_pc.p) - fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value)); - else + if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN) fprintf_unfiltered (file, ""); + else if (fi->next->prev_pc.status == CC_VALUE) + fprintf_unfiltered (file, "%s", + hex_string (fi->next->prev_pc.value)); + else if (fi->next->prev_pc.status == CC_NOT_SAVED) + val_print_not_saved (file); + else if (fi->next->prev_pc.status == CC_UNAVAILABLE) + val_print_unavailable (file); fprintf_unfiltered (file, ","); fprintf_unfiltered (file, "id="); if (fi->this_id.p) @@ -707,10 +729,10 @@ frame_find_by_id (struct frame_id id) return NULL; } -static int -frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) +static CORE_ADDR +frame_unwind_pc (struct frame_info *this_frame) { - if (!this_frame->prev_pc.p) + if (this_frame->prev_pc.status == CC_UNKNOWN) { if (gdbarch_unwind_pc_p (frame_unwind_arch (this_frame))) { @@ -740,24 +762,35 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { pc = gdbarch_unwind_pc (prev_gdbarch, this_frame); } - if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) + if (ex.reason < 0) { - this_frame->prev_pc.p = -1; - - if (frame_debug) - fprintf_unfiltered (gdb_stdlog, - "{ frame_unwind_pc (this_frame=%d)" - " -> }\n", - this_frame->level); - } - else if (ex.reason < 0) - { - throw_exception (ex); + if (ex.error == NOT_AVAILABLE_ERROR) + { + this_frame->prev_pc.status = CC_UNAVAILABLE; + + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ frame_unwind_pc (this_frame=%d)" + " -> }\n", + this_frame->level); + } + else if (ex.error == OPTIMIZED_OUT_ERROR) + { + this_frame->prev_pc.status = CC_NOT_SAVED; + + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "{ frame_unwind_pc (this_frame=%d)" + " -> }\n", + this_frame->level); + } + else + throw_exception (ex); } else { this_frame->prev_pc.value = pc; - this_frame->prev_pc.p = 1; + this_frame->prev_pc.status = CC_VALUE; if (frame_debug) fprintf_unfiltered (gdb_stdlog, "{ frame_unwind_pc (this_frame=%d) " @@ -769,27 +802,17 @@ frame_unwind_pc_if_available (struct frame_info *this_frame, CORE_ADDR *pc) else internal_error (__FILE__, __LINE__, _("No unwind_pc method")); } - if (this_frame->prev_pc.p < 0) - { - *pc = -1; - return 0; - } - else - { - *pc = this_frame->prev_pc.value; - return 1; - } -} -static CORE_ADDR -frame_unwind_pc (struct frame_info *this_frame) -{ - CORE_ADDR pc; - - if (!frame_unwind_pc_if_available (this_frame, &pc)) + if (this_frame->prev_pc.status == CC_VALUE) + return this_frame->prev_pc.value; + else if (this_frame->prev_pc.status == CC_UNAVAILABLE) throw_error (NOT_AVAILABLE_ERROR, _("PC not available")); + else if (this_frame->prev_pc.status == CC_NOT_SAVED) + throw_error (OPTIMIZED_OUT_ERROR, _("PC not saved")); else - return pc; + internal_error (__FILE__, __LINE__, + "unexpected prev_pc status: %d", + (int) this_frame->prev_pc.status); } CORE_ADDR @@ -798,13 +821,6 @@ frame_unwind_caller_pc (struct frame_info *this_frame) return frame_unwind_pc (skip_artificial_frames (this_frame)); } -int -frame_unwind_caller_pc_if_available (struct frame_info *this_frame, - CORE_ADDR *pc) -{ - return frame_unwind_pc_if_available (skip_artificial_frames (this_frame), pc); -} - int get_frame_func_if_available (struct frame_info *this_frame, CORE_ADDR *pc) { @@ -1572,7 +1588,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc) very likely to read this, and the corresponding unwinder is entitled to rely that the PC doesn't magically change. */ fi->next->prev_pc.value = pc; - fi->next->prev_pc.p = 1; + fi->next->prev_pc.status = CC_VALUE; /* We currently assume that frame chain's can't cross spaces. */ fi->pspace = fi->next->pspace; diff --git a/gdb/frame.h b/gdb/frame.h index a5e1629f98..f8d5bc17a7 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -548,14 +548,6 @@ extern void put_frame_register_bytes (struct frame_info *frame, int regnum, extern CORE_ADDR frame_unwind_caller_pc (struct frame_info *frame); -/* Same as frame_unwind_caller_pc, but returns a boolean indication of - whether the caller PC is determinable (when the PC is unavailable, - it will not be), instead of possibly throwing an error trying to - read unavailable memory or registers. */ - -extern int frame_unwind_caller_pc_if_available (struct frame_info *this_frame, - CORE_ADDR *pc); - /* Discard the specified frame. Restoring the registers to the state of the caller. */ extern void frame_pop (struct frame_info *frame); diff --git a/gdb/stack.c b/gdb/stack.c index 9a12eb378b..848bcb0a26 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1408,6 +1408,7 @@ frame_info (char *addr_exp, int from_tty) CORE_ADDR frame_pc; int frame_pc_p; CORE_ADDR caller_pc; + volatile struct gdb_exception ex; fi = parse_frame_specification_1 (addr_exp, "No stack.", &selected_frame_p); gdbarch = get_frame_arch (fi); @@ -1493,11 +1494,29 @@ frame_info (char *addr_exp, int from_tty) sal.line); puts_filtered ("; "); wrap_here (" "); - printf_filtered ("saved %s ", pc_regname); - if (frame_unwind_caller_pc_if_available (fi, &caller_pc)) - fputs_filtered (paddress (gdbarch, caller_pc), gdb_stdout); + printf_filtered ("saved %s = ", pc_regname); + + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + caller_pc = frame_unwind_caller_pc (fi); + } + if (ex.reason < 0) + { + switch (ex.error) + { + case NOT_AVAILABLE_ERROR: + val_print_unavailable (gdb_stdout); + break; + case OPTIMIZED_OUT_ERROR: + val_print_not_saved (gdb_stdout); + break; + default: + fprintf_filtered (gdb_stdout, _(""), ex.message); + break; + } + } else - fputs_filtered ("", gdb_stdout); + fputs_filtered (paddress (gdbarch, caller_pc), gdb_stdout); printf_filtered ("\n"); if (calling_frame_info == NULL) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 14bf46c386..52e7ddc9bf 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-12-06 Pedro Alves + + * gdb.dwarf2/dw2-undefined-ret-addr.S: New file. + * gdb.dwarf2/dw2-undefined-ret-addr.c: New file. + * gdb.dwarf2/dw2-undefined-ret-addr.exp: New file. + 2013-12-06 Doug Evans * gdb.base/break.exp: Fix setting of $baz. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.S b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.S new file mode 100644 index 0000000000..fc92016645 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.S @@ -0,0 +1,508 @@ +/* + Copyright 2013 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 . */ + + /* The FDE entry for "stop_frame" in the .debug_frame section has + been hand modified to mark the return address (rip) as undefined. + Otherwise this file is as generated by gcc 4.7.2 for x86_64. */ + .file "dw2-undefined-ret-addr.c" + .text +.Ltext0: + .globl stop_frame + .type stop_frame, @function +stop_frame: +.LFB0: + .file 1 "dw2-undefined-ret-addr.c" + .loc 1 19 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + .loc 1 22 0 + popq %rbp +.LCFI2: + ret +.LFE0: + .size stop_frame, .-stop_frame + .globl first_frame + .type first_frame, @function +first_frame: +.LFB1: + .loc 1 26 0 + pushq %rbp +.LCFI3: + movq %rsp, %rbp +.LCFI4: + .loc 1 27 0 + movl $0, %eax + call stop_frame + .loc 1 28 0 + popq %rbp +.LCFI5: + ret +.LFE1: + .size first_frame, .-first_frame + .globl main + .type main, @function +main: +.LFB2: + .loc 1 32 0 + pushq %rbp +.LCFI6: + movq %rsp, %rbp +.LCFI7: + .loc 1 33 0 + movl $0, %eax + call first_frame + .loc 1 35 0 + movl $0, %eax + .loc 1 36 0 + popq %rbp +.LCFI8: + ret +.LFE2: + .size main, .-main + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: + /* This FDE entry, for stop_frame was modified to mark + registers 0 -> 6 as being undefined. */ +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB0 + .quad .LFE0-.LFB0 + + /* START OF NEW CONTENT. */ + .byte 0x7 /* DW_CFA_undefined */ + .uleb128 0x10 /* ULEB128 register */ + /* END OF NEW CONTENT. */ + + .byte 0x4 + .long .LCFI0-.LFB0 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI2-.LCFI1 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE0: +.LSFDE2: + .long .LEFDE2-.LASFDE2 +.LASFDE2: + .long .Lframe0 + .quad .LFB1 + .quad .LFE1-.LFB1 + .byte 0x4 + .long .LCFI3-.LFB1 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI4-.LCFI3 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI5-.LCFI4 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE2: +.LSFDE4: + .long .LEFDE4-.LASFDE4 +.LASFDE4: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI6-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI7-.LCFI6 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI8-.LCFI7 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE4: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE7: + .long .LEFDE7-.LASFDE7 +.LASFDE7: + .long .LASFDE7-.Lframe1 + .long .LFB0 + .long .LFE0-.LFB0 + .uleb128 0 + .byte 0x4 + .long .LCFI0-.LFB0 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI2-.LCFI1 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE7: +.LSFDE9: + .long .LEFDE9-.LASFDE9 +.LASFDE9: + .long .LASFDE9-.Lframe1 + .long .LFB1 + .long .LFE1-.LFB1 + .uleb128 0 + .byte 0x4 + .long .LCFI3-.LFB1 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI4-.LCFI3 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI5-.LCFI4 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE9: +.LSFDE11: + .long .LEFDE11-.LASFDE11 +.LASFDE11: + .long .LASFDE11-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0 + .byte 0x4 + .long .LCFI6-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI7-.LCFI6 + .byte 0xd + .uleb128 0x6 + .byte 0x4 + .long .LCFI8-.LCFI7 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .align 8 +.LEFDE11: + .text +.Letext0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .long 0x8c + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .long .LASF0 + .byte 0x1 + .byte 0x12 + .quad .LFB0 + .quad .LFE0 + .long .LLST0 + .byte 0x1 + .uleb128 0x3 + .byte 0x1 + .long .LASF1 + .byte 0x1 + .byte 0x19 + .quad .LFB1 + .quad .LFE1 + .long .LLST1 + .byte 0x1 + .uleb128 0x4 + .byte 0x1 + .long .LASF5 + .byte 0x1 + .byte 0x1f + .long 0x88 + .quad .LFB2 + .quad .LFE2 + .long .LLST2 + .byte 0x1 + .uleb128 0x5 + .byte 0x4 + .byte 0x5 + .string "int" + .byte 0 + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0 + .byte 0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x2117 + .uleb128 0xc + .byte 0 + .byte 0 + .uleb128 0x3 + .uleb128 0x2e + .byte 0 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x2116 + .uleb128 0xc + .byte 0 + .byte 0 + .uleb128 0x4 + .uleb128 0x2e + .byte 0 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x2116 + .uleb128 0xc + .byte 0 + .byte 0 + .uleb128 0x5 + .uleb128 0x24 + .byte 0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0 + .byte 0 + .byte 0 + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB0-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LCFI2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad .LCFI2-.Ltext0 + .quad .LFE0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad 0 + .quad 0 +.LLST1: + .quad .LFB1-.Ltext0 + .quad .LCFI3-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI3-.Ltext0 + .quad .LCFI4-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI4-.Ltext0 + .quad .LCFI5-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad .LCFI5-.Ltext0 + .quad .LFE1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad 0 + .quad 0 +.LLST2: + .quad .LFB2-.Ltext0 + .quad .LCFI6-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI6-.Ltext0 + .quad .LCFI7-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI7-.Ltext0 + .quad .LCFI8-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad .LCFI8-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad 0 + .quad 0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0 + .value 0 + .value 0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0 + .quad 0 + .section .debug_line,"",@progbits +.Ldebug_line0: + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "stop_frame" +.LASF3: + .string "dw2-undefined-ret-addr.c" +.LASF2: + .string "GNU C 4.7.2" +.LASF1: + .string "first_frame" +.LASF5: + .string "main" +.LASF4: + .string "/home/username/src/gdb/testsuite/gdb.dwarf2" + .ident "GCC: (GNU) 4.7.2" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.c b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.c new file mode 100644 index 0000000000..6c5b06a94a --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.c @@ -0,0 +1,36 @@ +/* + Copyright 2013 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 . */ + +void +stop_frame () +{ + /* The debug information for this frame is modified in the accompanying + .S file, to mark the return address as undefined. */ +} + +void +first_frame () +{ + stop_frame (); +} + +int +main () +{ + first_frame (); + + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.exp b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.exp new file mode 100644 index 0000000000..40ac3563a5 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-undefined-ret-addr.exp @@ -0,0 +1,58 @@ +# Copyright 2013 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 . +load_lib dwarf.exp + +standard_testfile .S + +# This test can only be run on targets which support DWARF-2 and use gas. +if ![dwarf2_support] { + return 0 +} + +# This test can only be run on x86-64 targets. +if {![istarget x86_64-*] || ![is_lp64_target]} { + return 0 +} + +if {[prepare_for_testing "$testfile.exp" "$testfile" $srcfile {nodebug}]} { + return -1 +} + +if ![runto "stop_frame"] { + return -1 +} + +# stop_frame should be the outermost frame. + +# Check that backtrace shows only frame #0. +gdb_test "bt" "#0\[ \]\+stop_frame \[^\r\n\]\+" + +# And that "up" doesn't work. +gdb_test "up" \ + "Initial frame selected; you cannot go up\\." \ + "up refuses to go up" + +# "info frame" unwinds the PC for "saved ... = ". Make sure that +# doesn't cause an error, and shows "". +gdb_test "info frame" [join [list \ + "Stack level 0, frame at $hex\:" \ + " rip = $hex in stop_frame \\(dw2-undefined-ret-addr\\.c:22\\); saved rip = " \ + " Outermost frame: outermost" \ + " source language c\\." \ + " Arglist at $hex, args\: " \ + " Locals at $hex, Previous frame's sp is $hex" \ + " Saved registers\:" \ + " rbp at $hex.*" \ +] "\r\n"] diff --git a/gdb/valprint.c b/gdb/valprint.c index 0124934cb7..7ebcdfd991 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -339,11 +339,17 @@ void val_print_optimized_out (const struct value *val, struct ui_file *stream) { if (val != NULL && value_lval_const (val) == lval_register) - fprintf_filtered (stream, _("")); + val_print_not_saved (stream); else fprintf_filtered (stream, _("")); } +void +val_print_not_saved (struct ui_file *stream) +{ + fprintf_filtered (stream, _("")); +} + void val_print_unavailable (struct ui_file *stream) { diff --git a/gdb/valprint.h b/gdb/valprint.h index 1d86ed73da..8ed259d6b7 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -163,6 +163,9 @@ extern int read_string (CORE_ADDR addr, int len, int width, extern void val_print_optimized_out (const struct value *val, struct ui_file *stream); +/* Prints "" to STREAM. */ +extern void val_print_not_saved (struct ui_file *stream); + extern void val_print_unavailable (struct ui_file *stream); extern void val_print_invalid_address (struct ui_file *stream); -- 2.34.1