Home | History | Annotate | Line # | Download | only in gdb.base
      1  1.1.1.2  christos # Copyright 2021-2024 Free Software Foundation, Inc.
      2      1.1  christos 
      3      1.1  christos # This program is free software; you can redistribute it and/or modify
      4      1.1  christos # it under the terms of the GNU General Public License as published by
      5      1.1  christos # the Free Software Foundation; either version 3 of the License, or
      6      1.1  christos # (at your option) any later version.
      7      1.1  christos #
      8      1.1  christos # This program is distributed in the hope that it will be useful,
      9      1.1  christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10      1.1  christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11      1.1  christos # GNU General Public License for more details.
     12      1.1  christos #
     13      1.1  christos # You should have received a copy of the GNU General Public License
     14      1.1  christos # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15      1.1  christos 
     16      1.1  christos # Check that the unwinder produces consistent frame info, by making
     17      1.1  christos # sure that "info frame" shows the same result when stopped at a
     18      1.1  christos # function (level == 0), compared to when we find the same frame in
     19      1.1  christos # the stack at a level > 0.  Tests both the DWARF stack unwinder, and
     20      1.1  christos # the fallback heuristic unwinder.
     21      1.1  christos 
     22      1.1  christos standard_testfile backtrace.c
     23      1.1  christos 
     24  1.1.1.2  christos set flags {}
     25  1.1.1.2  christos lappend flags debug
     26  1.1.1.2  christos lappend_include_file flags $srcdir/lib/attributes.h
     27  1.1.1.2  christos 
     28  1.1.1.2  christos if { [build_executable "failed to prepare" $testfile $srcfile $flags] } {
     29      1.1  christos     return -1
     30      1.1  christos }
     31      1.1  christos 
     32      1.1  christos # Unwind to each function in FRAMES, and compare "info frame" output
     33      1.1  christos # to what was saved in the 'info_frame_before' array.
     34      1.1  christos proc compare_frames {frames} {
     35      1.1  christos     foreach_with_prefix compare_frame $frames {
     36      1.1  christos 	if {[gdb_test \
     37      1.1  christos 		 "frame function $compare_frame" \
     38      1.1  christos 		 " $compare_frame .*"] != 0} {
     39      1.1  christos 	    continue
     40      1.1  christos 	}
     41      1.1  christos 	set info_frame_after ""
     42      1.1  christos 	gdb_test_multiple "info frame" "" {
     43      1.1  christos 	    -re "(.*\r\n$::gdb_prompt $)" {
     44      1.1  christos 		set info_frame_after $expect_out(1,string)
     45      1.1  christos 		pass $gdb_test_name
     46      1.1  christos 	    }
     47      1.1  christos 	}
     48      1.1  christos 
     49      1.1  christos 	# Nuke the PC address, since it'll be different.  The
     50      1.1  christos 	# first time it's the actual PC before the call, the
     51      1.1  christos 	# second time it's the resume address after the call
     52      1.1  christos 	# returns.
     53      1.1  christos 	# E.g., on x86-64:
     54      1.1  christos 	#   rip = 0x555555555168 in main (gdb.base/backtrace.c:41); saved rip = 0x7ffff7dd90b3
     55      1.1  christos 	# vs
     56      1.1  christos 	#   rip = 0x555555555172 in main (gdb.base/backtrace.c:41); saved rip = 0x7ffff7dd90b3
     57      1.1  christos 	#
     58      1.1  christos 	set from \
     59      1.1  christos 	    "= $::hex in $compare_frame "
     60      1.1  christos 	set to \
     61      1.1  christos 	    "= \$hex in $compare_frame "
     62      1.1  christos 	regsub $from $::info_frame_before($compare_frame) $to \
     63      1.1  christos 	    ::info_frame_before($compare_frame)
     64      1.1  christos 	regsub $from $info_frame_after $to \
     65      1.1  christos 	    info_frame_after
     66      1.1  christos 
     67      1.1  christos 	# Remove the "caller of frame at" line, which didn't
     68      1.1  christos 	# appear the first time, since the frame hadn't called any
     69      1.1  christos 	# other function yet then.
     70      1.1  christos 	regsub "\r\n caller of frame at $::hex\r\n" \
     71      1.1  christos 	    $info_frame_after "\r\n" \
     72      1.1  christos 	    info_frame_after
     73      1.1  christos 	regsub ", caller of frame at $::hex" \
     74      1.1  christos 	    $info_frame_after "" \
     75      1.1  christos 	    info_frame_after
     76      1.1  christos 
     77      1.1  christos 	# "Stack level 0/1/2/3" -> "Stack level N"
     78      1.1  christos 	set from \
     79      1.1  christos 	    "Stack level $::decimal"
     80      1.1  christos 	set to \
     81      1.1  christos 	    "Stack level N"
     82      1.1  christos 	regsub $from $::info_frame_before($compare_frame) $to \
     83      1.1  christos 	    ::info_frame_before($compare_frame)
     84      1.1  christos 	regsub $from $info_frame_after $to \
     85      1.1  christos 	    info_frame_after
     86      1.1  christos 
     87      1.1  christos 	# For debugging.
     88      1.1  christos 	verbose -log "BEFORE:\n$::info_frame_before($compare_frame)"
     89      1.1  christos 	verbose -log "AFTER:\n$info_frame_after"
     90      1.1  christos 
     91      1.1  christos 	gdb_assert {[string match \
     92      1.1  christos 			 $::info_frame_before($compare_frame)\
     93      1.1  christos 			 $info_frame_after]} \
     94      1.1  christos 	    "info frame before/after match"
     95      1.1  christos     }
     96      1.1  christos }
     97      1.1  christos 
     98      1.1  christos proc test {dwarf_unwinder} {
     99      1.1  christos 
    100      1.1  christos     clean_restart $::binfile
    101      1.1  christos 
    102      1.1  christos     gdb_test_no_output "maint set dwarf unwinder $dwarf_unwinder"
    103      1.1  christos 
    104      1.1  christos     if {![runto_main]} {
    105      1.1  christos 	return 0
    106      1.1  christos     }
    107      1.1  christos 
    108      1.1  christos     array unset ::info_frame_before
    109      1.1  christos 
    110      1.1  christos     # Run to each function, and record "info frame" output in the
    111      1.1  christos     # 'info_frame_before' array.  At each stop, unwind to each
    112      1.1  christos     # already-recorded function, and compare "info frame" output to
    113      1.1  christos     # what was saved in the 'info_frame_before' array.
    114      1.1  christos     set funcs {"main" "foo" "bar" "baz"}
    115      1.1  christos     set idx_funcs 0
    116      1.1  christos     foreach_with_prefix stop_func $funcs {
    117      1.1  christos 	if {$idx_funcs != 0} {
    118      1.1  christos 	    gdb_breakpoint $stop_func
    119      1.1  christos 	    gdb_continue_to_breakpoint ".*$stop_func \(\).*"
    120      1.1  christos 	}
    121      1.1  christos 
    122      1.1  christos 	set ::info_frame_before($stop_func) ""
    123      1.1  christos 	gdb_test_multiple "info frame" "" {
    124      1.1  christos 	    -re "(.*\r\n$::gdb_prompt $)" {
    125      1.1  christos 		set ::info_frame_before($stop_func) $expect_out(1,string)
    126      1.1  christos 		pass $gdb_test_name
    127      1.1  christos 	    }
    128      1.1  christos 	}
    129      1.1  christos 
    130      1.1  christos 	if {$idx_funcs != 0} {
    131      1.1  christos 	    compare_frames [lreverse [lrange $funcs 0 $idx_funcs-1]]
    132      1.1  christos 	}
    133      1.1  christos 	incr idx_funcs
    134      1.1  christos     }
    135      1.1  christos }
    136      1.1  christos 
    137      1.1  christos foreach_with_prefix dwarf {"off" "on"} {
    138      1.1  christos     test $dwarf
    139      1.1  christos }
    140