| ... | @@ -697,7 +697,7 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ | ... | @@ -697,7 +697,7 @@ pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_ |
| 697 | var printed_any_frame = false; | 697 | var printed_any_frame = false; |
| 698 | while (true) switch (it.next()) { | 698 | while (true) switch (it.next()) { |
| 699 | .switch_to_fp => |unwind_error| { | 699 | .switch_to_fp => |unwind_error| { |
| 700 | if (StackIterator.fp_unwind_is_safe) continue; // no need to even warn | 700 | if (StackIterator.abi_requires_backchain or StackIterator.fp_unwind_is_safe) continue; // no need to even warn |
| 701 | const module_name = di.getModuleName(di_gpa, unwind_error.address) catch "???"; | 701 | const module_name = di.getModuleName(di_gpa, unwind_error.address) catch "???"; |
| 702 | const caption: []const u8 = switch (unwind_error.err) { | 702 | const caption: []const u8 = switch (unwind_error.err) { |
| 703 | error.MissingDebugInfo => "unwind info unavailable", | 703 | error.MissingDebugInfo => "unwind info unavailable", |
| ... | @@ -855,10 +855,22 @@ const StackIterator = union(enum) { | ... | @@ -855,10 +855,22 @@ const StackIterator = union(enum) { |
| 855 | } | 855 | } |
| 856 | } | 856 | } |
| 857 | | 857 | |
| 858 | /// On aarch64-macos, Apple mandate that the frame pointer is always used. | 858 | /// <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Respect-the-purpose-of-specific-CPU-registers> |
| 859 | /// TODO: are there any other architectures with guarantees like this? | | |
| 860 | const fp_unwind_is_safe = builtin.cpu.arch == .aarch64 and builtin.os.tag.isDarwin(); | 859 | const fp_unwind_is_safe = builtin.cpu.arch == .aarch64 and builtin.os.tag.isDarwin(); |
| 861 | | 860 | |
| | 861 | /// On some architectures, we can do FP unwinding even with `-fomit-frame-pointer` due to ABI |
| | 862 | /// requirements. Typically this is because the ABI requires a backchain regardless of whether |
| | 863 | /// codegen actually uses a frame pointer for stack frame access. |
| | 864 | const abi_requires_backchain = switch (builtin.cpu.arch) { |
| | 865 | .hexagon, |
| | 866 | .powerpc, |
| | 867 | .powerpcle, |
| | 868 | .powerpc64, |
| | 869 | .powerpc64le, |
| | 870 | => true, |
| | 871 | else => false, |
| | 872 | }; |
| | 873 | |
| 862 | /// Whether the current unwind strategy is allowed given `allow_unsafe`. | 874 | /// Whether the current unwind strategy is allowed given `allow_unsafe`. |
| 863 | fn stratOk(it: *const StackIterator, allow_unsafe: bool) bool { | 875 | fn stratOk(it: *const StackIterator, allow_unsafe: bool) bool { |
| 864 | return switch (it.*) { | 876 | return switch (it.*) { |
| ... | @@ -867,7 +879,7 @@ const StackIterator = union(enum) { | ... | @@ -867,7 +879,7 @@ const StackIterator = union(enum) { |
| 867 | // immediately regardless of anything. But FPs could also be omitted from a different | 879 | // immediately regardless of anything. But FPs could also be omitted from a different |
| 868 | // linked object, so it's not guaranteed to be safe, unless the target specifically | 880 | // linked object, so it's not guaranteed to be safe, unless the target specifically |
| 869 | // requires it. | 881 | // requires it. |
| 870 | .fp => !builtin.omit_frame_pointer and (fp_unwind_is_safe or allow_unsafe), | 882 | .fp => abi_requires_backchain or (!builtin.omit_frame_pointer and (fp_unwind_is_safe or allow_unsafe)), |
| 871 | }; | 883 | }; |
| 872 | } | 884 | } |
| 873 | | 885 | |