public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFC 0/4] Catch errors in get_prev_frame.
@ 2014-04-04 14:46 Andrew Burgess
  2014-04-04 14:47 ` [RFC 1/4] New tests for backtracing with a corrupted stack Andrew Burgess
                   ` (10 more replies)
  0 siblings, 11 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:46 UTC (permalink / raw)
  To: gdb-patches

While working on a reproducer for this patch:
  https://sourceware.org/ml/gdb-patches/2014-03/msg00629.html

I ran into a few other issues.  The route cause of the problems I'm
seeing is that not all errors thrown within get_prev_frame are caught.
This causes a couple of problems,

1. For the MI this means that commands like -stack-info-depth will
return an error rather than a result.  Even more annoying, is that
depending on where in the process the error is thrown enough state may
be left set that the /next/ time -stack-info-depth is asked, the correct
result is given!

2. For standard CLI backtraces our the results are (I think)
inconsistent, so for example some backtraces will end with a message
like: "Backtrace stopped: previous frame inner to this frame (corrupted
stack?)", this message will be displayed every time the backtrace is
requested, in other cases though, the reason is only displayed the first
time a backtrace is requested, this is the case when an uncaught error
causes the backtrace to stop, also in the uncaught error case the
"Backtrace stopped" prefix does not appear.

This patch set tries to fix both these issues by holding a frame
specific string that describes why the backtrace stopped at this frame
(only for the last frame in the backtrace obviously).  If this string is
not set then we still use the existing generic strings.

A new TRY_CATCH inside get_prev_frame catches (currently) all unhandled
errors, the error message from these errors is then used as a frame
specific stop reason string.  There's a new unwind_stop_reason code for
this case, UNWIND_MISC_ERROR.

If it's felt that catching all errors like this is too much then I could
soften this to just catching MEMORY_ERRORs, as right now the problems
I'm seeing all relate to accessing memory through a corrupted stack pointer.

Here's what each patch does:

#1 - This patch just adds some tests, some of the tests fail, and are
fixed by later patches in this series.

#2 - An error in the wrong place leaves a frame partially initialised,
this can then cause internal errors / assertions to fire.  Add a clean
up to fix this issue.

#3 Deprecate frame_stop_reason_string, rename all use sites.  I'm going
to add a new version in the next patch that takes a struct frame_info
pointer.

#4 Add the new TRY_CATCH and the new stop reason string into the
frame_info structure.

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC 1/4]  New tests for backtracing with a corrupted stack.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
@ 2014-04-04 14:47 ` Andrew Burgess
  2014-04-04 14:48 ` [RFC 2/4] Remove previous frame if we error during compute_frame_id Andrew Burgess
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:47 UTC (permalink / raw)
  To: gdb-patches

Two tests for backtracing when there's a corrupted stack pointer.

These tests live in the gdb.arch/ directory as they are amd64
specific, however, the tests use MI commands (as well as normal
commands).  I wasn't totally sure where the best place to put
the tests was, I'd either have to put arch specific code into
the gdb.mi/ directory, or mi specific code into gdb.arch/ ...

... I figured that putting some specific MI commands into gdb.arch/
was the lesser evil, my reasoning being that this covers a specific
bug/issue seen in this case, but is not aiming to exhaustively cover
the MI, it's not _really_ an MI test...  

Some of these tests fail without the rest of this patch set, so can't
be merged until everything else is ready, but all feedback appreciated.


Thanks,
Andrew

gdb/testsuite/ChangeLog:
    
	* gdb.arch/amd64-invalid-stack-middle.S: New file.
	* gdb.arch/amd64-invalid-stack-middle.c: New file.
	* gdb.arch/amd64-invalid-stack-middle.exp: New file.
	* gdb.arch/amd64-invalid-stack-top.c: New file.
	* gdb.arch/amd64-invalid-stack-top.exp: New file.

diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
new file mode 100644
index 0000000..3b4a067
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
@@ -0,0 +1,1410 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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 file is compiled from gdb.arch/amd64-invalid-stack-middle.c
+   using: 'gcc -g -O0 -S -dA' and gcc version '4.7.2'.
+   Changes were then made to the CFI entry for func2.  */
+        
+	.file	"amd64-invalid-stack-middle.c"
+	.text
+.Ltext0:
+	.globl	breakpt
+	.type	breakpt, @function
+breakpt:
+.LFB0:
+	.file 1 "amd64-invalid-stack-middle.c"
+	# amd64-invalid-stack-middle.c:25
+	.loc 1 25 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI0:
+	movq	%rsp, %rbp
+.LCFI1:
+	# amd64-invalid-stack-middle.c:27
+	.loc 1 27 0
+	popq	%rbp
+.LCFI2:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE0:
+	.size	breakpt, .-breakpt
+	.globl	func5
+	.type	func5, @function
+func5:
+.LFB1:
+	# amd64-invalid-stack-middle.c:31
+	.loc 1 31 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI3:
+	movq	%rsp, %rbp
+.LCFI4:
+	# amd64-invalid-stack-middle.c:32
+	.loc 1 32 0
+	movl	$0, %eax
+	call	breakpt
+	# amd64-invalid-stack-middle.c:33
+	.loc 1 33 0
+	popq	%rbp
+.LCFI5:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE1:
+	.size	func5, .-func5
+	.globl	func4
+	.type	func4, @function
+func4:
+.LFB2:
+	# amd64-invalid-stack-middle.c:37
+	.loc 1 37 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI6:
+	movq	%rsp, %rbp
+.LCFI7:
+	# amd64-invalid-stack-middle.c:38
+	.loc 1 38 0
+	movl	$0, %eax
+	call	func5
+	# amd64-invalid-stack-middle.c:39
+	.loc 1 39 0
+	popq	%rbp
+.LCFI8:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE2:
+	.size	func4, .-func4
+	.globl	func3
+	.type	func3, @function
+func3:
+.LFB3:
+	# amd64-invalid-stack-middle.c:43
+	.loc 1 43 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI9:
+	movq	%rsp, %rbp
+.LCFI10:
+	# amd64-invalid-stack-middle.c:44
+	.loc 1 44 0
+	movl	$0, %eax
+	call	func4
+	# amd64-invalid-stack-middle.c:45
+	.loc 1 45 0
+	popq	%rbp
+.LCFI11:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE3:
+	.size	func3, .-func3
+	.globl	func2
+	.type	func2, @function
+func2:
+.LFB4:
+	# amd64-invalid-stack-middle.c:49
+	.loc 1 49 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI12:
+	movq	%rsp, %rbp
+.LCFI13:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:50
+	.loc 1 50 0
+	movl	$0, %eax
+	call	func3
+	# amd64-invalid-stack-middle.c:51
+	.loc 1 51 0
+	leave
+.LCFI14:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE4:
+	.size	func2, .-func2
+	.globl	func1
+	.type	func1, @function
+func1:
+.LFB5:
+	# amd64-invalid-stack-middle.c:55
+	.loc 1 55 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI15:
+	movq	%rsp, %rbp
+.LCFI16:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:56
+	.loc 1 56 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func2
+	# amd64-invalid-stack-middle.c:57
+	.loc 1 57 0
+	leave
+.LCFI17:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE5:
+	.size	func1, .-func1
+	.section	.rodata
+.LC0:
+	.string	"amd64-invalid-stack-middle.c"
+.LC1:
+	.string	"ptr != ((void *) -1)"
+.LC2:
+	.string	"ans == 0"
+	.text
+	.type	make_invalid_ptr, @function
+make_invalid_ptr:
+.LFB6:
+	# amd64-invalid-stack-middle.c:65
+	.loc 1 65 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI18:
+	movq	%rsp, %rbp
+.LCFI19:
+	subq	$32, %rsp
+	# amd64-invalid-stack-middle.c:69
+	.loc 1 69 0
+	call	getpagesize
+	movl	%eax, -4(%rbp)
+	# amd64-invalid-stack-middle.c:70
+	.loc 1 70 0
+	movl	-4(%rbp), %eax
+	cltq
+	movl	$0, %r9d
+	movl	$-1, %r8d
+	movl	$34, %ecx
+	movl	$0, %edx
+	movq	%rax, %rsi
+	movl	$0, %edi
+	call	mmap
+	movq	%rax, -16(%rbp)
+	# amd64-invalid-stack-middle.c:73
+	.loc 1 73 0
+	cmpq	$-1, -16(%rbp)
+# SUCC: 3 (fallthru) 4
+	jne	.L8
+# BLOCK 3 seq:1
+# PRED: 2 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$73, %edx
+	movl	$.LC0, %esi
+	movl	$.LC1, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 4 seq:2
+# PRED: 2
+.L8:
+	# amd64-invalid-stack-middle.c:74
+	.loc 1 74 0
+	movl	-4(%rbp), %eax
+	movslq	%eax, %rdx
+	movq	-16(%rbp), %rax
+	movq	%rdx, %rsi
+	movq	%rax, %rdi
+	call	munmap
+	movl	%eax, -20(%rbp)
+	# amd64-invalid-stack-middle.c:75
+	.loc 1 75 0
+	cmpl	$0, -20(%rbp)
+# SUCC: 5 (fallthru) 6
+	je	.L9
+# BLOCK 5 seq:3
+# PRED: 4 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$75, %edx
+	movl	$.LC0, %esi
+	movl	$.LC2, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 6 seq:4
+# PRED: 4
+.L9:
+	# amd64-invalid-stack-middle.c:77
+	.loc 1 77 0
+	movq	-16(%rbp), %rax
+	# amd64-invalid-stack-middle.c:78
+	.loc 1 78 0
+	leave
+.LCFI20:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE6:
+	.size	make_invalid_ptr, .-make_invalid_ptr
+	.globl	main
+	.type	main, @function
+main:
+.LFB7:
+	# amd64-invalid-stack-middle.c:82
+	.loc 1 82 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI21:
+	movq	%rsp, %rbp
+.LCFI22:
+	subq	$16, %rsp
+	# amd64-invalid-stack-middle.c:85
+	.loc 1 85 0
+	call	make_invalid_ptr
+	movq	%rax, -8(%rbp)
+	# amd64-invalid-stack-middle.c:86
+	.loc 1 86 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func1
+	# amd64-invalid-stack-middle.c:88
+	.loc 1 88 0
+	movl	$0, %eax
+	# amd64-invalid-stack-middle.c:89
+	.loc 1 89 0
+	leave
+.LCFI23:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE7:
+	.size	main, .-main
+	.section	.rodata
+	.align 16
+	.type	__PRETTY_FUNCTION__.2362, @object
+	.size	__PRETTY_FUNCTION__.2362, 17
+__PRETTY_FUNCTION__.2362:
+	.string	"make_invalid_ptr"
+#APP
+	.section	.debug_frame,"",@progbits
+.Lframe0:
+	.long	.LECIE0-.LSCIE0	# Length of Common Information Entry
+.LSCIE0:
+	.long	0xffffffff	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE0:
+.LSFDE0:
+	.long	.LEFDE0-.LASFDE0	# FDE Length
+.LASFDE0:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB0	# FDE initial location
+	.quad	.LFE0-.LFB0	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE0:
+.LSFDE2:
+	.long	.LEFDE2-.LASFDE2	# FDE Length
+.LASFDE2:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB1	# FDE initial location
+	.quad	.LFE1-.LFB1	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE2:
+.LSFDE4:
+	.long	.LEFDE4-.LASFDE4	# FDE Length
+.LASFDE4:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB2	# FDE initial location
+	.quad	.LFE2-.LFB2	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE4:
+.LSFDE6:
+	.long	.LEFDE6-.LASFDE6	# FDE Length
+.LASFDE6:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB3	# FDE initial location
+	.quad	.LFE3-.LFB3	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE6:
+.LSFDE8:
+	.long	.LEFDE8-.LASFDE8	# FDE Length
+.LASFDE8:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB4		# FDE initial location
+	.quad	.LFE4-.LFB4	# FDE address range
+        .byte 0xf		# DW_CFA_def_cfa_expression
+        .uleb128 .LEDWBLK1 - .LSDWBLK1
+.LSDWBLK1:
+        .byte 0x75              # DW_OP_breg5
+        .sleb128 0x0            #        offset
+        .byte 0x94              # DW_OP_dref_size
+        .byte 0x8		#        size
+.LEDWBLK1:
+	.align 8		# Padding.
+.LEFDE8:
+.LSFDE10:
+	.long	.LEFDE10-.LASFDE10	# FDE Length
+.LASFDE10:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB5	# FDE initial location
+	.quad	.LFE5-.LFB5	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE10:
+.LSFDE12:
+	.long	.LEFDE12-.LASFDE12	# FDE Length
+.LASFDE12:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB6	# FDE initial location
+	.quad	.LFE6-.LFB6	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE12:
+.LSFDE14:
+	.long	.LEFDE14-.LASFDE14	# FDE Length
+.LASFDE14:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB7	# FDE initial location
+	.quad	.LFE7-.LFB7	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE14:
+#NO_APP
+#APP
+	.section	.eh_frame,"a",@progbits
+.Lframe1:
+	.long	.LECIE1-.LSCIE1	# Length of Common Information Entry
+.LSCIE1:
+	.long	0	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "zR\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.uleb128 0x1	# Augmentation size
+	.byte	0x3	# FDE Encoding (udata4)
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE1:
+.LSFDE17:
+	.long	.LEFDE17-.LASFDE17	# FDE Length
+.LASFDE17:
+	.long	.LASFDE17-.Lframe1	# FDE CIE offset
+	.long	.LFB0	# FDE initial location
+	.long	.LFE0-.LFB0	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE17:
+.LSFDE19:
+	.long	.LEFDE19-.LASFDE19	# FDE Length
+.LASFDE19:
+	.long	.LASFDE19-.Lframe1	# FDE CIE offset
+	.long	.LFB1	# FDE initial location
+	.long	.LFE1-.LFB1	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE19:
+.LSFDE21:
+	.long	.LEFDE21-.LASFDE21	# FDE Length
+.LASFDE21:
+	.long	.LASFDE21-.Lframe1	# FDE CIE offset
+	.long	.LFB2	# FDE initial location
+	.long	.LFE2-.LFB2	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE21:
+.LSFDE23:
+	.long	.LEFDE23-.LASFDE23	# FDE Length
+.LASFDE23:
+	.long	.LASFDE23-.Lframe1	# FDE CIE offset
+	.long	.LFB3	# FDE initial location
+	.long	.LFE3-.LFB3	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE23:
+.LSFDE25:
+	.long	.LEFDE25-.LASFDE25	# FDE Length
+.LASFDE25:
+	.long	.LASFDE25-.Lframe1	# FDE CIE offset
+	.long	.LFB4	# FDE initial location
+	.long	.LFE4-.LFB4	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI12-.LFB4
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI13-.LCFI12
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI14-.LCFI13
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE25:
+.LSFDE27:
+	.long	.LEFDE27-.LASFDE27	# FDE Length
+.LASFDE27:
+	.long	.LASFDE27-.Lframe1	# FDE CIE offset
+	.long	.LFB5	# FDE initial location
+	.long	.LFE5-.LFB5	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE27:
+.LSFDE29:
+	.long	.LEFDE29-.LASFDE29	# FDE Length
+.LASFDE29:
+	.long	.LASFDE29-.Lframe1	# FDE CIE offset
+	.long	.LFB6	# FDE initial location
+	.long	.LFE6-.LFB6	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE29:
+.LSFDE31:
+	.long	.LEFDE31-.LASFDE31	# FDE Length
+.LASFDE31:
+	.long	.LASFDE31-.Lframe1	# FDE CIE offset
+	.long	.LFB7	# FDE initial location
+	.long	.LFE7-.LFB7	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE31:
+#NO_APP
+	.text
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x1f1	# Length of Compilation Unit Info
+	.value	0x2	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x8	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF17	# DW_AT_producer: "GNU C 4.7.2"
+	.byte	0x1	# DW_AT_language
+	.long	.LASF18	# DW_AT_name: "amd64-invalid-stack-middle.c"
+	.long	.LASF19	# DW_AT_comp_dir: "/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+	.quad	.Ltext0	# DW_AT_low_pc
+	.quad	.Letext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x2d) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "long unsigned int"
+	.uleb128 0x2	# (DIE (0x34) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "unsigned char"
+	.uleb128 0x2	# (DIE (0x3b) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "short unsigned int"
+	.uleb128 0x2	# (DIE (0x42) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "unsigned int"
+	.uleb128 0x2	# (DIE (0x49) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "signed char"
+	.uleb128 0x2	# (DIE (0x50) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x57) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x2	# (DIE (0x5e) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "long int"
+	.uleb128 0x2	# (DIE (0x65) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "sizetype"
+	.uleb128 0x4	# (DIE (0x6c) DW_TAG_pointer_type)
+	.byte	0x8	# DW_AT_byte_size
+	.uleb128 0x2	# (DIE (0x6e) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "char"
+	.uleb128 0x5	# (DIE (0x75) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF9	# DW_AT_name: "breakpt"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x18	# DW_AT_decl_line
+	.quad	.LFB0	# DW_AT_low_pc
+	.quad	.LFE0	# DW_AT_high_pc
+	.long	.LLST0	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_call_sites
+	.uleb128 0x6	# (DIE (0x92) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF10	# DW_AT_name: "func5"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x1e	# DW_AT_decl_line
+	.quad	.LFB1	# DW_AT_low_pc
+	.quad	.LFE1	# DW_AT_high_pc
+	.long	.LLST1	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xaf) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF11	# DW_AT_name: "func4"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x24	# DW_AT_decl_line
+	.quad	.LFB2	# DW_AT_low_pc
+	.quad	.LFE2	# DW_AT_high_pc
+	.long	.LLST2	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xcc) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "func3"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x2a	# DW_AT_decl_line
+	.quad	.LFB3	# DW_AT_low_pc
+	.quad	.LFE3	# DW_AT_high_pc
+	.long	.LLST3	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x7	# (DIE (0xe9) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "func2"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB4	# DW_AT_low_pc
+	.quad	.LFE4	# DW_AT_high_pc
+	.long	.LLST4	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x11a	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x10b) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0xe9
+	.uleb128 0x7	# (DIE (0x11a) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF14	# DW_AT_name: "func1"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB5	# DW_AT_low_pc
+	.quad	.LFE5	# DW_AT_high_pc
+	.long	.LLST5	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x14b	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x13c) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x11a
+	.uleb128 0x9	# (DIE (0x14b) DW_TAG_subprogram)
+	.long	.LASF20	# DW_AT_name: "make_invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x40	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.long	0x6c	# DW_AT_type
+	.quad	.LFB6	# DW_AT_low_pc
+	.quad	.LFE6	# DW_AT_high_pc
+	.long	.LLST6	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x1af	# DW_AT_sibling
+	.uleb128 0xa	# (DIE (0x170) DW_TAG_variable)
+	.long	.LASF15	# DW_AT_name: "page_size"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.uleb128 0xb	# (DIE (0x17e) DW_TAG_variable)
+	.ascii "ans\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0xb	# (DIE (0x18c) DW_TAG_variable)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x43	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -32
+	.uleb128 0xc	# (DIE (0x19a) DW_TAG_variable)
+	.long	.LASF21	# DW_AT_name: "__PRETTY_FUNCTION__"
+	.long	0x1bf	# DW_AT_type
+	.byte	0x1	# DW_AT_artificial
+	.byte	0x9	# DW_AT_location
+	.byte	0x3	# DW_OP_addr
+	.quad	__PRETTY_FUNCTION__.2362
+	.byte	0	# end of children of DIE 0x14b
+	.uleb128 0xd	# (DIE (0x1af) DW_TAG_array_type)
+	.long	0x6e	# DW_AT_type
+	.long	0x1bf	# DW_AT_sibling
+	.uleb128 0xe	# (DIE (0x1b8) DW_TAG_subrange_type)
+	.long	0x65	# DW_AT_type
+	.byte	0x10	# DW_AT_upper_bound
+	.byte	0	# end of children of DIE 0x1af
+	.uleb128 0xf	# (DIE (0x1bf) DW_TAG_const_type)
+	.long	0x1af	# DW_AT_type
+	.uleb128 0x10	# (DIE (0x1c4) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF22	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x51	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.quad	.LFB7	# DW_AT_low_pc
+	.quad	.LFE7	# DW_AT_high_pc
+	.long	.LLST7	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0xa	# (DIE (0x1e5) DW_TAG_variable)
+	.long	.LASF16	# DW_AT_name: "invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x53	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x1c4
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0xf	# (TAG: DW_TAG_pointer_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xb	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xc	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xd	# (abbrev code)
+	.uleb128 0x1	# (TAG: DW_TAG_array_type)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xe	# (abbrev code)
+	.uleb128 0x21	# (TAG: DW_TAG_subrange_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2f	# (DW_AT_upper_bound)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0xf	# (abbrev code)
+	.uleb128 0x26	# (TAG: DW_TAG_const_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x10	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+	.quad	.LFB0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI1-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI1-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI2-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI2-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LFE0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST0)
+	.quad	0	# Location list terminator end (*.LLST0)
+.LLST1:
+	.quad	.LFB1-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI3-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI3-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI4-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI4-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI5-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI5-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LFE1-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST1)
+	.quad	0	# Location list terminator end (*.LLST1)
+.LLST2:
+	.quad	.LFB2-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI6-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI6-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI7-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI7-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI8-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI8-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LFE2-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST2)
+	.quad	0	# Location list terminator end (*.LLST2)
+.LLST3:
+	.quad	.LFB3-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI9-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI9-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI10-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI10-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI11-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI11-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LFE3-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST3)
+	.quad	0	# Location list terminator end (*.LLST3)
+.LLST4:
+	.quad	.LFB4-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI12-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI12-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI13-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI13-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI14-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI14-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LFE4-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST4)
+	.quad	0	# Location list terminator end (*.LLST4)
+.LLST5:
+	.quad	.LFB5-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI15-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI15-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI16-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI16-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI17-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI17-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LFE5-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST5)
+	.quad	0	# Location list terminator end (*.LLST5)
+.LLST6:
+	.quad	.LFB6-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI18-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI18-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI19-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI19-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI20-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI20-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LFE6-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST6)
+	.quad	0	# Location list terminator end (*.LLST6)
+.LLST7:
+	.quad	.LFB7-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI21-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI21-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI22-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI22-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI23-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI23-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LFE7-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST7)
+	.quad	0	# Location list terminator end (*.LLST7)
+	.section	.debug_aranges,"",@progbits
+	.long	0x2c	# Length of Address Ranges Info
+	.value	0x2	# DWARF Version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x8	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 16 byte boundary
+	.value	0
+	.quad	.Ltext0	# Address
+	.quad	.Letext0-.Ltext0	# Length
+	.quad	0
+	.quad	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF10:
+	.string	"func5"
+.LASF20:
+	.string	"make_invalid_ptr"
+.LASF21:
+	.string	"__PRETTY_FUNCTION__"
+.LASF18:
+	.string	"amd64-invalid-stack-middle.c"
+.LASF22:
+	.string	"main"
+.LASF14:
+	.string	"func1"
+.LASF17:
+	.string	"GNU C 4.7.2"
+.LASF11:
+	.string	"func4"
+.LASF0:
+	.string	"long unsigned int"
+.LASF1:
+	.string	"unsigned char"
+.LASF8:
+	.string	"char"
+.LASF6:
+	.string	"long int"
+.LASF15:
+	.string	"page_size"
+.LASF13:
+	.string	"func2"
+.LASF16:
+	.string	"invalid_ptr"
+.LASF2:
+	.string	"short unsigned int"
+.LASF4:
+	.string	"signed char"
+.LASF9:
+	.string	"breakpt"
+.LASF19:
+	.string	"/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+.LASF5:
+	.string	"short int"
+.LASF3:
+	.string	"unsigned int"
+.LASF12:
+	.string	"func3"
+.LASF7:
+	.string	"sizetype"
+	.ident	"GCC: (GNU) 4.7.2"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
new file mode 100644
index 0000000..b8fbf6f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void
+breakpt ()
+{
+  /* Nothing.  */
+}
+
+void
+func5 ()
+{
+  breakpt ();
+}
+
+void
+func4 ()
+{
+  func5 ();
+}
+
+void
+func3 ()
+{
+  func4 ();
+}
+
+void
+func2 (void *ptr)
+{
+  func3 ();
+}
+
+void
+func1 (void *ptr)
+{
+  func2 (ptr);
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
new file mode 100644
index 0000000..ef70a4f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -0,0 +1,94 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .S
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt\n"
+gdb_expect {
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
new file mode 100644
index 0000000..c821f18
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
@@ -0,0 +1,73 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void *global_invalid_ptr = NULL;
+
+void
+func2 (void)
+{
+  /* Replace the current stack pointer and frame pointer with the invalid
+     pointer.  */
+  asm ("mov %0, %%rsp\n\tmov %0, %%rbp" : : "r" (global_invalid_ptr));
+
+  /* Create a label for a breakpoint.  */
+  asm (".global breakpt\nbreakpt:");
+}
+
+void
+func1 (void *ptr)
+{
+  global_invalid_ptr = ptr;
+  func2 ();
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
new file mode 100644
index 0000000..6598cd4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -0,0 +1,97 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .c
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+# Use 'bt no-filters' here as the python filters will raise their own
+# error during initialisation, the no-filters case is simpler.
+
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt no-filters\n"
+gdb_expect {
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC 2/4] Remove previous frame if we error during compute_frame_id
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
  2014-04-04 14:47 ` [RFC 1/4] New tests for backtracing with a corrupted stack Andrew Burgess
@ 2014-04-04 14:48 ` Andrew Burgess
  2014-04-04 14:53   ` Andrew Burgess
  2014-04-04 14:49 ` [RFC 3/4] Deprecate frame_stop_reason_string Andrew Burgess
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:48 UTC (permalink / raw)
  To: gdb-patches

In get_prev_frame_if_no_cycle, if we throw an error during compute_frame_id
then we are left in a state where THIS_FRAME has a PREV_FRAME attached, but
PREV_FRAME has no frame id.  This is an unexpected state that causes
internal
errors and assertions to fire.

This patch adds a cleanup that removes the previous frame created by
get_prev_frame_raw if we get an error.

OK to apply?

Thanks,
Andrew



gdb/ChangeLog:

	* frame.c (remove_prev_frame): New function.
	(get_prev_frame_if_no_cycle): Create / discard cleanup using
	remove_prev_frame.

diff --git a/gdb/frame.c b/gdb/frame.c
index 97d54e9..5f05968 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1733,6 +1733,22 @@ frame_register_unwind_location (struct frame_info
*this_frame, int regnum,
     }
 }

+/* Called during frame unwinding to remove a previous frame pointer from a
+   frame passed in ARG.  */
+
+static void
+remove_prev_frame (void *arg)
+{
+  struct frame_info *this_frame, *prev_frame;
+
+  this_frame = (struct frame_info *) arg;
+  prev_frame = this_frame->prev;
+  gdb_assert (prev_frame != NULL);
+
+  prev_frame->next = NULL;
+  this_frame->prev = NULL;
+}
+
 /* Get the previous raw frame, and check that it is not identical to
    same other frame frame already in the chain.  If it is, there is
    most likely a stack cycle, so we discard it, and mark THIS_FRAME as
@@ -1745,28 +1761,36 @@ static struct frame_info *
 get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 {
   struct frame_info *prev_frame;
+  struct cleanup *prev_frame_cleanup;

   prev_frame = get_prev_frame_raw (this_frame);
   if (prev_frame == NULL)
     return NULL;

-  compute_frame_id (prev_frame);
-  if (frame_stash_add (prev_frame))
-    return prev_frame;
+  /* The cleanup will remove the previous frame that get_prev_frame_raw
+     linked onto THIS_FRAME.  */
+  prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);

-  /* Another frame with the same id was already in the stash.  We just
-     detected a cycle.  */
-  if (frame_debug)
+  compute_frame_id (prev_frame);
+  if (!frame_stash_add (prev_frame))
     {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, NULL);
-      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+      /* Another frame with the same id was already in the stash.  We just
+	 detected a cycle.  */
+      if (frame_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "-> ");
+	  fprint_frame (gdb_stdlog, NULL);
+	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+	}
+      this_frame->stop_reason = UNWIND_SAME_ID;
+      /* Unlink.  */
+      prev_frame->next = NULL;
+      this_frame->prev = NULL;
+      prev_frame = NULL;
     }
