authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-20 13:32:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-20 13:32:59-04:00
log907a7068ce374933630af2e88b57f0cfd10abb72
tree47c3180ada3c26891cc41e3b57d8f3c0c8541c73
parent1030cc97cacbf7f7389ff56601a1bde9e33d3763
parentc2542bb7b775118f69366849b18e139e120ddb16
signature Commit is signed but in an unrecognized format.

Merge branch 'dwarfy' of https://github.com/LemonBoy/zig into LemonBoy-dwarfy


2 files changed, 163 insertions(+), 4 deletions(-)

std/debug.zig+162-4
......@@ -692,7 +692,7 @@ pub fn printSourceAtAddressDwarf(
692692 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
693693 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
694694 defer line_info.deinit();
695 const symbol_name = "???";
695 const symbol_name = getSymbolNameDwarf(debug_info, address - 1) orelse "???"[0..2];
696696 try printLineInfo(
697697 out_stream,
698698 line_info,
......@@ -969,6 +969,8 @@ fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Sec
969969pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
970970 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
971971 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
972 di.func_list = ArrayList(Func).init(allocator);
973 try scanAllFunctions(di);
972974 try scanAllCompileUnits(di);
973975}
974976
......@@ -992,6 +994,7 @@ pub fn openElfDebugInfo(
992994 .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
993995 .abbrev_table_list = undefined,
994996 .compile_unit_list = undefined,
997 .func_list = undefined,
995998 };
996999 try openDwarfDebugInfo(&di, allocator);
9971000 return di;
......@@ -1162,6 +1165,7 @@ pub const DwarfInfo = struct {
11621165 debug_ranges: ?Section,
11631166 abbrev_table_list: ArrayList(AbbrevTableHeader),
11641167 compile_unit_list: ArrayList(CompileUnit),
1168 func_list: ArrayList(Func),
11651169
11661170 pub const Section = struct {
11671171 offset: usize,
......@@ -1301,6 +1305,14 @@ const Die = struct {
13011305 };
13021306 }
13031307
1308 fn getAttrRef(self: *const Die, id: u64) !u64 {
1309 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1310 return switch (form_value.*) {
1311 FormValue.Ref => |value| value,
1312 else => error.InvalidDebugInfo,
1313 };
1314 }
1315
13041316 fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
13051317 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
13061318 return switch (form_value.*) {
......@@ -1440,7 +1452,7 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
14401452 return parseFormValueBlockLen(allocator, in_stream, block_len);
14411453}
14421454
1443fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: i32) !FormValue {
1455fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, comptime size: i32) !FormValue {
14441456 return FormValue{
14451457 .Const = Constant{
14461458 .signed = signed,
......@@ -1449,8 +1461,9 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
14491461 2 => try in_stream.readIntLittle(u16),
14501462 4 => try in_stream.readIntLittle(u32),
14511463 8 => try in_stream.readIntLittle(u64),
1452 -1 => if (signed) try readULeb128(in_stream) else @intCast(u64, try readILeb128(in_stream)),
1453 else => unreachable,
1464 -1 => if (signed) @intCast(u64, try readILeb128(in_stream))
1465 else try readULeb128(in_stream),
1466 else => @compileError("Invalid size"),
14541467 },
14551468 },
14561469 };
......@@ -1571,6 +1584,26 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
15711584 return null;
15721585}
15731586
1587fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1588 const abbrev_code = try readULeb128(di.dwarf_in_stream);
1589 if (abbrev_code == 0) return null;
1590 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1591
1592 var result = Die{
1593 .tag_id = table_entry.tag_id,
1594 .has_children = table_entry.has_children,
1595 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1596 };
1597 try result.attrs.resize(table_entry.attrs.len);
1598 for (table_entry.attrs.toSliceConst()) |attr, i| {
1599 result.attrs.items[i] = Die.Attr{
1600 .id = attr.attr_id,
1601 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1602 };
1603 }
1604 return result;
1605}
1606
15741607fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
15751608 const abbrev_code = try readULeb128(di.dwarf_in_stream);
15761609 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
19541987 return error.MissingDebugInfo;
19551988}
19561989
1990const Func = struct {
1991 pc_range: ?PcRange,
1992 name: ?[]u8,
1993};
1994
1995fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]u8 {
1996 for (di.func_list.toSliceConst()) |*func| {
1997 if (func.pc_range) |range| {
1998 if (address >= range.start and address < range.end) {
1999 return func.name;
2000 }
2001 }
2002 }
2003
2004 return null;
2005}
2006
2007fn scanAllFunctions(di: *DwarfInfo) !void {
2008 const debug_info_end = di.debug_info.offset + di.debug_info.size;
2009 var this_unit_offset = di.debug_info.offset;
2010
2011 while (this_unit_offset < debug_info_end) {
2012 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
2013
2014 var is_64: bool = undefined;
2015 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
2016 if (unit_length == 0) return;
2017 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
2018
2019 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
2020 if (version < 2 or version > 5) return error.InvalidDebugInfo;
2021
2022 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);
2023
2024 const address_size = try di.dwarf_in_stream.readByte();
2025 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
2026
2027 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
2028 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
2029
2030 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
2031
2032 const next_unit_pos = this_unit_offset + next_offset;
2033
2034 while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
2035 const die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse continue;
2036 const after_die_offset = try di.dwarf_seekable_stream.getPos();
2037
2038 switch (die_obj.tag_id) {
2039 DW.TAG_subprogram,
2040 DW.TAG_inlined_subroutine,
2041 DW.TAG_subroutine,
2042 DW.TAG_entry_point => {
2043 const fn_name = x: {
2044 var depth: i32 = 3;
2045 var this_die_obj = die_obj;
2046 // Prenvent endless loops
2047 while (depth > 0) : (depth -= 1) {
2048 if (this_die_obj.getAttr(DW.AT_name)) |_| {
2049 const name = try this_die_obj.getAttrString(di, DW.AT_name);
2050 break :x name;
2051 }
2052 else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |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 }
2059 else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
2060 // Follow the DIE it points to and repeat
2061 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
2062 if (ref_offset > next_offset) return error.InvalidDebugInfo;
2063 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
2064 this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2065 }
2066 else {
2067 break :x null;
2068 }
2069 }
2070
2071 break :x null;
2072 };
2073
2074 const pc_range = x: {
2075 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
2076 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
2077 const pc_end = switch (high_pc_value.*) {
2078 FormValue.Address => |value| value,
2079 FormValue.Const => |value| b: {
2080 const offset = try value.asUnsignedLe();
2081 break :b (low_pc + offset);
2082 },
2083 else => return error.InvalidDebugInfo,
2084 };
2085 break :x PcRange{
2086 .start = low_pc,
2087 .end = pc_end,
2088 };
2089 } else {
2090 break :x null;
2091 }
2092 } else |err| {
2093 if (err != error.MissingDebugInfo) return err;
2094 break :x null;
2095 }
2096 };
2097
2098 try di.func_list.append(Func{
2099 .name = fn_name,
2100 .pc_range = pc_range,
2101 });
2102 },
2103 else => {
2104 continue;
2105 }
2106 }
2107
2108 try di.dwarf_seekable_stream.seekTo(after_die_offset);
2109 }
2110
2111 this_unit_offset += next_offset;
2112 }
2113}
2114
19572115fn scanAllCompileUnits(di: *DwarfInfo) !void {
19582116 const debug_info_end = di.debug_info.offset + di.debug_info.size;
19592117 var this_unit_offset = di.debug_info.offset;
std/dwarf.zig+1
......@@ -13,6 +13,7 @@ pub const TAG_reference_type = 0x10;
1313pub const TAG_compile_unit = 0x11;
1414pub const TAG_string_type = 0x12;
1515pub const TAG_structure_type = 0x13;
16pub const TAG_subroutine = 0x14;
1617pub const TAG_subroutine_type = 0x15;
1718pub const TAG_typedef = 0x16;
1819pub const TAG_union_type = 0x17;