| author | |
| committer | |
| log | e02655798fbd97a069ee8be38a6eceac18335a4d |
| tree | 29cd77dacb2f60f1258cdfd6a7e00e7d52735d82 |
| parent | e6ac082437b87fccf6a7e592f813d3403427e512 |
| parent | 39e34081ca9ed3bee0b850bdbf44068b163d1062 |
| signature |
Some ppc64 stuff5 files changed, 54 insertions(+), 35 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| ... | @@ -754,6 +754,13 @@ pub const Target = struct { | ... | @@ -754,6 +754,13 @@ pub const Target = struct { |
| 754 | }; | 754 | }; |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | pub fn isPPC64(arch: Arch) bool { | ||
| 758 | return switch (arch) { | ||
| 759 | .powerpc64, .powerpc64le => true, | ||
| 760 | else => false, | ||
| 761 | }; | ||
| 762 | } | ||
| 763 | |||
| 757 | pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { | 764 | pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { |
| 758 | for (arch.allCpuModels()) |cpu| { | 765 | for (arch.allCpuModels()) |cpu| { |
| 759 | if (mem.eql(u8, cpu_name, cpu.name)) { | 766 | if (mem.eql(u8, cpu_name, cpu.name)) { |
test/stack_traces.zig+3-3| ... | @@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void { | ... | @@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 282 | \\source.zig:10:8: [address] in main (test) | 282 | \\source.zig:10:8: [address] in main (test) |
| 283 | \\ foo(); | 283 | \\ foo(); |
| 284 | \\ ^ | 284 | \\ ^ |
| 285 | \\start.zig:319:29: [address] in std.start.posixCallMainAndExit (test) | 285 | \\start.zig:322:29: [address] in std.start.posixCallMainAndExit (test) |
| 286 | \\ return root.main(); | 286 | \\ return root.main(); |
| 287 | \\ ^ | 287 | \\ ^ |
| 288 | \\start.zig:151:5: [address] in std.start._start (test) | 288 | \\start.zig:154:5: [address] in std.start._start (test) |
| 289 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); | 289 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 290 | \\ ^ | 290 | \\ ^ |
| 291 | \\ | 291 | \\ |
| ... | @@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { | ... | @@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 294 | switch (std.Target.current.cpu.arch) { | 294 | switch (std.Target.current.cpu.arch) { |
| 295 | .aarch64 => "", // TODO disabled; results in segfault | 295 | .aarch64 => "", // TODO disabled; results in segfault |
| 296 | else => | 296 | else => |
| 297 | \\start.zig:151:5: [address] in std.start._start (test) | 297 | \\start.zig:154:5: [address] in std.start._start (test) |
| 298 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); | 298 | \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); |
| 299 | \\ ^ | 299 | \\ ^ |
| 300 | \\ | 300 | \\ |