try
{
- /* Cache base will be %esp plus cache->sp_offset (-8). */
+ /* Cache base will be %rsp plus cache->sp_offset (-8). */
get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8,
byte_order) + cache->sp_offset;
/* Cache pc will be the frame func. */
- cache->pc = get_frame_pc (this_frame);
+ cache->pc = get_frame_func (this_frame);
- /* The saved %esp will be at cache->base plus 16. */
+ /* The previous value of %rsp is cache->base plus 16. */
cache->saved_sp = cache->base + 16;
- /* The saved %eip will be at cache->base plus 8. */
+ /* The saved %rip will be at cache->base plus 8. */
cache->saved_regs[AMD64_RIP_REGNUM] = cache->base + 8;
cache->base_p = 1;
if (!cache->base_p)
(*this_id) = frame_id_build_unavailable_stack (cache->pc);
else
- (*this_id) = frame_id_build (cache->base + 8, cache->pc);
+ (*this_id) = frame_id_build (cache->base + 16, cache->pc);
}
static const struct frame_unwind amd64_epilogue_frame_unwind =
--- /dev/null
+# Copyright 2022 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/>. */
+
+# Single step through a simple (empty) function that was compiled
+# without DWARF debug information.
+#
+# At each instruction check that the frame-id, and frame base address,
+# are calculated correctly.
+#
+# Additionally, check we can correctly unwind to the previous frame,
+# and that the previous stack-pointer value, and frame base address
+# value, can be calculated correctly.
+
+standard_testfile .c -foo.c
+
+if {[prepare_for_testing_full "failed to prepare" \
+ [list ${testfile} debug \
+ $srcfile {debug} $srcfile2 {nodebug}]]} {
+ return -1
+}
+
+if ![runto_main] then {
+ return 0
+}
+
+# Return a two element list, the first element is the stack-pointer
+# value (from the $sp register), and the second element is the frame
+# base address (from the 'info frame' output).
+proc get_sp_and_fba { testname } {
+ with_test_prefix "get \$sp and frame base $testname" {
+ set sp [get_hexadecimal_valueof "\$sp" "*UNKNOWN*"]
+
+ set fba ""
+ gdb_test_multiple "info frame" "" {
+ -re "^info frame\r\n" {
+ exp_continue
+ }
+
+ -re "^Stack level ${::decimal}, frame at ($::hex):\r\n.*$::gdb_prompt $" {
+ set fba $expect_out(1,string)
+ }
+ }
+
+ return [list $sp $fba]
+ }
+}
+
+# Return the frame-id of the current frame, collected using the 'maint
+# print frame-id' command.
+proc get_fid { } {
+ set fid ""
+ gdb_test_multiple "maint print frame-id" "" {
+ -re "^maint print frame-id\r\n" {
+ exp_continue
+ }
+
+ -re "^frame-id for frame #${::decimal}: (\[^\r\n\]+).*" {
+ set fid $expect_out(1,string)
+ }
+ }
+ return $fid
+}
+
+# Record the current stack-pointer, and the frame base address.
+lassign [get_sp_and_fba "in main"] main_sp main_fba
+set main_fid [get_fid]
+
+# Now enter the foo function.
+gdb_breakpoint "*foo"
+gdb_continue_to_breakpoint "enter foo"
+
+# Figure out the range of addresses covered by this function.
+set last_addr_in_foo ""
+gdb_test_multiple "disassemble foo" "" {
+ -re "^disassemble foo\r\n" {
+ exp_continue
+ }
+
+ -re "^Dump of assembler code for function foo:\r\n" {
+ exp_continue
+ }
+
+ -re "^...($hex) \[^\r\n\]+\r\n" {
+ set last_addr_in_foo $expect_out(1,string)
+ exp_continue
+ }
+
+ -wrap -re "^End of assembler dump\\." {
+ gdb_assert { ![string equal $last_addr_in_foo ""] } \
+ "found some addresses in foo"
+ pass $gdb_test_name
+ }
+}
+
+# Record the current stack-pointer, and the frame base address.
+lassign [get_sp_and_fba "in foo"] foo_sp foo_fba
+set foo_fid [get_fid]
+
+for { set i_count 1 } { true } { incr i_count } {
+ with_test_prefix "instruction ${i_count}" {
+
+ # The current stack-pointer value can legitimately change
+ # throughout the lifetime of a function, so we don't check the
+ # current stack-pointer value. But the frame base address
+ # should not change, so we do check for that.
+ lassign [get_sp_and_fba "for foo"] sp_value fba_value
+ gdb_assert { $fba_value == $foo_fba }
+
+ # The frame-id should never change within a function, so check
+ # that now.
+ set fid [get_fid]
+ gdb_assert { [string equal $fid $foo_fid] } \
+ "check frame-id matches"
+
+ # Check that the previous frame is 'main'.
+ gdb_test "bt 2" "\r\n#1\\s+\[^\r\n\]+ in main \\(\\) .*"
+
+ # Move up the stack (to main).
+ gdb_test "up" \
+ "\r\n#1\\s+\[^\r\n\]+ in main \\(\\) .*"
+
+ # Check we can unwind the stack-pointer and the frame base
+ # address correctly.
+ lassign [get_sp_and_fba "for main"] sp_value fba_value
+ gdb_assert { $sp_value == $main_sp }
+ gdb_assert { $fba_value == $main_fba }
+
+ # Check we have a consistent value for main's frame-id.
+ set fid [get_fid]
+ gdb_assert { [string equal $fid $main_fid] }
+
+ # Move back to the inner most frame.
+ gdb_test "frame 0" ".*"
+
+ set pc [get_hexadecimal_valueof "\$pc" "*UNKNOWN*"]
+ if { $pc == $last_addr_in_foo } {
+ break
+ }
+
+ gdb_test "stepi" ".*"
+ }
+}