authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-10 18:43:19-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:15-04:00
log891fa3b8b54428ad8065de8660869cd38876e429
tree9b6fbdcfe1a87ce2b00335f51c76b1bba05129f5
parent5dfb159e15dc7c66118d47a06536d61f65522bb9

debug: fix initialization of the optional fields on StackIterator

dwarf: documentation fixups target: enable unwind tables on macho

6 files changed, 53 insertions(+), 51 deletions(-)

lib/std/debug.zig+41-39
...@@ -159,7 +159,7 @@ pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void {...@@ -159,7 +159,7 @@ pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void {
159 relocateContext(dest);159 relocateContext(dest);
160}160}
161161
162/// Updates any internal points in the context to reflect its current location162/// Updates any internal pointers in the context to reflect its current location
163pub fn relocateContext(context: *ThreadContext) void {163pub fn relocateContext(context: *ThreadContext) void {
164 return switch (native_os) {164 return switch (native_os) {
165 .macos => {165 .macos => {
...@@ -176,7 +176,7 @@ pub const have_getcontext = @hasDecl(os.system, "getcontext") and...@@ -176,7 +176,7 @@ pub const have_getcontext = @hasDecl(os.system, "getcontext") and
176});176});
177177
178/// Capture the current context. The register values in the context will reflect the178/// Capture the current context. The register values in the context will reflect the
179/// state after the platform `getcontext` function returned.179/// state after the platform `getcontext` function returns.
180///180///
181/// It is valid to call this if the platform doesn't have context capturing support,181/// It is valid to call this if the platform doesn't have context capturing support,
182/// in that case false will be returned.182/// in that case false will be returned.
...@@ -229,7 +229,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {...@@ -229,7 +229,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {
229229
230 var it = StackIterator.initWithContext(null, debug_info, context) catch return;230 var it = StackIterator.initWithContext(null, debug_info, context) catch return;
231 defer it.deinit();231 defer it.deinit();
232 printSourceAtAddress(debug_info, stderr, it.dwarf_context.pc, tty_config) catch return;232 printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return;
233233
234 while (it.next()) |return_address| {234 while (it.next()) |return_address| {
235 if (it.getLastError()) |unwind_error|235 if (it.getLastError()) |unwind_error|
...@@ -487,11 +487,13 @@ pub const StackIterator = struct {...@@ -487,11 +487,13 @@ pub const StackIterator = struct {
487 fp: usize,487 fp: usize,
488488
489 // When DebugInfo and a register context is available, this iterator can unwind489 // When DebugInfo and a register context is available, this iterator can unwind
490 // stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer).490 // stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer),
491 debug_info: ?*DebugInfo,491 // using DWARF and MachO unwind info.
492 dwarf_context: if (have_ucontext) DW.UnwindContext else void = undefined,492 unwind_state: if (have_ucontext) ?struct {
493 last_error: if (have_ucontext) ?UnwindError else void = undefined,493 debug_info: *DebugInfo,
494 last_error_address: if (have_ucontext) usize else void = undefined,494 dwarf_context: DW.UnwindContext,
495 last_error: ?UnwindError = null,
496 } else void = if (have_ucontext) null else {},
495497
496 pub fn init(first_address: ?usize, fp: ?usize) StackIterator {498 pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
497 if (native_arch == .sparc64) {499 if (native_arch == .sparc64) {
...@@ -504,32 +506,33 @@ pub const StackIterator = struct {...@@ -504,32 +506,33 @@ pub const StackIterator = struct {
504 return StackIterator{506 return StackIterator{
505 .first_address = first_address,507 .first_address = first_address,
506 .fp = fp orelse @frameAddress(),508 .fp = fp orelse @frameAddress(),
507 .debug_info = null,
508 };509 };
509 }510 }
510511
511 pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {512 pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {
512 var iterator = init(first_address, null);513 var iterator = init(first_address, null);
513 iterator.debug_info = debug_info;514 iterator.unwind_state = .{
514 iterator.dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory);515 .debug_info = debug_info,
515 iterator.last_error = null;516 .dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory),
517 };
518
516 return iterator;519 return iterator;
517 }520 }
518521
519 pub fn deinit(self: *StackIterator) void {522 pub fn deinit(self: *StackIterator) void {
520 if (have_ucontext and self.debug_info != null) self.dwarf_context.deinit();523 if (have_ucontext and self.unwind_state != null) self.unwind_state.?.dwarf_context.deinit();
521 }524 }
522525
523 pub fn getLastError(self: *StackIterator) ?struct {526 pub fn getLastError(self: *StackIterator) ?struct {
524 address: usize,
525 err: UnwindError,527 err: UnwindError,
528 address: usize,
526 } {529 } {
527 if (have_ucontext) {530 if (!have_ucontext) return null;
528 if (self.last_error) |err| {531 if (self.unwind_state) |*unwind_state| {
529 self.last_error = null;532 if (unwind_state.last_error) |err| {
530 return .{533 return .{
531 .address = self.last_error_address,
532 .err = err,534 .err = err,
535 .address = unwind_state.dwarf_context.pc,
533 };536 };
534 }537 }
535 }538 }
...@@ -620,13 +623,14 @@ pub const StackIterator = struct {...@@ -620,13 +623,14 @@ pub const StackIterator = struct {
620 }623 }
621624
622 fn next_unwind(self: *StackIterator) !usize {625 fn next_unwind(self: *StackIterator) !usize {
623 const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc);626 const unwind_state = &self.unwind_state.?;
627 const module = try unwind_state.debug_info.getModuleForAddress(unwind_state.dwarf_context.pc);
624 switch (native_os) {628 switch (native_os) {
625 .macos, .ios, .watchos, .tvos => {629 .macos, .ios, .watchos, .tvos => {
626 // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding630 // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding
627 // via DWARF before attempting to use the compact unwind info will produce incorrect results.631 // via DWARF before attempting to use the compact unwind info will produce incorrect results.
628 if (module.unwind_info) |unwind_info| {632 if (module.unwind_info) |unwind_info| {
629 if (macho.unwindFrame(&self.dwarf_context, unwind_info, module.base_address)) |return_address| {633 if (macho.unwindFrame(&unwind_state.dwarf_context, unwind_info, module.base_address)) |return_address| {
630 return return_address;634 return return_address;
631 } else |err| {635 } else |err| {
632 if (err != error.RequiresDWARFUnwind) return err;636 if (err != error.RequiresDWARFUnwind) return err;
...@@ -636,23 +640,25 @@ pub const StackIterator = struct {...@@ -636,23 +640,25 @@ pub const StackIterator = struct {
636 else => {},640 else => {},
637 }641 }
638642
639 if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {643 if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| {
640 return di.unwindFrame(&self.dwarf_context, module.base_address);644 return di.unwindFrame(&unwind_state.dwarf_context, module.base_address);
641 } else return error.MissingDebugInfo;645 } else return error.MissingDebugInfo;
642 }646 }
643647
644 fn next_internal(self: *StackIterator) ?usize {648 fn next_internal(self: *StackIterator) ?usize {
645 if (have_ucontext and self.debug_info != null) {649 if (have_ucontext) {
646 if (self.dwarf_context.pc == 0) return null;650 if (self.unwind_state) |*unwind_state| {
647 if (self.next_unwind()) |return_address| {651 if (unwind_state.dwarf_context.pc == 0) return null;
648 return return_address;652 if (unwind_state.last_error == null) {
649 } else |err| {653 if (self.next_unwind()) |return_address| {
650 self.last_error = err;654 return return_address;
651 self.last_error_address = self.dwarf_context.pc;655 } else |err| {
652656 unwind_state.last_error = err;
653 // Fall back to fp unwinding on the first failure, as the register context won't have been updated657
654 self.fp = self.dwarf_context.getFp() catch 0;658 // Fall back to fp-based unwinding on the first failure
655 self.debug_info = null;659 self.fp = unwind_state.dwarf_context.getFp() catch 0;
660 }
661 }
656 }662 }
657 }663 }
658664
...@@ -862,16 +868,12 @@ pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: us...@@ -862,16 +868,12 @@ pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: us
862pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {868pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
863 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {869 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
864 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),870 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
865 else => {871 else => return err,
866 return err;
867 },
868 };872 };
869873
870 const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) {874 const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) {
871 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),875 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
872 else => {876 else => return err,
873 return err;
874 },
875 };877 };
876 defer symbol_info.deinit(debug_info.allocator);878 defer symbol_info.deinit(debug_info.allocator);
877879
lib/std/dwarf.zig+3-3
...@@ -1639,7 +1639,7 @@ pub const DwarfInfo = struct {...@@ -1639,7 +1639,7 @@ pub const DwarfInfo = struct {
1639 // In order to support reading .eh_frame from the ELF file (vs using the already-mapped section),1639 // In order to support reading .eh_frame from the ELF file (vs using the already-mapped section),
1640 // scanAllUnwindInfo has already mapped any pc-relative offsets such that they we be relative to zero1640 // scanAllUnwindInfo has already mapped any pc-relative offsets such that they we be relative to zero
1641 // instead of the actual base address of the module. When using .eh_frame_hdr, PC can be used directly1641 // instead of the actual base address of the module. When using .eh_frame_hdr, PC can be used directly
1642 // as pointers will be decoded relative to the alreayd-mapped .eh_frame.1642 // as pointers will be decoded relative to the already-mapped .eh_frame.
1643 var mapped_pc: usize = undefined;1643 var mapped_pc: usize = undefined;
1644 if (di.eh_frame_hdr) |header| {1644 if (di.eh_frame_hdr) |header| {
1645 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;1645 const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null;
...@@ -1766,8 +1766,8 @@ pub const DwarfInfo = struct {...@@ -1766,8 +1766,8 @@ pub const DwarfInfo = struct {
1766 mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);1766 mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
17671767
1768 // The call instruction will have pushed the address of the instruction that follows the call as the return address1768 // The call instruction will have pushed the address of the instruction that follows the call as the return address
1769 // However, this return address may be past the end of the function if the caller was `noreturn`.1769 // However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one,
1770 // TODO: Check this on non-x86_641770 // then `context.pc` will always point to an instruction within the FDE for the previous function.
1771 const return_address = context.pc;1771 const return_address = context.pc;
1772 if (context.pc > 0) context.pc -= 1;1772 if (context.pc > 0) context.pc -= 1;
17731773
lib/std/dwarf/abi.zig+6-3
...@@ -26,7 +26,7 @@ pub fn ipRegNum() u8 {...@@ -26,7 +26,7 @@ pub fn ipRegNum() u8 {
2626
27pub fn fpRegNum(reg_context: RegisterContext) u8 {27pub fn fpRegNum(reg_context: RegisterContext) u8 {
28 return switch (builtin.cpu.arch) {28 return switch (builtin.cpu.arch) {
29 // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO29 // GCC on OS X historicaly did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO
30 .x86 => if (reg_context.eh_frame and reg_context.is_macho) 4 else 5,30 .x86 => if (reg_context.eh_frame and reg_context.is_macho) 4 else 5,
31 .x86_64 => 6,31 .x86_64 => 6,
32 .arm => 11,32 .arm => 11,
...@@ -75,6 +75,7 @@ fn RegValueReturnType(comptime ContextPtrType: type, comptime T: type) type {...@@ -75,6 +75,7 @@ fn RegValueReturnType(comptime ContextPtrType: type, comptime T: type) type {
75 });75 });
76}76}
7777
78/// Returns a pointer to a register stored in a ThreadContext, preserving the pointer attributes of the context.
78pub fn regValueNative(79pub fn regValueNative(
79 comptime T: type,80 comptime T: type,
80 thread_context_ptr: anytype,81 thread_context_ptr: anytype,
...@@ -343,9 +344,11 @@ pub fn regBytes(...@@ -343,9 +344,11 @@ pub fn regBytes(
343344
344/// Returns the ABI-defined default value this register has in the unwinding table345/// Returns the ABI-defined default value this register has in the unwinding table
345/// before running any of the CIE instructions. The DWARF spec defines these values346/// before running any of the CIE instructions. The DWARF spec defines these values
346// to be undefined, but allows ABI authors to override that default.347/// to be undefined, but allows ABI authors to override that default.
347pub fn getRegDefaultValue(reg_number: u8, out: []u8) void {348pub fn getRegDefaultValue(reg_number: u8, out: []u8) void {
348 // TODO: Implement any ABI-specific rules for the default value for registers349
350 // Implement any ABI-specific rules here
351
349 _ = reg_number;352 _ = reg_number;
350 @memset(out, undefined);353 @memset(out, undefined);
351}354}
lib/std/dwarf/expressions.zig+1-4
...@@ -14,7 +14,7 @@ pub const ExpressionContext = struct {...@@ -14,7 +14,7 @@ pub const ExpressionContext = struct {
14 /// This expression is from a DWARF64 section14 /// This expression is from a DWARF64 section
15 is_64: bool = false,15 is_64: bool = false,
1616
17 /// If specified, any addresses will pass through this function before being17 /// If specified, any addresses will pass through this function before being acccessed
18 isValidMemory: ?*const fn (address: usize) bool = null,18 isValidMemory: ?*const fn (address: usize) bool = null,
1919
20 /// The compilation unit this expression relates to, if any20 /// The compilation unit this expression relates to, if any
...@@ -1024,9 +1024,6 @@ pub fn Builder(comptime options: ExpressionOptions) type {...@@ -1024,9 +1024,6 @@ pub fn Builder(comptime options: ExpressionOptions) type {
1024 try writer.writeAll(value_bytes);1024 try writer.writeAll(value_bytes);
1025 }1025 }
10261026
1027 // pub fn writeImplicitPointer(writer: anytype, ) void {
1028 // }
1029
1030 };1027 };
1031}1028}
10321029
lib/std/os/linux.zig+1-1
...@@ -4695,7 +4695,7 @@ else...@@ -4695,7 +4695,7 @@ else
4695 /// processes.4695 /// processes.
4696 RTPRIO,4696 RTPRIO,
46974697
4698 /// Maximum CPU time in µs that a process scheduled under a real-time4698 /// Maximum CPU time in µs that a process scheduled under a real-time
4699 /// scheduling policy may consume without making a blocking system4699 /// scheduling policy may consume without making a blocking system
4700 /// call before being forcibly descheduled.4700 /// call before being forcibly descheduled.
4701 RTTIME,4701 RTTIME,
src/target.zig+1-1
...@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {...@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
510}510}
511511
512pub fn needUnwindTables(target: std.Target) bool {512pub fn needUnwindTables(target: std.Target) bool {
513 return target.os.tag == .windows;513 return target.os.tag == .windows or target.ofmt == .macho;
514}514}
515515
516pub fn defaultAddressSpace(516pub fn defaultAddressSpace(