| ... | ... | @@ -39,6 +39,7 @@ pub const call_frame = @import("Dwarf/call_frame.zig"); |
| 39 | 39 | endian: std.builtin.Endian, |
| 40 | 40 | sections: SectionArray = null_section_array, |
| 41 | 41 | is_macho: bool, |
| 42 | compile_units_sorted: bool, |
| 42 | 43 | |
| 43 | 44 | // Filled later by the initializer |
| 44 | 45 | abbrev_table_list: std.ArrayListUnmanaged(Abbrev.Table) = .{}, |
| ... | ... | @@ -728,9 +729,9 @@ pub const OpenError = ScanError; |
| 728 | 729 | /// Initialize DWARF info. The caller has the responsibility to initialize most |
| 729 | 730 | /// the `Dwarf` fields before calling. `binary_mem` is the raw bytes of the |
| 730 | 731 | /// main binary file (not the secondary debug info file). |
| 731 | | pub fn open(di: *Dwarf, gpa: Allocator) OpenError!void { |
| 732 | | try di.scanAllFunctions(gpa); |
| 733 | | try di.scanAllCompileUnits(gpa); |
| 732 | pub fn open(d: *Dwarf, gpa: Allocator) OpenError!void { |
| 733 | try d.scanAllFunctions(gpa); |
| 734 | try d.scanAllCompileUnits(gpa); |
| 734 | 735 | } |
| 735 | 736 | |
| 736 | 737 | const PcRange = struct { |
| ... | ... | @@ -1061,6 +1062,39 @@ fn scanAllCompileUnits(di: *Dwarf, allocator: Allocator) ScanError!void { |
| 1061 | 1062 | } |
| 1062 | 1063 | } |
| 1063 | 1064 | |
| 1065 | /// Populate missing PC ranges in compilation units, and then sort them by start address. |
| 1066 | /// Does not guarantee pc_range to be non-null because there could be missing debug info. |
| 1067 | pub fn sortCompileUnits(d: *Dwarf) ScanError!void { |
| 1068 | assert(!d.compile_units_sorted); |
| 1069 | |
| 1070 | for (d.compile_unit_list.items) |*cu| { |
| 1071 | if (cu.pc_range != null) continue; |
| 1072 | const ranges_value = cu.die.getAttr(AT.ranges) orelse continue; |
| 1073 | var iter = DebugRangeIterator.init(ranges_value, d, cu) catch continue; |
| 1074 | var start: u64 = maxInt(u64); |
| 1075 | var end: u64 = 0; |
| 1076 | while (try iter.next()) |range| { |
| 1077 | start = @min(start, range.start_addr); |
| 1078 | end = @max(end, range.end_addr); |
| 1079 | } |
| 1080 | if (end != 0) cu.pc_range = .{ |
| 1081 | .start = start, |
| 1082 | .end = end, |
| 1083 | }; |
| 1084 | } |
| 1085 | |
| 1086 | std.mem.sortUnstable(CompileUnit, d.compile_unit_list.items, {}, struct { |
| 1087 | fn lessThan(ctx: void, a: CompileUnit, b: CompileUnit) bool { |
| 1088 | _ = ctx; |
| 1089 | const a_range = a.pc_range orelse return false; |
| 1090 | const b_range = b.pc_range orelse return true; |
| 1091 | return a_range.start < b_range.start; |
| 1092 | } |
| 1093 | }.lessThan); |
| 1094 | |
| 1095 | d.compile_units_sorted = true; |
| 1096 | } |
| 1097 | |
| 1064 | 1098 | const DebugRangeIterator = struct { |
| 1065 | 1099 | base_address: u64, |
| 1066 | 1100 | section_type: Section.Id, |
| ... | ... | @@ -1208,6 +1242,7 @@ const DebugRangeIterator = struct { |
| 1208 | 1242 | } |
| 1209 | 1243 | }; |
| 1210 | 1244 | |
| 1245 | /// TODO: change this to binary searching the sorted compile unit list |
| 1211 | 1246 | pub fn findCompileUnit(di: *const Dwarf, target_address: u64) !*const CompileUnit { |
| 1212 | 1247 | for (di.compile_unit_list.items) |*compile_unit| { |
| 1213 | 1248 | if (compile_unit.pc_range) |range| { |
| ... | ... | @@ -2275,6 +2310,7 @@ pub const ElfModule = struct { |
| 2275 | 2310 | .endian = endian, |
| 2276 | 2311 | .sections = sections, |
| 2277 | 2312 | .is_macho = false, |
| 2313 | .compile_units_sorted = false, |
| 2278 | 2314 | }; |
| 2279 | 2315 | |
| 2280 | 2316 | try Dwarf.open(&di, gpa); |
| ... | ... | @@ -2326,6 +2362,8 @@ pub const ElfModule = struct { |
| 2326 | 2362 | } |
| 2327 | 2363 | }; |
| 2328 | 2364 | |
| 2365 | pub const ResolveSourceLocationsError = Allocator.Error || DeprecatedFixedBufferReader.Error; |
| 2366 | |
| 2329 | 2367 | /// Given an array of virtual memory addresses, sorted ascending, outputs a |
| 2330 | 2368 | /// corresponding array of source locations, by appending to the provided |
| 2331 | 2369 | /// array list. |
| ... | ... | @@ -2335,11 +2373,44 @@ pub fn resolveSourceLocations( |
| 2335 | 2373 | sorted_pc_addrs: []const u64, |
| 2336 | 2374 | /// Asserts its length equals length of `sorted_pc_addrs`. |
| 2337 | 2375 | output: []std.debug.SourceLocation, |
| 2338 | | ) error{ MissingDebugInfo, InvalidDebugInfo }!void { |
| 2376 | parent_prog_node: std.Progress.Node, |
| 2377 | ) ResolveSourceLocationsError!void { |
| 2339 | 2378 | assert(sorted_pc_addrs.len == output.len); |
| 2340 | | _ = d; |
| 2341 | | _ = gpa; |
| 2342 | | @panic("TODO"); |
| 2379 | assert(d.compile_units_sorted); |
| 2380 | |
| 2381 | const prog_node = parent_prog_node.start("Resolve Source Locations", sorted_pc_addrs.len); |
| 2382 | defer prog_node.end(); |
| 2383 | |
| 2384 | var cu_i: usize = 0; |
| 2385 | var cu: *const CompileUnit = &d.compile_unit_list.items[0]; |
| 2386 | var range = cu.pc_range.?; |
| 2387 | next_pc: for (sorted_pc_addrs, output) |pc, *out| { |
| 2388 | defer prog_node.completeOne(); |
| 2389 | while (pc >= range.end) { |
| 2390 | cu_i += 1; |
| 2391 | if (cu_i >= d.compile_unit_list.items.len) { |
| 2392 | out.* = std.debug.SourceLocation.invalid; |
| 2393 | continue :next_pc; |
| 2394 | } |
| 2395 | cu = &d.compile_unit_list.items[cu_i]; |
| 2396 | range = cu.pc_range orelse { |
| 2397 | out.* = std.debug.SourceLocation.invalid; |
| 2398 | continue :next_pc; |
| 2399 | }; |
| 2400 | } |
| 2401 | if (pc < range.start) { |
| 2402 | out.* = std.debug.SourceLocation.invalid; |
| 2403 | continue :next_pc; |
| 2404 | } |
| 2405 | // TODO: instead of calling this function, break the function up into one that parses the |
| 2406 | // information once and prepares a context that can be reused for the entire batch. |
| 2407 | if (getLineNumberInfo(d, gpa, cu.*, pc)) |src_loc| { |
| 2408 | out.* = src_loc; |
| 2409 | } else |err| switch (err) { |
| 2410 | error.MissingDebugInfo, error.InvalidDebugInfo => out.* = std.debug.SourceLocation.invalid, |
| 2411 | else => |e| return e, |
| 2412 | } |
| 2413 | } |
| 2343 | 2414 | } |
| 2344 | 2415 | |
| 2345 | 2416 | fn getSymbol(di: *Dwarf, allocator: Allocator, address: u64) !std.debug.Symbol { |