-  this_frame->stop_reason = UNWIND_SAME_ID;
-  /* Unlink.  */
-  prev_frame->next = NULL;
-  this_frame->prev = NULL;
-  return NULL;
+
+  discard_cleanups (prev_frame_cleanup);
+  return prev_frame;
 }

 /* Return a "struct frame_info" corresponding to the frame that called

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC 3/4] Deprecate frame_stop_reason_string
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
  2014-04-04 14:47 ` [RFC 1/4] New tests for backtracing with a corrupted stack Andrew Burgess
  2014-04-04 14:48 ` [RFC 2/4] Remove previous frame if we error during compute_frame_id Andrew Burgess
@ 2014-04-04 14:49 ` Andrew Burgess
  2014-04-04 14:55   ` Andrew Burgess
  2014-04-04 14:50 ` [RFC 4/4] Add TRY_CATCH to get_prev_frame and frame specific strop strings Andrew Burgess
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:49 UTC (permalink / raw)
  To: gdb-patches

Patch #4 adds frame specific stop reason strings.  It is better
to use that string rather than the existing generic stop reason
string.  This patch renames frame_stop_reason_string to
deprecated_frame_stop_reason_string and updates all the call sites.

This only makes sense if patch #4 is approved, but does this look ok?

Thanks,
Andrew

gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Update call to frame_stop_reason_string.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Update
	call to frame_stop_reason_string.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Update call
	to frame_stop_reason_string.

diff --git a/gdb/frame.c b/gdb/frame.c
index 5f05968..5a6e0c7 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2556,7 +2556,7 @@ get_frame_unwind_stop_reason (struct frame_info
*frame)
 /* Return a string explaining REASON.  */

 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index e451a93..7db5382 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -495,9 +495,10 @@ enum unwind_stop_reason

 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);

-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This is DEPRECATED,
+   use frame_stop_reason_string instead.  */

-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);

 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6031a7f..ddd062c 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -944,7 +944,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);

-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..e7fcfe3 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self,
PyObject *args)
       return NULL;
     }

-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }

diff --git a/gdb/stack.c b/gdb/stack.c
index da7d977..4fa9dd6 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 deprecated_frame_stop_reason_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int
show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     deprecated_frame_stop_reason_string (reason));
 	}
     }
 }

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [RFC 4/4] Add TRY_CATCH to get_prev_frame and frame specific strop strings
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (2 preceding siblings ...)
  2014-04-04 14:49 ` [RFC 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-04-04 14:50 ` Andrew Burgess
  2014-04-15  9:11 ` [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:50 UTC (permalink / raw)
  To: gdb-patches

Here a new TRY_CATCH is added to the core of get_prev_frame, all
uncaught errors are turned into UNWIND_MISC_ERROR, and where possible
the error message associated with the error is stored as a frame
specific stop reason string.  The reason string is held of the
frame OBSTACK so it lives as long as the frame does.

There's a new function for getting the frame_stop_reason_string,
this replaces the now (thanks to patch #3) old
frame_stop_reason_string function, I know that reusing the name
could confuse, but this function was not widely used, so I hope
that'll not be an issue.

Finally, I update the expected results from the tests in patch #1
now that everything should pass.

I don't know if you'll all be happy with me catching _all_ errors
in get_prev_frame.  Given that the issues I'm seeing "in the wild"
and which I've put into the tests are for accessing invalid memory
through a bad stack pointer, I could reduce the catching to only
catch MEMORY_ERRORs, then UNWIND_MISC_ERROR would become
UNWIND_MEMORY_ERROR.  I could even add the memory error detection
on top of the new MISC_ERROR case if preferred, though I'd need to
think of a new test...

Feedback welcome, or is this OK?

Thanks,
Andrew

gdb/ChangeLog:
    
	* frame.c (struct frame_info): Add stop_string field.
	(get_prev_frame_2): Renamed from get_prev_frame_1.
	(get_prev_frame_1): Old content moved into get_prev_frame_2.  Call
	get_prev_frame_2 inside TRY_CATCH, handle errors.
	(frame_stop_reason_string): New function definition.
	* frame.h (frame_stop_reason_string): New function declaration.
	* stack.c (frame_info): Switch to frame_stop_reason_string.
	(backtrace_command_1): Switch to frame_stop_reason_string.
	* unwind_stop_reason.def: Add UNWIND_MISC_ERROR.
    
gdb/testsuite/ChangeLog:
    
	* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
	* gdb.arch/amd64-invalid-stack-top.exp: Likewise.

diff --git a/gdb/frame.c b/gdb/frame.c
index 5a6e0c7..65ba49b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -146,6 +146,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1793,14 +1797,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_1, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
 static struct frame_info *
-get_prev_frame_1 (struct frame_info *this_frame)
+get_prev_frame_2 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1950,6 +1952,41 @@ get_prev_frame_1 (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+static struct frame_info *
+get_prev_frame_1 (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_2 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      this_frame->stop_reason = UNWIND_MISC_ERROR;
+      if (ex.message != NULL)
+	{
+	  char *stop_string;
+
+	  /* The error needs to live as long as the frame does.  */
+	  stop_string =
+	    FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
+	  strcpy (stop_string, ex.message);
+	  this_frame->stop_string = stop_string;
+	}
+      prev_frame = NULL;
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2571,6 +2608,26 @@ deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
     }
 }
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped at frame FI.  Must only be called if there is no previous
+   frame.  */
+
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  At some point
+     if DEPRECATED_FRAME_STOP_REASON_STRING is not used anywhere else then
+     its content could be moved into here.  */
+  return deprecated_frame_stop_reason_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 7db5382..1a5614d 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -500,6 +500,12 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
 const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  Should only be called for frames that don't have a
+   previous frame.  If there's no specific reason stored for a frame then
+   a generic reason string will be returned.  */
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
diff --git a/gdb/stack.c b/gdb/stack.c
index 4fa9dd6..3f8ecfb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 deprecated_frame_stop_reason_string (reason));
+			 frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     deprecated_frame_stop_reason_string (reason));
+			     frame_stop_reason_string (trailing));
 	}
     }
 }
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index ef70a4f..b53ad41 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
index 6598cd4..52869a2 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -46,27 +46,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def
index d7da7ea..84cfb75 100644
--- a/gdb/unwind_stop_reasons.def
+++ b/gdb/unwind_stop_reasons.def
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* The frame unwinder threw some other error which we caught.  */
+SET (UNWIND_MISC_ERROR, "miscellaneous error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MISC_ERROR)
 #endif

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC 2/4] Remove previous frame if we error during compute_frame_id
  2014-04-04 14:48 ` [RFC 2/4] Remove previous frame if we error during compute_frame_id Andrew Burgess
