| # 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 |