authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-20 13:49:02-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-20 13:49:02-04:00
logb864fe7e23e5c222e82cc6ccb840eb5e8e1bf15b
treebf2d55575f45dde19df5b4132d720b086fc754c7
parent1030cc97cacbf7f7389ff56601a1bde9e33d3763
parent9b83fe6b4c289ac7168bb052c3538ccd188ae83c
signature Commit is signed but in an unrecognized format.

Merge branch 'LemonBoy-dwarfy'


2 files changed, 164 insertions(+), 13 deletions(-)

std/debug.zig+163-13
...@@ -376,7 +376,6 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres...@@ -376,7 +376,6 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
376 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)376 // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records)
377 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,377 // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in,
378 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.378 // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection.
379
380 const subsection_end_index = sect_offset + subsect_hdr.Length;379 const subsection_end_index = sect_offset + subsect_hdr.Length;
381380
382 while (line_index < subsection_end_index) {381 while (line_index < subsection_end_index) {
...@@ -692,7 +691,7 @@ pub fn printSourceAtAddressDwarf(...@@ -692,7 +691,7 @@ pub fn printSourceAtAddressDwarf(
692 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);691 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
693 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {692 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
694 defer line_info.deinit();693 defer line_info.deinit();
695 const symbol_name = "???";694 const symbol_name = getSymbolNameDwarf(debug_info, address - 1) orelse "???";
696 try printLineInfo(695 try printLineInfo(
697 out_stream,696 out_stream,
698 line_info,697 line_info,
...@@ -969,6 +968,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec...@@ -969,6 +968,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec
969pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {968pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
970 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);969 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
971 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);970 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
971 di.func_list = ArrayList(Func).init(allocator);
972 try scanAllFunctions(di);
972 try scanAllCompileUnits(di);973 try scanAllCompileUnits(di);
973}974}
974975
...@@ -992,6 +993,7 @@ pub fn openElfDebugInfo(...@@ -992,6 +993,7 @@ pub fn openElfDebugInfo(
992 .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),993 .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
993 .abbrev_table_list = undefined,994 .abbrev_table_list = undefined,
994 .compile_unit_list = undefined,995 .compile_unit_list = undefined,
996 .func_list = undefined,
995 };997 };
996 try openDwarfDebugInfo(&di, allocator);998 try openDwarfDebugInfo(&di, allocator);
997 return di;999 return di;
...@@ -1162,6 +1164,7 @@ pub const DwarfInfo = struct {...@@ -1162,6 +1164,7 @@ pub const DwarfInfo = struct {
1162 debug_ranges: ?Section,1164 debug_ranges: ?Section,
1163 abbrev_table_list: ArrayList(AbbrevTableHeader),1165 abbrev_table_list: ArrayList(AbbrevTableHeader),
1164 compile_unit_list: ArrayList(CompileUnit),1166 compile_unit_list: ArrayList(CompileUnit),
1167 func_list: ArrayList(Func),
11651168
1166 pub const Section = struct {1169 pub const Section = struct {
1167 offset: usize,1170 offset: usize,
...@@ -1301,6 +1304,14 @@ const Die = struct {...@@ -1301,6 +1304,14 @@ const Die = struct {
1301 };1304 };
1302 }1305 }
13031306
1307 fn getAttrRef(self: *const Die, id: u64) !u64 {
1308 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1309 return switch (form_value.*) {
1310 FormValue.Ref => |value| value,
1311 else => error.InvalidDebugInfo,
1312 };
1313 }
1314
1304 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {1315 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
1305 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;1316 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1306 return switch (form_value.*) {1317 return switch (form_value.*) {
...@@ -1440,17 +1451,17 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !...@@ -1440,17 +1451,17 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
1440 return parseFormValueBlockLen(allocator, in_stream, block_len);1451 return parseFormValueBlockLen(allocator, in_stream, block_len);
1441}1452}
14421453
1443fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: i32) !FormValue {1454fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
1444 return FormValue{1455 return FormValue{
1445 .Const = Constant{1456 .Const = Constant{
1446 .signed = signed,1457 .signed = signed,
1447 .payload = switch (size) {1458 .payload = switch (size) {
1448 1 => try in_stream.readIntLittle(u8),1459 1 => try in_stream.readIntLittle(u8),
1449 2 => try in_stream.readIntLittle(u16),1460 2 => try in_stream.readIntLittle(u16),
1450 4 => try in_stream.readIntLittle(u32),1461 4 => try in_stream.readIntLittle(u32),
1451 8 => try in_stream.readIntLittle(u64),1462 8 => try in_stream.readIntLittle(u64),
1452 -1 => if (signed) try readULeb128(in_stream) else @intCast(u64, try readILeb128(in_stream)),1463 -1 => if (signed) @intCast(u64, try readILeb128(in_stream)) else try readULeb128(in_stream),
1453 else => unreachable,1464 else => @compileError("Invalid size"),
1454 },1465 },
1455 },1466 },
1456 };1467 };
...@@ -1467,10 +1478,10 @@ fn parseFormValueTargetAddrSize(in_stream: var) !u64 {...@@ -1467,10 +1478,10 @@ fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
1467fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {1478fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
1468 return FormValue{1479 return FormValue{
1469 .Ref = switch (size) {1480 .Ref = switch (size) {
1470 1 => try in_stream.readIntLittle(u8),1481 1 => try in_stream.readIntLittle(u8),
1471 2 => try in_stream.readIntLittle(u16),1482 2 => try in_stream.readIntLittle(u16),
1472 4 => try in_stream.readIntLittle(u32),1483 4 => try in_stream.readIntLittle(u32),
1473 8 => try in_stream.readIntLittle(u64),1484 8 => try in_stream.readIntLittle(u64),
1474 -1 => try readULeb128(in_stream),1485 -1 => try readULeb128(in_stream),
1475 else => unreachable,1486 else => unreachable,
1476 },1487 },
...@@ -1571,6 +1582,26 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con...@@ -1571,6 +1582,26 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
1571 return null;1582 return null;
1572}1583}
15731584
1585fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1586 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1587 if (abbrev_code == 0) return null;
1588 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1589
1590 var result = Die{
1591 .tag_id = table_entry.tag_id,
1592 .has_children = table_entry.has_children,
1593 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1594 };
1595 try result.attrs.resize(table_entry.attrs.len);
1596 for (table_entry.attrs.toSliceConst()) |attr, i| {
1597 result.attrs.items[i] = Die.Attr{
1598 .id = attr.attr_id,
1599 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1600 };
1601 }
1602 return result;
1603}
1604
1574fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {1605fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1575 const abbrev_code = try readULeb128(di.dwarf_in_stream);1606 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1576 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;1607 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
...@@ -1954,6 +1985,125 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1954,6 +1985,125 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1954 return error.MissingDebugInfo;1985 return error.MissingDebugInfo;
1955}1986}
19561987
1988const Func = struct {
1989 pc_range: ?PcRange,
1990 name: ?[]u8,
1991};
1992
1993fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]const u8 {
1994 for (di.func_list.toSliceConst()) |*func| {
1995 if (func.pc_range) |range| {
1996 if (address >= range.start and address < range.end) {
1997 return func.name;
1998 }
1999 }
2000 }
2001
2002 return null;
2003}
2004
2005fn scanAllFunctions(di: *DwarfInfo) !void {
2006 const debug_info_end = di.debug_info.offset + di.debug_info.size;
2007 var this_unit_offset = di.debug_info.offset;
2008
2009 while (this_unit_offset < debug_info_end) {
2010 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
2011
2012 var is_64: bool = undefined;
2013 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
2014 if (unit_length == 0) return;
2015 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
2016
2017 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
2018 if (version < 2 or version > 5) return error.InvalidDebugInfo;
2019
2020 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);
2021
2022 const address_size = try di.dwarf_in_stream.readByte();
2023 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
2024
2025 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
2026 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
2027
2028 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
2029
2030 const next_unit_pos = this_unit_offset + next_offset;
2031
2032 while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
2033 const die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse continue;
2034 const after_die_offset = try di.dwarf_seekable_stream.getPos();
2035
2036 switch (die_obj.tag_id) {
2037 DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
2038 const fn_name = x: {
2039 var depth: i32 = 3;
2040 var this_die_obj = die_obj;
2041 // Prenvent endless loops
2042 while (depth > 0) : (depth -= 1) {
2043 if (this_die_obj.getAttr(DW.AT_name)) |_| {
2044 const name = try this_die_obj.getAttrString(di, DW.AT_name);
2045 break :x name;
2046 } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
2047 // Follow the DIE it points to and repeat
2048 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
2049 if (ref_offset > next_offset) return error.InvalidDebugInfo;
2050 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
2051 this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2052 } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
2053 // Follow the DIE it points to and repeat
2054 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
2055 if (ref_offset > next_offset) return error.InvalidDebugInfo;
2056 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
2057 this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2058 } else {
2059 break :x null;
2060 }
2061 }
2062
2063 break :x null;
2064 };
2065
2066 const pc_range = x: {
2067 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
2068 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
2069 const pc_end = switch (high_pc_value.*) {
2070 FormValue.Address => |value| value,
2071 FormValue.Const => |value| b: {
2072 const offset = try value.asUnsignedLe();
2073 break :b (low_pc + offset);
2074 },
2075 else => return error.InvalidDebugInfo,
2076 };
2077 break :x PcRange{
2078 .start = low_pc,
2079 .end = pc_end,
2080 };
2081 } else {
2082 break :x null;
2083 }
2084 } else |err| {
2085 if (err != error.MissingDebugInfo) return err;
2086 break :x null;
2087 }
2088 };
2089
2090 try di.func_list.append(Func{
2091 .name = fn_name,
2092 .pc_range = pc_range,
2093 });
2094 },
2095 else => {
2096 continue;
2097 },
2098 }
2099
2100 try di.dwarf_seekable_stream.seekTo(after_die_offset);
2101 }
2102
2103 this_unit_offset += next_offset;
2104 }
2105}
2106
1957fn scanAllCompileUnits(di: *DwarfInfo) !void {2107fn scanAllCompileUnits(di: *DwarfInfo) !void {
1958 const debug_info_end = di.debug_info.offset + di.debug_info.size;2108 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1959 var this_unit_offset = di.debug_info.offset;2109 var this_unit_offset = di.debug_info.offset;
std/dwarf.zig+1
...@@ -13,6 +13,7 @@ pub const TAG_reference_type = 0x10;...@@ -13,6 +13,7 @@ pub const TAG_reference_type = 0x10;
13pub const TAG_compile_unit = 0x11;13pub const TAG_compile_unit = 0x11;
14pub const TAG_string_type = 0x12;14pub const TAG_string_type = 0x12;
15pub const TAG_structure_type = 0x13;15pub const TAG_structure_type = 0x13;
16pub const TAG_subroutine = 0x14;
16pub const TAG_subroutine_type = 0x15;17pub const TAG_subroutine_type = 0x15;
17pub const TAG_typedef = 0x16;18pub const TAG_typedef = 0x16;
18pub const TAG_union_type = 0x17;19pub const TAG_union_type = 0x17;