authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-26 09:55:04-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-26 09:55:04-05:00
log3839ea89785856bbed0624a6a18eb6e5acfb46c3
tree5aadd86ef359eb847bf842f9594690737f0e67c4
parentd9fb6c20540300013dc67ec144b555b8ab649646
signature Commit is signed but in an unrecognized format.

fix debug info code not being freestanding compatible

in stack tracing code, the idea was to detect the tty settings at the top of the stack and pass the information down. somewhere along the way this got changed so that setTtyColor was assuming the global stderr_file was related to the output stream the stack trace was being printed to. now, tty_color is changed to tty_config, and it is an enum rather than a bool, telling how tty colors are expected to be handled. windows is still incorrectly looking at stderr_file.

1 files changed, 123 insertions(+), 107 deletions(-)

lib/std/debug.zig+123-107
...@@ -81,10 +81,20 @@ pub fn getSelfDebugInfo() !*DebugInfo {...@@ -81,10 +81,20 @@ pub fn getSelfDebugInfo() !*DebugInfo {
81 }81 }
82}82}
8383
84fn wantTtyColor() bool {84fn detectTTYConfig() TTY.Config {
85 var bytes: [128]u8 = undefined;85 var bytes: [128]u8 = undefined;
86 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;86 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
87 return if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();87 if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| {
88 return .escape_codes;
89 } else |_| {
90 if (stderr_file.supportsAnsiEscapeCodes()) {
91 return .escape_codes;
92 } else if (builtin.os == .windows) {
93 return .windows_api;
94 } else {
95 return .no_color;
96 }
97 }
88}98}
8999
90/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.100/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
...@@ -99,7 +109,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -99,7 +109,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
99 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;109 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
100 return;110 return;
101 };111 };
102 writeCurrentStackTrace(stderr, debug_info, wantTtyColor(), start_addr) catch |err| {112 writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
103 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;113 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
104 return;114 return;
105 };115 };
...@@ -118,16 +128,16 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {...@@ -118,16 +128,16 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
118 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;128 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
119 return;129 return;
120 };130 };
121 const tty_color = wantTtyColor();131 const tty_config = detectTTYConfig();
122 printSourceAtAddress(debug_info, stderr, ip, tty_color) catch return;132 printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
123 const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*;133 const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*;
124 printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_color) catch return;134 printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return;
125 var it = StackIterator{135 var it = StackIterator{
126 .first_addr = null,136 .first_addr = null,
127 .fp = bp,137 .fp = bp,
128 };138 };
129 while (it.next()) |return_address| {139 while (it.next()) |return_address| {
130 printSourceAtAddress(debug_info, stderr, return_address - 1, tty_color) catch return;140 printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return;
131 }141 }
132}142}
133143
...@@ -191,7 +201,7 @@ pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {...@@ -191,7 +201,7 @@ pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
191 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;201 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
192 return;202 return;
193 };203 };
194 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, wantTtyColor()) catch |err| {204 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| {
195 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;205 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
196 return;206 return;
197 };207 };
...@@ -264,7 +274,7 @@ pub fn writeStackTrace(...@@ -264,7 +274,7 @@ pub fn writeStackTrace(
264 out_stream: var,274 out_stream: var,
265 allocator: *mem.Allocator,275 allocator: *mem.Allocator,
266 debug_info: *DebugInfo,276 debug_info: *DebugInfo,
267 tty_color: bool,277 tty_config: TTY.Config,
268) !void {278) !void {
269 if (builtin.strip_debug_info) return error.MissingDebugInfo;279 if (builtin.strip_debug_info) return error.MissingDebugInfo;
270 var frame_index: usize = 0;280 var frame_index: usize = 0;
...@@ -275,7 +285,7 @@ pub fn writeStackTrace(...@@ -275,7 +285,7 @@ pub fn writeStackTrace(
275 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;285 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
276 }) {286 }) {
277 const return_address = stack_trace.instruction_addresses[frame_index];287 const return_address = stack_trace.instruction_addresses[frame_index];
278 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color);288 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config);
279 }289 }
280}290}
281291
...@@ -319,20 +329,25 @@ pub const StackIterator = struct {...@@ -319,20 +329,25 @@ pub const StackIterator = struct {
319 }329 }
320};330};
321331
322pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {332pub fn writeCurrentStackTrace(
333 out_stream: var,
334 debug_info: *DebugInfo,
335 tty_config: TTY.Config,
336 start_addr: ?usize,
337) !void {
323 if (builtin.os == .windows) {338 if (builtin.os == .windows) {
324 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr);339 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
325 }340 }
326 var it = StackIterator.init(start_addr);341 var it = StackIterator.init(start_addr);
327 while (it.next()) |return_address| {342 while (it.next()) |return_address| {
328 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_color);343 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config);
329 }344 }
330}345}
331346
332pub fn writeCurrentStackTraceWindows(347pub fn writeCurrentStackTraceWindows(
333 out_stream: var,348 out_stream: var,
334 debug_info: *DebugInfo,349 debug_info: *DebugInfo,
335 tty_color: bool,350 tty_config: TTY.Config,
336 start_addr: ?usize,351 start_addr: ?usize,
337) !void {352) !void {
338 var addr_buf: [1024]usize = undefined;353 var addr_buf: [1024]usize = undefined;
...@@ -345,23 +360,28 @@ pub fn writeCurrentStackTraceWindows(...@@ -345,23 +360,28 @@ pub fn writeCurrentStackTraceWindows(
345 return;360 return;
346 } else 0;361 } else 0;
347 for (addrs[start_i..]) |addr| {362 for (addrs[start_i..]) |addr| {
348 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);363 try printSourceAtAddress(debug_info, out_stream, addr, tty_config);
349 }364 }
350}365}
351366
352/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,367/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
353/// make this `noasync fn` and remove the individual noasync calls.368/// make this `noasync fn` and remove the individual noasync calls.
354pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {369pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
355 if (builtin.os == .windows) {370 if (builtin.os == .windows) {
356 return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_color);371 return noasync printSourceAtAddressWindows(debug_info, out_stream, address, tty_config);
357 }372 }
358 if (comptime std.Target.current.isDarwin()) {373 if (comptime std.Target.current.isDarwin()) {
359 return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color);374 return noasync printSourceAtAddressMacOs(debug_info, out_stream, address, tty_config);
360 }375 }
361 return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_color);376 return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);
362}377}
363378
364fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {379fn printSourceAtAddressWindows(
380 di: *DebugInfo,
381 out_stream: var,
382 relocated_address: usize,
383 tty_config: TTY.Config,
384) !void {
365 const allocator = getDebugInfoAllocator();385 const allocator = getDebugInfoAllocator();
366 const base_address = process.getBaseAddress();386 const base_address = process.getBaseAddress();
367 const relative_address = relocated_address - base_address;387 const relative_address = relocated_address - base_address;
...@@ -379,7 +399,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres...@@ -379,7 +399,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
379 }399 }
380 } else {400 } else {
381 // we have no information to add to the address401 // we have no information to add to the address
382 return printLineInfo(out_stream, null, relocated_address, "???", "???", tty_color, printLineFromFileAnyOs);402 return printLineInfo(out_stream, null, relocated_address, "???", "???", tty_config, printLineFromFileAnyOs);
383 };403 };
384404
385 const mod = &di.modules[mod_index];405 const mod = &di.modules[mod_index];
...@@ -507,84 +527,80 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres...@@ -507,84 +527,80 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
507 relocated_address,527 relocated_address,
508 symbol_name,528 symbol_name,
509 obj_basename,529 obj_basename,
510 tty_color,530 tty_config,
511 printLineFromFileAnyOs,531 printLineFromFileAnyOs,
512 );532 );
513}533}
514534
515const TtyColor = enum {535pub const TTY = struct {
516 Red,536 pub const Color = enum {
517 Green,537 Red,
518 Cyan,538 Green,
519 White,539 Cyan,
520 Dim,540 White,
521 Bold,541 Dim,
522 Reset,542 Bold,
523};543 Reset,
524544 };
525/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
526fn setTtyColor(tty_color: TtyColor) void {
527 if (stderr_file.supportsAnsiEscapeCodes()) {
528 switch (tty_color) {
529 TtyColor.Red => {
530 stderr_file.write(RED) catch return;
531 },
532 TtyColor.Green => {
533 stderr_file.write(GREEN) catch return;
534 },
535 TtyColor.Cyan => {
536 stderr_file.write(CYAN) catch return;
537 },
538 TtyColor.White, TtyColor.Bold => {
539 stderr_file.write(WHITE) catch return;
540 },
541 TtyColor.Dim => {
542 stderr_file.write(DIM) catch return;
543 },
544 TtyColor.Reset => {
545 stderr_file.write(RESET) catch return;
546 },
547 }
548
549 return;
550 }
551545
552 if (builtin.os == .windows) {546 pub const Config = enum {
553 const S = struct {547 no_color,
554 var attrs: windows.WORD = undefined;548 escape_codes,
555 var init_attrs = false;549 // TODO give this a payload of file handle
556 };550 windows_api,
557 if (!S.init_attrs) {551
558 S.init_attrs = true;552 fn setColor(conf: Config, out_stream: var, color: Color) void {
559 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;553 switch (conf) {
560 // TODO handle error554 .no_color => return,
561 _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);555 .escape_codes => switch (color) {
562 S.attrs = info.wAttributes;556 .Red => out_stream.write(RED) catch return,
563 }557 .Green => out_stream.write(GREEN) catch return,
558 .Cyan => out_stream.write(CYAN) catch return,
559 .White, .Bold => out_stream.write(WHITE) catch return,
560 .Dim => out_stream.write(DIM) catch return,
561 .Reset => out_stream.write(RESET) catch return,
562 },
563 .windows_api => if (builtin.os == .windows) {
564 const S = struct {
565 var attrs: windows.WORD = undefined;
566 var init_attrs = false;
567 };
568 if (!S.init_attrs) {
569 S.init_attrs = true;
570 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
571 // TODO handle error
572 _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
573 S.attrs = info.wAttributes;
574 }
564575
565 // TODO handle errors576 // TODO handle errors
566 switch (tty_color) {577 switch (color) {
567 TtyColor.Red => {578 .Red => {
568 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};579 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};
569 },580 },
570 TtyColor.Green => {581 .Green => {
571 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};582 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};
572 },583 },
573 TtyColor.Cyan => {584 .Cyan => {
574 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};585 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
575 },586 },
576 TtyColor.White, TtyColor.Bold => {587 .White, .Bold => {
577 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};588 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
578 },589 },
579 TtyColor.Dim => {590 .Dim => {
580 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};591 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};
581 },592 },
582 TtyColor.Reset => {593 .Reset => {
583 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};594 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};
584 },595 },
596 }
597 } else {
598 unreachable;
599 },
600 }
585 }601 }
586 }602 };
587}603};
588604
589fn populateModule(di: *DebugInfo, mod: *Module) !void {605fn populateModule(di: *DebugInfo, mod: *Module) !void {
590 if (mod.populated)606 if (mod.populated)
...@@ -650,12 +666,12 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach...@@ -650,12 +666,12 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
650 return null;666 return null;
651}667}
652668
653fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {669fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
654 const base_addr = process.getBaseAddress();670 const base_addr = process.getBaseAddress();
655 const adjusted_addr = 0x100000000 + (address - base_addr);671 const adjusted_addr = 0x100000000 + (address - base_addr);
656672
657 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {673 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
658 return printLineInfo(out_stream, null, address, "???", "???", tty_color, printLineFromFileAnyOs);674 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFileAnyOs);
659 };675 };
660676
661 const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx));677 const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx));
...@@ -676,13 +692,13 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt...@@ -676,13 +692,13 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
676 address,692 address,
677 symbol_name,693 symbol_name,
678 compile_unit_name,694 compile_unit_name,
679 tty_color,695 tty_config,
680 printLineFromFileAnyOs,696 printLineFromFileAnyOs,
681 );697 );
682}698}
683699
684pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {700pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_config: TTY.Config) !void {
685 return debug_info.printSourceAtAddress(out_stream, address, tty_color, printLineFromFileAnyOs);701 return debug_info.printSourceAtAddress(out_stream, address, tty_config, printLineFromFileAnyOs);
686}702}
687703
688fn printLineInfo(704fn printLineInfo(
...@@ -691,10 +707,10 @@ fn printLineInfo(...@@ -691,10 +707,10 @@ fn printLineInfo(
691 address: usize,707 address: usize,
692 symbol_name: []const u8,708 symbol_name: []const u8,
693 compile_unit_name: []const u8,709 compile_unit_name: []const u8,
694 tty_color: bool,710 tty_config: TTY.Config,
695 comptime printLineFromFile: var,711 comptime printLineFromFile: var,
696) !void {712) !void {
697 if (tty_color) setTtyColor(.White);713 tty_config.setColor(out_stream, .White);
698714
699 if (line_info) |*li| {715 if (line_info) |*li| {
700 try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });716 try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
...@@ -702,11 +718,11 @@ fn printLineInfo(...@@ -702,11 +718,11 @@ fn printLineInfo(
702 try out_stream.print("???:?:?", .{});718 try out_stream.print("???:?:?", .{});
703 }719 }
704720
705 if (tty_color) setTtyColor(.Reset);721 tty_config.setColor(out_stream, .Reset);
706 try out_stream.write(": ");722 try out_stream.write(": ");
707 if (tty_color) setTtyColor(.Dim);723 tty_config.setColor(out_stream, .Dim);
708 try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });724 try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
709 if (tty_color) setTtyColor(.Reset);725 tty_config.setColor(out_stream, .Reset);
710 try out_stream.write("\n");726 try out_stream.write("\n");
711727
712 // Show the matching source code line if possible728 // Show the matching source code line if possible
...@@ -717,9 +733,9 @@ fn printLineInfo(...@@ -717,9 +733,9 @@ fn printLineInfo(
717 const space_needed = @intCast(usize, li.column - 1);733 const space_needed = @intCast(usize, li.column - 1);
718734
719 try out_stream.writeByteNTimes(' ', space_needed);735 try out_stream.writeByteNTimes(' ', space_needed);
720 if (tty_color) setTtyColor(.Green);736 tty_config.setColor(out_stream, .Green);
721 try out_stream.write("^");737 try out_stream.write("^");
722 if (tty_color) setTtyColor(.Reset);738 tty_config.setColor(out_stream, .Reset);
723 }739 }
724 try out_stream.write("\n");740 try out_stream.write("\n");
725 } else |err| switch (err) {741 } else |err| switch (err) {
...@@ -1167,11 +1183,11 @@ pub const DwarfInfo = struct {...@@ -1167,11 +1183,11 @@ pub const DwarfInfo = struct {
1167 self: *DwarfInfo,1183 self: *DwarfInfo,
1168 out_stream: var,1184 out_stream: var,
1169 address: usize,1185 address: usize,
1170 tty_color: bool,1186 tty_config: TTY.Config,
1171 comptime printLineFromFile: var,1187 comptime printLineFromFile: var,
1172 ) !void {1188 ) !void {
1173 const compile_unit = self.findCompileUnit(address) catch {1189 const compile_unit = self.findCompileUnit(address) catch {
1174 return printLineInfo(out_stream, null, address, "???", "???", tty_color, printLineFromFile);1190 return printLineInfo(out_stream, null, address, "???", "???", tty_config, printLineFromFile);
1175 };1191 };
11761192
1177 const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);1193 const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);
...@@ -1188,7 +1204,7 @@ pub const DwarfInfo = struct {...@@ -1188,7 +1204,7 @@ pub const DwarfInfo = struct {
1188 address,1204 address,
1189 symbol_name,1205 symbol_name,
1190 compile_unit_name,1206 compile_unit_name,
1191 tty_color,1207 tty_config,
1192 printLineFromFile,1208 printLineFromFile,
1193 );1209 );
1194 }1210 }