Commit c0cb676745

daurnimator <quae@daurnimator.com>
2019-11-15 08:46:18
std: refactor std/debug.zig DwarfInfo operations to be methods
1 parent f8a2dec
Changed files (1)
lib
lib/std/debug.zig
@@ -732,50 +732,8 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
     }
 }
 
-/// This function works in freestanding mode.
-/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
-pub fn printSourceAtAddressDwarf(
-    debug_info: *DwarfInfo,
-    out_stream: var,
-    address: usize,
-    tty_color: bool,
-    comptime printLineFromFile: var,
-) !void {
-    const compile_unit = findCompileUnit(debug_info, address) catch {
-        if (tty_color) {
-            try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
-        } else {
-            try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
-        }
-        return;
-    };
-    const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
-    if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address)) |line_info| {
-        defer line_info.deinit();
-        const symbol_name = getSymbolNameDwarf(debug_info, address) orelse "???";
-        try printLineInfo(
-            out_stream,
-            line_info,
-            address,
-            symbol_name,
-            compile_unit_name,
-            tty_color,
-            printLineFromFile,
-        );
-    } else |err| switch (err) {
-        error.MissingDebugInfo, error.InvalidDebugInfo => {
-            if (tty_color) {
-                try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
-            } else {
-                try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
-            }
-        },
-        else => return err,
-    }
-}
-
 pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