@ 2014-04-04 14:53   ` Andrew Burgess
  2014-04-15 19:02     ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:53 UTC (permalink / raw)
  To: gdb-patches

Gah! The patch was corrupted in the last post. Try again:

In get_prev_frame_if_no_cycle, if we throw an error during compute_frame_id
then we are left in a state where THIS_FRAME has a PREV_FRAME attached, but
PREV_FRAME has no frame id.  This is an unexpected state that causes internal
errors and assertions to fire.

This patch adds a cleanup that removes the previous frame created by
get_prev_frame_raw if we get an error.

OK to apply?

Thanks,
Andrew



gdb/ChangeLog:

	* frame.c (remove_prev_frame): New function.
	(get_prev_frame_if_no_cycle): Create / discard cleanup using
	remove_prev_frame.

diff --git a/gdb/frame.c b/gdb/frame.c
index 97d54e9..5f05968 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1733,6 +1733,22 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
     }
 }
 +/* Called during frame unwinding to remove a previous frame pointer from a
+   frame passed in ARG.  */
+
+static void
+remove_prev_frame (void *arg)
+{
+  struct frame_info *this_frame, *prev_frame;
+
+  this_frame = (struct frame_info *) arg;
+  prev_frame = this_frame->prev;
+  gdb_assert (prev_frame != NULL);
+
+  prev_frame->next = NULL;
+  this_frame->prev = NULL;
+}
+
 /* Get the previous raw frame, and check that it is not identical to
    same other frame frame already in the chain.  If it is, there is
    most likely a stack cycle, so we discard it, and mark THIS_FRAME as
@@ -1745,28 +1761,36 @@ static struct frame_info *
 get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 {
   struct frame_info *prev_frame;
+  struct cleanup *prev_frame_cleanup;
    prev_frame = get_prev_frame_raw (this_frame);
   if (prev_frame == NULL)
     return NULL;
 -  compute_frame_id (prev_frame);
-  if (frame_stash_add (prev_frame))
-    return prev_frame;
+  /* The cleanup will remove the previous frame that get_prev_frame_raw
+     linked onto THIS_FRAME.  */
+  prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
 -  /* Another frame with the same id was already in the stash.  We just
-     detected a cycle.  */
-  if (frame_debug)
+  compute_frame_id (prev_frame);
+  if (!frame_stash_add (prev_frame))
     {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, NULL);
-      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+      /* Another frame with the same id was already in the stash.  We just
+	 detected a cycle.  */
+      if (frame_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "-> ");
+	  fprint_frame (gdb_stdlog, NULL);
+	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+	}
+      this_frame->stop_reason = UNWIND_SAME_ID;
+      /* Unlink.  */
+      prev_frame->next = NULL;
+      this_frame->prev = NULL;
+      prev_frame = NULL;
     }
-  this_frame->stop_reason = UNWIND_SAME_ID;
-  /* Unlink.  */
-  prev_frame->next = NULL;
-  this_frame->prev = NULL;
-  return NULL;
+
+  discard_cleanups (prev_frame_cleanup);
+  return prev_frame;
 }
  /* Return a "struct frame_info" corresponding to the frame that called

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC 3/4] Deprecate frame_stop_reason_string
  2014-04-04 14:49 ` [RFC 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-04-04 14:55   ` Andrew Burgess
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-04 14:55 UTC (permalink / raw)
  To: gdb-patches

Gah! Patch was line wrapped in the last post, try again:

Patch #4 adds frame specific stop reason strings.  It is better
to use that string rather than the existing generic stop reason
string.  This patch renames frame_stop_reason_string to
deprecated_frame_stop_reason_string and updates all the call sites.

This only makes sense if patch #4 is approved, but does this look ok?

Thanks,
Andrew

gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Update call to frame_stop_reason_string.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Update
	call to frame_stop_reason_string.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Update call
	to frame_stop_reason_string.

diff --git a/gdb/frame.c b/gdb/frame.c
index 5f05968..5a6e0c7 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2556,7 +2556,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
 /* Return a string explaining REASON.  */
 
 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index e451a93..7db5382 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -495,9 +495,10 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This is DEPRECATED,
+   use frame_stop_reason_string instead.  */
 
-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6031a7f..ddd062c 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -944,7 +944,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..e7fcfe3 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
       return NULL;
     }
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
diff --git a/gdb/stack.c b/gdb/stack.c
index da7d977..4fa9dd6 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 deprecated_frame_stop_reason_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     deprecated_frame_stop_reason_string (reason));
 	}
     }
 }


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC 0/4] Catch errors in get_prev_frame.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (3 preceding siblings ...)
  2014-04-04 14:50 ` [RFC 4/4] Add TRY_CATCH to get_prev_frame and frame specific strop strings Andrew Burgess
@ 2014-04-15  9:11 ` Andrew Burgess
  2014-04-17 10:15 ` [PATCH v2 " Andrew Burgess
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-15  9:11 UTC (permalink / raw)
  To: gdb-patches

Ping.

On 04/04/2014 3:46 PM, Andrew Burgess wrote:
> While working on a reproducer for this patch:
>   https://sourceware.org/ml/gdb-patches/2014-03/msg00629.html
> 
> I ran into a few other issues.  The route cause of the problems I'm
> seeing is that not all errors thrown within get_prev_frame are caught.
> This causes a couple of problems,
> 
> 1. For the MI this means that commands like -stack-info-depth will
> return an error rather than a result.  Even more annoying, is that
> depending on where in the process the error is thrown enough state may
> be left set that the /next/ time -stack-info-depth is asked, the correct
> result is given!
> 
> 2. For standard CLI backtraces our the results are (I think)
> inconsistent, so for example some backtraces will end with a message
> like: "Backtrace stopped: previous frame inner to this frame (corrupted
> stack?)", this message will be displayed every time the backtrace is
> requested, in other cases though, the reason is only displayed the first
> time a backtrace is requested, this is the case when an uncaught error
> causes the backtrace to stop, also in the uncaught error case the
> "Backtrace stopped" prefix does not appear.
> 
> This patch set tries to fix both these issues by holding a frame
> specific string that describes why the backtrace stopped at this frame
> (only for the last frame in the backtrace obviously).  If this string is
> not set then we still use the existing generic strings.
> 
> A new TRY_CATCH inside get_prev_frame catches (currently) all unhandled
> errors, the error message from these errors is then used as a frame
> specific stop reason string.  There's a new unwind_stop_reason code for
> this case, UNWIND_MISC_ERROR.
> 
> If it's felt that catching all errors like this is too much then I could
> soften this to just catching MEMORY_ERRORs, as right now the problems
> I'm seeing all relate to accessing memory through a corrupted stack pointer.
> 
> Here's what each patch does:
> 
> #1 - This patch just adds some tests, some of the tests fail, and are
> fixed by later patches in this series.
> 
> #2 - An error in the wrong place leaves a frame partially initialised,
> this can then cause internal errors / assertions to fire.  Add a clean
> up to fix this issue.
> 
> #3 Deprecate frame_stop_reason_string, rename all use sites.  I'm going
> to add a new version in the next patch that takes a struct frame_info
> pointer.
> 
> #4 Add the new TRY_CATCH and the new stop reason string into the
> frame_info structure.
> 
> Thanks,
> Andrew
> 
> 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [RFC 2/4] Remove previous frame if we error during compute_frame_id
  2014-04-04 14:53   ` Andrew Burgess
@ 2014-04-15 19:02     ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2014-04-15 19:02 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On 04/04/2014 03:53 PM, Andrew Burgess wrote:
> Gah! The patch was corrupted in the last post. Try again:

Seems to still be corrupt.

$ git am /tmp/mbox
Applying: New tests for backtracing with a corrupted stack.
/home/pedro/gdb/mygit/src/.git/rebase-apply/patch:27: trailing whitespace.

/home/pedro/gdb/mygit/src/.git/rebase-apply/patch:48: trailing whitespace.
# SUCC: EXIT [100.0%]
/home/pedro/gdb/mygit/src/.git/rebase-apply/patch:72: trailing whitespace.
# SUCC: EXIT [100.0%]
/home/pedro/gdb/mygit/src/.git/rebase-apply/patch:96: trailing whitespace.
# SUCC: EXIT [100.0%]
/home/pedro/gdb/mygit/src/.git/rebase-apply/patch:120: trailing whitespace.
# SUCC: EXIT [100.0%]
warning: squelched 10 whitespace errors
warning: 15 lines add whitespace errors.
Applying: Remove previous frame if we error during compute_frame_id
fatal: corrupt patch at line 27
Patch failed at 0002 Remove previous frame if we error during compute_frame_id
The copy of the patch that failed is found in:
   /home/pedro/gdb/mygit/src/.git/rebase-apply/patch
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

Are you using git send-email ?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (7 preceding siblings ...)
  2014-04-17 10:15 ` [PATCH v2 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
@ 2014-04-17 10:15 ` Andrew Burgess
  2014-04-17 10:15 ` [PATCH v2 3/4] Deprecate frame_stop_reason_string Andrew Burgess
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-17 10:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

gdb/ChangeLog:

	* frame.c (struct frame_info): Add stop_string field.
	(get_prev_frame_2): Renamed from get_prev_frame_1.
	(get_prev_frame_1): Old content moved into get_prev_frame_2.  Call
	get_prev_frame_2 inside TRY_CATCH, handle errors.
	(frame_stop_reason_string): New function definition.
	* frame.h (frame_stop_reason_string): New function declaration.
	* stack.c (frame_info): Switch to frame_stop_reason_string.
	(backtrace_command_1): Switch to frame_stop_reason_string.
	* unwind_stop_reason.def: Add UNWIND_MISC_ERROR.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
	* gdb.arch/amd64-invalid-stack-top.exp: Likewise.
~ChangeLog~
---
 gdb/frame.c                                        | 69 ++++++++++++++++++++--
 gdb/frame.h                                        |  6 ++
 gdb/stack.c                                        |  4 +-
 .../gdb.arch/amd64-invalid-stack-middle.exp        | 22 +------
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp | 22 +------
 gdb/unwind_stop_reasons.def                        |  5 +-
 6 files changed, 81 insertions(+), 47 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 5a6e0c7..65ba49b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -146,6 +146,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1793,14 +1797,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_1, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
 static struct frame_info *
-get_prev_frame_1 (struct frame_info *this_frame)
+get_prev_frame_2 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1950,6 +1952,41 @@ get_prev_frame_1 (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+static struct frame_info *
+get_prev_frame_1 (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_2 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      this_frame->stop_reason = UNWIND_MISC_ERROR;
+      if (ex.message != NULL)
+	{
+	  char *stop_string;
+
+	  /* The error needs to live as long as the frame does.  */
+	  stop_string =
+	    FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
+	  strcpy (stop_string, ex.message);
+	  this_frame->stop_string = stop_string;
+	}
+      prev_frame = NULL;
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2571,6 +2608,26 @@ deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
     }
 }
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped at frame FI.  Must only be called if there is no previous
+   frame.  */
+
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  At some point
+     if DEPRECATED_FRAME_STOP_REASON_STRING is not used anywhere else then
+     its content could be moved into here.  */
+  return deprecated_frame_stop_reason_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 7db5382..1a5614d 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -500,6 +500,12 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
 const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  Should only be called for frames that don't have a
+   previous frame.  If there's no specific reason stored for a frame then
+   a generic reason string will be returned.  */
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
diff --git a/gdb/stack.c b/gdb/stack.c
index 4fa9dd6..3f8ecfb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 deprecated_frame_stop_reason_string (reason));
+			 frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     deprecated_frame_stop_reason_string (reason));
+			     frame_stop_reason_string (trailing));
 	}
     }
 }
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index ef70a4f..b53ad41 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
index 6598cd4..52869a2 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -46,27 +46,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def
index d7da7ea..84cfb75 100644
--- a/gdb/unwind_stop_reasons.def
+++ b/gdb/unwind_stop_reasons.def
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* The frame unwinder threw some other error which we caught.  */
+SET (UNWIND_MISC_ERROR, "miscellaneous error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MISC_ERROR)
 #endif
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 0/4] Catch errors in get_prev_frame.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (4 preceding siblings ...)
  2014-04-15  9:11 ` [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
@ 2014-04-17 10:15 ` Andrew Burgess
  2014-04-17 10:15 ` [PATCH v2 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-17 10:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Seems I messed up the last patch series quite a bit, so this time I'm
trying out git send-email.  Sorry for the noise, please let me know if it
still looks broken.

Nothing has changed here except, I hope, the patches should be well formed.

Thanks,
Andrew


Andrew Burgess (4):
  New test for backtrace when the stack pointer is invalid (inaccessible).
  Remove previous frame if an error occurs when computing frame id during unwind.
  Deprecate frame_stop_reason_string.
  Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.

 gdb/frame.c                                        |  123 +-
 gdb/frame.h                                        |   11 +-
 gdb/guile/scm-frame.c                              |    2 +-
 gdb/python/py-frame.c                              |    2 +-
 gdb/stack.c                                        |    4 +-
 .../gdb.arch/amd64-invalid-stack-middle.S          | 1410 ++++++++++++++++++++
 .../gdb.arch/amd64-invalid-stack-middle.c          |   89 ++
 .../gdb.arch/amd64-invalid-stack-middle.exp        |   78 ++
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c   |   73 +
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp |   81 ++
 gdb/unwind_stop_reasons.def                        |    5 +-
 11 files changed, 1850 insertions(+), 28 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp

-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 3/4] Deprecate frame_stop_reason_string.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (8 preceding siblings ...)
  2014-04-17 10:15 ` [PATCH v2 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
@ 2014-04-17 10:15 ` Andrew Burgess
  2014-04-29 19:56   ` Pedro Alves
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
  10 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-17 10:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
        * stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Update call to frame_stop_reason_string.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Update
	call to frame_stop_reason_string.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Update call
	to frame_stop_reason_string.
~ChangeLog~
---
 gdb/frame.c           | 2 +-
 gdb/frame.h           | 5 +++--
 gdb/guile/scm-frame.c | 2 +-
 gdb/python/py-frame.c | 2 +-
 gdb/stack.c           | 4 ++--
 5 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 5f05968..5a6e0c7 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2556,7 +2556,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
 /* Return a string explaining REASON.  */
 
 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index e451a93..7db5382 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -495,9 +495,10 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This is DEPRECATED,
+   use frame_stop_reason_string instead.  */
 
-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6031a7f..ddd062c 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -944,7 +944,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..e7fcfe3 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
       return NULL;
     }
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
diff --git a/gdb/stack.c b/gdb/stack.c
index da7d977..4fa9dd6 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 deprecated_frame_stop_reason_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     deprecated_frame_stop_reason_string (reason));
 	}
     }
 }
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 2/4] Remove previous frame if an error occurs when computing frame id during unwind.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (5 preceding siblings ...)
  2014-04-17 10:15 ` [PATCH v2 " Andrew Burgess
@ 2014-04-17 10:15 ` Andrew Burgess
  2014-04-17 10:15 ` [PATCH v2 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-17 10:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

gdb/ChangeLog:

	* frame.c (remove_prev_frame): New function.
	(get_prev_frame_if_no_cycle): Create / discard cleanup using
	remove_prev_frame.
~ChangeLog~
---
 gdb/frame.c | 52 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 97d54e9..5f05968 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1733,6 +1733,22 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
     }
 }
 
+/* Called during frame unwinding to remove a previous frame pointer from a
+   frame passed in ARG.  */
+
+static void
+remove_prev_frame (void *arg)
+{
+  struct frame_info *this_frame, *prev_frame;
+
+  this_frame = (struct frame_info *) arg;
+  prev_frame = this_frame->prev;
+  gdb_assert (prev_frame != NULL);
+
+  prev_frame->next = NULL;
+  this_frame->prev = NULL;
+}
+
 /* Get the previous raw frame, and check that it is not identical to
    same other frame frame already in the chain.  If it is, there is
    most likely a stack cycle, so we discard it, and mark THIS_FRAME as
@@ -1745,28 +1761,36 @@ static struct frame_info *
 get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 {
   struct frame_info *prev_frame;
+  struct cleanup *prev_frame_cleanup;
 
   prev_frame = get_prev_frame_raw (this_frame);
   if (prev_frame == NULL)
     return NULL;
 
-  compute_frame_id (prev_frame);
-  if (frame_stash_add (prev_frame))
-    return prev_frame;
+  /* The cleanup will remove the previous frame that get_prev_frame_raw
+     linked onto THIS_FRAME.  */
+  prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
 
-  /* Another frame with the same id was already in the stash.  We just
-     detected a cycle.  */
-  if (frame_debug)
+  compute_frame_id (prev_frame);
+  if (!frame_stash_add (prev_frame))
     {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, NULL);
-      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+      /* Another frame with the same id was already in the stash.  We just
+	 detected a cycle.  */
+      if (frame_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "-> ");
+	  fprint_frame (gdb_stdlog, NULL);
+	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+	}
+      this_frame->stop_reason = UNWIND_SAME_ID;
+      /* Unlink.  */
+      prev_frame->next = NULL;
+      this_frame->prev = NULL;
+      prev_frame = NULL;
     }
-  this_frame->stop_reason = UNWIND_SAME_ID;
-  /* Unlink.  */
-  prev_frame->next = NULL;
-  this_frame->prev = NULL;
-  return NULL;
+
+  discard_cleanups (prev_frame_cleanup);
+  return prev_frame;
 }
 
 /* Return a "struct frame_info" corresponding to the frame that called
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v2 1/4] New test for backtrace when the stack pointer is invalid (inaccessible).
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (6 preceding siblings ...)
  2014-04-17 10:15 ` [PATCH v2 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
@ 2014-04-17 10:15 ` Andrew Burgess
  2014-04-17 10:15 ` [PATCH v2 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-17 10:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Two new tests are added, one where the stack is invalid at some middle
frame, and one where the stack is invalid in the first frame.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.S: New file.
	* gdb.arch/amd64-invalid-stack-middle.c: New file.
	* gdb.arch/amd64-invalid-stack-middle.exp: New file.
	* gdb.arch/amd64-invalid-stack-top.c: New file.
        * gdb.arch/amd64-invalid-stack-top.exp: New file.
---
 .../gdb.arch/amd64-invalid-stack-middle.S          | 1410 ++++++++++++++++++++
 .../gdb.arch/amd64-invalid-stack-middle.c          |   89 ++
 .../gdb.arch/amd64-invalid-stack-middle.exp        |   94 ++
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c   |   73 +
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp |   97 ++
 5 files changed, 1763 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp

diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
new file mode 100644
index 0000000..3b4a067
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
@@ -0,0 +1,1410 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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 file is compiled from gdb.arch/amd64-invalid-stack-middle.c
+   using: 'gcc -g -O0 -S -dA' and gcc version '4.7.2'.
+   Changes were then made to the CFI entry for func2.  */
+        
+	.file	"amd64-invalid-stack-middle.c"
+	.text
+.Ltext0:
+	.globl	breakpt
+	.type	breakpt, @function
+breakpt:
+.LFB0:
+	.file 1 "amd64-invalid-stack-middle.c"
+	# amd64-invalid-stack-middle.c:25
+	.loc 1 25 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI0:
+	movq	%rsp, %rbp
+.LCFI1:
+	# amd64-invalid-stack-middle.c:27
+	.loc 1 27 0
+	popq	%rbp
+.LCFI2:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE0:
+	.size	breakpt, .-breakpt
+	.globl	func5
+	.type	func5, @function
+func5:
+.LFB1:
+	# amd64-invalid-stack-middle.c:31
+	.loc 1 31 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI3:
+	movq	%rsp, %rbp
+.LCFI4:
+	# amd64-invalid-stack-middle.c:32
+	.loc 1 32 0
+	movl	$0, %eax
+	call	breakpt
+	# amd64-invalid-stack-middle.c:33
+	.loc 1 33 0
+	popq	%rbp
+.LCFI5:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE1:
+	.size	func5, .-func5
+	.globl	func4
+	.type	func4, @function
+func4:
+.LFB2:
+	# amd64-invalid-stack-middle.c:37
+	.loc 1 37 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI6:
+	movq	%rsp, %rbp
+.LCFI7:
+	# amd64-invalid-stack-middle.c:38
+	.loc 1 38 0
+	movl	$0, %eax
+	call	func5
+	# amd64-invalid-stack-middle.c:39
+	.loc 1 39 0
+	popq	%rbp
+.LCFI8:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE2:
+	.size	func4, .-func4
+	.globl	func3
+	.type	func3, @function
+func3:
+.LFB3:
+	# amd64-invalid-stack-middle.c:43
+	.loc 1 43 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI9:
+	movq	%rsp, %rbp
+.LCFI10:
+	# amd64-invalid-stack-middle.c:44
+	.loc 1 44 0
+	movl	$0, %eax
+	call	func4
+	# amd64-invalid-stack-middle.c:45
+	.loc 1 45 0
+	popq	%rbp
+.LCFI11:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE3:
+	.size	func3, .-func3
+	.globl	func2
+	.type	func2, @function
+func2:
+.LFB4:
+	# amd64-invalid-stack-middle.c:49
+	.loc 1 49 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI12:
+	movq	%rsp, %rbp
+.LCFI13:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:50
+	.loc 1 50 0
+	movl	$0, %eax
+	call	func3
+	# amd64-invalid-stack-middle.c:51
+	.loc 1 51 0
+	leave
+.LCFI14:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE4:
+	.size	func2, .-func2
+	.globl	func1
+	.type	func1, @function
+func1:
+.LFB5:
+	# amd64-invalid-stack-middle.c:55
+	.loc 1 55 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI15:
+	movq	%rsp, %rbp
+.LCFI16:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:56
+	.loc 1 56 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func2
+	# amd64-invalid-stack-middle.c:57
+	.loc 1 57 0
+	leave
+.LCFI17:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE5:
+	.size	func1, .-func1
+	.section	.rodata
+.LC0:
+	.string	"amd64-invalid-stack-middle.c"
+.LC1:
+	.string	"ptr != ((void *) -1)"
+.LC2:
+	.string	"ans == 0"
+	.text
+	.type	make_invalid_ptr, @function
+make_invalid_ptr:
+.LFB6:
+	# amd64-invalid-stack-middle.c:65
+	.loc 1 65 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI18:
+	movq	%rsp, %rbp
+.LCFI19:
+	subq	$32, %rsp
+	# amd64-invalid-stack-middle.c:69
+	.loc 1 69 0
+	call	getpagesize
+	movl	%eax, -4(%rbp)
+	# amd64-invalid-stack-middle.c:70
+	.loc 1 70 0
+	movl	-4(%rbp), %eax
+	cltq
+	movl	$0, %r9d
+	movl	$-1, %r8d
+	movl	$34, %ecx
+	movl	$0, %edx
+	movq	%rax, %rsi
+	movl	$0, %edi
+	call	mmap
+	movq	%rax, -16(%rbp)
+	# amd64-invalid-stack-middle.c:73
+	.loc 1 73 0
+	cmpq	$-1, -16(%rbp)
+# SUCC: 3 (fallthru) 4
+	jne	.L8
+# BLOCK 3 seq:1
+# PRED: 2 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$73, %edx
+	movl	$.LC0, %esi
+	movl	$.LC1, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 4 seq:2
+# PRED: 2
+.L8:
+	# amd64-invalid-stack-middle.c:74
+	.loc 1 74 0
+	movl	-4(%rbp), %eax
+	movslq	%eax, %rdx
+	movq	-16(%rbp), %rax
+	movq	%rdx, %rsi
+	movq	%rax, %rdi
+	call	munmap
+	movl	%eax, -20(%rbp)
+	# amd64-invalid-stack-middle.c:75
+	.loc 1 75 0
+	cmpl	$0, -20(%rbp)
+# SUCC: 5 (fallthru) 6
+	je	.L9
+# BLOCK 5 seq:3
+# PRED: 4 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$75, %edx
+	movl	$.LC0, %esi
+	movl	$.LC2, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 6 seq:4
+# PRED: 4
+.L9:
+	# amd64-invalid-stack-middle.c:77
+	.loc 1 77 0
+	movq	-16(%rbp), %rax
+	# amd64-invalid-stack-middle.c:78
+	.loc 1 78 0
+	leave
+.LCFI20:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE6:
+	.size	make_invalid_ptr, .-make_invalid_ptr
+	.globl	main
+	.type	main, @function
+main:
+.LFB7:
+	# amd64-invalid-stack-middle.c:82
+	.loc 1 82 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI21:
+	movq	%rsp, %rbp
+.LCFI22:
+	subq	$16, %rsp
+	# amd64-invalid-stack-middle.c:85
+	.loc 1 85 0
+	call	make_invalid_ptr
+	movq	%rax, -8(%rbp)
+	# amd64-invalid-stack-middle.c:86
+	.loc 1 86 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func1
+	# amd64-invalid-stack-middle.c:88
+	.loc 1 88 0
+	movl	$0, %eax
+	# amd64-invalid-stack-middle.c:89
+	.loc 1 89 0
+	leave
+.LCFI23:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE7:
+	.size	main, .-main
+	.section	.rodata
+	.align 16
+	.type	__PRETTY_FUNCTION__.2362, @object
+	.size	__PRETTY_FUNCTION__.2362, 17
+__PRETTY_FUNCTION__.2362:
+	.string	"make_invalid_ptr"
+#APP
+	.section	.debug_frame,"",@progbits
+.Lframe0:
+	.long	.LECIE0-.LSCIE0	# Length of Common Information Entry
+.LSCIE0:
+	.long	0xffffffff	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE0:
+.LSFDE0:
+	.long	.LEFDE0-.LASFDE0	# FDE Length
+.LASFDE0:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB0	# FDE initial location
+	.quad	.LFE0-.LFB0	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE0:
+.LSFDE2:
+	.long	.LEFDE2-.LASFDE2	# FDE Length
+.LASFDE2:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB1	# FDE initial location
+	.quad	.LFE1-.LFB1	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE2:
+.LSFDE4:
+	.long	.LEFDE4-.LASFDE4	# FDE Length
+.LASFDE4:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB2	# FDE initial location
+	.quad	.LFE2-.LFB2	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE4:
+.LSFDE6:
+	.long	.LEFDE6-.LASFDE6	# FDE Length
+.LASFDE6:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB3	# FDE initial location
+	.quad	.LFE3-.LFB3	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE6:
+.LSFDE8:
+	.long	.LEFDE8-.LASFDE8	# FDE Length
+.LASFDE8:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB4		# FDE initial location
+	.quad	.LFE4-.LFB4	# FDE address range
+        .byte 0xf		# DW_CFA_def_cfa_expression
+        .uleb128 .LEDWBLK1 - .LSDWBLK1
+.LSDWBLK1:
+        .byte 0x75              # DW_OP_breg5
+        .sleb128 0x0            #        offset
+        .byte 0x94              # DW_OP_dref_size
+        .byte 0x8		#        size
+.LEDWBLK1:
+	.align 8		# Padding.
+.LEFDE8:
+.LSFDE10:
+	.long	.LEFDE10-.LASFDE10	# FDE Length
+.LASFDE10:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB5	# FDE initial location
+	.quad	.LFE5-.LFB5	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE10:
+.LSFDE12:
+	.long	.LEFDE12-.LASFDE12	# FDE Length
+.LASFDE12:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB6	# FDE initial location
+	.quad	.LFE6-.LFB6	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE12:
+.LSFDE14:
+	.long	.LEFDE14-.LASFDE14	# FDE Length
+.LASFDE14:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB7	# FDE initial location
+	.quad	.LFE7-.LFB7	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE14:
+#NO_APP
+#APP
+	.section	.eh_frame,"a",@progbits
+.Lframe1:
+	.long	.LECIE1-.LSCIE1	# Length of Common Information Entry
+.LSCIE1:
+	.long	0	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "zR\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.uleb128 0x1	# Augmentation size
+	.byte	0x3	# FDE Encoding (udata4)
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE1:
+.LSFDE17:
+	.long	.LEFDE17-.LASFDE17	# FDE Length
+.LASFDE17:
+	.long	.LASFDE17-.Lframe1	# FDE CIE offset
+	.long	.LFB0	# FDE initial location
+	.long	.LFE0-.LFB0	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE17:
+.LSFDE19:
+	.long	.LEFDE19-.LASFDE19	# FDE Length
+.LASFDE19:
+	.long	.LASFDE19-.Lframe1	# FDE CIE offset
+	.long	.LFB1	# FDE initial location
+	.long	.LFE1-.LFB1	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE19:
+.LSFDE21:
+	.long	.LEFDE21-.LASFDE21	# FDE Length
+.LASFDE21:
+	.long	.LASFDE21-.Lframe1	# FDE CIE offset
+	.long	.LFB2	# FDE initial location
+	.long	.LFE2-.LFB2	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE21:
+.LSFDE23:
+	.long	.LEFDE23-.LASFDE23	# FDE Length
+.LASFDE23:
+	.long	.LASFDE23-.Lframe1	# FDE CIE offset
+	.long	.LFB3	# FDE initial location
+	.long	.LFE3-.LFB3	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE23:
+.LSFDE25:
+	.long	.LEFDE25-.LASFDE25	# FDE Length
+.LASFDE25:
+	.long	.LASFDE25-.Lframe1	# FDE CIE offset
+	.long	.LFB4	# FDE initial location
+	.long	.LFE4-.LFB4	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI12-.LFB4
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI13-.LCFI12
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI14-.LCFI13
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE25:
+.LSFDE27:
+	.long	.LEFDE27-.LASFDE27	# FDE Length
+.LASFDE27:
+	.long	.LASFDE27-.Lframe1	# FDE CIE offset
+	.long	.LFB5	# FDE initial location
+	.long	.LFE5-.LFB5	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE27:
+.LSFDE29:
+	.long	.LEFDE29-.LASFDE29	# FDE Length
+.LASFDE29:
+	.long	.LASFDE29-.Lframe1	# FDE CIE offset
+	.long	.LFB6	# FDE initial location
+	.long	.LFE6-.LFB6	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE29:
+.LSFDE31:
+	.long	.LEFDE31-.LASFDE31	# FDE Length
+.LASFDE31:
+	.long	.LASFDE31-.Lframe1	# FDE CIE offset
+	.long	.LFB7	# FDE initial location
+	.long	.LFE7-.LFB7	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE31:
+#NO_APP
+	.text
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x1f1	# Length of Compilation Unit Info
+	.value	0x2	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x8	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF17	# DW_AT_producer: "GNU C 4.7.2"
+	.byte	0x1	# DW_AT_language
+	.long	.LASF18	# DW_AT_name: "amd64-invalid-stack-middle.c"
+	.long	.LASF19	# DW_AT_comp_dir: "/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+	.quad	.Ltext0	# DW_AT_low_pc
+	.quad	.Letext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x2d) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "long unsigned int"
+	.uleb128 0x2	# (DIE (0x34) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "unsigned char"
+	.uleb128 0x2	# (DIE (0x3b) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "short unsigned int"
+	.uleb128 0x2	# (DIE (0x42) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "unsigned int"
+	.uleb128 0x2	# (DIE (0x49) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "signed char"
+	.uleb128 0x2	# (DIE (0x50) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x57) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x2	# (DIE (0x5e) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "long int"
+	.uleb128 0x2	# (DIE (0x65) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "sizetype"
+	.uleb128 0x4	# (DIE (0x6c) DW_TAG_pointer_type)
+	.byte	0x8	# DW_AT_byte_size
+	.uleb128 0x2	# (DIE (0x6e) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "char"
+	.uleb128 0x5	# (DIE (0x75) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF9	# DW_AT_name: "breakpt"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x18	# DW_AT_decl_line
+	.quad	.LFB0	# DW_AT_low_pc
+	.quad	.LFE0	# DW_AT_high_pc
+	.long	.LLST0	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_call_sites
+	.uleb128 0x6	# (DIE (0x92) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF10	# DW_AT_name: "func5"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x1e	# DW_AT_decl_line
+	.quad	.LFB1	# DW_AT_low_pc
+	.quad	.LFE1	# DW_AT_high_pc
+	.long	.LLST1	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xaf) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF11	# DW_AT_name: "func4"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x24	# DW_AT_decl_line
+	.quad	.LFB2	# DW_AT_low_pc
+	.quad	.LFE2	# DW_AT_high_pc
+	.long	.LLST2	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xcc) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "func3"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x2a	# DW_AT_decl_line
+	.quad	.LFB3	# DW_AT_low_pc
+	.quad	.LFE3	# DW_AT_high_pc
+	.long	.LLST3	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x7	# (DIE (0xe9) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "func2"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB4	# DW_AT_low_pc
+	.quad	.LFE4	# DW_AT_high_pc
+	.long	.LLST4	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x11a	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x10b) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0xe9
+	.uleb128 0x7	# (DIE (0x11a) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF14	# DW_AT_name: "func1"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB5	# DW_AT_low_pc
+	.quad	.LFE5	# DW_AT_high_pc
+	.long	.LLST5	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x14b	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x13c) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x11a
+	.uleb128 0x9	# (DIE (0x14b) DW_TAG_subprogram)
+	.long	.LASF20	# DW_AT_name: "make_invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x40	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.long	0x6c	# DW_AT_type
+	.quad	.LFB6	# DW_AT_low_pc
+	.quad	.LFE6	# DW_AT_high_pc
+	.long	.LLST6	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x1af	# DW_AT_sibling
+	.uleb128 0xa	# (DIE (0x170) DW_TAG_variable)
+	.long	.LASF15	# DW_AT_name: "page_size"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.uleb128 0xb	# (DIE (0x17e) DW_TAG_variable)
+	.ascii "ans\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0xb	# (DIE (0x18c) DW_TAG_variable)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x43	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -32
+	.uleb128 0xc	# (DIE (0x19a) DW_TAG_variable)
+	.long	.LASF21	# DW_AT_name: "__PRETTY_FUNCTION__"
+	.long	0x1bf	# DW_AT_type
+	.byte	0x1	# DW_AT_artificial
+	.byte	0x9	# DW_AT_location
+	.byte	0x3	# DW_OP_addr
+	.quad	__PRETTY_FUNCTION__.2362
+	.byte	0	# end of children of DIE 0x14b
+	.uleb128 0xd	# (DIE (0x1af) DW_TAG_array_type)
+	.long	0x6e	# DW_AT_type
+	.long	0x1bf	# DW_AT_sibling
+	.uleb128 0xe	# (DIE (0x1b8) DW_TAG_subrange_type)
+	.long	0x65	# DW_AT_type
+	.byte	0x10	# DW_AT_upper_bound
+	.byte	0	# end of children of DIE 0x1af
+	.uleb128 0xf	# (DIE (0x1bf) DW_TAG_const_type)
+	.long	0x1af	# DW_AT_type
+	.uleb128 0x10	# (DIE (0x1c4) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF22	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x51	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.quad	.LFB7	# DW_AT_low_pc
+	.quad	.LFE7	# DW_AT_high_pc
+	.long	.LLST7	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0xa	# (DIE (0x1e5) DW_TAG_variable)
+	.long	.LASF16	# DW_AT_name: "invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x53	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x1c4
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0xf	# (TAG: DW_TAG_pointer_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xb	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xc	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xd	# (abbrev code)
+	.uleb128 0x1	# (TAG: DW_TAG_array_type)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xe	# (abbrev code)
+	.uleb128 0x21	# (TAG: DW_TAG_subrange_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2f	# (DW_AT_upper_bound)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0xf	# (abbrev code)
+	.uleb128 0x26	# (TAG: DW_TAG_const_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x10	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+	.quad	.LFB0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI1-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI1-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI2-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI2-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LFE0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST0)
+	.quad	0	# Location list terminator end (*.LLST0)
+.LLST1:
+	.quad	.LFB1-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI3-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI3-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI4-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI4-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI5-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI5-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LFE1-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST1)
+	.quad	0	# Location list terminator end (*.LLST1)
+.LLST2:
+	.quad	.LFB2-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI6-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI6-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI7-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI7-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI8-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI8-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LFE2-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST2)
+	.quad	0	# Location list terminator end (*.LLST2)
+.LLST3:
+	.quad	.LFB3-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI9-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI9-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI10-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI10-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI11-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI11-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LFE3-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST3)
+	.quad	0	# Location list terminator end (*.LLST3)
+.LLST4:
+	.quad	.LFB4-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI12-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI12-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI13-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI13-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI14-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI14-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LFE4-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST4)
+	.quad	0	# Location list terminator end (*.LLST4)
+.LLST5:
+	.quad	.LFB5-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI15-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI15-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI16-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI16-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI17-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI17-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LFE5-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST5)
+	.quad	0	# Location list terminator end (*.LLST5)
+.LLST6:
+	.quad	.LFB6-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI18-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI18-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI19-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI19-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI20-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI20-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LFE6-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST6)
+	.quad	0	# Location list terminator end (*.LLST6)
+.LLST7:
+	.quad	.LFB7-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI21-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI21-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI22-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI22-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI23-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI23-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LFE7-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST7)
+	.quad	0	# Location list terminator end (*.LLST7)
+	.section	.debug_aranges,"",@progbits
+	.long	0x2c	# Length of Address Ranges Info
+	.value	0x2	# DWARF Version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x8	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 16 byte boundary
+	.value	0
+	.quad	.Ltext0	# Address
+	.quad	.Letext0-.Ltext0	# Length
+	.quad	0
+	.quad	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF10:
+	.string	"func5"
+.LASF20:
+	.string	"make_invalid_ptr"
+.LASF21:
+	.string	"__PRETTY_FUNCTION__"
+.LASF18:
+	.string	"amd64-invalid-stack-middle.c"
+.LASF22:
+	.string	"main"
+.LASF14:
+	.string	"func1"
+.LASF17:
+	.string	"GNU C 4.7.2"
+.LASF11:
+	.string	"func4"
+.LASF0:
+	.string	"long unsigned int"
+.LASF1:
+	.string	"unsigned char"
+.LASF8:
+	.string	"char"
+.LASF6:
+	.string	"long int"
+.LASF15:
+	.string	"page_size"
+.LASF13:
+	.string	"func2"
+.LASF16:
+	.string	"invalid_ptr"
+.LASF2:
+	.string	"short unsigned int"
+.LASF4:
+	.string	"signed char"
+.LASF9:
+	.string	"breakpt"
+.LASF19:
+	.string	"/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+.LASF5:
+	.string	"short int"
+.LASF3:
+	.string	"unsigned int"
+.LASF12:
+	.string	"func3"
+.LASF7:
+	.string	"sizetype"
+	.ident	"GCC: (GNU) 4.7.2"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
new file mode 100644
index 0000000..b8fbf6f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void
+breakpt ()
+{
+  /* Nothing.  */
+}
+
+void
+func5 ()
+{
+  breakpt ();
+}
+
+void
+func4 ()
+{
+  func5 ();
+}
+
+void
+func3 ()
+{
+  func4 ();
+}
+
+void
+func2 (void *ptr)
+{
+  func3 ();
+}
+
+void
+func1 (void *ptr)
+{
+  func2 (ptr);
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
new file mode 100644
index 0000000..ef70a4f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -0,0 +1,94 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .S
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt\n"
+gdb_expect {
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
new file mode 100644
index 0000000..c821f18
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
@@ -0,0 +1,73 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void *global_invalid_ptr = NULL;
+
+void
+func2 (void)
+{
+  /* Replace the current stack pointer and frame pointer with the invalid
+     pointer.  */
+  asm ("mov %0, %%rsp\n\tmov %0, %%rbp" : : "r" (global_invalid_ptr));
+
+  /* Create a label for a breakpoint.  */
+  asm (".global breakpt\nbreakpt:");
+}
+
+void
+func1 (void *ptr)
+{
+  global_invalid_ptr = ptr;
+  func2 ();
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
new file mode 100644
index 0000000..6598cd4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -0,0 +1,97 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .c
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+# Use 'bt no-filters' here as the python filters will raise their own
+# error during initialisation, the no-filters case is simpler.
+
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt no-filters\n"
+gdb_expect {
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 3/4] Deprecate frame_stop_reason_string.
  2014-04-17 10:15 ` [PATCH v2 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-04-29 19:56   ` Pedro Alves
  2014-04-30 10:46     ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-04-29 19:56 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

I find such a patch with no description/rationale at all very
hard to reason about.  The description isn't included
in the cover letter of this series either.  Please don't make
us jump through hoops to figure things out.  :-(

E.g., why is this deprecated?  Why can't all callers be adjusted
to the new function you're adding?  These are the sorts of
explanations that should be included in the commit log.

-- 
Pedro Alves

On 04/17/2014 11:15 AM, Andrew Burgess wrote:
> gdb/ChangeLog:
> 
> 	* frame.c (frame_stop_reason_string): Rename to ...
> 	(deprecated_frame_stop_reason_string): this.
> 	* frame.h (frame_stop_reason_string): Rename to ...
> 	(deprecated_frame_stop_reason_string): this.
>         * stack.c (frame_info): Update call to frame_stop_reason_string.
> 	(backtrace_command_1): Update call to frame_stop_reason_string.
> 	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Update
> 	call to frame_stop_reason_string.
> 	* python/py-frame.c (gdbpy_frame_stop_reason_string): Update call
> 	to frame_stop_reason_string.
> ~ChangeLog~
> ---
>  gdb/frame.c           | 2 +-
>  gdb/frame.h           | 5 +++--
>  gdb/guile/scm-frame.c | 2 +-
>  gdb/python/py-frame.c | 2 +-
>  gdb/stack.c           | 4 ++--
>  5 files changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 5f05968..5a6e0c7 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -2556,7 +2556,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
>  /* Return a string explaining REASON.  */
>  
>  const char *
> -frame_stop_reason_string (enum unwind_stop_reason reason)
> +deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
>  {
>    switch (reason)
>      {
> diff --git a/gdb/frame.h b/gdb/frame.h
> index e451a93..7db5382 100644
> --- a/gdb/frame.h
> +++ b/gdb/frame.h
> @@ -495,9 +495,10 @@ enum unwind_stop_reason
>  
>  enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
>  
> -/* Translate a reason code to an informative string.  */
> +/* Translate a reason code to an informative string.  This is DEPRECATED,
> +   use frame_stop_reason_string instead.  */
>  
> -const char *frame_stop_reason_string (enum unwind_stop_reason);
> +const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
>  
>  /* Unwind the stack frame so that the value of REGNUM, in the previous
>     (up, older) frame is returned.  If VALUEP is NULL, don't
> diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
> index 6031a7f..ddd062c 100644
> --- a/gdb/guile/scm-frame.c
> +++ b/gdb/guile/scm-frame.c
> @@ -944,7 +944,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
>    if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
>      scm_out_of_range (FUNC_NAME, reason_scm);
>  
> -  str = frame_stop_reason_string (reason);
> +  str = deprecated_frame_stop_reason_string (reason);
>    return gdbscm_scm_from_c_string (str);
>  }
>  \f
> diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
> index 8c80d39..e7fcfe3 100644
> --- a/gdb/python/py-frame.c
> +++ b/gdb/python/py-frame.c
> @@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
>        return NULL;
>      }
>  
> -  str = frame_stop_reason_string (reason);
> +  str = deprecated_frame_stop_reason_string (reason);
>    return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
>  }
>  
> diff --git a/gdb/stack.c b/gdb/stack.c
> index da7d977..4fa9dd6 100644
> --- a/gdb/stack.c
> +++ b/gdb/stack.c
> @@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
>        reason = get_frame_unwind_stop_reason (fi);
>        if (reason != UNWIND_NO_REASON)
>  	printf_filtered (_(" Outermost frame: %s\n"),
> -			 frame_stop_reason_string (reason));
> +			 deprecated_frame_stop_reason_string (reason));
>      }
>    else if (get_frame_type (fi) == TAILCALL_FRAME)
>      puts_filtered (" tail call frame");
> @@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
>  	  reason = get_frame_unwind_stop_reason (trailing);
>  	  if (reason >= UNWIND_FIRST_ERROR)
>  	    printf_filtered (_("Backtrace stopped: %s\n"),
> -			     frame_stop_reason_string (reason));
> +			     deprecated_frame_stop_reason_string (reason));
>  	}
>      }
>  }
> 


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2 3/4] Deprecate frame_stop_reason_string.
  2014-04-29 19:56   ` Pedro Alves
@ 2014-04-30 10:46     ` Andrew Burgess
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:46 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 29/04/2014 8:20 PM, Pedro Alves wrote:
> I find such a patch with no description/rationale at all very
> hard to reason about.  The description isn't included
> in the cover letter of this series either.  Please don't make
> us jump through hoops to figure things out.  :-(

Pedro,

You're right.  Sorry.  I messed up.

I'll post a V3 in which I'm going to try event harder.

Once again, sorry for wasting your time.

Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
  2014-04-30 10:55   ` [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
@ 2014-04-30 10:55   ` Andrew Burgess
  2014-05-28 17:26     ` Pedro Alves
  2014-04-30 10:55   ` [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
  2014-04-30 10:55   ` [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
  3 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Patch #4 adds frame specific stop reason strings.  It is better to use that
string rather than the existing generic stop reason string.  This patch
renames frame_stop_reason_string to deprecated_frame_stop_reason_string and
updates all the call sites to use the deprecated name.

Patch #4 adds the new frame specific stop reason, and some uses of the
deprecated funciton will be moved to this new API, however, in the python
and guile scripting API we expose a function that converts the stop reason
code into a string, without a frame, this will be harder to convert to the
new API and so I have currently left using the
deprecated_frame_stop_reason_string function.

This patch only makes sense if patch #4 is approved, but does this look ok?

Thanks,
Andrew




gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(deprecated_frame_stop_reason_string): this.
        * stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Update call to frame_stop_reason_string.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Update
	call to frame_stop_reason_string.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Update call
	to frame_stop_reason_string.
---
 gdb/frame.c           | 2 +-
 gdb/frame.h           | 5 +++--
 gdb/guile/scm-frame.c | 2 +-
 gdb/python/py-frame.c | 2 +-
 gdb/stack.c           | 4 ++--
 5 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 5f05968..5a6e0c7 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2556,7 +2556,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
 /* Return a string explaining REASON.  */
 
 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index e451a93..7db5382 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -495,9 +495,10 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This is DEPRECATED,
+   use frame_stop_reason_string instead.  */
 
-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6031a7f..ddd062c 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -944,7 +944,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..e7fcfe3 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
       return NULL;
     }
 
-  str = frame_stop_reason_string (reason);
+  str = deprecated_frame_stop_reason_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
diff --git a/gdb/stack.c b/gdb/stack.c
index da7d977..4fa9dd6 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 deprecated_frame_stop_reason_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     deprecated_frame_stop_reason_string (reason));
 	}
     }
 }
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v3 0/4] Catch errors in get_prev_frame.
  2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
                   ` (9 preceding siblings ...)
  2014-04-17 10:15 ` [PATCH v2 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-04-30 10:55 ` Andrew Burgess
  2014-04-30 10:55   ` [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
                     ` (3 more replies)
  10 siblings, 4 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

This V3 patch completely replaces the previous patch posted here:
  https://sourceware.org/ml/gdb-patches/2014-04/msg00064.html
Which due to a series of blunders is pretty much unreviewable. The content
of this series is identical to the previous attempts but the patches should
be correctly formatted, and the email text description is included too.

Patch Description:

While working on a reproducer for this patch:
  https://sourceware.org/ml/gdb-patches/2014-03/msg00629.html

I ran into a few other issues.  The route cause of the problems I'm seeing
is that not all errors thrown within get_prev_frame are caught.  This
causes a couple of problems,

1. For the MI this means that commands like -stack-info-depth will
return an error rather than a result.  Even more annoying, is that
depending on where in the process the error is thrown enough state may
be left set that the /next/ time -stack-info-depth is asked, the correct
result is given!

2. For standard CLI backtraces our the results are (I think) inconsistent,
so for example some backtraces will end with a message like: "Backtrace
stopped: previous frame inner to this frame (corrupted stack?)", this
message will be displayed every time the backtrace is requested, in other
cases though, the reason is only displayed the first time a backtrace is
requested, this is the case when an uncaught error causes the backtrace to
stop, also in the uncaught error case the "Backtrace stopped" prefix does
not appear.

This patch set tries to fix both these issues by holding a frame specific
string that describes why the backtrace stopped at this frame (only for the
last frame in the backtrace obviously).  If this string is not set then we
still use the existing generic strings.

A new TRY_CATCH inside get_prev_frame catches (currently) all unhandled
errors, the error message from these errors is then used as a frame
specific stop reason string.  There's a new unwind_stop_reason code for
this case, UNWIND_MISC_ERROR.

If it's felt that catching all errors like this is too much then I could
soften this to just catching MEMORY_ERRORs, as right now the problems I'm
seeing all relate to accessing memory through a corrupted stack pointer.

Thanks,
Andrew



Andrew Burgess (4):
  New test for backtrace when the stack pointer is invalid (inaccessible).
  Remove previous frame if an error occurs when computing frame id during unwind.
  Deprecate frame_stop_reason_string.
  Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.

 gdb/frame.c                                        |  123 +-
 gdb/frame.h                                        |   11 +-
 gdb/guile/scm-frame.c                              |    2 +-
 gdb/python/py-frame.c                              |    2 +-
 gdb/stack.c                                        |    4 +-
 .../gdb.arch/amd64-invalid-stack-middle.S          | 1410 ++++++++++++++++++++
 .../gdb.arch/amd64-invalid-stack-middle.c          |   89 ++
 .../gdb.arch/amd64-invalid-stack-middle.exp        |   78 ++
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c   |   73 +
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp |   81 ++
 gdb/unwind_stop_reasons.def                        |    5 +-
 11 files changed, 1850 insertions(+), 28 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp

-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind.
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
@ 2014-04-30 10:55   ` Andrew Burgess
  2014-05-16 15:37     ` Pedro Alves
  2014-04-30 10:55   ` [PATCH v3 3/4] Deprecate frame_stop_reason_string Andrew Burgess
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

In get_prev_frame_if_no_cycle, if we throw an error during compute_frame_id
then we are left in a state where THIS_FRAME has a PREV_FRAME attached, but
PREV_FRAME has no frame id.  This is an unexpected state that causes
internal errors and assertions to fire.

This patch adds a cleanup that removes the previous frame created by
get_prev_frame_raw if we get an error.

OK to apply?

Thanks,
Andrew



gdb/ChangeLog:

	* frame.c (remove_prev_frame): New function.
	(get_prev_frame_if_no_cycle): Create / discard cleanup using
	remove_prev_frame.

---
 gdb/frame.c | 52 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 97d54e9..5f05968 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1733,6 +1733,22 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
     }
 }
 
