authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-08 16:31:04+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
log421102ba724370d04f14016006141a51c0f3e296
tree0db8c0dbf687586c3f8ad725324a04e3b12bcc21
parentdc7cff8ebc5f00c784647c0bd1b40dec70a5008f

zld: move parsing debug info into object


2 files changed, 205 insertions(+), 166 deletions(-)

src/link/MachO/Object.zig+135
...@@ -2,6 +2,7 @@ const Object = @This();...@@ -2,6 +2,7 @@ const Object = @This();
22
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const dwarf = std.dwarf;
5const fs = std.fs;6const fs = std.fs;
6const io = std.io;7const io = std.io;
7const log = std.log.scoped(.object);8const log = std.log.scoped(.object);
...@@ -43,6 +44,10 @@ dwarf_debug_ranges_index: ?u16 = null,...@@ -43,6 +44,10 @@ dwarf_debug_ranges_index: ?u16 = null,
43symtab: std.ArrayListUnmanaged(Symbol) = .{},44symtab: std.ArrayListUnmanaged(Symbol) = .{},
44strtab: std.ArrayListUnmanaged(u8) = .{},45strtab: std.ArrayListUnmanaged(u8) = .{},
4546
47stabs: std.ArrayListUnmanaged(Stab) = .{},
48tu_path: ?[]const u8 = null,
49tu_mtime: ?u64 = null,
50
46data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},51data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
4752
48pub const Section = struct {53pub const Section = struct {
...@@ -62,6 +67,82 @@ pub const Section = struct {...@@ -62,6 +67,82 @@ pub const Section = struct {
62 }67 }
63};68};
6469
70const Stab = struct {
71 tag: Tag,
72 symbol: u32,
73 size: ?u64 = null,
74
75 const Tag = enum {
76 function,
77 global,
78 static,
79 };
80};
81
82const DebugInfo = struct {
83 inner: dwarf.DwarfInfo,
84 debug_info: []u8,
85 debug_abbrev: []u8,
86 debug_str: []u8,
87 debug_line: []u8,
88 debug_ranges: []u8,
89
90 pub fn parseFromObject(allocator: *Allocator, object: *const Object) !?DebugInfo {
91 var debug_info = blk: {
92 const index = object.dwarf_debug_info_index orelse return null;
93 break :blk try object.readSection(allocator, index);
94 };
95 var debug_abbrev = blk: {
96 const index = object.dwarf_debug_abbrev_index orelse return null;
97 break :blk try object.readSection(allocator, index);
98 };
99 var debug_str = blk: {
100 const index = object.dwarf_debug_str_index orelse return null;
101 break :blk try object.readSection(allocator, index);
102 };
103 var debug_line = blk: {
104 const index = object.dwarf_debug_line_index orelse return null;
105 break :blk try object.readSection(allocator, index);
106 };
107 var debug_ranges = blk: {
108 if (object.dwarf_debug_ranges_index) |ind| {
109 break :blk try object.readSection(allocator, ind);
110 }
111 break :blk try allocator.alloc(u8, 0);
112 };
113
114 var inner: dwarf.DwarfInfo = .{
115 .endian = .Little,
116 .debug_info = debug_info,
117 .debug_abbrev = debug_abbrev,
118 .debug_str = debug_str,
119 .debug_line = debug_line,
120 .debug_ranges = debug_ranges,
121 };
122 try dwarf.openDwarfDebugInfo(&inner, allocator);
123
124 return DebugInfo{
125 .inner = inner,
126 .debug_info = debug_info,
127 .debug_abbrev = debug_abbrev,
128 .debug_str = debug_str,
129 .debug_line = debug_line,
130 .debug_ranges = debug_ranges,
131 };
132 }
133
134 pub fn deinit(self: *DebugInfo, allocator: *Allocator) void {
135 allocator.free(self.debug_info);
136 allocator.free(self.debug_abbrev);
137 allocator.free(self.debug_str);
138 allocator.free(self.debug_line);
139 allocator.free(self.debug_ranges);
140 self.inner.abbrev_table_list.deinit();
141 self.inner.compile_unit_list.deinit();
142 self.inner.func_list.deinit();
143 }
144};
145
65pub fn init(allocator: *Allocator) Object {146pub fn init(allocator: *Allocator) Object {
66 return .{147 return .{
67 .allocator = allocator,148 .allocator = allocator,
...@@ -81,11 +162,16 @@ pub fn deinit(self: *Object) void {...@@ -81,11 +162,16 @@ pub fn deinit(self: *Object) void {
81162
82 self.symtab.deinit(self.allocator);163 self.symtab.deinit(self.allocator);
83 self.strtab.deinit(self.allocator);164 self.strtab.deinit(self.allocator);
165 self.stabs.deinit(self.allocator);
84 self.data_in_code_entries.deinit(self.allocator);166 self.data_in_code_entries.deinit(self.allocator);
85167
86 if (self.name) |n| {168 if (self.name) |n| {
87 self.allocator.free(n);169 self.allocator.free(n);
88 }170 }
171
172 if (self.tu_path) |tu_path| {
173 self.allocator.free(tu_path);
174 }
89}175}
90176
91pub fn closeFile(self: Object) void {177pub fn closeFile(self: Object) void {
...@@ -124,6 +210,7 @@ pub fn parse(self: *Object) !void {...@@ -124,6 +210,7 @@ pub fn parse(self: *Object) !void {
124 try self.parseSections();210 try self.parseSections();
125 if (self.symtab_cmd_index != null) try self.parseSymtab();211 if (self.symtab_cmd_index != null) try self.parseSymtab();
126 if (self.data_in_code_cmd_index != null) try self.readDataInCode();212 if (self.data_in_code_cmd_index != null) try self.readDataInCode();
213 try self.parseDebugInfo();
127}214}
128215
129pub fn readLoadCommands(self: *Object, reader: anytype) !void {216pub fn readLoadCommands(self: *Object, reader: anytype) !void {
...@@ -271,6 +358,54 @@ pub fn parseSymtab(self: *Object) !void {...@@ -271,6 +358,54 @@ pub fn parseSymtab(self: *Object) !void {
271 try self.strtab.appendSlice(self.allocator, strtab);358 try self.strtab.appendSlice(self.allocator, strtab);
272}359}
273360
361pub fn parseDebugInfo(self: *Object) !void {
362 var debug_info = blk: {
363 var di = try DebugInfo.parseFromObject(self.allocator, self);
364 break :blk di orelse return;
365 };
366 defer debug_info.deinit(self.allocator);
367
368 log.warn("parsing debug info in '{s}'", .{self.name.?});
369
370 // We assume there is only one CU.
371 const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {
372 error.MissingDebugInfo => {
373 // TODO audit cases with missing debug info and audit our dwarf.zig module.
374 log.warn("invalid or missing debug info in {s}; skipping", .{self.name.?});
375 return;
376 },
377 else => |e| return e,
378 };
379 const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name);
380 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);
381
382 self.tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name });
383 self.tu_mtime = mtime: {
384 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
385 const stat = try self.file.?.stat();
386 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
387 };
388
389 for (self.symtab.items) |sym, index| {
390 const sym_name = self.getString(sym.inner.n_strx);
391 const size = blk: for (debug_info.inner.func_list.items) |func| {
392 if (func.pc_range) |range| {
393 if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) {
394 break :blk range.end - range.start;
395 }
396 }
397 } else null;
398
399 // TODO How do we work out static, global, local?
400 const tag: Stab.Tag = if (size == null) .global else .function;
401 try self.stabs.append(self.allocator, .{
402 .tag = tag,
403 .size = size,
404 .symbol = @intCast(u32, index),
405 });
406 }
407}
408
274pub fn getString(self: *const Object, str_off: u32) []const u8 {409pub fn getString(self: *const Object, str_off: u32) []const u8 {
275 assert(str_off < self.strtab.items.len);410 assert(str_off < self.strtab.items.len);
276 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));411 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
src/link/MachO/Zld.zig+70-166
...@@ -2,7 +2,6 @@ const Zld = @This();...@@ -2,7 +2,6 @@ const Zld = @This();
22
3const std = @import("std");3const std = @import("std");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const dwarf = std.dwarf;
6const leb = std.leb;5const leb = std.leb;
7const mem = std.mem;6const mem = std.mem;
8const meta = std.meta;7const meta = std.meta;
...@@ -110,70 +109,6 @@ pub const SectionMapping = struct {...@@ -110,70 +109,6 @@ pub const SectionMapping = struct {
110 offset: u32,109 offset: u32,
111};110};
112111
113const DebugInfo = struct {
114 inner: dwarf.DwarfInfo,
115 debug_info: []u8,
116 debug_abbrev: []u8,
117 debug_str: []u8,
118 debug_line: []u8,
119 debug_ranges: []u8,
120
121 pub fn parseFromObject(allocator: *Allocator, object: Object) !?DebugInfo {
122 var debug_info = blk: {
123 const index = object.dwarf_debug_info_index orelse return null;
124 break :blk try object.readSection(allocator, index);
125 };
126 var debug_abbrev = blk: {
127 const index = object.dwarf_debug_abbrev_index orelse return null;
128 break :blk try object.readSection(allocator, index);
129 };
130 var debug_str = blk: {
131 const index = object.dwarf_debug_str_index orelse return null;
132 break :blk try object.readSection(allocator, index);
133 };
134 var debug_line = blk: {
135 const index = object.dwarf_debug_line_index orelse return null;
136 break :blk try object.readSection(allocator, index);
137 };
138 var debug_ranges = blk: {
139 if (object.dwarf_debug_ranges_index) |ind| {
140 break :blk try object.readSection(allocator, ind);
141 }
142 break :blk try allocator.alloc(u8, 0);
143 };
144
145 var inner: dwarf.DwarfInfo = .{
146 .endian = .Little,
147 .debug_info = debug_info,
148 .debug_abbrev = debug_abbrev,
149 .debug_str = debug_str,
150 .debug_line = debug_line,
151 .debug_ranges = debug_ranges,
152 };
153 try dwarf.openDwarfDebugInfo(&inner, allocator);
154
155 return DebugInfo{
156 .inner = inner,
157 .debug_info = debug_info,
158 .debug_abbrev = debug_abbrev,
159 .debug_str = debug_str,
160 .debug_line = debug_line,
161 .debug_ranges = debug_ranges,
162 };
163 }
164
165 pub fn deinit(self: *DebugInfo, allocator: *Allocator) void {
166 allocator.free(self.debug_info);
167 allocator.free(self.debug_abbrev);
168 allocator.free(self.debug_str);
169 allocator.free(self.debug_line);
170 allocator.free(self.debug_ranges);
171 self.inner.abbrev_table_list.deinit();
172 self.inner.compile_unit_list.deinit();
173 self.inner.func_list.deinit();
174 }
175};
176
177/// Default path to dyld112/// Default path to dyld
178const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";113const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
179114
...@@ -2510,108 +2445,77 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2510,108 +2445,77 @@ fn writeDebugInfo(self: *Zld) !void {
2510 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);2445 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
2511 defer stabs.deinit();2446 defer stabs.deinit();
25122447
2513 for (self.objects.items) |object, object_id| {2448 for (self.objects.items) |object| {
2514 var debug_info = blk: {2449 const tu_path = object.tu_path orelse continue;
2515 var di = try DebugInfo.parseFromObject(self.allocator, object);2450 const tu_mtime = object.tu_mtime orelse continue;
2516 break :blk di orelse continue;2451 const dirname = std.fs.path.dirname(tu_path) orelse "./";
2517 };2452 // Current dir
2518 defer debug_info.deinit(self.allocator);2453 try stabs.append(.{
25192454 .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]),
2520 // We assume there is only one CU.2455 .n_type = macho.N_SO,
2521 const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {2456 .n_sect = 0,
2522 error.MissingDebugInfo => {2457 .n_desc = 0,
2523 // TODO audit cases with missing debug info and audit our dwarf.zig module.2458 .n_value = 0,
2524 log.warn("invalid or missing debug info in {s}; skipping", .{object.name});2459 });
2525 continue;2460 // Artifact name
2526 },2461 try stabs.append(.{
2527 else => |e| return e,2462 .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]),
2528 };2463 .n_type = macho.N_SO,
2529 const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name);2464 .n_sect = 0,
2530 const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);2465 .n_desc = 0,
25312466 .n_value = 0,
2532 {2467 });
2533 const tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name });2468 // Path to object file with debug info
2534 defer self.allocator.free(tu_path);2469 try stabs.append(.{
2535 const dirname = std.fs.path.dirname(tu_path) orelse "./";2470 .n_strx = try self.makeString(object.name.?),
2536 // Current dir2471 .n_type = macho.N_OSO,
2537 try stabs.append(.{2472 .n_sect = 0,
2538 .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]),2473 .n_desc = 1,
2539 .n_type = macho.N_SO,2474 .n_value = tu_mtime,
2540 .n_sect = 0,2475 });
2541 .n_desc = 0,
2542 .n_value = 0,
2543 });
2544 // Artifact name
2545 try stabs.append(.{
2546 .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]),
2547 .n_type = macho.N_SO,
2548 .n_sect = 0,
2549 .n_desc = 0,
2550 .n_value = 0,
2551 });
2552 // Path to object file with debug info
2553 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
2554 const stat = try object.file.?.stat();
2555 const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
2556 try stabs.append(.{
2557 .n_strx = try self.makeString(object.name.?),
2558 .n_type = macho.N_OSO,
2559 .n_sect = 0,
2560 .n_desc = 1,
2561 .n_value = mtime,
2562 });
2563 }
2564 log.warn("analyzing debug info in '{s}'", .{object.name});
25652476
2566 for (object.symtab.items) |sym| {2477 for (object.stabs.items) |stab| {
2567 const sym_name = object.getString(sym.inner.n_strx);2478 const sym = object.symtab.items[stab.symbol];
2568 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {2479 switch (stab.tag) {
2569 if (func.pc_range) |range| {2480 .function => {
2570 // TODO source address needs to be preserved2481 try stabs.append(.{
2571 if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) {2482 .n_strx = 0,
2572 break :blk range.end - range.start;2483 .n_type = macho.N_BNSYM,
2573 }2484 .n_sect = sym.inner.n_sect,
2574 }2485 .n_desc = 0,
2575 } else null;2486 .n_value = sym.inner.n_value,
25762487 });
2577 if (maybe_size) |size| {2488 try stabs.append(.{
2578 try stabs.append(.{2489 .n_strx = sym.inner.n_strx,
2579 .n_strx = 0,2490 .n_type = macho.N_FUN,
2580 .n_type = macho.N_BNSYM,2491 .n_sect = sym.inner.n_sect,
2581 .n_sect = sym.inner.n_sect,2492 .n_desc = 0,
2582 .n_desc = 0,2493 .n_value = sym.inner.n_value,
2583 .n_value = sym.inner.n_value,2494 });
2584 });2495 try stabs.append(.{
2585 try stabs.append(.{2496 .n_strx = 0,
2586 .n_strx = sym.inner.n_strx,2497 .n_type = macho.N_FUN,
2587 .n_type = macho.N_FUN,2498 .n_sect = 0,
2588 .n_sect = sym.inner.n_sect,2499 .n_desc = 0,
2589 .n_desc = 0,2500 .n_value = stab.size.?,
2590 .n_value = sym.inner.n_value,2501 });
2591 });2502 try stabs.append(.{
2592 try stabs.append(.{2503 .n_strx = 0,
2593 .n_strx = 0,2504 .n_type = macho.N_ENSYM,
2594 .n_type = macho.N_FUN,2505 .n_sect = sym.inner.n_sect,
2595 .n_sect = 0,2506 .n_desc = 0,
2596 .n_desc = 0,2507 .n_value = stab.size.?,
2597 .n_value = size,2508 });
2598 });2509 },
2599 try stabs.append(.{2510 else => {
2600 .n_strx = 0,2511 try stabs.append(.{
2601 .n_type = macho.N_ENSYM,2512 .n_strx = sym.inner.n_strx,
2602 .n_sect = sym.inner.n_sect,2513 .n_type = macho.N_STSYM,
2603 .n_desc = 0,2514 .n_sect = sym.inner.n_sect,
2604 .n_value = size,2515 .n_desc = 0,
2605 });2516 .n_value = sym.inner.n_value,
2606 } else {2517 });
2607 // TODO need a way to differentiate symbols: global, static, local, etc.2518 },
2608 try stabs.append(.{
2609 .n_strx = sym.inner.n_strx,
2610 .n_type = macho.N_STSYM,
2611 .n_sect = sym.inner.n_sect,
2612 .n_desc = 0,
2613 .n_value = sym.inner.n_value,
2614 });
2615 }2519 }
2616 }2520 }
26172521