-    return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
+    return debug_info.printSourceAtAddress(out_stream, address, tty_color, printLineFromFileAnyOs);
 }
 
 fn printLineInfo(
@@ -1034,8 +992,8 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
     di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
     di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
     di.func_list = ArrayList(Func).init(allocator);
-    try scanAllFunctions(di);
-    try scanAllCompileUnits(di);
+    try di.scanAllFunctions();
+    try di.scanAllCompileUnits();
 }
 
 pub fn openElfDebugInfo(
@@ -1253,6 +1211,492 @@ pub const DwarfInfo = struct {
     pub fn readString(self: *DwarfInfo) ![]u8 {
         return readStringRaw(self.allocator(), self.dwarf_in_stream);
     }
+
+    /// This function works in freestanding mode.
+    /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
+    pub fn printSourceAtAddress(
+        self: *DwarfInfo,
+        out_stream: var,
+        address: usize,
+        tty_color: bool,
+        comptime printLineFromFile: var,
+    ) !void {
+        const compile_unit = self.findCompileUnit(address) catch {
+            if (tty_color) {
+                try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
+            } else {
+                try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
+            }
+            return;
+        };
+        const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);
+        if (self.getLineNumberInfo(compile_unit.*, address)) |line_info| {
+            defer line_info.deinit();
+            const symbol_name = self.getSymbolName(address) orelse "???";
+            try printLineInfo(
+                out_stream,
+                line_info,
+                address,
+                symbol_name,
+                compile_unit_name,
+                tty_color,
+                printLineFromFile,
+            );
+        } else |err| switch (err) {
+            error.MissingDebugInfo, error.InvalidDebugInfo => {
+                if (tty_color) {
+                    try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
+                } else {
+                    try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
+                }
+            },
+            else => return err,
+        }
+    }
+
+    fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
+        for (di.func_list.toSliceConst()) |*func| {
+            if (func.pc_range) |range| {
+                if (address >= range.start and address < range.end) {
+                    return func.name;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    fn scanAllFunctions(di: *DwarfInfo) !void {
+        const debug_info_end = di.debug_info.offset + di.debug_info.size;
+        var this_unit_offset = di.debug_info.offset;
+
+        while (this_unit_offset < debug_info_end) {
+            try di.dwarf_seekable_stream.seekTo(this_unit_offset);
+
+            var is_64: bool = undefined;
+            const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
+            if (unit_length == 0) return;
+            const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
+
+            const version = try di.dwarf_in_stream.readInt(u16, di.endian);
+            if (version < 2 or version > 5) return error.InvalidDebugInfo;
+
+            const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
+
+            const address_size = try di.dwarf_in_stream.readByte();
+            if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
+
+            const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
+            const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
+
+            try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
+
+            const next_unit_pos = this_unit_offset + next_offset;
+
+            while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
+                const die_obj = (try di.parseDie(abbrev_table, is_64)) orelse continue;
+                const after_die_offset = try di.dwarf_seekable_stream.getPos();
+
+                switch (die_obj.tag_id) {
+                    DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
+                        const fn_name = x: {
+                            var depth: i32 = 3;
+                            var this_die_obj = die_obj;
+                            // Prenvent endless loops
+                            while (depth > 0) : (depth -= 1) {
+                                if (this_die_obj.getAttr(DW.AT_name)) |_| {
+                                    const name = try this_die_obj.getAttrString(di, DW.AT_name);
+                                    break :x name;
+                                } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
+                                    // Follow the DIE it points to and repeat
+                                    const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
+                                    if (ref_offset > next_offset) return error.InvalidDebugInfo;
+                                    try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
+                                    this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+                                } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
+                                    // Follow the DIE it points to and repeat
+                                    const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
+                                    if (ref_offset > next_offset) return error.InvalidDebugInfo;
+                                    try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
+                                    this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+                                } else {
+                                    break :x null;
+                                }
+                            }
+
+                            break :x null;
+                        };
+
+                        const pc_range = x: {
+                            if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
+                                if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
+                                    const pc_end = switch (high_pc_value.*) {
+                                        FormValue.Address => |value| value,
+                                        FormValue.Const => |value| b: {
+                                            const offset = try value.asUnsignedLe();
+                                            break :b (low_pc + offset);
+                                        },
+                                        else => return error.InvalidDebugInfo,
+                                    };
+                                    break :x PcRange{
+                                        .start = low_pc,
+                                        .end = pc_end,
+                                    };
+                                } else {
+                                    break :x null;
+                                }
+                            } else |err| {
+                                if (err != error.MissingDebugInfo) return err;
+                                break :x null;
+                            }
+                        };
+
+                        try di.func_list.append(Func{
+                            .name = fn_name,
+                            .pc_range = pc_range,
+                        });
+                    },
+                    else => {
+                        continue;
+                    },
+                }
+
+                try di.dwarf_seekable_stream.seekTo(after_die_offset);
+            }
+
+            this_unit_offset += next_offset;
+        }
+    }
+
+    fn scanAllCompileUnits(di: *DwarfInfo) !void {
+        const debug_info_end = di.debug_info.offset + di.debug_info.size;
+        var this_unit_offset = di.debug_info.offset;
+
+        while (this_unit_offset < debug_info_end) {
+            try di.dwarf_seekable_stream.seekTo(this_unit_offset);
+
+            var is_64: bool = undefined;
+            const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
+            if (unit_length == 0) return;
+            const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
+
+            const version = try di.dwarf_in_stream.readInt(u16, di.endian);
+            if (version < 2 or version > 5) return error.InvalidDebugInfo;
+
+            const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
+
+            const address_size = try di.dwarf_in_stream.readByte();
+            if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
+
+            const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
+            const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
+
+            try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
+
+            const compile_unit_die = try di.allocator().create(Die);
+            compile_unit_die.* = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+
+            if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
+
+            const pc_range = x: {
+                if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
+                    if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
+                        const pc_end = switch (high_pc_value.*) {
+                            FormValue.Address => |value| value,
+                            FormValue.Const => |value| b: {
+                                const offset = try value.asUnsignedLe();
+                                break :b (low_pc + offset);
+                            },
+                            else => return error.InvalidDebugInfo,
+                        };
+                        break :x PcRange{
+                            .start = low_pc,
+                            .end = pc_end,
+                        };
+                    } else {
+                        break :x null;
+                    }
+                } else |err| {
+                    if (err != error.MissingDebugInfo) return err;
+                    break :x null;
+                }
+            };
+
+            try di.compile_unit_list.append(CompileUnit{
+                .version = version,
+                .is_64 = is_64,
+                .pc_range = pc_range,
+                .die = compile_unit_die,
+            });
+
+            this_unit_offset += next_offset;
+        }
+    }
+
+    fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
+        for (di.compile_unit_list.toSlice()) |*compile_unit| {
+            if (compile_unit.pc_range) |range| {
+                if (target_address >= range.start and target_address < range.end) return compile_unit;
+            }
+            if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
+                var base_address: usize = 0;
+                if (di.debug_ranges) |debug_ranges| {
+                    try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
+                    while (true) {
+                        const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
+                        const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
+                        if (begin_addr == 0 and end_addr == 0) {
+                            break;
+                        }
+                        if (begin_addr == maxInt(usize)) {
+                            base_address = begin_addr;
+                            continue;
+                        }
+                        if (target_address >= begin_addr and target_address < end_addr) {
+                            return compile_unit;
+                        }
+                    }
+                }
+            } else |err| {
+                if (err != error.MissingDebugInfo) return err;
+                continue;
+            }
+        }
+        return error.MissingDebugInfo;
+    }
+
+    /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
+    /// seeks in the stream and parses it.
+    fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
+        for (di.abbrev_table_list.toSlice()) |*header| {
+            if (header.offset == abbrev_offset) {
+                return &header.table;
+            }
+        }
+        try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
+        try di.abbrev_table_list.append(AbbrevTableHeader{
+            .offset = abbrev_offset,
+            .table = try di.parseAbbrevTable(),
+        });
+        return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
+    }
+
+    fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
+        var result = AbbrevTable.init(di.allocator());
+        while (true) {
+            const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
+            if (abbrev_code == 0) return result;
+            try result.append(AbbrevTableEntry{
+                .abbrev_code = abbrev_code,
+                .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
+                .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
+                .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
+            });
+            const attrs = &result.items[result.len - 1].attrs;
+
+            while (true) {
+                const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
+                const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
+                if (attr_id == 0 and form_id == 0) break;
+                try attrs.append(AbbrevAttr{
+                    .attr_id = attr_id,
+                    .form_id = form_id,
+                });
+            }
+        }
+    }
+
+    fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
+        const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
+        if (abbrev_code == 0) return null;
+        const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
+
+        var result = Die{
+            .tag_id = table_entry.tag_id,
+            .has_children = table_entry.has_children,
+            .attrs = ArrayList(Die.Attr).init(di.allocator()),
+        };
+        try result.attrs.resize(table_entry.attrs.len);
+        for (table_entry.attrs.toSliceConst()) |attr, i| {
+            result.attrs.items[i] = Die.Attr{
+                .id = attr.attr_id,
+                .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
+            };
+        }
+        return result;
+    }
+
+    fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
+        const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
+        const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
+
+        assert(line_info_offset < di.debug_line.size);
+
+        try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
+
+        var is_64: bool = undefined;
+        const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
+        if (unit_length == 0) {
+            return error.MissingDebugInfo;
+        }
+        const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
+
+        const version = try di.dwarf_in_stream.readInt(u16, di.endian);
+        // TODO support 3 and 5
+        if (version != 2 and version != 4) return error.InvalidDebugInfo;
+
+        const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
+        const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
+
+        const minimum_instruction_length = try di.dwarf_in_stream.readByte();
+        if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+
+        if (version >= 4) {
+            // maximum_operations_per_instruction
+            _ = try di.dwarf_in_stream.readByte();
+        }
+
+        const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
+        const line_base = try di.dwarf_in_stream.readByteSigned();
+
+        const line_range = try di.dwarf_in_stream.readByte();
+        if (line_range == 0) return error.InvalidDebugInfo;
+
+        const opcode_base = try di.dwarf_in_stream.readByte();
+
+        const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
+
+        {
+            var i: usize = 0;
+            while (i < opcode_base - 1) : (i += 1) {
+                standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
+            }
+        }
+
+        var include_directories = ArrayList([]u8).init(di.allocator());
+        try include_directories.append(compile_unit_cwd);
+        while (true) {
+            const dir = try di.readString();
+            if (dir.len == 0) break;
+            try include_directories.append(dir);
+        }
+
+        var file_entries = ArrayList(FileEntry).init(di.allocator());
+        var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
+
+        while (true) {
+            const file_name = try di.readString();
+            if (file_name.len == 0) break;
+            const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
+            const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
+            const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
+            try file_entries.append(FileEntry{
+                .file_name = file_name,
+                .dir_index = dir_index,
+                .mtime = mtime,
+                .len_bytes = len_bytes,
+            });
+        }
+
+        try di.dwarf_seekable_stream.seekTo(prog_start_offset);
+
+        while (true) {
+            const opcode = try di.dwarf_in_stream.readByte();
+
+            if (opcode == DW.LNS_extended_op) {
+                const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
+                if (op_size < 1) return error.InvalidDebugInfo;
+                var sub_op = try di.dwarf_in_stream.readByte();
+                switch (sub_op) {
+                    DW.LNE_end_sequence => {
+                        prog.end_sequence = true;
+                        if (try prog.checkLineMatch()) |info| return info;
+                        return error.MissingDebugInfo;
+                    },
+                    DW.LNE_set_address => {
+                        const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
+                        prog.address = addr;
+                    },
+                    DW.LNE_define_file => {
+                        const file_name = try di.readString();
+                        const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
+                        const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
+                        const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
+                        try file_entries.append(FileEntry{
+                            .file_name = file_name,
+                            .dir_index = dir_index,
+                            .mtime = mtime,
+                            .len_bytes = len_bytes,
+                        });
+                    },
+                    else => {
+                        const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
+                        try di.dwarf_seekable_stream.seekBy(fwd_amt);
+                    },
+                }
+            } else if (opcode >= opcode_base) {
+                // special opcodes
+                const adjusted_opcode = opcode - opcode_base;
+                const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
+                const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
+                prog.line += inc_line;
+                prog.address += inc_addr;
+                if (try prog.checkLineMatch()) |info| return info;
+                prog.basic_block = false;
+            } else {
+                switch (opcode) {
+                    DW.LNS_copy => {
+                        if (try prog.checkLineMatch()) |info| return info;
+                        prog.basic_block = false;
+                    },
+                    DW.LNS_advance_pc => {
+                        const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
+                        prog.address += arg * minimum_instruction_length;
+                    },
+                    DW.LNS_advance_line => {
+                        const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
+                        prog.line += arg;
+                    },
+                    DW.LNS_set_file => {
+                        const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
+                        prog.file = arg;
+                    },
+                    DW.LNS_set_column => {
+                        const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
+                        prog.column = arg;
+                    },
+                    DW.LNS_negate_stmt => {
+                        prog.is_stmt = !prog.is_stmt;
+                    },
+                    DW.LNS_set_basic_block => {
+                        prog.basic_block = true;
+                    },
+                    DW.LNS_const_add_pc => {
+                        const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
+                        prog.address += inc_addr;
+                    },
+                    DW.LNS_fixed_advance_pc => {
+                        const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
+                        prog.address += arg;
+                    },
+                    DW.LNS_set_prologue_end => {},
+                    else => {
+                        if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
+                        const len_bytes = standard_opcode_lengths[opcode - 1];
+                        try di.dwarf_seekable_stream.seekBy(len_bytes);
+                    },
+                }
+            }
+        }
+
+        return error.MissingDebugInfo;
+    }
+
+    fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
+        const pos = di.debug_str.offset + offset;
+        try di.dwarf_seekable_stream.seekTo(pos);
+        return di.readString();
+    }
 };
 
 pub const DebugInfo = switch (builtin.os) {
@@ -1391,7 +1835,7 @@ const Die = struct {
         const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
         return switch (form_value.*) {
             FormValue.String => |value| value,
-            FormValue.StrPtr => |offset| getString(di, offset),
+            FormValue.StrPtr => |offset| di.getString(offset),
             else => error.InvalidDebugInfo,
         };
     }
@@ -1504,12 +1948,6 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
     return buf.toSlice();
 }
 
-fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
-    const pos = di.debug_str.offset + offset;
-    try di.dwarf_seekable_stream.seekTo(pos);
-    return di.readString();
-}
-
 // TODO the noasyncs here are workarounds
 fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
     const buf = try allocator.alloc(u8, size);
@@ -1636,47 +2074,6 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
     };
 }
 
-fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
-    var result = AbbrevTable.init(di.allocator());
-    while (true) {
-        const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
-        if (abbrev_code == 0) return result;
-        try result.append(AbbrevTableEntry{
-            .abbrev_code = abbrev_code,
-            .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
-            .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
-            .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
-        });
-        const attrs = &result.items[result.len - 1].attrs;
-
-        while (true) {
-            const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
-            const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
-            if (attr_id == 0 and form_id == 0) break;
-            try attrs.append(AbbrevAttr{
-                .attr_id = attr_id,
-                .form_id = form_id,
-            });
-        }
-    }
-}
-
-/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
-/// seeks in the stream and parses it.
-fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
-    for (di.abbrev_table_list.toSlice()) |*header| {
-        if (header.offset == abbrev_offset) {
-            return &header.table;
-        }
-    }
-    try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
-    try di.abbrev_table_list.append(AbbrevTableHeader{
-        .offset = abbrev_offset,
-        .table = try parseAbbrevTable(di),
-    });
-    return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
-}
-
 fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
     for (abbrev_table.toSliceConst()) |*table_entry| {
         if (table_entry.abbrev_code == abbrev_code) return table_entry;
@@ -1684,26 +2081,6 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
     return null;
 }
 
-fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
-    const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
-    if (abbrev_code == 0) return null;
-    const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
-
-    var result = Die{
-        .tag_id = table_entry.tag_id,
-        .has_children = table_entry.has_children,
-        .attrs = ArrayList(Die.Attr).init(di.allocator()),
-    };
-    try result.attrs.resize(table_entry.attrs.len);
-    for (table_entry.attrs.toSliceConst()) |attr, i| {
-        result.attrs.items[i] = Die.Attr{
-            .id = attr.attr_id,
-            .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
-        };
-    }
-    return result;
-}
-
 fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
     const ofile = symbol.ofile orelse return error.MissingDebugInfo;
     const gop = try di.ofiles.getOrPut(ofile);
@@ -1907,388 +2284,11 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
     return error.MissingDebugInfo;
 }
 
-fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
-    const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
-    const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
-
-    assert(line_info_offset < di.debug_line.size);
-
-    try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
-
-    var is_64: bool = undefined;
-    const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
-    if (unit_length == 0) {
-        return error.MissingDebugInfo;
-    }
-    const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
-
-    const version = try di.dwarf_in_stream.readInt(u16, di.endian);
-    // TODO support 3 and 5
-    if (version != 2 and version != 4) return error.InvalidDebugInfo;
-
-    const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
-    const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
-
-    const minimum_instruction_length = try di.dwarf_in_stream.readByte();
-    if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
-
-    if (version >= 4) {
-        // maximum_operations_per_instruction
-        _ = try di.dwarf_in_stream.readByte();
-    }
-
-    const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
-    const line_base = try di.dwarf_in_stream.readByteSigned();
-
-    const line_range = try di.dwarf_in_stream.readByte();
-    if (line_range == 0) return error.InvalidDebugInfo;
-
-    const opcode_base = try di.dwarf_in_stream.readByte();
-
-    const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
-
-    {
-        var i: usize = 0;
-        while (i < opcode_base - 1) : (i += 1) {
-            standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
-        }
-    }
-
-    var include_directories = ArrayList([]u8).init(di.allocator());
-    try include_directories.append(compile_unit_cwd);
-    while (true) {
-        const dir = try di.readString();
-        if (dir.len == 0) break;
-        try include_directories.append(dir);
-    }
-
-    var file_entries = ArrayList(FileEntry).init(di.allocator());
-    var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
-
-    while (true) {
-        const file_name = try di.readString();
-        if (file_name.len == 0) break;
-        const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
-        const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
-        const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
-        try file_entries.append(FileEntry{
-            .file_name = file_name,
-            .dir_index = dir_index,
-            .mtime = mtime,
-            .len_bytes = len_bytes,
-        });
-    }
-
-    try di.dwarf_seekable_stream.seekTo(prog_start_offset);
-
-    while (true) {
-        const opcode = try di.dwarf_in_stream.readByte();
-
-        if (opcode == DW.LNS_extended_op) {
-            const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
-            if (op_size < 1) return error.InvalidDebugInfo;
-            var sub_op = try di.dwarf_in_stream.readByte();
-            switch (sub_op) {
-                DW.LNE_end_sequence => {
-                    prog.end_sequence = true;
-                    if (try prog.checkLineMatch()) |info| return info;
-                    return error.MissingDebugInfo;
-                },
-                DW.LNE_set_address => {
-                    const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
-                    prog.address = addr;
-                },
-                DW.LNE_define_file => {
-                    const file_name = try di.readString();
-                    const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
-                    const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
-                    const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
-                    try file_entries.append(FileEntry{
-                        .file_name = file_name,
-                        .dir_index = dir_index,
-                        .mtime = mtime,
-                        .len_bytes = len_bytes,
-                    });
-                },
-                else => {
-                    const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
-                    try di.dwarf_seekable_stream.seekBy(fwd_amt);
-                },
-            }
-        } else if (opcode >= opcode_base) {
-            // special opcodes
-            const adjusted_opcode = opcode - opcode_base;
-            const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
-            const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
-            prog.line += inc_line;
-            prog.address += inc_addr;
-            if (try prog.checkLineMatch()) |info| return info;
-            prog.basic_block = false;
-        } else {
-            switch (opcode) {
-                DW.LNS_copy => {
-                    if (try prog.checkLineMatch()) |info| return info;
-                    prog.basic_block = false;
-                },
-                DW.LNS_advance_pc => {
-                    const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
-                    prog.address += arg * minimum_instruction_length;
-                },
-                DW.LNS_advance_line => {
-                    const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
-                    prog.line += arg;
-                },
-                DW.LNS_set_file => {
-                    const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
-                    prog.file = arg;
-                },
-                DW.LNS_set_column => {
-                    const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
-                    prog.column = arg;
-                },
-                DW.LNS_negate_stmt => {
-                    prog.is_stmt = !prog.is_stmt;
-                },
-                DW.LNS_set_basic_block => {
-                    prog.basic_block = true;
-                },
-                DW.LNS_const_add_pc => {
-                    const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
-                    prog.address += inc_addr;
-                },
-                DW.LNS_fixed_advance_pc => {
-                    const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
-                    prog.address += arg;
-                },
-                DW.LNS_set_prologue_end => {},
-                else => {
-                    if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
-                    const len_bytes = standard_opcode_lengths[opcode - 1];
-                    try di.dwarf_seekable_stream.seekBy(len_bytes);
-                },
-            }
-        }
-    }
-
-    return error.MissingDebugInfo;
-}
-
 const Func = struct {
     pc_range: ?PcRange,
     name: ?[]u8,
 };
 
-fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]const u8 {
-    for (di.func_list.toSliceConst()) |*func| {
-        if (func.pc_range) |range| {
-            if (address >= range.start and address < range.end) {
-                return func.name;
-            }
-        }
-    }
-
-    return null;
-}
-
-fn scanAllFunctions(di: *DwarfInfo) !void {
-    const debug_info_end = di.debug_info.offset + di.debug_info.size;
-    var this_unit_offset = di.debug_info.offset;
-
-    while (this_unit_offset < debug_info_end) {
-        try di.dwarf_seekable_stream.seekTo(this_unit_offset);
-
-        var is_64: bool = undefined;
-        const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
-        if (unit_length == 0) return;
-        const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
-
-        const version = try di.dwarf_in_stream.readInt(u16, di.endian);
-        if (version < 2 or version > 5) return error.InvalidDebugInfo;
-
-        const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
-
-        const address_size = try di.dwarf_in_stream.readByte();
-        if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
-
-        const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
-        const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
-
-        try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
-
-        const next_unit_pos = this_unit_offset + next_offset;
-
-        while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
-            const die_obj = (try parseDie(di, abbrev_table, is_64)) orelse continue;
-            const after_die_offset = try di.dwarf_seekable_stream.getPos();
-
-            switch (die_obj.tag_id) {
-                DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
-                    const fn_name = x: {
-                        var depth: i32 = 3;
-                        var this_die_obj = die_obj;
-                        // Prenvent endless loops
-                        while (depth > 0) : (depth -= 1) {
-                            if (this_die_obj.getAttr(DW.AT_name)) |_| {
-                                const name = try this_die_obj.getAttrString(di, DW.AT_name);
-                                break :x name;
-                            } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
-                                // Follow the DIE it points to and repeat
-                                const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
-                                if (ref_offset > next_offset) return error.InvalidDebugInfo;
-                                try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
-                                this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
-                            } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
-                                // Follow the DIE it points to and repeat
-                                const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
-                                if (ref_offset > next_offset) return error.InvalidDebugInfo;
-                                try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
-                                this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
-                            } else {
-                                break :x null;
-                            }
-                        }
-
-                        break :x null;
-                    };
-
-                    const pc_range = x: {
-                        if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
-                            if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
-                                const pc_end = switch (high_pc_value.*) {
-                                    FormValue.Address => |value| value,
-                                    FormValue.Const => |value| b: {
-                                        const offset = try value.asUnsignedLe();
-                                        break :b (low_pc + offset);
-                                    },
-                                    else => return error.InvalidDebugInfo,
-                                };
-                                break :x PcRange{
-                                    .start = low_pc,
-                                    .end = pc_end,
-                                };
-                            } else {
-                                break :x null;
-                            }
-                        } else |err| {
-                            if (err != error.MissingDebugInfo) return err;
-                            break :x null;
-                        }
-                    };
-
-                    try di.func_list.append(Func{
-                        .name = fn_name,
-                        .pc_range = pc_range,
-                    });
-                },
-                else => {
-                    continue;
-                },
-            }
-
-            try di.dwarf_seekable_stream.seekTo(after_die_offset);
-        }
-
-        this_unit_offset += next_offset;
-    }
-}
-
-fn scanAllCompileUnits(di: *DwarfInfo) !void {
-    const debug_info_end = di.debug_info.offset + di.debug_info.size;
-    var this_unit_offset = di.debug_info.offset;
-
-    while (this_unit_offset < debug_info_end) {
-        try di.dwarf_seekable_stream.seekTo(this_unit_offset);
-
-        var is_64: bool = undefined;
-        const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
-        if (unit_length == 0) return;
-        const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
-
-        const version = try di.dwarf_in_stream.readInt(u16, di.endian);
-        if (version < 2 or version > 5) return error.InvalidDebugInfo;
-
-        const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
-
-        const address_size = try di.dwarf_in_stream.readByte();
-        if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
-
-        const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
-        const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
-
-        try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
-
-        const compile_unit_die = try di.allocator().create(Die);
-        compile_unit_die.* = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
-
-        if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
-
-        const pc_range = x: {
-            if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
-                if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
-                    const pc_end = switch (high_pc_value.*) {
-                        FormValue.Address => |value| value,
-                        FormValue.Const => |value| b: {
-                            const offset = try value.asUnsignedLe();
-                            break :b (low_pc + offset);
-                        },
-                        else => return error.InvalidDebugInfo,
-                    };
-                    break :x PcRange{
-                        .start = low_pc,
-                        .end = pc_end,
-                    };
-                } else {
-                    break :x null;
-                }
-            } else |err| {
-                if (err != error.MissingDebugInfo) return err;
-                break :x null;
-            }
-        };
-
-        try di.compile_unit_list.append(CompileUnit{
-            .version = version,
-            .is_64 = is_64,
-            .pc_range = pc_range,
-            .die = compile_unit_die,
-        });
-
-        this_unit_offset += next_offset;
-    }
-}
-
-fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
-    for (di.compile_unit_list.toSlice()) |*compile_unit| {
-        if (compile_unit.pc_range) |range| {
-            if (target_address >= range.start and target_address < range.end) return compile_unit;
-        }
-        if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
-            var base_address: usize = 0;
-            if (di.debug_ranges) |debug_ranges| {
-                try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
-                while (true) {
-                    const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
-                    const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
-                    if (begin_addr == 0 and end_addr == 0) {
-                        break;
-                    }
-                    if (begin_addr == maxInt(usize)) {
-                        base_address = begin_addr;
-                        continue;
-                    }
-                    if (target_address >= begin_addr and target_address < end_addr) {
-                        return compile_unit;
-                    }
-                }
-            }
-        } else |err| {
-            if (err != error.MissingDebugInfo) return err;
-            continue;
-        }
-    }
-    return error.MissingDebugInfo;
-}
-
 fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
     // TODO https://github.com/ziglang/zig/issues/863
     const size = (T.bit_count + 7) / 8;