+/* Called during frame unwinding to remove a previous frame pointer from a
+   frame passed in ARG.  */
+
+static void
+remove_prev_frame (void *arg)
+{
+  struct frame_info *this_frame, *prev_frame;
+
+  this_frame = (struct frame_info *) arg;
+  prev_frame = this_frame->prev;
+  gdb_assert (prev_frame != NULL);
+
+  prev_frame->next = NULL;
+  this_frame->prev = NULL;
+}
+
 /* Get the previous raw frame, and check that it is not identical to
    same other frame frame already in the chain.  If it is, there is
    most likely a stack cycle, so we discard it, and mark THIS_FRAME as
@@ -1745,28 +1761,36 @@ static struct frame_info *
 get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 {
   struct frame_info *prev_frame;
+  struct cleanup *prev_frame_cleanup;
 
   prev_frame = get_prev_frame_raw (this_frame);
   if (prev_frame == NULL)
     return NULL;
 
-  compute_frame_id (prev_frame);
-  if (frame_stash_add (prev_frame))
-    return prev_frame;
+  /* The cleanup will remove the previous frame that get_prev_frame_raw
+     linked onto THIS_FRAME.  */
+  prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
 
-  /* Another frame with the same id was already in the stash.  We just
-     detected a cycle.  */
-  if (frame_debug)
+  compute_frame_id (prev_frame);
+  if (!frame_stash_add (prev_frame))
     {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, NULL);
-      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+      /* Another frame with the same id was already in the stash.  We just
+	 detected a cycle.  */
+      if (frame_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "-> ");
+	  fprint_frame (gdb_stdlog, NULL);
+	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+	}
+      this_frame->stop_reason = UNWIND_SAME_ID;
+      /* Unlink.  */
+      prev_frame->next = NULL;
+      this_frame->prev = NULL;
+      prev_frame = NULL;
     }
-  this_frame->stop_reason = UNWIND_SAME_ID;
-  /* Unlink.  */
-  prev_frame->next = NULL;
-  this_frame->prev = NULL;
-  return NULL;
+
+  discard_cleanups (prev_frame_cleanup);
+  return prev_frame;
 }
 
 /* Return a "struct frame_info" corresponding to the frame that called
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
  2014-04-30 10:55   ` [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
  2014-04-30 10:55   ` [PATCH v3 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-04-30 10:55   ` Andrew Burgess
  2014-05-28 18:31     ` Pedro Alves
  2014-04-30 10:55   ` [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
  3 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Here a new TRY_CATCH is added to the core of get_prev_frame, all uncaught
errors are turned into UNWIND_MISC_ERROR, and where possible the error
message associated with the error is stored as a frame specific stop reason
string.  The reason string is held of the frame OBSTACK so it lives as long
as the frame does.

There's a new function for getting the frame_stop_reason_string, this
replaces the now (thanks to patch #3) old frame_stop_reason_string
function, I know that reusing the name could confuse, but this function was
not widely used, so I hope that'll not be an issue.

Finally, I update the expected results from the tests in patch #1 now that
everything should pass.

I don't know if you'll all be happy with me catching _all_ errors in
get_prev_frame.  Given that the issues I'm seeing "in the wild" and which
I've put into the tests are for accessing invalid memory through a bad
stack pointer, I could reduce the catching to only catch MEMORY_ERRORs,
then UNWIND_MISC_ERROR would become UNWIND_MEMORY_ERROR.  I could even add
the memory error detection on top of the new MISC_ERROR case if preferred,
though I'd need to think of a new test...

Feedback welcome, or is this OK?

Thanks,
Andrew




gdb/ChangeLog:

	* frame.c (struct frame_info): Add stop_string field.
	(get_prev_frame_2): Renamed from get_prev_frame_1.
	(get_prev_frame_1): Old content moved into get_prev_frame_2.  Call
	get_prev_frame_2 inside TRY_CATCH, handle errors.
	(frame_stop_reason_string): New function definition.
	* frame.h (frame_stop_reason_string): New function declaration.
	* stack.c (frame_info): Switch to frame_stop_reason_string.
	(backtrace_command_1): Switch to frame_stop_reason_string.
	* unwind_stop_reason.def: Add UNWIND_MISC_ERROR.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
	* gdb.arch/amd64-invalid-stack-top.exp: Likewise.
---
 gdb/frame.c                                        | 69 ++++++++++++++++++++--
 gdb/frame.h                                        |  6 ++
 gdb/stack.c                                        |  4 +-
 .../gdb.arch/amd64-invalid-stack-middle.exp        | 22 +------
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp | 22 +------
 gdb/unwind_stop_reasons.def                        |  5 +-
 6 files changed, 81 insertions(+), 47 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 5a6e0c7..65ba49b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -146,6 +146,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1793,14 +1797,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_1, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
 static struct frame_info *
-get_prev_frame_1 (struct frame_info *this_frame)
+get_prev_frame_2 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1950,6 +1952,41 @@ get_prev_frame_1 (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+static struct frame_info *
+get_prev_frame_1 (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_2 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      this_frame->stop_reason = UNWIND_MISC_ERROR;
+      if (ex.message != NULL)
+	{
+	  char *stop_string;
+
+	  /* The error needs to live as long as the frame does.  */
+	  stop_string =
+	    FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
+	  strcpy (stop_string, ex.message);
+	  this_frame->stop_string = stop_string;
+	}
+      prev_frame = NULL;
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2571,6 +2608,26 @@ deprecated_frame_stop_reason_string (enum unwind_stop_reason reason)
     }
 }
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped at frame FI.  Must only be called if there is no previous
+   frame.  */
+
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  At some point
+     if DEPRECATED_FRAME_STOP_REASON_STRING is not used anywhere else then
+     its content could be moved into here.  */
+  return deprecated_frame_stop_reason_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 7db5382..1a5614d 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -500,6 +500,12 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
 const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  Should only be called for frames that don't have a
