Merge branch 'dwarfy' of https://github.com/LemonBoy/zig into LemonBoy-dwarfy
commit
907a7068ce
166
std/debug.zig
166
std/debug.zig
|
@ -692,7 +692,7 @@ pub fn printSourceAtAddressDwarf(
|
|||
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
||||
if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
|
||||
defer line_info.deinit();
|
||||
const symbol_name = "???";
|
||||
const symbol_name = getSymbolNameDwarf(debug_info, address - 1) orelse "???"[0..2];
|
||||
try printLineInfo(
|
||||
out_stream,
|
||||
line_info,
|
||||
|
@ -969,6 +969,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -992,6 +994,7 @@ pub fn openElfDebugInfo(
|
|||
.debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
|
||||
.abbrev_table_list = undefined,
|
||||
.compile_unit_list = undefined,
|
||||
.func_list = undefined,
|
||||
};
|
||||
try openDwarfDebugInfo(&di, allocator);
|
||||
return di;
|
||||
|
@ -1162,6 +1165,7 @@ pub const DwarfInfo = struct {
|
|||
debug_ranges: ?Section,
|
||||
abbrev_table_list: ArrayList(AbbrevTableHeader),
|
||||
compile_unit_list: ArrayList(CompileUnit),
|
||||
func_list: ArrayList(Func),
|
||||
|
||||
pub const Section = struct {
|
||||
offset: usize,
|
||||
|
@ -1301,6 +1305,14 @@ const Die = struct {
|
|||
};
|
||||
}
|
||||
|
||||
fn getAttrRef(self: *const Die, id: u64) !u64 {
|
||||
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||
return switch (form_value.*) {
|
||||
FormValue.Ref => |value| value,
|
||||
else => error.InvalidDebugInfo,
|
||||
};
|
||||
}
|
||||
|
||||
fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
|
||||
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||
return switch (form_value.*) {
|
||||
|
@ -1440,7 +1452,7 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
|
|||
return parseFormValueBlockLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: i32) !FormValue {
|
||||
fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
|
||||
return FormValue{
|
||||
.Const = Constant{
|
||||
.signed = signed,
|
||||
|
@ -1449,8 +1461,9 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
|
|||
2 => try in_stream.readIntLittle(u16),
|
||||
4 => try in_stream.readIntLittle(u32),
|
||||
8 => try in_stream.readIntLittle(u64),
|
||||
-1 => if (signed) try readULeb128(in_stream) else @intCast(u64, try readILeb128(in_stream)),
|
||||
else => unreachable,
|
||||
-1 => if (signed) @intCast(u64, try readILeb128(in_stream))
|
||||
else try readULeb128(in_stream),
|
||||
else => @compileError("Invalid size"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1571,6 +1584,26 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
|
|||
return null;
|
||||
}
|
||||
|
||||
fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
|
||||
const abbrev_code = try readULeb128(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 parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
|
||||
const abbrev_code = try readULeb128(di.dwarf_in_stream);
|
||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
|
||||
|
@ -1954,6 +1987,131 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
|
|||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
const Func = struct {
|
||||
pc_range: ?PcRange,
|
||||
name: ?[]u8,
|
||||
};
|
||||
|
||||
fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]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) usize(12) else 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 parseDie1(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 parseDie1(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_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 parseDie1(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;
|
||||
|
|
|
@ -13,6 +13,7 @@ pub const TAG_reference_type = 0x10;
|
|||
pub const TAG_compile_unit = 0x11;
|
||||
pub const TAG_string_type = 0x12;
|
||||
pub const TAG_structure_type = 0x13;
|
||||
pub const TAG_subroutine = 0x14;
|
||||
pub const TAG_subroutine_type = 0x15;
|
||||
pub const TAG_typedef = 0x16;
|
||||
pub const TAG_union_type = 0x17;
|
||||
|
|
Loading…
Reference in New Issue