| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | //! properties. |
| 8 | 8 | |
| 9 | 9 | const std = @import("../std.zig"); |
| 10 | const builtin = @import("builtin"); |
| 10 | 11 | const Allocator = std.mem.Allocator; |
| 11 | 12 | const Path = std.Build.Cache.Path; |
| 12 | 13 | const Dwarf = std.debug.Dwarf; |
| ... | ... | @@ -17,7 +18,7 @@ const SourceLocation = std.debug.Coverage.SourceLocation; |
| 17 | 18 | const Info = @This(); |
| 18 | 19 | |
| 19 | 20 | /// Sorted by key, ascending. |
| 20 | | address_map: std.AutoArrayHashMapUnmanaged(u64, Dwarf.ElfModule), |
| 21 | address_map: std.AutoArrayHashMapUnmanaged(u64, std.debug.SelfInfo.Module), |
| 21 | 22 | /// Externally managed, outlives this `Info` instance. |
| 22 | 23 | coverage: *Coverage, |
| 23 | 24 | |
| ... | ... | @@ -25,19 +26,40 @@ pub const LoadError = Dwarf.ElfModule.LoadError; |
| 25 | 26 | |
| 26 | 27 | pub fn load(gpa: Allocator, path: Path, coverage: *Coverage) LoadError!Info { |
| 27 | 28 | var sections: Dwarf.SectionArray = Dwarf.null_section_array; |
| 28 | | var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null); |
| 29 | | try elf_module.dwarf.populateRanges(gpa); |
| 30 | 29 | var info: Info = .{ |
| 31 | 30 | .address_map = .{}, |
| 32 | 31 | .coverage = coverage, |
| 33 | 32 | }; |
| 34 | | try info.address_map.put(gpa, elf_module.base_address, elf_module); |
| 33 | switch (builtin.os.tag) { |
| 34 | .linux => { |
| 35 | var elf_module = try Dwarf.ElfModule.loadPath(gpa, path, null, null, &sections, null); |
| 36 | try elf_module.dwarf.populateRanges(gpa); |
| 37 | try info.address_map.put(gpa, elf_module.base_address, elf_module); |
| 38 | }, |
| 39 | .macos => { |
| 40 | const macho_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| switch (err) { |
| 41 | error.FileNotFound => return error.MissingDebugInfo, |
| 42 | else => return error.InvalidDebugInfo, |
| 43 | }; |
| 44 | // readMachoDebugInfo takes ownership of the file |
| 45 | // defer elf_file.close(); |
| 46 | var module = std.debug.SelfInfo.readMachODebugInfo(gpa, macho_file) catch { |
| 47 | return error.InvalidDebugInfo; |
| 48 | }; |
| 49 | |
| 50 | module.base_address = 0; |
| 51 | module.vmaddr_slide = 0; |
| 52 | |
| 53 | try info.address_map.put(gpa, 0, module); |
| 54 | }, |
| 55 | else => @compileError("TODO: implement debug info loading for the target platform"), |
| 56 | } |
| 35 | 57 | return info; |
| 36 | 58 | } |
| 37 | 59 | |
| 38 | 60 | pub fn deinit(info: *Info, gpa: Allocator) void { |
| 39 | | for (info.address_map.values()) |*elf_module| { |
| 40 | | elf_module.dwarf.deinit(gpa); |
| 61 | for (info.address_map.values()) |*module| { |
| 62 | module.deinit(gpa); |
| 41 | 63 | } |
| 42 | 64 | info.address_map.deinit(gpa); |
| 43 | 65 | info.* = undefined; |
| ... | ... | @@ -57,6 +79,53 @@ pub fn resolveAddresses( |
| 57 | 79 | ) ResolveAddressesError!void { |
| 58 | 80 | assert(sorted_pc_addrs.len == output.len); |
| 59 | 81 | if (info.address_map.entries.len != 1) @panic("TODO"); |
| 60 | | const elf_module = &info.address_map.values()[0]; |
| 61 | | return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf); |
| 82 | |
| 83 | switch (builtin.os.tag) { |
| 84 | else => @compileError("unsupported"), |
| 85 | .linux => { |
| 86 | const elf_module = &info.address_map.values()[0]; |
| 87 | return info.coverage.resolveAddressesDwarf(gpa, sorted_pc_addrs, output, &elf_module.dwarf); |
| 88 | }, |
| 89 | .macos => { |
| 90 | const module = &info.address_map.values()[0]; |
| 91 | |
| 92 | var idx: usize = 0; |
| 93 | while (idx < sorted_pc_addrs.len) : (idx += 1) { |
| 94 | const ofile = (module.getOFileInfoForAddress(gpa, sorted_pc_addrs[idx]) catch return error.InvalidDebugInfo); |
| 95 | if (ofile.o_file_info.?.di.ranges.items.len == 0) { |
| 96 | try ofile.o_file_info.?.di.populateRanges(gpa); |
| 97 | } |
| 98 | // const last = ofile.ranges.getLastOrNull() orelse return; |
| 99 | // var end_idx = idx; |
| 100 | // while (end_idx < sorted_pc_addrs.len and |
| 101 | // sorted_pc_addrs[end_idx] < last.end) end_idx += 1; |
| 102 | |
| 103 | // if (end_idx == idx) { |
| 104 | // std.debug.panic("made no progress", .{}); |
| 105 | // } |
| 106 | // |
| 107 | |
| 108 | const stab_symbol = std.mem.sliceTo(module.strings[ofile.symbol.?.strx..], 0); |
| 109 | const offset = ofile.relocated_address - ofile.symbol.?.addr; |
| 110 | // Translate again the address, this time into an address inside the |
| 111 | // .o file |
| 112 | const relocated_address_o = ofile.o_file_info.?.addr_table.get(stab_symbol) orelse @panic("error"); |
| 113 | |
| 114 | try info.coverage.resolveAddressesDwarf( |
| 115 | gpa, |
| 116 | &.{relocated_address_o + offset}, |
| 117 | output[idx..][0..1], |
| 118 | &ofile.o_file_info.?.di, |
| 119 | ); |
| 120 | |
| 121 | // std.debug.print("{x} -> {x} -> {}\n", .{ |
| 122 | // sorted_pc_addrs[idx], |
| 123 | // relocated_address_o + offset, |
| 124 | // output[idx], |
| 125 | // }); |
| 126 | |
| 127 | // idx = end_idx; |
| 128 | } |
| 129 | }, |
| 130 | } |
| 62 | 131 | } |