+   previous frame.  If there's no specific reason stored for a frame then
+   a generic reason string will be returned.  */
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
diff --git a/gdb/stack.c b/gdb/stack.c
index 4fa9dd6..3f8ecfb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 deprecated_frame_stop_reason_string (reason));
+			 frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     deprecated_frame_stop_reason_string (reason));
+			     frame_stop_reason_string (trailing));
 	}
     }
 }
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index ef70a4f..b53ad41 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
index 6598cd4..52869a2 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -46,27 +46,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def
index d7da7ea..84cfb75 100644
--- a/gdb/unwind_stop_reasons.def
+++ b/gdb/unwind_stop_reasons.def
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* The frame unwinder threw some other error which we caught.  */
+SET (UNWIND_MISC_ERROR, "miscellaneous error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MISC_ERROR)
 #endif
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible).
  2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
                     ` (2 preceding siblings ...)
  2014-04-30 10:55   ` [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
@ 2014-04-30 10:55   ` Andrew Burgess
  2014-05-28 18:42     ` Pedro Alves
  3 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-04-30 10:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Two tests for backtracing when there's a corrupted stack pointer.

These tests live in the gdb.arch/ directory as they are amd64 specific,
however, the tests use MI commands (as well as normal commands).  I wasn't
totally sure where the best place to put the tests was, I'd either have to
put arch specific code into the gdb.mi/ directory, or mi specific code into
gdb.arch/ ...

... I figured that putting some specific MI commands into gdb.arch/ was the
lesser evil, my reasoning being that this covers a specific bug/issue seen
in this case, but is not aiming to exhaustively cover the MI, it's not
_really_ an MI test...

Some of these tests fail without the rest of this patch set, so can't be
merged until everything else is ready, but all feedback appreciated.


Thanks,
Andrew




Two new tests are added, one where the stack is invalid at some middle
frame, and one where the stack is invalid in the first frame.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.S: New file.
	* gdb.arch/amd64-invalid-stack-middle.c: New file.
	* gdb.arch/amd64-invalid-stack-middle.exp: New file.
	* gdb.arch/amd64-invalid-stack-top.c: New file.
        * gdb.arch/amd64-invalid-stack-top.exp: New file.
---
 .../gdb.arch/amd64-invalid-stack-middle.S          | 1410 ++++++++++++++++++++
 .../gdb.arch/amd64-invalid-stack-middle.c          |   89 ++
 .../gdb.arch/amd64-invalid-stack-middle.exp        |   94 ++
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c   |   73 +
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp |   97 ++
 5 files changed, 1763 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp

diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
new file mode 100644
index 0000000..3b4a067
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
@@ -0,0 +1,1410 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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 file is compiled from gdb.arch/amd64-invalid-stack-middle.c
+   using: 'gcc -g -O0 -S -dA' and gcc version '4.7.2'.
+   Changes were then made to the CFI entry for func2.  */
+        
+	.file	"amd64-invalid-stack-middle.c"
+	.text
+.Ltext0:
+	.globl	breakpt
+	.type	breakpt, @function
+breakpt:
+.LFB0:
+	.file 1 "amd64-invalid-stack-middle.c"
+	# amd64-invalid-stack-middle.c:25
+	.loc 1 25 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI0:
+	movq	%rsp, %rbp
+.LCFI1:
+	# amd64-invalid-stack-middle.c:27
+	.loc 1 27 0
+	popq	%rbp
+.LCFI2:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE0:
+	.size	breakpt, .-breakpt
+	.globl	func5
+	.type	func5, @function
+func5:
+.LFB1:
+	# amd64-invalid-stack-middle.c:31
+	.loc 1 31 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI3:
+	movq	%rsp, %rbp
+.LCFI4:
+	# amd64-invalid-stack-middle.c:32
+	.loc 1 32 0
+	movl	$0, %eax
+	call	breakpt
+	# amd64-invalid-stack-middle.c:33
+	.loc 1 33 0
+	popq	%rbp
+.LCFI5:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE1:
+	.size	func5, .-func5
+	.globl	func4
+	.type	func4, @function
+func4:
+.LFB2:
+	# amd64-invalid-stack-middle.c:37
+	.loc 1 37 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI6:
+	movq	%rsp, %rbp
+.LCFI7:
+	# amd64-invalid-stack-middle.c:38
+	.loc 1 38 0
+	movl	$0, %eax
+	call	func5
+	# amd64-invalid-stack-middle.c:39
+	.loc 1 39 0
+	popq	%rbp
+.LCFI8:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE2:
+	.size	func4, .-func4
+	.globl	func3
+	.type	func3, @function
+func3:
+.LFB3:
+	# amd64-invalid-stack-middle.c:43
+	.loc 1 43 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI9:
+	movq	%rsp, %rbp
+.LCFI10:
+	# amd64-invalid-stack-middle.c:44
+	.loc 1 44 0
+	movl	$0, %eax
+	call	func4
+	# amd64-invalid-stack-middle.c:45
+	.loc 1 45 0
+	popq	%rbp
+.LCFI11:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE3:
+	.size	func3, .-func3
+	.globl	func2
+	.type	func2, @function
+func2:
+.LFB4:
+	# amd64-invalid-stack-middle.c:49
+	.loc 1 49 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI12:
+	movq	%rsp, %rbp
+.LCFI13:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:50
+	.loc 1 50 0
+	movl	$0, %eax
+	call	func3
+	# amd64-invalid-stack-middle.c:51
+	.loc 1 51 0
+	leave
+.LCFI14:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE4:
+	.size	func2, .-func2
+	.globl	func1
+	.type	func1, @function
+func1:
+.LFB5:
+	# amd64-invalid-stack-middle.c:55
+	.loc 1 55 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI15:
+	movq	%rsp, %rbp
+.LCFI16:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:56
+	.loc 1 56 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func2
+	# amd64-invalid-stack-middle.c:57
+	.loc 1 57 0
+	leave
+.LCFI17:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE5:
+	.size	func1, .-func1
+	.section	.rodata
+.LC0:
+	.string	"amd64-invalid-stack-middle.c"
+.LC1:
+	.string	"ptr != ((void *) -1)"
+.LC2:
+	.string	"ans == 0"
+	.text
+	.type	make_invalid_ptr, @function
+make_invalid_ptr:
+.LFB6:
+	# amd64-invalid-stack-middle.c:65
+	.loc 1 65 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI18:
+	movq	%rsp, %rbp
+.LCFI19:
+	subq	$32, %rsp
+	# amd64-invalid-stack-middle.c:69
+	.loc 1 69 0
+	call	getpagesize
+	movl	%eax, -4(%rbp)
+	# amd64-invalid-stack-middle.c:70
+	.loc 1 70 0
+	movl	-4(%rbp), %eax
+	cltq
+	movl	$0, %r9d
+	movl	$-1, %r8d
+	movl	$34, %ecx
+	movl	$0, %edx
+	movq	%rax, %rsi
+	movl	$0, %edi
+	call	mmap
+	movq	%rax, -16(%rbp)
+	# amd64-invalid-stack-middle.c:73
+	.loc 1 73 0
+	cmpq	$-1, -16(%rbp)
+# SUCC: 3 (fallthru) 4
+	jne	.L8
+# BLOCK 3 seq:1
+# PRED: 2 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$73, %edx
+	movl	$.LC0, %esi
+	movl	$.LC1, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 4 seq:2
+# PRED: 2
+.L8:
+	# amd64-invalid-stack-middle.c:74
+	.loc 1 74 0
+	movl	-4(%rbp), %eax
+	movslq	%eax, %rdx
+	movq	-16(%rbp), %rax
+	movq	%rdx, %rsi
+	movq	%rax, %rdi
+	call	munmap
+	movl	%eax, -20(%rbp)
+	# amd64-invalid-stack-middle.c:75
+	.loc 1 75 0
+	cmpl	$0, -20(%rbp)
+# SUCC: 5 (fallthru) 6
+	je	.L9
+# BLOCK 5 seq:3
+# PRED: 4 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$75, %edx
+	movl	$.LC0, %esi
+	movl	$.LC2, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 6 seq:4
+# PRED: 4
+.L9:
+	# amd64-invalid-stack-middle.c:77
+	.loc 1 77 0
+	movq	-16(%rbp), %rax
+	# amd64-invalid-stack-middle.c:78
+	.loc 1 78 0
+	leave
+.LCFI20:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE6:
+	.size	make_invalid_ptr, .-make_invalid_ptr
+	.globl	main
+	.type	main, @function
+main:
+.LFB7:
+	# amd64-invalid-stack-middle.c:82
+	.loc 1 82 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI21:
+	movq	%rsp, %rbp
+.LCFI22:
+	subq	$16, %rsp
+	# amd64-invalid-stack-middle.c:85
+	.loc 1 85 0
+	call	make_invalid_ptr
+	movq	%rax, -8(%rbp)
+	# amd64-invalid-stack-middle.c:86
+	.loc 1 86 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func1
+	# amd64-invalid-stack-middle.c:88
+	.loc 1 88 0
+	movl	$0, %eax
+	# amd64-invalid-stack-middle.c:89
+	.loc 1 89 0
+	leave
+.LCFI23:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE7:
+	.size	main, .-main
+	.section	.rodata
+	.align 16
+	.type	__PRETTY_FUNCTION__.2362, @object
+	.size	__PRETTY_FUNCTION__.2362, 17
+__PRETTY_FUNCTION__.2362:
+	.string	"make_invalid_ptr"
+#APP
+	.section	.debug_frame,"",@progbits
+.Lframe0:
+	.long	.LECIE0-.LSCIE0	# Length of Common Information Entry
+.LSCIE0:
+	.long	0xffffffff	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE0:
+.LSFDE0:
+	.long	.LEFDE0-.LASFDE0	# FDE Length
+.LASFDE0:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB0	# FDE initial location
+	.quad	.LFE0-.LFB0	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE0:
+.LSFDE2:
+	.long	.LEFDE2-.LASFDE2	# FDE Length
+.LASFDE2:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB1	# FDE initial location
+	.quad	.LFE1-.LFB1	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE2:
+.LSFDE4:
+	.long	.LEFDE4-.LASFDE4	# FDE Length
+.LASFDE4:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB2	# FDE initial location
+	.quad	.LFE2-.LFB2	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE4:
+.LSFDE6:
+	.long	.LEFDE6-.LASFDE6	# FDE Length
+.LASFDE6:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB3	# FDE initial location
+	.quad	.LFE3-.LFB3	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE6:
+.LSFDE8:
+	.long	.LEFDE8-.LASFDE8	# FDE Length
+.LASFDE8:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB4		# FDE initial location
+	.quad	.LFE4-.LFB4	# FDE address range
+        .byte 0xf		# DW_CFA_def_cfa_expression
+        .uleb128 .LEDWBLK1 - .LSDWBLK1
+.LSDWBLK1:
+        .byte 0x75              # DW_OP_breg5
+        .sleb128 0x0            #        offset
+        .byte 0x94              # DW_OP_dref_size
+        .byte 0x8		#        size
+.LEDWBLK1:
+	.align 8		# Padding.
+.LEFDE8:
+.LSFDE10:
+	.long	.LEFDE10-.LASFDE10	# FDE Length
+.LASFDE10:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB5	# FDE initial location
+	.quad	.LFE5-.LFB5	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE10:
+.LSFDE12:
+	.long	.LEFDE12-.LASFDE12	# FDE Length
+.LASFDE12:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB6	# FDE initial location
+	.quad	.LFE6-.LFB6	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE12:
+.LSFDE14:
+	.long	.LEFDE14-.LASFDE14	# FDE Length
+.LASFDE14:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB7	# FDE initial location
+	.quad	.LFE7-.LFB7	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE14:
+#NO_APP
+#APP
+	.section	.eh_frame,"a",@progbits
+.Lframe1:
+	.long	.LECIE1-.LSCIE1	# Length of Common Information Entry
+.LSCIE1:
+	.long	0	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "zR\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.uleb128 0x1	# Augmentation size
+	.byte	0x3	# FDE Encoding (udata4)
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE1:
+.LSFDE17:
+	.long	.LEFDE17-.LASFDE17	# FDE Length
+.LASFDE17:
+	.long	.LASFDE17-.Lframe1	# FDE CIE offset
+	.long	.LFB0	# FDE initial location
+	.long	.LFE0-.LFB0	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE17:
+.LSFDE19:
+	.long	.LEFDE19-.LASFDE19	# FDE Length
+.LASFDE19:
+	.long	.LASFDE19-.Lframe1	# FDE CIE offset
+	.long	.LFB1	# FDE initial location
+	.long	.LFE1-.LFB1	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE19:
+.LSFDE21:
+	.long	.LEFDE21-.LASFDE21	# FDE Length
+.LASFDE21:
+	.long	.LASFDE21-.Lframe1	# FDE CIE offset
+	.long	.LFB2	# FDE initial location
+	.long	.LFE2-.LFB2	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE21:
+.LSFDE23:
+	.long	.LEFDE23-.LASFDE23	# FDE Length
+.LASFDE23:
+	.long	.LASFDE23-.Lframe1	# FDE CIE offset
+	.long	.LFB3	# FDE initial location
+	.long	.LFE3-.LFB3	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE23:
+.LSFDE25:
+	.long	.LEFDE25-.LASFDE25	# FDE Length
+.LASFDE25:
+	.long	.LASFDE25-.Lframe1	# FDE CIE offset
+	.long	.LFB4	# FDE initial location
+	.long	.LFE4-.LFB4	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI12-.LFB4
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI13-.LCFI12
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI14-.LCFI13
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE25:
+.LSFDE27:
+	.long	.LEFDE27-.LASFDE27	# FDE Length
+.LASFDE27:
+	.long	.LASFDE27-.Lframe1	# FDE CIE offset
+	.long	.LFB5	# FDE initial location
+	.long	.LFE5-.LFB5	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE27:
+.LSFDE29:
+	.long	.LEFDE29-.LASFDE29	# FDE Length
+.LASFDE29:
+	.long	.LASFDE29-.Lframe1	# FDE CIE offset
+	.long	.LFB6	# FDE initial location
+	.long	.LFE6-.LFB6	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE29:
+.LSFDE31:
+	.long	.LEFDE31-.LASFDE31	# FDE Length
+.LASFDE31:
+	.long	.LASFDE31-.Lframe1	# FDE CIE offset
+	.long	.LFB7	# FDE initial location
+	.long	.LFE7-.LFB7	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE31:
+#NO_APP
+	.text
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x1f1	# Length of Compilation Unit Info
+	.value	0x2	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x8	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF17	# DW_AT_producer: "GNU C 4.7.2"
+	.byte	0x1	# DW_AT_language
+	.long	.LASF18	# DW_AT_name: "amd64-invalid-stack-middle.c"
+	.long	.LASF19	# DW_AT_comp_dir: "/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+	.quad	.Ltext0	# DW_AT_low_pc
+	.quad	.Letext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x2d) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "long unsigned int"
+	.uleb128 0x2	# (DIE (0x34) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "unsigned char"
+	.uleb128 0x2	# (DIE (0x3b) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "short unsigned int"
+	.uleb128 0x2	# (DIE (0x42) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "unsigned int"
+	.uleb128 0x2	# (DIE (0x49) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "signed char"
+	.uleb128 0x2	# (DIE (0x50) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x57) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x2	# (DIE (0x5e) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "long int"
+	.uleb128 0x2	# (DIE (0x65) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "sizetype"
+	.uleb128 0x4	# (DIE (0x6c) DW_TAG_pointer_type)
+	.byte	0x8	# DW_AT_byte_size
+	.uleb128 0x2	# (DIE (0x6e) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "char"
+	.uleb128 0x5	# (DIE (0x75) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF9	# DW_AT_name: "breakpt"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x18	# DW_AT_decl_line
+	.quad	.LFB0	# DW_AT_low_pc
+	.quad	.LFE0	# DW_AT_high_pc
+	.long	.LLST0	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_call_sites
+	.uleb128 0x6	# (DIE (0x92) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF10	# DW_AT_name: "func5"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x1e	# DW_AT_decl_line
+	.quad	.LFB1	# DW_AT_low_pc
+	.quad	.LFE1	# DW_AT_high_pc
+	.long	.LLST1	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xaf) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF11	# DW_AT_name: "func4"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x24	# DW_AT_decl_line
+	.quad	.LFB2	# DW_AT_low_pc
+	.quad	.LFE2	# DW_AT_high_pc
+	.long	.LLST2	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xcc) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "func3"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x2a	# DW_AT_decl_line
+	.quad	.LFB3	# DW_AT_low_pc
+	.quad	.LFE3	# DW_AT_high_pc
+	.long	.LLST3	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x7	# (DIE (0xe9) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "func2"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB4	# DW_AT_low_pc
+	.quad	.LFE4	# DW_AT_high_pc
+	.long	.LLST4	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x11a	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x10b) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0xe9
+	.uleb128 0x7	# (DIE (0x11a) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF14	# DW_AT_name: "func1"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB5	# DW_AT_low_pc
+	.quad	.LFE5	# DW_AT_high_pc
+	.long	.LLST5	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x14b	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x13c) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x11a
+	.uleb128 0x9	# (DIE (0x14b) DW_TAG_subprogram)
+	.long	.LASF20	# DW_AT_name: "make_invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x40	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.long	0x6c	# DW_AT_type
+	.quad	.LFB6	# DW_AT_low_pc
+	.quad	.LFE6	# DW_AT_high_pc
+	.long	.LLST6	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x1af	# DW_AT_sibling
+	.uleb128 0xa	# (DIE (0x170) DW_TAG_variable)
+	.long	.LASF15	# DW_AT_name: "page_size"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.uleb128 0xb	# (DIE (0x17e) DW_TAG_variable)
+	.ascii "ans\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0xb	# (DIE (0x18c) DW_TAG_variable)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x43	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -32
+	.uleb128 0xc	# (DIE (0x19a) DW_TAG_variable)
+	.long	.LASF21	# DW_AT_name: "__PRETTY_FUNCTION__"
+	.long	0x1bf	# DW_AT_type
+	.byte	0x1	# DW_AT_artificial
+	.byte	0x9	# DW_AT_location
+	.byte	0x3	# DW_OP_addr
+	.quad	__PRETTY_FUNCTION__.2362
+	.byte	0	# end of children of DIE 0x14b
+	.uleb128 0xd	# (DIE (0x1af) DW_TAG_array_type)
+	.long	0x6e	# DW_AT_type
+	.long	0x1bf	# DW_AT_sibling
+	.uleb128 0xe	# (DIE (0x1b8) DW_TAG_subrange_type)
+	.long	0x65	# DW_AT_type
+	.byte	0x10	# DW_AT_upper_bound
+	.byte	0	# end of children of DIE 0x1af
+	.uleb128 0xf	# (DIE (0x1bf) DW_TAG_const_type)
+	.long	0x1af	# DW_AT_type
+	.uleb128 0x10	# (DIE (0x1c4) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF22	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x51	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.quad	.LFB7	# DW_AT_low_pc
+	.quad	.LFE7	# DW_AT_high_pc
+	.long	.LLST7	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0xa	# (DIE (0x1e5) DW_TAG_variable)
+	.long	.LASF16	# DW_AT_name: "invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x53	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x1c4
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0xf	# (TAG: DW_TAG_pointer_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xb	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xc	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xd	# (abbrev code)
+	.uleb128 0x1	# (TAG: DW_TAG_array_type)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xe	# (abbrev code)
+	.uleb128 0x21	# (TAG: DW_TAG_subrange_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2f	# (DW_AT_upper_bound)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0xf	# (abbrev code)
+	.uleb128 0x26	# (TAG: DW_TAG_const_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x10	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+	.quad	.LFB0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI1-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI1-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI2-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI2-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LFE0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST0)
+	.quad	0	# Location list terminator end (*.LLST0)
+.LLST1:
+	.quad	.LFB1-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI3-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI3-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI4-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI4-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI5-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI5-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LFE1-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST1)
+	.quad	0	# Location list terminator end (*.LLST1)
+.LLST2:
+	.quad	.LFB2-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI6-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI6-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI7-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI7-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI8-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI8-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LFE2-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST2)
+	.quad	0	# Location list terminator end (*.LLST2)
+.LLST3:
+	.quad	.LFB3-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI9-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI9-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI10-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI10-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI11-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI11-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LFE3-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST3)
+	.quad	0	# Location list terminator end (*.LLST3)
+.LLST4:
+	.quad	.LFB4-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI12-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI12-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI13-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI13-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI14-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI14-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LFE4-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST4)
+	.quad	0	# Location list terminator end (*.LLST4)
+.LLST5:
+	.quad	.LFB5-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI15-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI15-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI16-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI16-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI17-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI17-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LFE5-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST5)
+	.quad	0	# Location list terminator end (*.LLST5)
+.LLST6:
+	.quad	.LFB6-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI18-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI18-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI19-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI19-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI20-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI20-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LFE6-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST6)
+	.quad	0	# Location list terminator end (*.LLST6)
+.LLST7:
+	.quad	.LFB7-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI21-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI21-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI22-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI22-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI23-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI23-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LFE7-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST7)
+	.quad	0	# Location list terminator end (*.LLST7)
+	.section	.debug_aranges,"",@progbits
+	.long	0x2c	# Length of Address Ranges Info
+	.value	0x2	# DWARF Version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x8	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 16 byte boundary
+	.value	0
+	.quad	.Ltext0	# Address
+	.quad	.Letext0-.Ltext0	# Length
+	.quad	0
+	.quad	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF10:
+	.string	"func5"
+.LASF20:
+	.string	"make_invalid_ptr"
+.LASF21:
+	.string	"__PRETTY_FUNCTION__"
+.LASF18:
+	.string	"amd64-invalid-stack-middle.c"
+.LASF22:
+	.string	"main"
+.LASF14:
+	.string	"func1"
+.LASF17:
+	.string	"GNU C 4.7.2"
+.LASF11:
+	.string	"func4"
+.LASF0:
+	.string	"long unsigned int"
+.LASF1:
+	.string	"unsigned char"
+.LASF8:
+	.string	"char"
+.LASF6:
+	.string	"long int"
+.LASF15:
+	.string	"page_size"
+.LASF13:
+	.string	"func2"
+.LASF16:
+	.string	"invalid_ptr"
+.LASF2:
+	.string	"short unsigned int"
+.LASF4:
+	.string	"signed char"
+.LASF9:
+	.string	"breakpt"
+.LASF19:
+	.string	"/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+.LASF5:
+	.string	"short int"
+.LASF3:
+	.string	"unsigned int"
+.LASF12:
+	.string	"func3"
+.LASF7:
+	.string	"sizetype"
+	.ident	"GCC: (GNU) 4.7.2"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
new file mode 100644
index 0000000..b8fbf6f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void
+breakpt ()
+{
+  /* Nothing.  */
+}
+
+void
+func5 ()
+{
+  breakpt ();
+}
+
+void
+func4 ()
+{
+  func5 ();
+}
+
+void
+func3 ()
+{
+  func4 ();
+}
+
+void
+func2 (void *ptr)
+{
+  func3 ();
+}
+
+void
+func1 (void *ptr)
+{
+  func2 (ptr);
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
new file mode 100644
index 0000000..ef70a4f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -0,0 +1,94 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .S
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt\n"
+gdb_expect {
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
new file mode 100644
index 0000000..c821f18
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
@@ -0,0 +1,73 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void *global_invalid_ptr = NULL;
+
+void
+func2 (void)
+{
+  /* Replace the current stack pointer and frame pointer with the invalid
+     pointer.  */
+  asm ("mov %0, %%rsp\n\tmov %0, %%rbp" : : "r" (global_invalid_ptr));
+
+  /* Create a label for a breakpoint.  */
+  asm (".global breakpt\nbreakpt:");
+}
+
+void
+func1 (void *ptr)
+{
+  global_invalid_ptr = ptr;
+  func2 ();
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main ()
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
new file mode 100644
index 0000000..6598cd4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -0,0 +1,97 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .c
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+# Use 'bt no-filters' here as the python filters will raise their own
+# error during initialisation, the no-filters case is simpler.
+
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt no-filters\n"
+gdb_expect {
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind.
  2014-04-30 10:55   ` [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
@ 2014-05-16 15:37     ` Pedro Alves
  2014-05-28 23:16       ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-05-16 15:37 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 04/30/2014 11:55 AM, Andrew Burgess wrote:
> In get_prev_frame_if_no_cycle, if we throw an error during compute_frame_id
> then we are left in a state where THIS_FRAME has a PREV_FRAME attached, but
> PREV_FRAME has no frame id.  This is an unexpected state that causes
> internal errors and assertions to fire.
> 
> This patch adds a cleanup that removes the previous frame created by
> get_prev_frame_raw if we get an error.
> 
> OK to apply?

This is OK.  Thank you.

(I guess it could go in immediately if you adjust
the test to expect the error and only try each command
once.)

I was looking at the rest of the series, but something came
up and I'm afraid I won't be able to reply today.  Sigh.  :-(

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-04-30 10:55   ` [PATCH v3 3/4] Deprecate frame_stop_reason_string Andrew Burgess
@ 2014-05-28 17:26     ` Pedro Alves
  2014-05-28 23:26       ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-05-28 17:26 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 04/30/2014 11:55 AM, Andrew Burgess wrote:
> Patch #4 adds frame specific stop reason strings.  It is better to use that
> string rather than the existing generic stop reason string.  This patch
> renames frame_stop_reason_string to deprecated_frame_stop_reason_string and
> updates all the call sites to use the deprecated name.
> 
> Patch #4 adds the new frame specific stop reason, and some uses of the
> deprecated funciton will be moved to this new API, however, in the python
> and guile scripting API we expose a function that converts the stop reason
> code into a string, without a frame, this will be harder to convert to the

WDYM, harder?  It seems downright impossible to me.  :-)

The function still serves it's purpose of mapping the enum values
to string equivalents.  I don't really see a need to mark it deprecated.

IMO, the real problem with its signature is the "frame_" in its name.
The function converts an 'enum unwind_stop_reason' value to a string,
so like other similar cases in the tree, how about renaming the function
to match?  E.g.:

-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *unwind_stop_reason_to_string (enum unwind_stop_reason);

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-04-30 10:55   ` [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
@ 2014-05-28 18:31     ` Pedro Alves
  2014-05-28 23:35       ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-05-28 18:31 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 04/30/2014 11:55 AM, Andrew Burgess wrote:
> Here a new TRY_CATCH is added to the core of get_prev_frame, all uncaught
> errors are turned into UNWIND_MISC_ERROR, and where possible the error
> message associated with the error is stored as a frame specific stop reason
> string.  The reason string is held of the frame OBSTACK so it lives as long
> as the frame does.
> 
> There's a new function for getting the frame_stop_reason_string, this
> replaces the now (thanks to patch #3) old frame_stop_reason_string
> function, I know that reusing the name could confuse, but this function was
> not widely used, so I hope that'll not be an issue.

Sounds like we'll want to expose this to Python too.  If you're not
planning on doing that, could you file a PR once this goes in?

> 
> Finally, I update the expected results from the tests in patch #1 now that
> everything should pass.
> 
> I don't know if you'll all be happy with me catching _all_ errors in
> get_prev_frame.

Yeah, that makes me somewhat nervous.  E.g., this catches and
swallows TARGET_CLOSE_ERROR.

> Given that the issues I'm seeing "in the wild" and which
> I've put into the tests are for accessing invalid memory through a bad
> stack pointer, I could reduce the catching to only catch MEMORY_ERRORs,
> then UNWIND_MISC_ERROR would become UNWIND_MEMORY_ERROR.  

I think I'd prefer that.  This swallows TARGET_CLOSE_ERROR, for example.

Could you please include both MI and CLI before/after examples
in the description/commit log, please?  You had something
close to that in the cover letter, but that doesn't make it to
the repository.


> I could even add
> the memory error detection on top of the new MISC_ERROR case if preferred,
> though I'd need to think of a new test...

I didn't understand this.

> 
> Feedback welcome, or is this OK?

> 	* unwind_stop_reason.def: Add UNWIND_MISC_ERROR.

Values added here are exposed to Python/scheme automatically.
But, we need to document them manually in the manual.  E.g.
for python, in gdb/python.texi in the table beneath the
description of Frame.unwind_stop_reason ().

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible).
  2014-04-30 10:55   ` [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
@ 2014-05-28 18:42     ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2014-05-28 18:42 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 04/30/2014 11:55 AM, Andrew Burgess wrote:

> +
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include <assert.h>
> +
> +void
> +breakpt ()

'(void)' here and elsewhere.

> +int
> +main ()

Otherwise looks fine.

(I'd have slightly preferred that the patch
for the crash included the test, adjusted as necessary, and
then the follow up patches added / built on the existing test.)

Thanks,
-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind.
  2014-05-16 15:37     ` Pedro Alves
@ 2014-05-28 23:16       ` Andrew Burgess
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Burgess @ 2014-05-28 23:16 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16/05/2014 4:37 PM, Pedro Alves wrote:
> On 04/30/2014 11:55 AM, Andrew Burgess wrote:
>> In get_prev_frame_if_no_cycle, if we throw an error during compute_frame_id
>> then we are left in a state where THIS_FRAME has a PREV_FRAME attached, but
>> PREV_FRAME has no frame id.  This is an unexpected state that causes
>> internal errors and assertions to fire.
>>
>> This patch adds a cleanup that removes the previous frame created by
>> get_prev_frame_raw if we get an error.
>>
>> OK to apply?
> 
> This is OK.  Thank you.
> 
> (I guess it could go in immediately if you adjust
> the test to expect the error and only try each command
> once.)

Here's a revised patch that includes some tests, the gdb code hasn't changed
I've merged in the changes you suggested in your review:
  https://sourceware.org/ml/gdb-patches/2014-05/msg00698.html

The only thing that might be controversial is I've added some XFAIL for the
four cases that would be fixed by the later parts of this patch series, I wasn't
planning to raise a bugzilla bug though...

Given that you've OK'd the tests (with fixes) and the code, I'll push this in
a couple of days unless someone objects to my use of XFAIL like this.

Thanks,
Andrew

gdb/ChangeLog:

	* frame.c (remove_prev_frame): New function.
	(get_prev_frame_if_no_cycle): Create / discard cleanup using
	remove_prev_frame.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.S: New file.
	* gdb.arch/amd64-invalid-stack-middle.c: New file.
	* gdb.arch/amd64-invalid-stack-middle.exp: New file.
	* gdb.arch/amd64-invalid-stack-top.c: New file.
	* gdb.arch/amd64-invalid-stack-top.exp: New file.
---
 gdb/frame.c                                        |   52 +-
 .../gdb.arch/amd64-invalid-stack-middle.S          | 1410 ++++++++++++++++++++
 .../gdb.arch/amd64-invalid-stack-middle.c          |   89 ++
 .../gdb.arch/amd64-invalid-stack-middle.exp        |  108 ++
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c   |   73 +
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp |  111 ++
 6 files changed, 1829 insertions(+), 14 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp

diff --git a/gdb/frame.c b/gdb/frame.c
index 013d602..cbff25f 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1738,6 +1738,22 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
     }
 }
 
+/* Called during frame unwinding to remove a previous frame pointer from a
+   frame passed in ARG.  */
+
+static void
+remove_prev_frame (void *arg)
+{
+  struct frame_info *this_frame, *prev_frame;
+
+  this_frame = (struct frame_info *) arg;
+  prev_frame = this_frame->prev;
+  gdb_assert (prev_frame != NULL);
+
+  prev_frame->next = NULL;
+  this_frame->prev = NULL;
+}
+
 /* Get the previous raw frame, and check that it is not identical to
    same other frame frame already in the chain.  If it is, there is
    most likely a stack cycle, so we discard it, and mark THIS_FRAME as
@@ -1750,28 +1766,36 @@ static struct frame_info *
 get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 {
   struct frame_info *prev_frame;
+  struct cleanup *prev_frame_cleanup;
 
   prev_frame = get_prev_frame_raw (this_frame);
   if (prev_frame == NULL)
     return NULL;
 
-  compute_frame_id (prev_frame);
-  if (frame_stash_add (prev_frame))
-    return prev_frame;
+  /* The cleanup will remove the previous frame that get_prev_frame_raw
+     linked onto THIS_FRAME.  */
+  prev_frame_cleanup = make_cleanup (remove_prev_frame, this_frame);
 
-  /* Another frame with the same id was already in the stash.  We just
-     detected a cycle.  */
-  if (frame_debug)
+  compute_frame_id (prev_frame);
+  if (!frame_stash_add (prev_frame))
     {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, NULL);
-      fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+      /* Another frame with the same id was already in the stash.  We just
+	 detected a cycle.  */
+      if (frame_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog, "-> ");
+	  fprint_frame (gdb_stdlog, NULL);
+	  fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
+	}
+      this_frame->stop_reason = UNWIND_SAME_ID;
+      /* Unlink.  */
+      prev_frame->next = NULL;
+      this_frame->prev = NULL;
+      prev_frame = NULL;
     }
-  this_frame->stop_reason = UNWIND_SAME_ID;
-  /* Unlink.  */
-  prev_frame->next = NULL;
-  this_frame->prev = NULL;
-  return NULL;
+
+  discard_cleanups (prev_frame_cleanup);
+  return prev_frame;
 }
 
 /* Return a "struct frame_info" corresponding to the frame that called
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
new file mode 100644
index 0000000..3b4a067
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.S
@@ -0,0 +1,1410 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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 file is compiled from gdb.arch/amd64-invalid-stack-middle.c
+   using: 'gcc -g -O0 -S -dA' and gcc version '4.7.2'.
+   Changes were then made to the CFI entry for func2.  */
+        
+	.file	"amd64-invalid-stack-middle.c"
+	.text
+.Ltext0:
+	.globl	breakpt
+	.type	breakpt, @function
+breakpt:
+.LFB0:
+	.file 1 "amd64-invalid-stack-middle.c"
+	# amd64-invalid-stack-middle.c:25
+	.loc 1 25 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI0:
+	movq	%rsp, %rbp
+.LCFI1:
+	# amd64-invalid-stack-middle.c:27
+	.loc 1 27 0
+	popq	%rbp
+.LCFI2:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE0:
+	.size	breakpt, .-breakpt
+	.globl	func5
+	.type	func5, @function
+func5:
+.LFB1:
+	# amd64-invalid-stack-middle.c:31
+	.loc 1 31 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI3:
+	movq	%rsp, %rbp
+.LCFI4:
+	# amd64-invalid-stack-middle.c:32
+	.loc 1 32 0
+	movl	$0, %eax
+	call	breakpt
+	# amd64-invalid-stack-middle.c:33
+	.loc 1 33 0
+	popq	%rbp
+.LCFI5:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE1:
+	.size	func5, .-func5
+	.globl	func4
+	.type	func4, @function
+func4:
+.LFB2:
+	# amd64-invalid-stack-middle.c:37
+	.loc 1 37 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI6:
+	movq	%rsp, %rbp
+.LCFI7:
+	# amd64-invalid-stack-middle.c:38
+	.loc 1 38 0
+	movl	$0, %eax
+	call	func5
+	# amd64-invalid-stack-middle.c:39
+	.loc 1 39 0
+	popq	%rbp
+.LCFI8:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE2:
+	.size	func4, .-func4
+	.globl	func3
+	.type	func3, @function
+func3:
+.LFB3:
+	# amd64-invalid-stack-middle.c:43
+	.loc 1 43 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI9:
+	movq	%rsp, %rbp
+.LCFI10:
+	# amd64-invalid-stack-middle.c:44
+	.loc 1 44 0
+	movl	$0, %eax
+	call	func4
+	# amd64-invalid-stack-middle.c:45
+	.loc 1 45 0
+	popq	%rbp
+.LCFI11:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE3:
+	.size	func3, .-func3
+	.globl	func2
+	.type	func2, @function
+func2:
+.LFB4:
+	# amd64-invalid-stack-middle.c:49
+	.loc 1 49 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI12:
+	movq	%rsp, %rbp
+.LCFI13:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:50
+	.loc 1 50 0
+	movl	$0, %eax
+	call	func3
+	# amd64-invalid-stack-middle.c:51
+	.loc 1 51 0
+	leave
+.LCFI14:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE4:
+	.size	func2, .-func2
+	.globl	func1
+	.type	func1, @function
+func1:
+.LFB5:
+	# amd64-invalid-stack-middle.c:55
+	.loc 1 55 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI15:
+	movq	%rsp, %rbp
+.LCFI16:
+	subq	$8, %rsp
+	movq	%rdi, -8(%rbp)
+	# amd64-invalid-stack-middle.c:56
+	.loc 1 56 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func2
+	# amd64-invalid-stack-middle.c:57
+	.loc 1 57 0
+	leave
+.LCFI17:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE5:
+	.size	func1, .-func1
+	.section	.rodata
+.LC0:
+	.string	"amd64-invalid-stack-middle.c"
+.LC1:
+	.string	"ptr != ((void *) -1)"
+.LC2:
+	.string	"ans == 0"
+	.text
+	.type	make_invalid_ptr, @function
+make_invalid_ptr:
+.LFB6:
+	# amd64-invalid-stack-middle.c:65
+	.loc 1 65 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI18:
+	movq	%rsp, %rbp
+.LCFI19:
+	subq	$32, %rsp
+	# amd64-invalid-stack-middle.c:69
+	.loc 1 69 0
+	call	getpagesize
+	movl	%eax, -4(%rbp)
+	# amd64-invalid-stack-middle.c:70
+	.loc 1 70 0
+	movl	-4(%rbp), %eax
+	cltq
+	movl	$0, %r9d
+	movl	$-1, %r8d
+	movl	$34, %ecx
+	movl	$0, %edx
+	movq	%rax, %rsi
+	movl	$0, %edi
+	call	mmap
+	movq	%rax, -16(%rbp)
+	# amd64-invalid-stack-middle.c:73
+	.loc 1 73 0
+	cmpq	$-1, -16(%rbp)
+# SUCC: 3 (fallthru) 4
+	jne	.L8
+# BLOCK 3 seq:1
+# PRED: 2 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$73, %edx
+	movl	$.LC0, %esi
+	movl	$.LC1, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 4 seq:2
+# PRED: 2
+.L8:
+	# amd64-invalid-stack-middle.c:74
+	.loc 1 74 0
+	movl	-4(%rbp), %eax
+	movslq	%eax, %rdx
+	movq	-16(%rbp), %rax
+	movq	%rdx, %rsi
+	movq	%rax, %rdi
+	call	munmap
+	movl	%eax, -20(%rbp)
+	# amd64-invalid-stack-middle.c:75
+	.loc 1 75 0
+	cmpl	$0, -20(%rbp)
+# SUCC: 5 (fallthru) 6
+	je	.L9
+# BLOCK 5 seq:3
+# PRED: 4 (fallthru)
+	movl	$__PRETTY_FUNCTION__.2362, %ecx
+	movl	$75, %edx
+	movl	$.LC0, %esi
+	movl	$.LC2, %edi
+# SUCC:
+	call	__assert_fail
+# BLOCK 6 seq:4
+# PRED: 4
+.L9:
+	# amd64-invalid-stack-middle.c:77
+	.loc 1 77 0
+	movq	-16(%rbp), %rax
+	# amd64-invalid-stack-middle.c:78
+	.loc 1 78 0
+	leave
+.LCFI20:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE6:
+	.size	make_invalid_ptr, .-make_invalid_ptr
+	.globl	main
+	.type	main, @function
+main:
+.LFB7:
+	# amd64-invalid-stack-middle.c:82
+	.loc 1 82 0
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+	pushq	%rbp
+.LCFI21:
+	movq	%rsp, %rbp
+.LCFI22:
+	subq	$16, %rsp
+	# amd64-invalid-stack-middle.c:85
+	.loc 1 85 0
+	call	make_invalid_ptr
+	movq	%rax, -8(%rbp)
+	# amd64-invalid-stack-middle.c:86
+	.loc 1 86 0
+	movq	-8(%rbp), %rax
+	movq	%rax, %rdi
+	call	func1
+	# amd64-invalid-stack-middle.c:88
+	.loc 1 88 0
+	movl	$0, %eax
+	# amd64-invalid-stack-middle.c:89
+	.loc 1 89 0
+	leave
+.LCFI23:
+# SUCC: EXIT [100.0%] 
+	ret
+.LFE7:
+	.size	main, .-main
+	.section	.rodata
+	.align 16
+	.type	__PRETTY_FUNCTION__.2362, @object
+	.size	__PRETTY_FUNCTION__.2362, 17
+__PRETTY_FUNCTION__.2362:
+	.string	"make_invalid_ptr"
+#APP
+	.section	.debug_frame,"",@progbits
+.Lframe0:
+	.long	.LECIE0-.LSCIE0	# Length of Common Information Entry
+.LSCIE0:
+	.long	0xffffffff	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE0:
+.LSFDE0:
+	.long	.LEFDE0-.LASFDE0	# FDE Length
+.LASFDE0:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB0	# FDE initial location
+	.quad	.LFE0-.LFB0	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE0:
+.LSFDE2:
+	.long	.LEFDE2-.LASFDE2	# FDE Length
+.LASFDE2:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB1	# FDE initial location
+	.quad	.LFE1-.LFB1	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE2:
+.LSFDE4:
+	.long	.LEFDE4-.LASFDE4	# FDE Length
+.LASFDE4:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB2	# FDE initial location
+	.quad	.LFE2-.LFB2	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE4:
+.LSFDE6:
+	.long	.LEFDE6-.LASFDE6	# FDE Length
+.LASFDE6:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB3	# FDE initial location
+	.quad	.LFE3-.LFB3	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE6:
+.LSFDE8:
+	.long	.LEFDE8-.LASFDE8	# FDE Length
+.LASFDE8:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB4		# FDE initial location
+	.quad	.LFE4-.LFB4	# FDE address range
+        .byte 0xf		# DW_CFA_def_cfa_expression
+        .uleb128 .LEDWBLK1 - .LSDWBLK1
+.LSDWBLK1:
+        .byte 0x75              # DW_OP_breg5
+        .sleb128 0x0            #        offset
+        .byte 0x94              # DW_OP_dref_size
+        .byte 0x8		#        size
+.LEDWBLK1:
+	.align 8		# Padding.
+.LEFDE8:
+.LSFDE10:
+	.long	.LEFDE10-.LASFDE10	# FDE Length
+.LASFDE10:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB5	# FDE initial location
+	.quad	.LFE5-.LFB5	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE10:
+.LSFDE12:
+	.long	.LEFDE12-.LASFDE12	# FDE Length
+.LASFDE12:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB6	# FDE initial location
+	.quad	.LFE6-.LFB6	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE12:
+.LSFDE14:
+	.long	.LEFDE14-.LASFDE14	# FDE Length
+.LASFDE14:
+	.long	.Lframe0	# FDE CIE offset
+	.quad	.LFB7	# FDE initial location
+	.quad	.LFE7-.LFB7	# FDE address range
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE14:
+#NO_APP
+#APP
+	.section	.eh_frame,"a",@progbits
+.Lframe1:
+	.long	.LECIE1-.LSCIE1	# Length of Common Information Entry
+.LSCIE1:
+	.long	0	# CIE Identifier Tag
+	.byte	0x1	# CIE Version
+	.ascii "zR\0"	# CIE Augmentation
+	.uleb128 0x1	# CIE Code Alignment Factor
+	.sleb128 -8	# CIE Data Alignment Factor
+	.byte	0x10	# CIE RA Column
+	.uleb128 0x1	# Augmentation size
+	.byte	0x3	# FDE Encoding (udata4)
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.byte	0x90	# DW_CFA_offset, column 0x10
+	.uleb128 0x1
+	.align 8
+.LECIE1:
+.LSFDE17:
+	.long	.LEFDE17-.LASFDE17	# FDE Length
+.LASFDE17:
+	.long	.LASFDE17-.Lframe1	# FDE CIE offset
+	.long	.LFB0	# FDE initial location
+	.long	.LFE0-.LFB0	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI0-.LFB0
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI2-.LCFI1
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE17:
+.LSFDE19:
+	.long	.LEFDE19-.LASFDE19	# FDE Length
+.LASFDE19:
+	.long	.LASFDE19-.Lframe1	# FDE CIE offset
+	.long	.LFB1	# FDE initial location
+	.long	.LFE1-.LFB1	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI3-.LFB1
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI4-.LCFI3
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI5-.LCFI4
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE19:
+.LSFDE21:
+	.long	.LEFDE21-.LASFDE21	# FDE Length
+.LASFDE21:
+	.long	.LASFDE21-.Lframe1	# FDE CIE offset
+	.long	.LFB2	# FDE initial location
+	.long	.LFE2-.LFB2	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI6-.LFB2
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI8-.LCFI7
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE21:
+.LSFDE23:
+	.long	.LEFDE23-.LASFDE23	# FDE Length
+.LASFDE23:
+	.long	.LASFDE23-.Lframe1	# FDE CIE offset
+	.long	.LFB3	# FDE initial location
+	.long	.LFE3-.LFB3	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI9-.LFB3
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI11-.LCFI10
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE23:
+.LSFDE25:
+	.long	.LEFDE25-.LASFDE25	# FDE Length
+.LASFDE25:
+	.long	.LASFDE25-.Lframe1	# FDE CIE offset
+	.long	.LFB4	# FDE initial location
+	.long	.LFE4-.LFB4	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI12-.LFB4
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI13-.LCFI12
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI14-.LCFI13
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE25:
+.LSFDE27:
+	.long	.LEFDE27-.LASFDE27	# FDE Length
+.LASFDE27:
+	.long	.LASFDE27-.Lframe1	# FDE CIE offset
+	.long	.LFB5	# FDE initial location
+	.long	.LFE5-.LFB5	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI15-.LFB5
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI16-.LCFI15
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI17-.LCFI16
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE27:
+.LSFDE29:
+	.long	.LEFDE29-.LASFDE29	# FDE Length
+.LASFDE29:
+	.long	.LASFDE29-.Lframe1	# FDE CIE offset
+	.long	.LFB6	# FDE initial location
+	.long	.LFE6-.LFB6	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI18-.LFB6
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI19-.LCFI18
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI20-.LCFI19
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE29:
+.LSFDE31:
+	.long	.LEFDE31-.LASFDE31	# FDE Length
+.LASFDE31:
+	.long	.LASFDE31-.Lframe1	# FDE CIE offset
+	.long	.LFB7	# FDE initial location
+	.long	.LFE7-.LFB7	# FDE address range
+	.uleb128 0	# Augmentation size
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI21-.LFB7
+	.byte	0xe	# DW_CFA_def_cfa_offset
+	.uleb128 0x10
+	.byte	0x86	# DW_CFA_offset, column 0x6
+	.uleb128 0x2
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI22-.LCFI21
+	.byte	0xd	# DW_CFA_def_cfa_register
+	.uleb128 0x6
+	.byte	0x4	# DW_CFA_advance_loc4
+	.long	.LCFI23-.LCFI22
+	.byte	0xc	# DW_CFA_def_cfa
+	.uleb128 0x7
+	.uleb128 0x8
+	.align 8
+.LEFDE31:
+#NO_APP
+	.text
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x1f1	# Length of Compilation Unit Info
+	.value	0x2	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x8	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF17	# DW_AT_producer: "GNU C 4.7.2"
+	.byte	0x1	# DW_AT_language
+	.long	.LASF18	# DW_AT_name: "amd64-invalid-stack-middle.c"
+	.long	.LASF19	# DW_AT_comp_dir: "/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+	.quad	.Ltext0	# DW_AT_low_pc
+	.quad	.Letext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x2d) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "long unsigned int"
+	.uleb128 0x2	# (DIE (0x34) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "unsigned char"
+	.uleb128 0x2	# (DIE (0x3b) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "short unsigned int"
+	.uleb128 0x2	# (DIE (0x42) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "unsigned int"
+	.uleb128 0x2	# (DIE (0x49) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "signed char"
+	.uleb128 0x2	# (DIE (0x50) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x57) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x2	# (DIE (0x5e) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "long int"
+	.uleb128 0x2	# (DIE (0x65) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "sizetype"
+	.uleb128 0x4	# (DIE (0x6c) DW_TAG_pointer_type)
+	.byte	0x8	# DW_AT_byte_size
+	.uleb128 0x2	# (DIE (0x6e) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "char"
+	.uleb128 0x5	# (DIE (0x75) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF9	# DW_AT_name: "breakpt"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x18	# DW_AT_decl_line
+	.quad	.LFB0	# DW_AT_low_pc
+	.quad	.LFE0	# DW_AT_high_pc
+	.long	.LLST0	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_call_sites
+	.uleb128 0x6	# (DIE (0x92) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF10	# DW_AT_name: "func5"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x1e	# DW_AT_decl_line
+	.quad	.LFB1	# DW_AT_low_pc
+	.quad	.LFE1	# DW_AT_high_pc
+	.long	.LLST1	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xaf) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF11	# DW_AT_name: "func4"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x24	# DW_AT_decl_line
+	.quad	.LFB2	# DW_AT_low_pc
+	.quad	.LFE2	# DW_AT_high_pc
+	.long	.LLST2	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x6	# (DIE (0xcc) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "func3"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x2a	# DW_AT_decl_line
+	.quad	.LFB3	# DW_AT_low_pc
+	.quad	.LFE3	# DW_AT_high_pc
+	.long	.LLST3	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x7	# (DIE (0xe9) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "func2"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB4	# DW_AT_low_pc
+	.quad	.LFE4	# DW_AT_high_pc
+	.long	.LLST4	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x11a	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x10b) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x30	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0xe9
+	.uleb128 0x7	# (DIE (0x11a) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF14	# DW_AT_name: "func1"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.quad	.LFB5	# DW_AT_low_pc
+	.quad	.LFE5	# DW_AT_high_pc
+	.long	.LLST5	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x14b	# DW_AT_sibling
+	.uleb128 0x8	# (DIE (0x13c) DW_TAG_formal_parameter)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x36	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x11a
+	.uleb128 0x9	# (DIE (0x14b) DW_TAG_subprogram)
+	.long	.LASF20	# DW_AT_name: "make_invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x40	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_prototyped
+	.long	0x6c	# DW_AT_type
+	.quad	.LFB6	# DW_AT_low_pc
+	.quad	.LFE6	# DW_AT_high_pc
+	.long	.LLST6	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.long	0x1af	# DW_AT_sibling
+	.uleb128 0xa	# (DIE (0x170) DW_TAG_variable)
+	.long	.LASF15	# DW_AT_name: "page_size"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.uleb128 0xb	# (DIE (0x17e) DW_TAG_variable)
+	.ascii "ans\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x42	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0xb	# (DIE (0x18c) DW_TAG_variable)
+	.ascii "ptr\0"	# DW_AT_name
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x43	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -32
+	.uleb128 0xc	# (DIE (0x19a) DW_TAG_variable)
+	.long	.LASF21	# DW_AT_name: "__PRETTY_FUNCTION__"
+	.long	0x1bf	# DW_AT_type
+	.byte	0x1	# DW_AT_artificial
+	.byte	0x9	# DW_AT_location
+	.byte	0x3	# DW_OP_addr
+	.quad	__PRETTY_FUNCTION__.2362
+	.byte	0	# end of children of DIE 0x14b
+	.uleb128 0xd	# (DIE (0x1af) DW_TAG_array_type)
+	.long	0x6e	# DW_AT_type
+	.long	0x1bf	# DW_AT_sibling
+	.uleb128 0xe	# (DIE (0x1b8) DW_TAG_subrange_type)
+	.long	0x65	# DW_AT_type
+	.byte	0x10	# DW_AT_upper_bound
+	.byte	0	# end of children of DIE 0x1af
+	.uleb128 0xf	# (DIE (0x1bf) DW_TAG_const_type)
+	.long	0x1af	# DW_AT_type
+	.uleb128 0x10	# (DIE (0x1c4) DW_TAG_subprogram)
+	.byte	0x1	# DW_AT_external
+	.long	.LASF22	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x51	# DW_AT_decl_line
+	.long	0x57	# DW_AT_type
+	.quad	.LFB7	# DW_AT_low_pc
+	.quad	.LFE7	# DW_AT_high_pc
+	.long	.LLST7	# DW_AT_frame_base
+	.byte	0x1	# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0xa	# (DIE (0x1e5) DW_TAG_variable)
+	.long	.LASF16	# DW_AT_name: "invalid_ptr"
+	.byte	0x1	# DW_AT_decl_file (amd64-invalid-stack-middle.c)
+	.byte	0x53	# DW_AT_decl_line
+	.long	0x6c	# DW_AT_type
+	.byte	0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -24
+	.byte	0	# end of children of DIE 0x1c4
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0xf	# (TAG: DW_TAG_pointer_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xb	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xc	# (abbrev code)
+	.uleb128 0x34	# (TAG: DW_TAG_variable)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0xa	# (DW_FORM_block1)
+	.byte	0
+	.byte	0
+	.uleb128 0xd	# (abbrev code)
+	.uleb128 0x1	# (TAG: DW_TAG_array_type)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0xe	# (abbrev code)
+	.uleb128 0x21	# (TAG: DW_TAG_subrange_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2f	# (DW_AT_upper_bound)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0xf	# (abbrev code)
+	.uleb128 0x26	# (TAG: DW_TAG_const_type)
+	.byte	0	# DW_children_no
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x10	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0xc	# (DW_FORM_flag)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+	.quad	.LFB0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI0-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI1-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI1-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LCFI2-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI2-.Ltext0	# Location list begin address (*.LLST0)
+	.quad	.LFE0-.Ltext0	# Location list end address (*.LLST0)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST0)
+	.quad	0	# Location list terminator end (*.LLST0)
+.LLST1:
+	.quad	.LFB1-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI3-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI3-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI4-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI4-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LCFI5-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI5-.Ltext0	# Location list begin address (*.LLST1)
+	.quad	.LFE1-.Ltext0	# Location list end address (*.LLST1)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST1)
+	.quad	0	# Location list terminator end (*.LLST1)
+.LLST2:
+	.quad	.LFB2-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI6-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI6-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI7-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI7-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LCFI8-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI8-.Ltext0	# Location list begin address (*.LLST2)
+	.quad	.LFE2-.Ltext0	# Location list end address (*.LLST2)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST2)
+	.quad	0	# Location list terminator end (*.LLST2)
+.LLST3:
+	.quad	.LFB3-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI9-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI9-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI10-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI10-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LCFI11-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI11-.Ltext0	# Location list begin address (*.LLST3)
+	.quad	.LFE3-.Ltext0	# Location list end address (*.LLST3)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST3)
+	.quad	0	# Location list terminator end (*.LLST3)
+.LLST4:
+	.quad	.LFB4-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI12-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI12-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI13-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI13-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LCFI14-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI14-.Ltext0	# Location list begin address (*.LLST4)
+	.quad	.LFE4-.Ltext0	# Location list end address (*.LLST4)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST4)
+	.quad	0	# Location list terminator end (*.LLST4)
+.LLST5:
+	.quad	.LFB5-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI15-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI15-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI16-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI16-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LCFI17-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI17-.Ltext0	# Location list begin address (*.LLST5)
+	.quad	.LFE5-.Ltext0	# Location list end address (*.LLST5)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST5)
+	.quad	0	# Location list terminator end (*.LLST5)
+.LLST6:
+	.quad	.LFB6-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI18-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI18-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI19-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI19-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LCFI20-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI20-.Ltext0	# Location list begin address (*.LLST6)
+	.quad	.LFE6-.Ltext0	# Location list end address (*.LLST6)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST6)
+	.quad	0	# Location list terminator end (*.LLST6)
+.LLST7:
+	.quad	.LFB7-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI21-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	.LCFI21-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI22-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 16
+	.quad	.LCFI22-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LCFI23-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x76	# DW_OP_breg6
+	.sleb128 16
+	.quad	.LCFI23-.Ltext0	# Location list begin address (*.LLST7)
+	.quad	.LFE7-.Ltext0	# Location list end address (*.LLST7)
+	.value	0x2	# Location expression size
+	.byte	0x77	# DW_OP_breg7
+	.sleb128 8
+	.quad	0	# Location list terminator begin (*.LLST7)
+	.quad	0	# Location list terminator end (*.LLST7)
+	.section	.debug_aranges,"",@progbits
+	.long	0x2c	# Length of Address Ranges Info
+	.value	0x2	# DWARF Version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x8	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 16 byte boundary
+	.value	0
+	.quad	.Ltext0	# Address
+	.quad	.Letext0-.Ltext0	# Length
+	.quad	0
+	.quad	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF10:
+	.string	"func5"
+.LASF20:
+	.string	"make_invalid_ptr"
+.LASF21:
+	.string	"__PRETTY_FUNCTION__"
+.LASF18:
+	.string	"amd64-invalid-stack-middle.c"
+.LASF22:
+	.string	"main"
+.LASF14:
+	.string	"func1"
+.LASF17:
+	.string	"GNU C 4.7.2"
+.LASF11:
+	.string	"func4"
+.LASF0:
+	.string	"long unsigned int"
+.LASF1:
+	.string	"unsigned char"
+.LASF8:
+	.string	"char"
+.LASF6:
+	.string	"long int"
+.LASF15:
+	.string	"page_size"
+.LASF13:
+	.string	"func2"
+.LASF16:
+	.string	"invalid_ptr"
+.LASF2:
+	.string	"short unsigned int"
+.LASF4:
+	.string	"signed char"
+.LASF9:
+	.string	"breakpt"
+.LASF19:
+	.string	"/home/gdb/binutils-gdb/gdb/testsuite/gdb.arch"
+.LASF5:
+	.string	"short int"
+.LASF3:
+	.string	"unsigned int"
+.LASF12:
+	.string	"func3"
+.LASF7:
+	.string	"sizetype"
+	.ident	"GCC: (GNU) 4.7.2"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
new file mode 100644
index 0000000..05bbd1d
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.c
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void
+breakpt (void)
+{
+  /* Nothing.  */
+}
+
+void
+func5 (void)
+{
+  breakpt ();
+}
+
+void
+func4 (void)
+{
+  func5 ();
+}
+
+void
+func3 (void)
+{
+  func4 ();
+}
+
+void
+func2 (void *ptr)
+{
+  func3 ();
+}
+
+void
+func1 (void *ptr)
+{
+  func2 (ptr);
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main (void)
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
new file mode 100644
index 0000000..8ad5b18
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -0,0 +1,108 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .S
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt\n"
+gdb_expect {
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+set test_name "check mi -stack-info-depth command, first time"
+send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
+gdb_expect {
+    -re "\\^done,depth=\"4\"\r\n$gdb_prompt $" {
+	pass $test_name
+    }
+    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
+	xfail $test_name
+    }
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+set test_name "check mi -stack-list-frames command, first time"
+send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
+gdb_expect {
+    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]\r\n$gdb_prompt $" {
+	pass $test_name
+    }
+    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
+	xfail $test_name
+    }
+}
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
new file mode 100644
index 0000000..168dc55
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.c
@@ -0,0 +1,73 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.
+*/
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <assert.h>
+
+void *global_invalid_ptr = NULL;
+
+void
+func2 (void)
+{
+  /* Replace the current stack pointer and frame pointer with the invalid
+     pointer.  */
+  asm ("mov %0, %%rsp\n\tmov %0, %%rbp" : : "r" (global_invalid_ptr));
+
+  /* Create a label for a breakpoint.  */
+  asm (".global breakpt\nbreakpt:");
+}
+
+void
+func1 (void *ptr)
+{
+  global_invalid_ptr = ptr;
+  func2 ();
+}
+
+/* Finds and returns an invalid pointer, mmaps in a page, grabs a pointer
+   to it then unmaps the page again.  This is almost certainly "undefined"
+   behaviour, but should be good enough for this small test program.  */
+
+static void *
+make_invalid_ptr (void)
+{
+  int page_size, ans;
+  void *ptr;
+  
+  page_size = getpagesize ();
+  ptr =  mmap (0, page_size, PROT_NONE,
+	       MAP_PRIVATE | MAP_ANONYMOUS,
+	       -1, 0);
+  assert (ptr != MAP_FAILED);
+  ans = munmap (ptr, page_size);
+  assert (ans == 0);
+
+  return ptr;
+}
+
+int 
+main (void)
+{
+  void *invalid_ptr;
+
+  invalid_ptr = make_invalid_ptr ();
+  func1 (invalid_ptr);
+  
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
new file mode 100644
index 0000000..0225326
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -0,0 +1,111 @@
+# Copyright (C) 2014 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/>.
+
+# In this test we're looking at how gdb handles backtraces and
+# investigating the stack depth when confronted with an "invalid" stack,
+# that is a stack where the first few frames are normal, and then there's a
+# frame where the stack in unreadable.
+#
+# One interesting bug that has been observed is that gdb will sometime
+# exhibit different behaviour the first time a stack command is run
+# compared to the second (and later) times a command is run.  This is
+# because the first time a command is run gdb actually tries to figure out
+# the answer, while the second (and later) times gdb relies on the answer
+# cached from the first time.  As a result in this test each command is
+# run twice, and we restart gdb before testing each different command to
+# ensure that nothing is being cached.
+
+set opts {}
+standard_testfile .c
+
+if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
+    verbose "Skipping ${testfile}."
+    return
+}
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} $opts] } {
+    return -1
+}
+
+if ![runto breakpt] {
+    return -1
+}
+
+# Use 'bt no-filters' here as the python filters will raise their own
+# error during initialisation, the no-filters case is simpler.
+
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+	 "first backtrace, with error message"
+
+send_gdb "bt no-filters\n"
+gdb_expect {
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
+	# Currently gdb will not display the error message associated with
+	# the truncated backtrace after the first backtrace has been
+	# completed.  Ideally, we would do this.  If this case is ever hit
+	# then we have started to display the backtrace in all cases and
+	# the xpass should becomd a pass, and the previous pass case below
+	# should be removed, or changed to a fail.
+	xpass "second backtrace, with error message"
+    }
+    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
+	pass "second backtrace, without error message"
+    }
+    timeout {
+	fail "second backtrace (timeout)"
+    }
+}
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+set test_name "check mi -stack-info-depth command, first time"
+send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
+gdb_expect {
+    -re "\\^done,depth=\"1\"\r\n$gdb_prompt $" {
+	pass $test_name
+    }
+    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
+	xfail $test_name
+    }
+}
+
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, second time"
+
+clean_restart ${binfile}
+
+if ![runto breakpt] {
+    return -1
+}
+
+set test_name "check mi -stack-list-frames command, first time"
+send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
+gdb_expect {
+    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]\r\n$gdb_prompt $" {
+	pass $test_name
+    }
+    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
+	xfail $test_name
+    }
+}
+
+
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, second time"
-- 
1.8.1.3








^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-05-28 17:26     ` Pedro Alves
@ 2014-05-28 23:26       ` Andrew Burgess
  2014-05-29  9:00         ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-05-28 23:26 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 28/05/2014 6:26 PM, Pedro Alves wrote:
> On 04/30/2014 11:55 AM, Andrew Burgess wrote:
>> Patch #4 adds frame specific stop reason strings.  It is better to use that
>> string rather than the existing generic stop reason string.  This patch
>> renames frame_stop_reason_string to deprecated_frame_stop_reason_string and
>> updates all the call sites to use the deprecated name.
>>
>> Patch #4 adds the new frame specific stop reason, and some uses of the
>> deprecated funciton will be moved to this new API, however, in the python
>> and guile scripting API we expose a function that converts the stop reason
>> code into a string, without a frame, this will be harder to convert to the
> 
> The function still serves it's purpose of mapping the enum values
> to string equivalents.  I don't really see a need to mark it deprecated.

I guess not.  In my head I figured if you were going to show a string then
you'd always be better going through the new frame specific interface, as
any string it returns might be "more specific" to this frame, and strings
are always (that's my assumption / guess) just being displayed to the user
so more specific would be better.
For program control you'd still have the get_frame_unwind_stop_reason which
returns the enum value.
I wasn't sure where the old function would still serve a really useful
role, and I worried it would be used in places the frame specific version
would be better.

That said, I don't object to keeping it around.  It can always be removed
later if it turns out that it's not used.

> IMO, the real problem with its signature is the "frame_" in its name.
> The function converts an 'enum unwind_stop_reason' value to a string,
> so like other similar cases in the tree, how about renaming the function
> to match?  E.g.:
> 
> -const char *frame_stop_reason_string (enum unwind_stop_reason);
> +const char *unwind_stop_reason_to_string (enum unwind_stop_reason);

I've gone with this suggestion, updated patch below.  Is this OK to apply?

Thanks,
Andrew


gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(unwind_frame_stop_reason_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(unwind_frame_stop_reason_string): this.
        * stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Likewise.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Likewise.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Likewise.
---
 gdb/frame.c           | 2 +-
 gdb/frame.h           | 6 ++++--
 gdb/guile/scm-frame.c | 2 +-
 gdb/python/py-frame.c | 2 +-
 gdb/stack.c           | 4 ++--
 5 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index cbff25f..ee2b711 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2561,7 +2561,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
 /* Return a string explaining REASON.  */
 
 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+unwind_frame_stop_reason_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index ad03a0b..5acb2a2 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -501,9 +501,11 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This returns a
+   general string describing the stop reason, for a possibly frame
+   specific reason string, use frame_stop_reason_string.  */
 
-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *unwind_frame_stop_reason_string (enum unwind_stop_reason);
 
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 8800923..0191a7a 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -933,7 +933,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);
 
-  str = frame_stop_reason_string (reason);
+  str = unwind_frame_stop_reason_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..ba17837 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
       return NULL;
     }
 
-  str = frame_stop_reason_string (reason);
+  str = unwind_frame_stop_reason_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
diff --git a/gdb/stack.c b/gdb/stack.c
index 297ba32..a113a03 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1529,7 +1529,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 unwind_frame_stop_reason_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1848,7 +1848,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     unwind_frame_stop_reason_string (reason));
 	}
     }
 }
-- 
1.8.1.3



 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-05-28 18:31     ` Pedro Alves
@ 2014-05-28 23:35       ` Andrew Burgess
  2014-05-29  9:41         ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-05-28 23:35 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 28/05/2014 7:31 PM, Pedro Alves wrote:
> On 04/30/2014 11:55 AM, Andrew Burgess wrote:
>> Here a new TRY_CATCH is added to the core of get_prev_frame, all uncaught
>> errors are turned into UNWIND_MISC_ERROR, and where possible the error
>> message associated with the error is stored as a frame specific stop reason
>> string.  The reason string is held of the frame OBSTACK so it lives as long
>> as the frame does.
>>
>> There's a new function for getting the frame_stop_reason_string, this
>> replaces the now (thanks to patch #3) old frame_stop_reason_string
>> function, I know that reusing the name could confuse, but this function was
>> not widely used, so I hope that'll not be an issue.
> 
> Sounds like we'll want to expose this to Python too.  If you're not
> planning on doing that, could you file a PR once this goes in?

I'm happy to add the new python (and even guile) functions, I figured
I'd post a follow up patch once these were merged ... if that's OK.

> 
>>
>> I don't know if you'll all be happy with me catching _all_ errors in
>> get_prev_frame.
> 
> Yeah, that makes me somewhat nervous.  E.g., this catches and
> swallows TARGET_CLOSE_ERROR.
> 
>> Given that the issues I'm seeing "in the wild" and which
>> I've put into the tests are for accessing invalid memory through a bad
>> stack pointer, I could reduce the catching to only catch MEMORY_ERRORs,
>> then UNWIND_MISC_ERROR would become UNWIND_MEMORY_ERROR.  
> 
> I think I'd prefer that.  This swallows TARGET_CLOSE_ERROR, for example.

I've changed the patch to only catch MEMORY_ERROR now.

> 
> Could you please include both MI and CLI before/after examples
> in the description/commit log, please?  You had something
> close to that in the cover letter, but that doesn't make it to
> the repository.

I've included my proposed commit message below too along with
the patch.
> 
> 
>> I could even add
>> the memory error detection on top of the new MISC_ERROR case if preferred,
>> though I'd need to think of a new test...
> 
> I didn't understand this.

Sorry, I just meant I could add FRAME_MEMORY_ERROR and FRAME_MISC_ERROR, but
as you point out, some errors really /don't/ make sense to catch.  But given
your good point about TARGET_CLOSE_ERROR I don't think FRAME_MISC_ERROR is a
good idea any more, we now just have FRAME_MEMORY_ERROR as the new stop
reason.
 
>> 	* unwind_stop_reason.def: Add UNWIND_MISC_ERROR.
> 
> Values added here are exposed to Python/scheme automatically.
> But, we need to document them manually in the manual.  E.g.
> for python, in gdb/python.texi in the table beneath the
> description of Frame.unwind_stop_reason ().

Done.

Thanks for the review, and is this OK to push?

Thanks,
Andrew


Commit message:

Currently a MEMORY_ERROR raised during unwinding a frame will cause the
unwind to stop with an error message, for example:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
  Cannot access memory at address 0x2aaaaaab0000

However, frame #4 is marked as being the end of the stack unwind, so a
subsequent request for the backtrace looses the error message, such as:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50

When fetching the backtrace, or requesting the stack depth using the MI
interface the situation is even worse, the first time a request is made
we encounter the memory error and so the MI returns an error instead of
the correct result, for example:

  (gdb) -stack-info-depth
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

Or,

  (gdb) -stack-list-frames
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

However, once one of these commands has been used gdb has, internally,
walked the stack and figured that out that frame #4 is the bottom of the
stack, so the second time an MI command is tried you'll get the "expected"
result:

  (gdb) -stack-info-depth
  ^done,depth="5"

Or,

  (gdb) -stack-list-frames
  ^done,stack=[frame={level="0", .. snip lots .. }]

After this patch the MEMORY_ERROR encountered during the frame unwind is
attached to frame #4 as the stop reason, and is displayed in the CLI each
time the backtrace is requested.  In the MI, catching the error means that
the "expected" result is returned the first time the MI command is issued.

---

gdb/ChangeLog:

	* frame.c (struct frame_info): Add stop_string field.
	(get_prev_frame_always_1): Renamed from get_prev_frame_always.
	(get_prev_frame_always): Old content moved into
	get_prev_frame_always_1.  Call get_prev_frame_always_1 inside
	TRY_CATCH, handle MEMORY_ERROR exceptions.
	(frame_stop_reason_string): New function definition.
	* frame.h (frame_stop_reason_string): New function declaration.
	* stack.c (frame_info): Switch to frame_stop_reason_string.
	(backtrace_command_1): Switch to frame_stop_reason_string.
	* unwind_stop_reason.def: Add UNWIND_MEMORY_ERROR.
	(LAST_ENTRY): Changed to UNWIND_MEMORY_ERROR.
	* guile/lib/gdb.scm: Add FRAME_UNWIND_MEMORY_ERROR to export list.

gdb/doc/ChangeLog:

	* guile.texi (Frames In Guile): Mention FRAME_UNWIND_MEMORY_ERROR.
	* python.texi (Frames In Python): Mention
	gdb.FRAME_UNWIND_MEMORY_ERROR.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
	* gdb.arch/amd64-invalid-stack-top.exp: Likewise.
---
 gdb/doc/guile.texi                                 |  3 +
 gdb/doc/python.texi                                |  3 +
 gdb/frame.c                                        | 74 ++++++++++++++++++++--
 gdb/frame.h                                        |  6 ++
 gdb/guile/lib/gdb.scm                              |  1 +
 gdb/stack.c                                        |  4 +-
 .../gdb.arch/amd64-invalid-stack-middle.exp        | 48 +++-----------
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp | 49 +++-----------
 gdb/unwind_stop_reasons.def                        |  5 +-
 9 files changed, 104 insertions(+), 89 deletions(-)

diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 3e03c7c..bc2a2ce 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -1827,6 +1827,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index ce8ec78..006b873 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3199,6 +3199,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item gdb.FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item gdb.FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
diff --git a/gdb/frame.c b/gdb/frame.c
index ee2b711..517ef08 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -145,6 +145,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1798,14 +1802,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_always, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
-struct frame_info *
-get_prev_frame_always (struct frame_info *this_frame)
+static struct frame_info *
+get_prev_frame_always_1 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1955,6 +1957,46 @@ get_prev_frame_always (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+struct frame_info *
+get_prev_frame_always (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_always_1 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      if (ex.error == MEMORY_ERROR)
+	{
+	  this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+	  if (ex.message != NULL)
+	    {
+	      char *stop_string;
+
+	      /* The error needs to live as long as the frame does.  */
+	      stop_string =
+		FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
+	      strcpy (stop_string, ex.message);
+	      this_frame->stop_string = stop_string;
+	    }
+	  prev_frame = NULL;
+	}
+      else
+	throw_exception (ex);
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2576,6 +2618,24 @@ unwind_frame_stop_reason_string (enum unwind_stop_reason reason)
     }
 }
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped at frame FI.  Must only be called if there is no previous
+   frame.  */
+
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  */
+  return unwind_frame_stop_reason_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 5acb2a2..1a094d9 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -507,6 +507,12 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
 const char *unwind_frame_stop_reason_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  Should only be called for frames that don't have a
+   previous frame.  If there's no specific reason stored for a frame then
+   a generic reason string will be returned.  */
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
diff --git a/gdb/guile/lib/gdb.scm b/gdb/guile/lib/gdb.scm
index ec739c7..abc4a67 100644
--- a/gdb/guile/lib/gdb.scm
+++ b/gdb/guile/lib/gdb.scm
@@ -169,6 +169,7 @@
  FRAME_UNWIND_INNER_ID
  FRAME_UNWIND_SAME_ID
  FRAME_UNWIND_NO_SAVED_PC
+ FRAME_UNWIND_MEMORY_ERROR
 
  frame?
  frame-valid?
diff --git a/gdb/stack.c b/gdb/stack.c
index a113a03..4f16238 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1529,7 +1529,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 unwind_frame_stop_reason_string (reason));
+			 frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1848,7 +1848,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     unwind_frame_stop_reason_string (reason));
+			     frame_stop_reason_string (trailing));
 	}
     }
 }
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index 8ad5b18..b53ad41 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -71,16 +55,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"4\"\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"4\"" \
@@ -92,16 +69,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
index 0225326..17c79d7 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -45,27 +45,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -73,16 +57,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"1\"\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"1\"" \
@@ -94,17 +71,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
-
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def
index d7da7ea..8cef537 100644
--- a/gdb/unwind_stop_reasons.def
+++ b/gdb/unwind_stop_reasons.def
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* There was an error accessing memory while unwinding this frame.  */
+SET (UNWIND_MEMORY_ERROR, "memory error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MEMORY_ERROR)
 #endif
-- 
1.8.1.3






^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-05-28 23:26       ` Andrew Burgess
@ 2014-05-29  9:00         ` Pedro Alves
  2014-05-29  9:53           ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-05-29  9:00 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 05/29/2014 12:26 AM, Andrew Burgess wrote:
> On 28/05/2014 6:26 PM, Pedro Alves wrote:
>> On 04/30/2014 11:55 AM, Andrew Burgess wrote:

>> IMO, the real problem with its signature is the "frame_" in its name.
>> The function converts an 'enum unwind_stop_reason' value to a string,
>> so like other similar cases in the tree, how about renaming the function
>> to match?  E.g.:
>>
>> -const char *frame_stop_reason_string (enum unwind_stop_reason);
>> +const char *unwind_stop_reason_to_string (enum unwind_stop_reason);
> 
> I've gone with this suggestion, updated patch below.  Is this OK to apply?

Not yet, sorry.

> 	* frame.c (frame_stop_reason_string): Rename to ...
> 	(unwind_frame_stop_reason_string): this.

This still has "frame" in the name, and misses the "to".  Any reason for that?

The specific suggestion had a logic --

 convert "enum unwind_stop_reason" to "string" -> "unwind_stop_reason_to_string".

That is just like target_waitstatus_to_string and
target_xfer_status_to_string, for example.

Without even looking at the function's declaration, I can tell
that is converting the enum value.  While "unwind_frame_stop_reason_string"
without the "to" doesn't give me that impression, and is very much
confusable with the new frame_stop_reason_string.

> 	* frame.h (frame_stop_reason_string): Rename to ...
> 	(unwind_frame_stop_reason_string): this.
>         * stack.c (frame_info): Update call to frame_stop_reason_string.
> 	(backtrace_command_1): Likewise.
> 	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Likewise.
> 	* python/py-frame.c (gdbpy_frame_stop_reason_string): Likewise.

...

> diff --git a/gdb/frame.h b/gdb/frame.h
> index ad03a0b..5acb2a2 100644
> --- a/gdb/frame.h
> +++ b/gdb/frame.h
> @@ -501,9 +501,11 @@ enum unwind_stop_reason
>  
>  enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
>  
> -/* Translate a reason code to an informative string.  */
> +/* Translate a reason code to an informative string.  This returns a
> +   general string describing the stop reason, for a possibly frame
> +   specific reason string, use frame_stop_reason_string.  */

Please remove this comment hunk from this patch, so that the patch
remains independent, and so that it can go in immediately even if
further discuss patch #4.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-05-28 23:35       ` Andrew Burgess
@ 2014-05-29  9:41         ` Pedro Alves
  2014-05-29 23:02           ` Andrew Burgess
  0 siblings, 1 reply; 34+ messages in thread
From: Pedro Alves @ 2014-05-29  9:41 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 05/29/2014 12:35 AM, Andrew Burgess wrote:
> On 28/05/2014 7:31 PM, Pedro Alves wrote:
>> On 04/30/2014 11:55 AM, Andrew Burgess wrote:
>>> Here a new TRY_CATCH is added to the core of get_prev_frame, all uncaught
>>> errors are turned into UNWIND_MISC_ERROR, and where possible the error
>>> message associated with the error is stored as a frame specific stop reason
>>> string.  The reason string is held of the frame OBSTACK so it lives as long
>>> as the frame does.
>>>
>>> There's a new function for getting the frame_stop_reason_string, this
>>> replaces the now (thanks to patch #3) old frame_stop_reason_string
>>> function, I know that reusing the name could confuse, but this function was
>>> not widely used, so I hope that'll not be an issue.
>>
>> Sounds like we'll want to expose this to Python too.  If you're not
>> planning on doing that, could you file a PR once this goes in?
> 
> I'm happy to add the new python (and even guile) functions, I figured
> I'd post a follow up patch once these were merged ... if that's OK.

That's great, thanks.

> Commit message:
> 
> Currently a MEMORY_ERROR raised during unwinding a frame will cause the
> unwind to stop with an error message, for example:
> 
>   (gdb) bt
>   #0  breakpt () at amd64-invalid-stack-middle.c:27
>   #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
>   #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
>   #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
>   #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
>   Cannot access memory at address 0x2aaaaaab0000
> 
> However, frame #4 is marked as being the end of the stack unwind, so a
> subsequent request for the backtrace looses the error message, such as:
> 
>   (gdb) bt
>   #0  breakpt () at amd64-invalid-stack-middle.c:27
>   #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
>   #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
>   #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
>   #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
> 
> When fetching the backtrace, or requesting the stack depth using the MI
> interface the situation is even worse, the first time a request is made
> we encounter the memory error and so the MI returns an error instead of
> the correct result, for example:
> 
>   (gdb) -stack-info-depth
>   ^error,msg="Cannot access memory at address 0x2aaaaaab0000"
> 
> Or,
> 
>   (gdb) -stack-list-frames
>   ^error,msg="Cannot access memory at address 0x2aaaaaab0000"
> 
> However, once one of these commands has been used gdb has, internally,
> walked the stack and figured that out that frame #4 is the bottom of the
> stack, so the second time an MI command is tried you'll get the "expected"
> result:
> 
>   (gdb) -stack-info-depth
>   ^done,depth="5"
> 
> Or,
> 
>   (gdb) -stack-list-frames
>   ^done,stack=[frame={level="0", .. snip lots .. }]

Now here's an excellent description / commit message.  Thanks!

> 
> After this patch the MEMORY_ERROR encountered during the frame unwind is
> attached to frame #4 as the stop reason, and is displayed in the CLI each
> time the backtrace is requested.

Please show examples of this in the commit log too.

> In the MI, catching the error means that
> the "expected" result is returned the first time the MI command is issued.

> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -3199,6 +3199,9 @@ stack corruption.
>  The frame unwinder did not find any saved PC, but we needed
>  one to unwind further.
>  
> +@item gdb.FRAME_UNWIND_MEMORY_ERROR
> +The frame unwinder caused an error while trying to access memory.

> +
> +	      /* The error needs to live as long as the frame does.  */
> +	      stop_string =
> +		FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);

#1 - Per GNU coding conventions, operators go on the next line, and '='
is an operator (assignment), so:

	      stop_string
		= FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);

#2 - sizeof (char) is 1 by definition, so no need for calloc, actually.
And then that might fit on a single line:

	      stop_string = FRAME_OBSTACK_ZALLOC (strlen (ex.message) + 1);

> +	      strcpy (stop_string, ex.message);
> +	      this_frame->stop_string = stop_string;

But even better we could do this instead:

	      size_t size;

              size = strlen (ex.message) + 1;
              this_frame->stop_string = FRAME_OBSTACK_ZALLOC (size);
              memcpy (this_frame->stop_string, ex.message, size);

> +	    }
> +	  prev_frame = NULL;
> +	}
> +      else
> +	throw_exception (ex);
> +    }
> +
> +  return prev_frame;
> +}
> +
>  /* Construct a new "struct frame_info" and link it previous to
>     this_frame.  */
>  
> @@ -2576,6 +2618,24 @@ unwind_frame_stop_reason_string (enum unwind_stop_reason reason)
>      }
>  }
>  

