| ... | ... | @@ -938,8 +938,8 @@ const StackIterator = union(enum) { |
| 938 | 938 | .fp => |fp| { |
| 939 | 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; |
| 942 | | const ra_addr = applyOffset(fp, ra_offset) orelse return .end; |
| 941 | const bp_addr = applyOffset(fp, fp_to_bp_offset) orelse return .end; |
| 942 | const ra_addr = applyOffset(fp, fp_to_ra_offset) orelse return .end; |
| 943 | 943 | |
| 944 | 944 | if (bp_addr == 0 or !mem.isAligned(bp_addr, @alignOf(usize)) or |
| 945 | 945 | ra_addr == 0 or !mem.isAligned(ra_addr, @alignOf(usize))) |
| ... | ... | @@ -950,7 +950,7 @@ const StackIterator = union(enum) { |
| 950 | 950 | |
| 951 | 951 | const bp_ptr: *const usize = @ptrFromInt(bp_addr); |
| 952 | 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 | 955 | // The stack grows downards, so `bp > fp` should always hold. If it doesn't, this |
| 956 | 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 | 967 | } |
| 968 | 968 | |
| 969 | 969 | /// Offset of the saved base pointer (previous frame pointer) wrt the frame pointer. |
| 970 | | const bp_offset = off: { |
| 971 | | // On RISC-V the frame pointer points to the top of the saved register |
| 972 | | // area, on pretty much every other architecture it points to the stack |
| 973 | | // slot where the previous frame pointer is saved. |
| 970 | const fp_to_bp_offset = off: { |
| 971 | // On LoongArch and RISC-V, the frame pointer points to the top of the saved register area, |
| 972 | // in which the base pointer is the first word. |
| 974 | 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 | 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 | 978 | break :off 0; |
| 978 | 979 | }; |
| 979 | 980 | |
| 980 | 981 | /// Offset of the saved return address wrt the frame pointer. |
| 981 | | const ra_offset = off: { |
| 982 | | if (native_arch.isLoongArch() or native_arch.isRISCV()) break :off -1 * @sizeOf(usize); |
| 983 | | if (native_arch.isSPARC()) break :off 15 * @sizeOf(usize); |
| 982 | const fp_to_ra_offset = off: { |
| 983 | // On LoongArch and RISC-V, the frame pointer points to the top of the saved register area, |
| 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 | 986 | if (native_arch.isPowerPC64()) break :off 2 * @sizeOf(usize); |
| 985 | 987 | // On s390x, r14 is the link register and we need to grab it from its customary slot in the |
| 986 | 988 | // register save area (ELF ABI s390x Supplement §1.2.2.2). |
| 987 | 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 | 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. |
| 992 | | const bp_bias = bias: { |
| 996 | /// Value to add to the stack pointer and frame/base pointers to get the real location being |
| 997 | /// pointed to. Yes, SPARC really does this. |
| 998 | const stack_bias = bias: { |
| 993 | 999 | if (native_arch.isSPARC()) break :bias 2047; |
| 994 | 1000 | break :bias 0; |
| 995 | 1001 | }; |