| author | |
| committer | |
| log | 96fe97105108da6cdd631c69856cdb6a8a11cffd |
| tree | 85ff66adfc0f47b596d3c1773c8a7fac86083383 |
| parent | 3ab4d112e001398e6ba60a0497ecf9265d49f157 |
* Smaller startup sequence for ppc64
* Terminate the frame-pointer chain when executing _start
* Make the stack traces work on ppc64
* Make the stack traces coloured on ppc64, some ioctls numbers are
different and the whole set of constants should be audited.4 files changed, 51 insertions(+), 32 deletions(-)
lib/std/debug.zig+17-9| ... | @@ -327,9 +327,9 @@ pub fn writeStackTrace( | ... | @@ -327,9 +327,9 @@ pub fn writeStackTrace( |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | pub const StackIterator = struct { | 329 | pub const StackIterator = struct { |
| 330 | // Skip every frame before this address is found | 330 | // Skip every frame before this address is found. |
| 331 | first_address: ?usize, | 331 | first_address: ?usize, |
| 332 | // Last known value of the frame pointer register | 332 | // Last known value of the frame pointer register. |
| 333 | fp: usize, | 333 | fp: usize, |
| 334 | 334 | ||
| 335 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { | 335 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| ... | @@ -339,14 +339,19 @@ pub const StackIterator = struct { | ... | @@ -339,14 +339,19 @@ pub const StackIterator = struct { |
| 339 | }; | 339 | }; |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | // On some architectures such as x86 the frame pointer is the address where | 342 | // Negative offset of the saved BP wrt the frame pointer. |
| 343 | // the previous fp is stored, while on some other architectures such as | ||
| 344 | // RISC-V it points to the "top" of the frame, just above where the previous | ||
| 345 | // fp and the return address are stored. | ||
| 346 | const fp_offset = if (builtin.arch.isRISCV()) | 343 | const fp_offset = if (builtin.arch.isRISCV()) |
| 344 | // On RISC-V the frame pointer points to the top of the saved register | ||
| 345 | // area, on pretty much every other architecture it points to the stack | ||
| 346 | // slot where the previous frame pointer is saved. | ||
| 347 | 2 * @sizeOf(usize) | 347 | 2 * @sizeOf(usize) |
| 348 | else | 348 | else |
| 349 | 0; | 349 | 0; |
| 350 | // Positive offset of the saved PC wrt the frame pointer. | ||
| 351 | const pc_offset = if (builtin.arch == .powerpc64le) | ||
| 352 | 2 * @sizeOf(usize) | ||
| 353 | else | ||
| 354 | @sizeOf(usize); | ||
| 350 | 355 | ||
| 351 | pub fn next(self: *StackIterator) ?usize { | 356 | pub fn next(self: *StackIterator) ?usize { |
| 352 | var address = self.next_internal() orelse return null; | 357 | var address = self.next_internal() orelse return null; |
| ... | @@ -364,7 +369,7 @@ pub const StackIterator = struct { | ... | @@ -364,7 +369,7 @@ pub const StackIterator = struct { |
| 364 | fn next_internal(self: *StackIterator) ?usize { | 369 | fn next_internal(self: *StackIterator) ?usize { |
| 365 | const fp = math.sub(usize, self.fp, fp_offset) catch return null; | 370 | const fp = math.sub(usize, self.fp, fp_offset) catch return null; |
| 366 | 371 | ||
| 367 | // Sanity check | 372 | // Sanity check. |
| 368 | if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) | 373 | if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) |
| 369 | return null; | 374 | return null; |
| 370 | 375 | ||
| ... | @@ -373,11 +378,14 @@ pub const StackIterator = struct { | ... | @@ -373,11 +378,14 @@ pub const StackIterator = struct { |
| 373 | // Sanity check: the stack grows down thus all the parent frames must be | 378 | // Sanity check: the stack grows down thus all the parent frames must be |
| 374 | // be at addresses that are greater (or equal) than the previous one. | 379 | // be at addresses that are greater (or equal) than the previous one. |
| 375 | // A zero frame pointer often signals this is the last frame, that case | 380 | // A zero frame pointer often signals this is the last frame, that case |
| 376 | // is gracefully handled by the next call to next_internal | 381 | // is gracefully handled by the next call to next_internal. |
| 377 | if (new_fp != 0 and new_fp < self.fp) | 382 | if (new_fp != 0 and new_fp < self.fp) |
| 378 | return null; | 383 | return null; |
| 379 | 384 | ||
| 380 | const new_pc = @intToPtr(*const usize, fp + @sizeOf(usize)).*; | 385 | const new_pc = @intToPtr( |
| 386 | *const usize, | ||
| 387 | math.add(usize, fp, pc_offset) catch return null, | ||
| 388 | ).*; | ||
| 381 | 389 | ||
| 382 | self.fp = new_fp; | 390 | self.fp = new_fp; |
| 383 | 391 |
lib/std/os/bits/linux.zig+3-2| ... | @@ -29,6 +29,7 @@ pub usingnamespace @import("linux/prctl.zig"); | ... | @@ -29,6 +29,7 @@ pub usingnamespace @import("linux/prctl.zig"); |
| 29 | pub usingnamespace @import("linux/securebits.zig"); | 29 | pub usingnamespace @import("linux/securebits.zig"); |
| 30 | 30 | ||
| 31 | const is_mips = builtin.arch.isMIPS(); | 31 | const is_mips = builtin.arch.isMIPS(); |
| 32 | const is_ppc64 = builtin.arch.isPPC64(); | ||
| 32 | 33 | ||
| 33 | pub const pid_t = i32; | 34 | pub const pid_t = i32; |
| 34 | pub const fd_t = i32; | 35 | pub const fd_t = i32; |
| ... | @@ -540,8 +541,8 @@ pub const TIOCGPGRP = 0x540F; | ... | @@ -540,8 +541,8 @@ pub const TIOCGPGRP = 0x540F; |
| 540 | pub const TIOCSPGRP = 0x5410; | 541 | pub const TIOCSPGRP = 0x5410; |
| 541 | pub const TIOCOUTQ = if (is_mips) 0x7472 else 0x5411; | 542 | pub const TIOCOUTQ = if (is_mips) 0x7472 else 0x5411; |
| 542 | pub const TIOCSTI = 0x5412; | 543 | pub const TIOCSTI = 0x5412; |
| 543 | pub const TIOCGWINSZ = if (is_mips) 0x40087468 else 0x5413; | 544 | pub const TIOCGWINSZ = if (is_mips or is_ppc64) 0x40087468 else 0x5413; |
| 544 | pub const TIOCSWINSZ = if (is_mips) 0x80087467 else 0x5414; | 545 | pub const TIOCSWINSZ = if (is_mips or is_ppc64) 0x80087467 else 0x5414; |
| 545 | pub const TIOCMGET = 0x5415; | 546 | pub const TIOCMGET = 0x5415; |
| 546 | pub const TIOCMBIS = 0x5416; | 547 | pub const TIOCMBIS = 0x5416; |
| 547 | pub const TIOCMBIC = 0x5417; | 548 | pub const TIOCMBIC = 0x5417; |
lib/std/start.zig+24-21| ... | @@ -102,46 +102,49 @@ fn _start() callconv(.Naked) noreturn { | ... | @@ -102,46 +102,49 @@ fn _start() callconv(.Naked) noreturn { |
| 102 | 102 | ||
| 103 | switch (builtin.arch) { | 103 | switch (builtin.arch) { |
| 104 | .x86_64 => { | 104 | .x86_64 => { |
| 105 | starting_stack_ptr = asm ("" | 105 | starting_stack_ptr = asm volatile ( |
| 106 | \\ xor %%rbp, %%rbp | ||
| 106 | : [argc] "={rsp}" (-> [*]usize) | 107 | : [argc] "={rsp}" (-> [*]usize) |
| 107 | ); | 108 | ); |
| 108 | }, | 109 | }, |
| 109 | .i386 => { | 110 | .i386 => { |
| 110 | starting_stack_ptr = asm ("" | 111 | starting_stack_ptr = asm volatile ( |
| 112 | \\ xor %%ebp, %%ebp | ||
| 111 | : [argc] "={esp}" (-> [*]usize) | 113 | : [argc] "={esp}" (-> [*]usize) |
| 112 | ); | 114 | ); |
| 113 | }, | 115 | }, |
| 114 | .aarch64, .aarch64_be, .arm => { | 116 | .aarch64, .aarch64_be, .arm, .armeb => { |
| 115 | starting_stack_ptr = asm ("mov %[argc], sp" | 117 | starting_stack_ptr = asm volatile ( |
| 116 | : [argc] "=r" (-> [*]usize) | 118 | \\ mov fp, #0 |
| 119 | \\ mov lr, #0 | ||
| 120 | : [argc] "={sp}" (-> [*]usize) | ||
| 117 | ); | 121 | ); |
| 118 | }, | 122 | }, |
| 119 | .riscv64 => { | 123 | .riscv64 => { |
| 120 | starting_stack_ptr = asm ("mv %[argc], sp" | 124 | starting_stack_ptr = asm volatile ( |
| 121 | : [argc] "=r" (-> [*]usize) | 125 | \\ li s0, 0 |
| 126 | \\ li ra, 0 | ||
| 127 | : [argc] "={sp}" (-> [*]usize) | ||
| 122 | ); | 128 | ); |
| 123 | }, | 129 | }, |
| 124 | .mips, .mipsel => { | 130 | .mips, .mipsel => { |
| 125 | // Need noat here because LLVM is free to pick any register | 131 | // The lr is already zeroed on entry, as specified by the ABI. |
| 126 | starting_stack_ptr = asm ( | 132 | starting_stack_ptr = asm volatile ( |
| 127 | \\ .set noat | 133 | \\ move $fp, $0 |
| 128 | \\ move %[argc], $sp | 134 | : [argc] "={sp}" (-> [*]usize) |
| 129 | : [argc] "=r" (-> [*]usize) | ||
| 130 | ); | 135 | ); |
| 131 | }, | 136 | }, |
| 132 | .powerpc64le => { | 137 | .powerpc64le => { |
| 133 | // Before returning the stack pointer, we have to set up a backchain | 138 | // Setup the initial stack frame and clear the back chain pointer. |
| 134 | // and a few other registers required by the ELFv2 ABI. | ||
| 135 | // TODO: Support powerpc64 (big endian) on ELFv2. | 139 | // TODO: Support powerpc64 (big endian) on ELFv2. |
| 136 | starting_stack_ptr = asm ( | 140 | starting_stack_ptr = asm volatile ( |
| 137 | \\ mr 4, 1 | 141 | \\ mr 4, 1 |
| 138 | \\ subi 1, 1, 32 | 142 | \\ li 0, 0 |
| 139 | \\ li 5, 0 | 143 | \\ stdu 0, -32(1) |
| 140 | \\ std 5, 0(1) | 144 | \\ mtlr 0 |
| 141 | \\ mr %[argc], 4 | 145 | : [argc] "={r4}" (-> [*]usize) |
| 142 | : [argc] "=r" (-> [*]usize) | ||
| 143 | : | 146 | : |
| 144 | : "r4", "r5" | 147 | : "r0" |
| 145 | ); | 148 | ); |
| 146 | }, | 149 | }, |
| 147 | else => @compileError("unsupported arch"), | 150 | else => @compileError("unsupported arch"), |
lib/std/target.zig+7| ... | @@ -735,6 +735,13 @@ pub const Target = struct { | ... | @@ -735,6 +735,13 @@ pub const Target = struct { |
| 735 | }; | 735 | }; |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | pub fn isPPC64(arch: Arch) bool { | ||
| 739 | return switch (arch) { | ||
| 740 | .powerpc64, .powerpc64le => true, | ||
| 741 | else => false, | ||
| 742 | }; | ||
| 743 | } | ||
| 744 | |||
| 738 | pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { | 745 | pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { |
| 739 | for (arch.allCpuModels()) |cpu| { | 746 | for (arch.allCpuModels()) |cpu| { |
| 740 | if (mem.eql(u8, cpu_name, cpu.name)) { | 747 | if (mem.eql(u8, cpu_name, cpu.name)) { |