> +/* Return a possibly frame specific string explaining why the unwind
> +   stopped here.  Should only be called for frames that don't have a
> +   previous frame.  If there's no specific reason stored for a frame then
> +   a generic reason string will be returned.  */
> +const char *frame_stop_reason_string (struct frame_info *);

Let's include an example to make it clearer:

/* Return a possibly frame specific string explaining why the unwind
   stopped here.  E.g., if unwinding tripped on a memory error, this
   will return the error description string, which includes the address
   that we failed to access.  If there's no specific reason stored for
   a frame then a generic reason string will be returned.

   Should only be called for frames that don't have a previous frame.  */

(I imagine that this "Should" will need to be addressed when we expose
this to Python somehow.  We wouldn't want failure to comply to that
to cause an internal error.)


> +/* Return a possibly frame specific string explaining why the unwind
> +   stopped at frame FI.  Must only be called if there is no previous
> +   frame.  */

Let's just remove this comment, thus avoiding maintaining the same
description in two places.  Note it was already divergent from the
comment in the header.

> +
> +const char *
> +frame_stop_reason_string (struct frame_info *fi)
> +{
> +  gdb_assert (fi->prev_p);
> +  gdb_assert (fi->prev == NULL);
> +
> +  /* Return the specific string if we have one.  */
> +  if (fi->stop_string)
> +    return fi->stop_string;

  if (fi->stop_string != NULL)
    return fi->stop_string;

Otherwise looks good.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-05-29  9:00         ` Pedro Alves
@ 2014-05-29  9:53           ` Andrew Burgess
  2014-05-29  9:56             ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-05-29  9:53 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 29/05/2014 10:00 AM, Pedro Alves wrote:
> On 05/29/2014 12:26 AM, Andrew Burgess wrote:
>> On 28/05/2014 6:26 PM, Pedro Alves wrote:
>>> On 04/30/2014 11:55 AM, Andrew Burgess wrote:
> 
>>> IMO, the real problem with its signature is the "frame_" in its name.
>>> The function converts an 'enum unwind_stop_reason' value to a string,
>>> so like other similar cases in the tree, how about renaming the function
>>> to match?  E.g.:
>>>
>>> -const char *frame_stop_reason_string (enum unwind_stop_reason);
>>> +const char *unwind_stop_reason_to_string (enum unwind_stop_reason);
>>
>> I've gone with this suggestion, updated patch below.  Is this OK to apply?
> 
> Not yet, sorry.
> 
>> 	* frame.c (frame_stop_reason_string): Rename to ...
>> 	(unwind_frame_stop_reason_string): this.
> 
> This still has "frame" in the name, and misses the "to".  Any reason for that?

No, just me being special :)

