| ... | @@ -938,8 +938,8 @@ const StackIterator = union(enum) { | ... | @@ -938,8 +938,8 @@ const StackIterator = union(enum) { |
| 938 | .fp => |fp| { | 938 | .fp => |fp| { |
| 939 | if (fp == 0) return .end; // we reached the "sentinel" base pointer | 939 | if (fp == 0) return .end; // we reached the "sentinel" base pointer |
| 940 | | 940 | |
| 941 | const bp_addr = applyOffset(fp, bp_offset) orelse return .end; | 941 | const bp_addr = applyOffset(fp, fp_to_bp_offset) orelse return .end; |
| 942 | const ra_addr = applyOffset(fp, ra_offset) orelse return .end; | 942 | const ra_addr = applyOffset(fp, fp_to_ra_offset) orelse return .end; |
| 943 | | 943 | |
| 944 | if (bp_addr == 0 or !mem.isAligned(bp_addr, @alignOf(usize)) or | 944 | if (bp_addr == 0 or !mem.isAligned(bp_addr, @alignOf(usize)) or |
| 945 | ra_addr == 0 or !mem.isAligned(ra_addr, @alignOf(usize))) | 945 | ra_addr == 0 or !mem.isAligned(ra_addr, @alignOf(usize))) |
| ... | @@ -950,7 +950,7 @@ const StackIterator = union(enum) { | ... | @@ -950,7 +950,7 @@ const StackIterator = union(enum) { |
| 950 | | 950 | |
| 951 | const bp_ptr: *const usize = @ptrFromInt(bp_addr); | 951 | const bp_ptr: *const usize = @ptrFromInt(bp_addr); |
| 952 | const ra_ptr: *const usize = @ptrFromInt(ra_addr); | 952 | const ra_ptr: *const usize = @ptrFromInt(ra_addr); |
| 953 | const bp = applyOffset(bp_ptr.*, bp_bias) orelse return .end; | 953 | const bp = applyOffset(bp_ptr.*, stack_bias) orelse return .end; |
| 954 | | 954 | |
| 955 | // The stack grows downards, so `bp > fp` should always hold. If it doesn't, this | 955 | // The stack grows downards, so `bp > fp` should always hold. If it doesn't, this |
| 956 | // frame is invalid, so we'll treat it as though it we reached end of stack. The | 956 | // frame is invalid, so we'll treat it as though it we reached end of stack. The |
| ... | @@ -967,29 +967,35 @@ const StackIterator = union(enum) { | ... | @@ -967,29 +967,35 @@ const StackIterator = union(enum) { |
| 967 | } | 967 | } |
| 968 | | 968 | |
| 969 | /// Offset of the saved base pointer (previous frame pointer) wrt the frame pointer. | 969 | /// Offset of the saved base pointer (previous frame pointer) wrt the frame pointer. |
| 970 | const bp_offset = off: { | 970 | const fp_to_bp_offset = off: { |
| 971 | // On RISC-V the frame pointer points to the top of the saved register | 971 | // On LoongArch and RISC-V, the frame pointer points to the top of the saved register area, |
| 972 | // area, on pretty much every other architecture it points to the stack | 972 | // in which the base pointer is the first word. |
| 973 | // slot where the previous frame pointer is saved. | | |
| 974 | if (native_arch.isLoongArch() or native_arch.isRISCV()) break :off -2 * @sizeOf(usize); | 973 | if (native_arch.isLoongArch() or native_arch.isRISCV()) break :off -2 * @sizeOf(usize); |
| 975 | // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. | 974 | // On SPARC, the frame pointer points to the save area which holds 16 slots for the local |
| | 975 | // and incoming registers. The base pointer (i6) is stored in its customary save slot. |
| 976 | if (native_arch.isSPARC()) break :off 14 * @sizeOf(usize); | 976 | if (native_arch.isSPARC()) break :off 14 * @sizeOf(usize); |
| | 977 | // Everywhere else, the frame pointer points directly to the location of the base pointer. |
| 977 | break :off 0; | 978 | break :off 0; |
| 978 | }; | 979 | }; |
| 979 | | 980 | |
| 980 | /// Offset of the saved return address wrt the frame pointer. | 981 | /// Offset of the saved return address wrt the frame pointer. |
| 981 | const ra_offset = off: { | 982 | const fp_to_ra_offset = off: { |
| 982 | if (native_arch.isLoongArch() or native_arch.isRISCV()) break :off -1 * @sizeOf(usize); | 983 | // On LoongArch and RISC-V, the frame pointer points to the top of the saved register area, |
| 983 | if (native_arch.isSPARC()) break :off 15 * @sizeOf(usize); | 984 | // in which the return address is the second word. |
| | 985 | if (native_arch.isRISCV() or native_arch.isLoongArch()) break :off -1 * @sizeOf(usize); |
| 984 | if (native_arch.isPowerPC64()) break :off 2 * @sizeOf(usize); | 986 | if (native_arch.isPowerPC64()) break :off 2 * @sizeOf(usize); |
| 985 | // On s390x, r14 is the link register and we need to grab it from its customary slot in the | 987 | // On s390x, r14 is the link register and we need to grab it from its customary slot in the |
| 986 | // register save area (ELF ABI s390x Supplement §1.2.2.2). | 988 | // register save area (ELF ABI s390x Supplement §1.2.2.2). |
| 987 | if (native_arch == .s390x) break :off 14 * @sizeOf(usize); | 989 | if (native_arch == .s390x) break :off 14 * @sizeOf(usize); |
| | 990 | // On SPARC, the frame pointer points to the save area which holds 16 slots for the local |
| | 991 | // and incoming registers. The return address (i7) is stored in its customary save slot. |
| | 992 | if (native_arch.isSPARC()) break :off 15 * @sizeOf(usize); |
| 988 | break :off @sizeOf(usize); | 993 | break :off @sizeOf(usize); |
| 989 | }; | 994 | }; |
| 990 | | 995 | |
| 991 | /// Value to add to a base pointer after loading it from the stack. Yes, SPARC really does this. | 996 | /// Value to add to the stack pointer and frame/base pointers to get the real location being |
| 992 | const bp_bias = bias: { | 997 | /// pointed to. Yes, SPARC really does this. |
| | 998 | const stack_bias = bias: { |
| 993 | if (native_arch.isSPARC()) break :bias 2047; | 999 | if (native_arch.isSPARC()) break :bias 2047; |
| 994 | break :bias 0; | 1000 | break :bias 0; |
| 995 | }; | 1001 | }; |