# Copyright 2002 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 2 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # This file was written by Jason Molenda (jmolenda@apple.com) # This file looks at $pc via different mechanisms as we go up and down the # stack. If the pc is consistently wrong, this test won't flag any failures, # but if the pc is reported differently, we can catch that. if $tracelevel then { strace $tracelevel } set prms_id 0 set bug_id 0 set testfile "pc-verify" set srcfile ${testfile}.c set binfile ${objdir}/${subdir}/${testfile} global hex if { [gdb_compile "${srcdir}/${subdir}/$srcfile" "${binfile}" executable {debug}] != "" } { gdb_suppress_entire_file "Testcase compile failed, so all tests in this fil e will automatically fail." } # Start with a fresh gdb gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} if ![runto_main] then { fail "pc-verify tests suppressed" return -1 } ##### ##### Gather some information in main() before we call into a subroutine. ##### gdb_test "next" ".*factorial.*" "next over boring line" send_gdb "info line\n" gdb_expect { -re ".*Line.*starts at address ($hex) .*ends at ($hex) <main.$decimal>.\[\r\n\]*$gdb_prompt $" { set main_info_line_start $expect_out(1,string) set main_info_line_end $expect_out(2,string) pass "info line in main()." } -re ".*$gdb_prompt $" { fail "info line in main()." } timeout { fail "info line in main(). (timeout)" } } #warning "got pc value of $main_info_line_start\n" send_gdb "p/x \$pc\n" gdb_expect { -re ".*$decimal = ($hex)\[\r\n\]*$gdb_prompt $" { set main_cur_pc $expect_out(1,string) pass "Get pc value in main() #1" } -re ".*$gdb_prompt $" { fail "Get pc value in main() #1" } timeout { fail "Get pc value in main() #1 (timeout)" } } send_gdb "p/x \$fp\n" gdb_expect { -re ".*$decimal = ($hex)\[\r\n\]*$gdb_prompt $" { set main_cur_fp $expect_out(1,string) pass "Get fp value in main() #1" } -re ".*$gdb_prompt $" { fail "Get fp value in main() #1" } timeout { fail "Get fp value in main() #1 (timeout)" } } send_gdb "info fr\n" gdb_expect { -re ".*Stack level 0, frame at ($hex):.*(pc|eip|rip) = ($hex) in main.*$gdb_prompt $" { set main_current_fp_from_info_frame $expect_out(1,string) set main_current_pc_from_info_frame $expect_out(3,string) pass "info frame in main #1." } -re ".*$gdb_prompt $" { fail "info frame in main #1." } timeout { fail "info frame in main #1. (timeout)" } } if {$main_current_pc_from_info_frame != $main_cur_pc} then { fail "p/x \$pc returns the same as info frame's \$pc" } else { pass "p/x \$pc returns the same as info frame's \$pc" } # on x86, $fp (aka EBP) points two words into the stack frame. # info frame will report the correct frame address, which starts # with the saved EIP, then the saved ESP. EBP points to the # space below that. So for the sake of this comparison add the # offset to EBP so it matches info frame's output. if [istarget "i\[3-6\]86-apple-darwin*"] { set offset 8 } else { set offset 0 } if {$main_current_fp_from_info_frame != $main_cur_fp + $offset} then { fail "p/x \$fp returns the same as info frame's \$fp" } else { pass "p/x \$fp returns the same as info frame's \$fp" } ##### ##### Call into factorial(), see if the numbers make sense down there. ##### gdb_test "step" ".*factorial.*" "step into factorial" send_gdb "bt\n" gdb_expect { -re ".*#0 *factorial.*#1 *($hex) in main.*$gdb_prompt $" { set main_calling_pc_from_backtrace $expect_out(1,string) pass "backtrace in factorial level 1." } -re ".*$gdb_prompt $" { fail "backtrace in factorial level 1." } timeout { fail "backtrace in factorial level 1. (timeout)" } } if { $main_calling_pc_from_backtrace < $main_info_line_start || \ $main_calling_pc_from_backtrace > $main_info_line_end } then { fail "pc from backtrace is within info line range" } else { pass "pc from backtrace is within info line range" } send_gdb "info fr\n" gdb_expect { -re "Stack level 0, frame at ($hex).*(pc|eip|rip) = ($hex) in factorial.*saved (pc|eip|rip) ($hex).*$gdb_prompt $" { set factorial_info_frame_fp $expect_out(1,string) set factorial_info_frame_pc $expect_out(3,string) set factorial_info_frame_saved_pc $expect_out(5,string) pass "info frame in factorial" } -re ".*$gdb_prompt $" { fail "info frame in factorial" } timeout { fail info frame in factorial. (timeout)" } } if { $factorial_info_frame_saved_pc < $main_info_line_start || \ $factorial_info_frame_saved_pc > $main_info_line_end } then { fail "pc from info frame in factorial is within info line range" } else { pass "pc from info frame in factorial is within info line range" } gdb_test "up" ".*in main.*" "change frame back to main" send_gdb "p/x \$pc\n" gdb_expect { -re ".*$decimal = ($hex)\[\r\n\]*$gdb_prompt $" { set new_main_pc $expect_out(1,string) pass "Get pc value in main() #2" } -re ".*$gdb_prompt $" { fail "Get pc value in main() #2" } timeout { fail "Get pc value in main() #2 (timeout)" } } if {$new_main_pc == $factorial_info_frame_saved_pc} then { pass "\$pc in main is the same as the saved pc from factorial" } else { fail "\$pc in main is the same as the saved pc from factorial" } if { $new_main_pc < $main_info_line_start || \ $new_main_pc > $main_info_line_end } then { fail "p/x \$pc at stack level 1 reports pc within correct range" } else { pass "p/x \$pc at stack level 1 reports pc within correct range" } gdb_exit return 0