I think this attempt should do it,
  frame_stop_reason_string -> unwind_stop_reason_to_string

OK?

Thanks,
Andrew

---

This function is confusingly named, the "frame_" in the name implies it
somehow is frame dependent, when in reality the function just converts an
'enum unwind_stop_reason' value to a string.

gdb/ChangeLog:

	* frame.c (frame_stop_reason_string): Rename to ...
	(unwind_stop_reason_to_string): this.
	* frame.h (frame_stop_reason_string): Rename to ...
	(unwind_stop_reason_to_string): this.
	* stack.c (frame_info): Update call to frame_stop_reason_string.
	(backtrace_command_1): Likewise.
	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Likewise.
	* python/py-frame.c (gdbpy_frame_stop_reason_string): Likewise.
---
 gdb/frame.c           | 2 +-
 gdb/frame.h           | 2 +-
 gdb/guile/scm-frame.c | 2 +-
 gdb/python/py-frame.c | 2 +-
 gdb/stack.c           | 4 ++--
 5 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index cbff25f..f44cf50 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2561,7 +2561,7 @@ get_frame_unwind_stop_reason (struct frame_info *frame)
 /* Return a string explaining REASON.  */
 
 const char *
-frame_stop_reason_string (enum unwind_stop_reason reason)
+unwind_stop_reason_to_string (enum unwind_stop_reason reason)
 {
   switch (reason)
     {
diff --git a/gdb/frame.h b/gdb/frame.h
index ad03a0b..79881521d 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -503,7 +503,7 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
 /* Translate a reason code to an informative string.  */
 
-const char *frame_stop_reason_string (enum unwind_stop_reason);
+const char *unwind_stop_reason_to_string (enum unwind_stop_reason);
 
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 8800923..9c0b00d 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -933,7 +933,7 @@ gdbscm_unwind_stop_reason_string (SCM reason_scm)
   if (reason < UNWIND_FIRST || reason > UNWIND_LAST)
     scm_out_of_range (FUNC_NAME, reason_scm);
 
-  str = frame_stop_reason_string (reason);
+  str = unwind_stop_reason_to_string (reason);
   return gdbscm_scm_from_c_string (str);
 }
 \f
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 8c80d39..77077d3 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -588,7 +588,7 @@ gdbpy_frame_stop_reason_string (PyObject *self, PyObject *args)
       return NULL;
     }
 
