pc-verify.exp   [plain text]


# 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