-  str = frame_stop_reason_string (reason);
+  str = unwind_stop_reason_to_string (reason);
   return PyUnicode_Decode (str, strlen (str), host_charset (), NULL);
 }
 
diff --git a/gdb/stack.c b/gdb/stack.c
index 297ba32..630a363 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1529,7 +1529,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 frame_stop_reason_string (reason));
+			 unwind_stop_reason_to_string (reason));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1848,7 +1848,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     frame_stop_reason_string (reason));
+			     unwind_stop_reason_to_string (reason));
 	}
     }
 }
-- 
1.8.1.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 3/4] Deprecate frame_stop_reason_string.
  2014-05-29  9:53           ` Andrew Burgess
@ 2014-05-29  9:56             ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2014-05-29  9:56 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 05/29/2014 10:52 AM, Andrew Burgess wrote:
> On 29/05/2014 10:00 AM, Pedro Alves wrote:

>> This still has "frame" in the name, and misses the "to".  Any reason for that?
> 
> No, just me being special :)

LOL!

> This function is confusingly named, the "frame_" in the name implies it
> somehow is frame dependent, when in reality the function just converts an
> 'enum unwind_stop_reason' value to a string.

Excellent and concise description/log.

> 
> gdb/ChangeLog:
> 
> 	* frame.c (frame_stop_reason_string): Rename to ...
> 	(unwind_stop_reason_to_string): this.
> 	* frame.h (frame_stop_reason_string): Rename to ...
> 	(unwind_stop_reason_to_string): this.
> 	* stack.c (frame_info): Update call to frame_stop_reason_string.
> 	(backtrace_command_1): Likewise.
> 	* guile/scm-frame.c (gdbscm_unwind_stop_reason_string): Likewise.
> 	* python/py-frame.c (gdbpy_frame_stop_reason_string): Likewise.

OK

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-05-29  9:41         ` Pedro Alves
@ 2014-05-29 23:02           ` Andrew Burgess
  2014-05-30 11:46             ` Pedro Alves
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Burgess @ 2014-05-29 23:02 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 29/05/2014 10:41 AM, Pedro Alves wrote:
> On 05/29/2014 12:35 AM, Andrew Burgess wrote:
>> On 28/05/2014 7:31 PM, Pedro Alves wrote:
>>> On 04/30/2014 11:55 AM, Andrew Burgess wrote:

> 
> Now here's an excellent description / commit message.  Thanks!
> 
>>
>> After this patch the MEMORY_ERROR encountered during the frame unwind is
>> attached to frame #4 as the stop reason, and is displayed in the CLI each
>> time the backtrace is requested.
> 
> Please show examples of this in the commit log too.

Done.

> 
>> +
>> +	      /* The error needs to live as long as the frame does.  */
>> +	      stop_string =
>> +		FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
> 
> #1 - Per GNU coding conventions, operators go on the next line, and '='
> is an operator (assignment), so:
> 
> 	      stop_string
> 		= FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char);
> 
> #2 - sizeof (char) is 1 by definition, so no need for calloc, actually.
> And then that might fit on a single line:
> 
> 	      stop_string = FRAME_OBSTACK_ZALLOC (strlen (ex.message) + 1);
> 
>> +	      strcpy (stop_string, ex.message);
>> +	      this_frame->stop_string = stop_string;
> 
> But even better we could do this instead:
> 
> 	      size_t size;
> 
>               size = strlen (ex.message) + 1;
>               this_frame->stop_string = FRAME_OBSTACK_ZALLOC (size);
>               memcpy (this_frame->stop_string, ex.message, size);

I've changed to this, except that I'm still using a stack local stop_string
to create the message, then assigning to this_frame->stop_string, this allow
this_frame->stop_string to be 'const char *' rather than just 'char *'.  I've
added a comment.

> 
> Let's include an example to make it clearer:
> 
> /* Return a possibly frame specific string explaining why the unwind
>    stopped here.  E.g., if unwinding tripped on a memory error, this
>    will return the error description string, which includes the address
>    that we failed to access.  If there's no specific reason stored for
>    a frame then a generic reason string will be returned.
> 
>    Should only be called for frames that don't have a previous frame.  */
> 
> (I imagine that this "Should" will need to be addressed when we expose
> this to Python somehow.  We wouldn't want failure to comply to that
> to cause an internal error.)

I've updated the comment.  I agree with needing to guard against user error
when we expose this to python/guile, but we can do that later.

>> +/* Return a possibly frame specific string explaining why the unwind
>> +   stopped at frame FI.  Must only be called if there is no previous
>> +   frame.  */
> 
> Let's just remove this comment, thus avoiding maintaining the same
> description in two places.  Note it was already divergent from the
> comment in the header.

Done.

> 
>> +
>> +const char *
>> +frame_stop_reason_string (struct frame_info *fi)
>> +{
>> +  gdb_assert (fi->prev_p);
>> +  gdb_assert (fi->prev == NULL);
>> +
>> +  /* Return the specific string if we have one.  */
>> +  if (fi->stop_string)
>> +    return fi->stop_string;
> 
>   if (fi->stop_string != NULL)
>     return fi->stop_string;

Fixed.


Here's the latest version, other than the above changes nothing has really changed.
You seemed happy enough with the last iteration, so if I don't hear anything
else I'll push this in a few days.

Thanks for your time,
Andrew


---

Currently a MEMORY_ERROR raised during unwinding a frame will cause the
unwind to stop with an error message, for example:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
  Cannot access memory at address 0x2aaaaaab0000

However, frame #4 is marked as being the end of the stack unwind, so a
subsequent request for the backtrace looses the error message, such as:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50

When fetching the backtrace, or requesting the stack depth using the MI
interface the situation is even worse, the first time a request is made
we encounter the memory error and so the MI returns an error instead of
the correct result, for example:

  (gdb) -stack-info-depth
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

Or,

  (gdb) -stack-list-frames
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

However, once one of these commands has been used gdb has, internally,
walked the stack and figured that out that frame #4 is the bottom of the
stack, so the second time an MI command is tried you'll get the "expected"
result:

  (gdb) -stack-info-depth
  ^done,depth="5"

Or,

  (gdb) -stack-list-frames
  ^done,stack=[frame={level="0", .. snip lots .. }]

After this patch the MEMORY_ERROR encountered during the frame unwind is
attached to frame #4 as the stop reason, and is displayed in the CLI each
time the backtrace is requested.  In the MI, catching the error means that
the "expected" result is returned the first time the MI command is issued.
So, from the CLI the results of the backtrace will be:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
  Backtrace stopped: Cannot access memory at address 0x2aaaaaab0000

Each and every time that the backtrace is requested, while the MI output
will similarly be consistently:

  (gdb) -stack-info-depth
  ^done,depth="5"

Or,

  (gdb) -stack-list-frames
  ^done,stack=[frame={level="0", .. snip lots .. }]

gdb/ChangeLog:

	* frame.c (struct frame_info): Add stop_string field.
	(get_prev_frame_always_1): Renamed from get_prev_frame_always.
	(get_prev_frame_always): Old content moved into
	get_prev_frame_always_1.  Call get_prev_frame_always_1 inside
	TRY_CATCH, handle MEMORY_ERROR exceptions.
	(frame_stop_reason_string): New function definition.
	* frame.h (unwind_stop_reason_to_string): Extend comment to
	mention frame_stop_reason_string.
	(frame_stop_reason_string): New function declaration.
	* stack.c (frame_info): Switch to frame_stop_reason_string.
	(backtrace_command_1): Switch to frame_stop_reason_string.
	* unwind_stop_reason.def: Add UNWIND_MEMORY_ERROR.
	(LAST_ENTRY): Changed to UNWIND_MEMORY_ERROR.
	* guile/lib/gdb.scm: Add FRAME_UNWIND_MEMORY_ERROR to export list.

gdb/doc/ChangeLog:

	* guile.texi (Frames In Guile): Mention FRAME_UNWIND_MEMORY_ERROR.
	* python.texi (Frames In Python): Mention
	gdb.FRAME_UNWIND_MEMORY_ERROR.

gdb/testsuite/ChangeLog:

	* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
	* gdb.arch/amd64-invalid-stack-top.exp: Likewise.
---
 gdb/doc/guile.texi                                 |  3 +
 gdb/doc/python.texi                                |  3 +
 gdb/frame.c                                        | 74 ++++++++++++++++++++--
 gdb/frame.h                                        | 15 ++++-
 gdb/guile/lib/gdb.scm                              |  1 +
 gdb/stack.c                                        |  4 +-
 .../gdb.arch/amd64-invalid-stack-middle.exp        | 48 +++-----------
 gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp | 49 +++-----------
 gdb/unwind_stop_reasons.def                        |  5 +-
 9 files changed, 112 insertions(+), 90 deletions(-)

diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi
index 3e03c7c..bc2a2ce 100644
--- a/gdb/doc/guile.texi
+++ b/gdb/doc/guile.texi
@@ -1827,6 +1827,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index ce8ec78..006b873 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -3199,6 +3199,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item gdb.FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item gdb.FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
diff --git a/gdb/frame.c b/gdb/frame.c
index f44cf50..8dea9c4 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -145,6 +145,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1798,14 +1802,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_always, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
-struct frame_info *
-get_prev_frame_always (struct frame_info *this_frame)
+static struct frame_info *
+get_prev_frame_always_1 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1955,6 +1957,50 @@ get_prev_frame_always (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+struct frame_info *
+get_prev_frame_always (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_always_1 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      if (ex.error == MEMORY_ERROR)
+	{
+	  this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+	  if (ex.message != NULL)
+	    {
+	      char *stop_string;
+	      size_t size;
+
+	      /* The error needs to live as long as the frame does.
+	         Allocate using stack local STOP_STRING then assign the
+	         pointer to the frame, this allows the STOP_STRING on the
+	         frame to be of type 'const char *'.  */
+	      size = strlen (ex.message) + 1;
+	      stop_string = frame_obstack_zalloc (size);
+	      memcpy (stop_string, ex.message, size);
+	      this_frame->stop_string = stop_string;
+	    }
+	  prev_frame = NULL;
+	}
+      else
+	throw_exception (ex);
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2576,6 +2622,20 @@ unwind_stop_reason_to_string (enum unwind_stop_reason reason)
     }
 }
 
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string != NULL)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  */
+  return unwind_stop_reason_to_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
diff --git a/gdb/frame.h b/gdb/frame.h
index 79881521d..59564f9 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -501,10 +501,23 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This converts the
+   generic stop reason codes into a generic string describing the code.
+   For a possibly frame specific string explaining the stop reason, use
+   FRAME_STOP_REASON_STRING instead.  */
 
 const char *unwind_stop_reason_to_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  E.g., if unwinding tripped on a memory error, this
+   will return the error description string, which includes the address
+   that we failed to access.  If there's no specific reason stored for
+   a frame then a generic reason string will be returned.
+
+   Should only be called for frames that don't have a previous frame.  */
+
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
diff --git a/gdb/guile/lib/gdb.scm b/gdb/guile/lib/gdb.scm
index ec739c7..abc4a67 100644
--- a/gdb/guile/lib/gdb.scm
+++ b/gdb/guile/lib/gdb.scm
@@ -169,6 +169,7 @@
  FRAME_UNWIND_INNER_ID
  FRAME_UNWIND_SAME_ID
  FRAME_UNWIND_NO_SAVED_PC
+ FRAME_UNWIND_MEMORY_ERROR
 
  frame?
  frame-valid?
diff --git a/gdb/stack.c b/gdb/stack.c
index 630a363..4f16238 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1529,7 +1529,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
 	printf_filtered (_(" Outermost frame: %s\n"),
-			 unwind_stop_reason_to_string (reason));
+			 frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1848,7 +1848,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
 	  reason = get_frame_unwind_stop_reason (trailing);
 	  if (reason >= UNWIND_FIRST_ERROR)
 	    printf_filtered (_("Backtrace stopped: %s\n"),
-			     unwind_stop_reason_to_string (reason));
+			     frame_stop_reason_string (trailing));
 	}
     }
 }
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index 8ad5b18..b53ad41 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -71,16 +55,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"4\"\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"4\"" \
@@ -92,16 +69,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
index 0225326..17c79d7 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
@@ -45,27 +45,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
 	 "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-	# Currently gdb will not display the error message associated with
-	# the truncated backtrace after the first backtrace has been
-	# completed.  Ideally, we would do this.  If this case is ever hit
-	# then we have started to display the backtrace in all cases and
-	# the xpass should becomd a pass, and the previous pass case below
-	# should be removed, or changed to a fail.
-	xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-	pass "second backtrace, without error message"
-    }
-    timeout {
-	fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+	 "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -73,16 +57,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"1\"\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"1\"" \
@@ -94,17 +71,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]\r\n$gdb_prompt $" {
-	pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-	xfail $test_name
-    }
-}
-
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def
index d7da7ea..8cef537 100644
--- a/gdb/unwind_stop_reasons.def
+++ b/gdb/unwind_stop_reasons.def
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* There was an error accessing memory while unwinding this frame.  */
+SET (UNWIND_MEMORY_ERROR, "memory error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MEMORY_ERROR)
 #endif
-- 
1.8.1.3


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind.
  2014-05-29 23:02           ` Andrew Burgess
@ 2014-05-30 11:46             ` Pedro Alves
  0 siblings, 0 replies; 34+ messages in thread
From: Pedro Alves @ 2014-05-30 11:46 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 05/30/2014 12:02 AM, Andrew Burgess wrote:

> Here's the latest version, other than the above changes nothing has really changed.
> You seemed happy enough with the last iteration, so if I don't hear anything
> else I'll push this in a few days.

Yeah, I'm happy.  Please push.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2014-05-30 11:46 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-04 14:46 [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
2014-04-04 14:47 ` [RFC 1/4] New tests for backtracing with a corrupted stack Andrew Burgess
2014-04-04 14:48 ` [RFC 2/4] Remove previous frame if we error during compute_frame_id Andrew Burgess
2014-04-04 14:53   ` Andrew Burgess
2014-04-15 19:02     ` Pedro Alves
2014-04-04 14:49 ` [RFC 3/4] Deprecate frame_stop_reason_string Andrew Burgess
2014-04-04 14:55   ` Andrew Burgess
2014-04-04 14:50 ` [RFC 4/4] Add TRY_CATCH to get_prev_frame and frame specific strop strings Andrew Burgess
2014-04-15  9:11 ` [RFC 0/4] Catch errors in get_prev_frame Andrew Burgess
2014-04-17 10:15 ` [PATCH v2 " Andrew Burgess
2014-04-17 10:15 ` [PATCH v2 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
2014-04-17 10:15 ` [PATCH v2 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
2014-04-17 10:15 ` [PATCH v2 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
2014-04-17 10:15 ` [PATCH v2 3/4] Deprecate frame_stop_reason_string Andrew Burgess
2014-04-29 19:56   ` Pedro Alves
2014-04-30 10:46     ` Andrew Burgess
2014-04-30 10:55 ` [PATCH v3 0/4] Catch errors in get_prev_frame Andrew Burgess
2014-04-30 10:55   ` [PATCH v3 2/4] Remove previous frame if an error occurs when computing frame id during unwind Andrew Burgess
2014-05-16 15:37     ` Pedro Alves
2014-05-28 23:16       ` Andrew Burgess
2014-04-30 10:55   ` [PATCH v3 3/4] Deprecate frame_stop_reason_string Andrew Burgess
2014-05-28 17:26     ` Pedro Alves
2014-05-28 23:26       ` Andrew Burgess
2014-05-29  9:00         ` Pedro Alves
2014-05-29  9:53           ` Andrew Burgess
2014-05-29  9:56             ` Pedro Alves
2014-04-30 10:55   ` [PATCH v3 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind Andrew Burgess
2014-05-28 18:31     ` Pedro Alves
2014-05-28 23:35       ` Andrew Burgess
2014-05-29  9:41         ` Pedro Alves
2014-05-29 23:02           ` Andrew Burgess
2014-05-30 11:46             ` Pedro Alves
2014-04-30 10:55   ` [PATCH v3 1/4] New test for backtrace when the stack pointer is invalid (inaccessible) Andrew Burgess
2014-05-28 18:42     ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).