authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-04-11 14:34:13-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-04-11 14:34:13-04:00
log3ce024dd857b4b139651258b5339e32ddad87ade
tree687112ace822fa036ecc828515eeb927bade15d9
parenta895c59971d16481a85b6bff7618a3f9e2a4e0ae
parent51eb4ebec1435dc0050bd1d40c48416019972e65
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

A bunch of fixes for the DWARF parser (#2254)

* Correct parsing of DWARF line_info section * Fix reading of udata/sdata encoded attributes * Add definition for DW_AT_alignment Even though it's been standardized in DWARF5 some compilers produce it anyway for DWARF4 infos too. * Fix reading of reference attributes * Distinguish between absolute/relative addresses

2 files changed, 172 insertions(+), 177 deletions(-)

std/debug.zig+169-177
......@@ -1213,7 +1213,6 @@ const CompileUnit = struct {
12131213 version: u16,
12141214 is_64: bool,
12151215 die: *Die,
1216 index: usize,
12171216 pc_range: ?PcRange,
12181217};
12191218
......@@ -1244,21 +1243,19 @@ const FormValue = union(enum) {
12441243 ExprLoc: []u8,
12451244 Flag: bool,
12461245 SecOffset: u64,
1247 Ref: []u8,
1246 Ref: u64,
12481247 RefAddr: u64,
1249 RefSig8: u64,
12501248 String: []u8,
12511249 StrPtr: u64,
12521250};
12531251
12541252const Constant = struct {
1255 payload: []u8,
1253 payload: u64,
12561254 signed: bool,
12571255
12581256 fn asUnsignedLe(self: *const Constant) !u64 {
1259 if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
12601257 if (self.signed) return error.InvalidDebugInfo;
1261 return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
1258 return self.payload;
12621259 }
12631260};
12641261
......@@ -1443,11 +1440,18 @@ fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !
14431440 return parseFormValueBlockLen(allocator, in_stream, block_len);
14441441}
14451442
1446fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue {
1443fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: bool, size: i32) !FormValue {
14471444 return FormValue{
14481445 .Const = Constant{
14491446 .signed = signed,
1450 .payload = try readAllocBytes(allocator, in_stream, size),
1447 .payload = switch (size) {
1448 1 => try in_stream.readIntLittle(u8),
1449 2 => try in_stream.readIntLittle(u16),
1450 4 => try in_stream.readIntLittle(u32),
1451 8 => try in_stream.readIntLittle(u64),
1452 -1 => if (signed) try readULeb128(in_stream) else @intCast(u64, try readILeb128(in_stream)),
1453 else => unreachable,
1454 },
14511455 },
14521456 };
14531457}
......@@ -1460,14 +1464,17 @@ fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
14601464 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
14611465}
14621466
1463fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1464 const buf = try readAllocBytes(allocator, in_stream, size);
1465 return FormValue{ .Ref = buf };
1466}
1467
1468fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
1469 const block_len = try in_stream.readIntLittle(T);
1470 return parseFormValueRefLen(allocator, in_stream, block_len);
1467fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
1468 return FormValue{
1469 .Ref = switch (size) {
1470 1 => try in_stream.readIntLittle(u8),
1471 2 => try in_stream.readIntLittle(u16),
1472 4 => try in_stream.readIntLittle(u32),
1473 8 => try in_stream.readIntLittle(u64),
1474 -1 => try readULeb128(in_stream),
1475 else => unreachable,
1476 },
1477 };
14711478}
14721479
14731480fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
......@@ -1485,9 +1492,8 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
14851492 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
14861493 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
14871494 DW.FORM_udata, DW.FORM_sdata => {
1488 const block_len = try readULeb128(in_stream);
14891495 const signed = form_id == DW.FORM_sdata;
1490 return parseFormValueConstant(allocator, in_stream, signed, block_len);
1496 return parseFormValueConstant(allocator, in_stream, signed, -1);
14911497 },
14921498 DW.FORM_exprloc => {
14931499 const size = try readULeb128(in_stream);
......@@ -1498,17 +1504,14 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
14981504 DW.FORM_flag_present => FormValue{ .Flag = true },
14991505 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
15001506
1501 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
1502 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
1503 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
1504 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
1505 DW.FORM_ref_udata => {
1506 const ref_len = try readULeb128(in_stream);
1507 return parseFormValueRefLen(allocator, in_stream, ref_len);
1508 },
1507 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, 1),
1508 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, 2),
1509 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, 4),
1510 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, 8),
1511 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
15091512
15101513 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1511 DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
1514 DW.FORM_ref_sig8 => FormValue{ .Ref = try in_stream.readIntLittle(u64) },
15121515
15131516 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
15141517 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
......@@ -1787,173 +1790,165 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
17871790
17881791fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
17891792 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1793 const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
17901794
1791 const debug_line_end = di.debug_line.offset + di.debug_line.size;
1792 var this_offset = di.debug_line.offset;
1793 var this_index: usize = 0;
1794
1795 while (this_offset < debug_line_end) : (this_index += 1) {
1796 try di.dwarf_seekable_stream.seekTo(this_offset);
1795 assert(line_info_offset < di.debug_line.size);
17971796
1798 var is_64: bool = undefined;
1799 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1800 if (unit_length == 0) return error.MissingDebugInfo;
1801 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
1797 try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
18021798
1803 if (compile_unit.index != this_index) {
1804 this_offset += next_offset;
1805 continue;
1806 }
1799 var is_64: bool = undefined;
1800 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1801 if (unit_length == 0) {
1802 return error.MissingDebugInfo;
1803 }
1804 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
18071805
1808 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1809 // TODO support 3 and 5
1810 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1806 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1807 // TODO support 3 and 5
1808 if (version != 2 and version != 4) return error.InvalidDebugInfo;
18111809
1812 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);
1813 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
1810 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);
1811 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
18141812
1815 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1816 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1813 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1814 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
18171815
1818 if (version >= 4) {
1819 // maximum_operations_per_instruction
1820 _ = try di.dwarf_in_stream.readByte();
1821 }
1816 if (version >= 4) {
1817 // maximum_operations_per_instruction
1818 _ = try di.dwarf_in_stream.readByte();
1819 }
18221820
1823 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1824 const line_base = try di.dwarf_in_stream.readByteSigned();
1821 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1822 const line_base = try di.dwarf_in_stream.readByteSigned();
18251823
1826 const line_range = try di.dwarf_in_stream.readByte();
1827 if (line_range == 0) return error.InvalidDebugInfo;
1824 const line_range = try di.dwarf_in_stream.readByte();
1825 if (line_range == 0) return error.InvalidDebugInfo;
18281826
1829 const opcode_base = try di.dwarf_in_stream.readByte();
1827 const opcode_base = try di.dwarf_in_stream.readByte();
18301828
1831 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1829 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
18321830
1833 {
1834 var i: usize = 0;
1835 while (i < opcode_base - 1) : (i += 1) {
1836 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
1837 }
1831 {
1832 var i: usize = 0;
1833 while (i < opcode_base - 1) : (i += 1) {
1834 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
18381835 }
1836 }
18391837
1840 var include_directories = ArrayList([]u8).init(di.allocator());
1841 try include_directories.append(compile_unit_cwd);
1842 while (true) {
1843 const dir = try di.readString();
1844 if (dir.len == 0) break;
1845 try include_directories.append(dir);
1846 }
1838 var include_directories = ArrayList([]u8).init(di.allocator());
1839 try include_directories.append(compile_unit_cwd);
1840 while (true) {
1841 const dir = try di.readString();
1842 if (dir.len == 0) break;
1843 try include_directories.append(dir);
1844 }
18471845
1848 var file_entries = ArrayList(FileEntry).init(di.allocator());
1849 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1846 var file_entries = ArrayList(FileEntry).init(di.allocator());
1847 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
18501848
1851 while (true) {
1852 const file_name = try di.readString();
1853 if (file_name.len == 0) break;
1854 const dir_index = try readULeb128(di.dwarf_in_stream);
1855 const mtime = try readULeb128(di.dwarf_in_stream);
1856 const len_bytes = try readULeb128(di.dwarf_in_stream);
1857 try file_entries.append(FileEntry{
1858 .file_name = file_name,
1859 .dir_index = dir_index,
1860 .mtime = mtime,
1861 .len_bytes = len_bytes,
1862 });
1863 }
1849 while (true) {
1850 const file_name = try di.readString();
1851 if (file_name.len == 0) break;
1852 const dir_index = try readULeb128(di.dwarf_in_stream);
1853 const mtime = try readULeb128(di.dwarf_in_stream);
1854 const len_bytes = try readULeb128(di.dwarf_in_stream);
1855 try file_entries.append(FileEntry{
1856 .file_name = file_name,
1857 .dir_index = dir_index,
1858 .mtime = mtime,
1859 .len_bytes = len_bytes,
1860 });
1861 }
18641862
1865 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
1863 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
18661864
1867 while (true) {
1868 const opcode = try di.dwarf_in_stream.readByte();
1869
1870 if (opcode == DW.LNS_extended_op) {
1871 const op_size = try readULeb128(di.dwarf_in_stream);
1872 if (op_size < 1) return error.InvalidDebugInfo;
1873 var sub_op = try di.dwarf_in_stream.readByte();
1874 switch (sub_op) {
1875 DW.LNE_end_sequence => {
1876 prog.end_sequence = true;
1877 if (try prog.checkLineMatch()) |info| return info;
1878 return error.MissingDebugInfo;
1879 },
1880 DW.LNE_set_address => {
1881 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1882 prog.address = addr;
1883 },
1884 DW.LNE_define_file => {
1885 const file_name = try di.readString();
1886 const dir_index = try readULeb128(di.dwarf_in_stream);
1887 const mtime = try readULeb128(di.dwarf_in_stream);
1888 const len_bytes = try readULeb128(di.dwarf_in_stream);
1889 try file_entries.append(FileEntry{
1890 .file_name = file_name,
1891 .dir_index = dir_index,
1892 .mtime = mtime,
1893 .len_bytes = len_bytes,
1894 });
1895 },
1896 else => {
1897 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1898 try di.dwarf_seekable_stream.seekForward(fwd_amt);
1899 },
1900 }
1901 } else if (opcode >= opcode_base) {
1902 // special opcodes
1903 const adjusted_opcode = opcode - opcode_base;
1904 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1905 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1906 prog.line += inc_line;
1907 prog.address += inc_addr;
1908 if (try prog.checkLineMatch()) |info| return info;
1909 prog.basic_block = false;
1910 } else {
1911 switch (opcode) {
1912 DW.LNS_copy => {
1913 if (try prog.checkLineMatch()) |info| return info;
1914 prog.basic_block = false;
1915 },
1916 DW.LNS_advance_pc => {
1917 const arg = try readULeb128(di.dwarf_in_stream);
1918 prog.address += arg * minimum_instruction_length;
1919 },
1920 DW.LNS_advance_line => {
1921 const arg = try readILeb128(di.dwarf_in_stream);
1922 prog.line += arg;
1923 },
1924 DW.LNS_set_file => {
1925 const arg = try readULeb128(di.dwarf_in_stream);
1926 prog.file = arg;
1927 },
1928 DW.LNS_set_column => {
1929 const arg = try readULeb128(di.dwarf_in_stream);
1930 prog.column = arg;
1931 },
1932 DW.LNS_negate_stmt => {
1933 prog.is_stmt = !prog.is_stmt;
1934 },
1935 DW.LNS_set_basic_block => {
1936 prog.basic_block = true;
1937 },
1938 DW.LNS_const_add_pc => {
1939 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1940 prog.address += inc_addr;
1941 },
1942 DW.LNS_fixed_advance_pc => {
1943 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
1944 prog.address += arg;
1945 },
1946 DW.LNS_set_prologue_end => {},
1947 else => {
1948 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1949 const len_bytes = standard_opcode_lengths[opcode - 1];
1950 try di.dwarf_seekable_stream.seekForward(len_bytes);
1951 },
1952 }
1865 while (true) {
1866 const opcode = try di.dwarf_in_stream.readByte();
1867
1868 if (opcode == DW.LNS_extended_op) {
1869 const op_size = try readULeb128(di.dwarf_in_stream);
1870 if (op_size < 1) return error.InvalidDebugInfo;
1871 var sub_op = try di.dwarf_in_stream.readByte();
1872 switch (sub_op) {
1873 DW.LNE_end_sequence => {
1874 prog.end_sequence = true;
1875 if (try prog.checkLineMatch()) |info| return info;
1876 return error.MissingDebugInfo;
1877 },
1878 DW.LNE_set_address => {
1879 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1880 prog.address = addr;
1881 },
1882 DW.LNE_define_file => {
1883 const file_name = try di.readString();
1884 const dir_index = try readULeb128(di.dwarf_in_stream);
1885 const mtime = try readULeb128(di.dwarf_in_stream);
1886 const len_bytes = try readULeb128(di.dwarf_in_stream);
1887 try file_entries.append(FileEntry{
1888 .file_name = file_name,
1889 .dir_index = dir_index,
1890 .mtime = mtime,
1891 .len_bytes = len_bytes,
1892 });
1893 },
1894 else => {
1895 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1896 try di.dwarf_seekable_stream.seekForward(fwd_amt);
1897 },
1898 }
1899 } else if (opcode >= opcode_base) {
1900 // special opcodes
1901 const adjusted_opcode = opcode - opcode_base;
1902 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1903 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
1904 prog.line += inc_line;
1905 prog.address += inc_addr;
1906 if (try prog.checkLineMatch()) |info| return info;
1907 prog.basic_block = false;
1908 } else {
1909 switch (opcode) {
1910 DW.LNS_copy => {
1911 if (try prog.checkLineMatch()) |info| return info;
1912 prog.basic_block = false;
1913 },
1914 DW.LNS_advance_pc => {
1915 const arg = try readULeb128(di.dwarf_in_stream);
1916 prog.address += arg * minimum_instruction_length;
1917 },
1918 DW.LNS_advance_line => {
1919 const arg = try readILeb128(di.dwarf_in_stream);
1920 prog.line += arg;
1921 },
1922 DW.LNS_set_file => {
1923 const arg = try readULeb128(di.dwarf_in_stream);
1924 prog.file = arg;
1925 },
1926 DW.LNS_set_column => {
1927 const arg = try readULeb128(di.dwarf_in_stream);
1928 prog.column = arg;
1929 },
1930 DW.LNS_negate_stmt => {
1931 prog.is_stmt = !prog.is_stmt;
1932 },
1933 DW.LNS_set_basic_block => {
1934 prog.basic_block = true;
1935 },
1936 DW.LNS_const_add_pc => {
1937 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1938 prog.address += inc_addr;
1939 },
1940 DW.LNS_fixed_advance_pc => {
1941 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
1942 prog.address += arg;
1943 },
1944 DW.LNS_set_prologue_end => {},
1945 else => {
1946 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1947 const len_bytes = standard_opcode_lengths[opcode - 1];
1948 try di.dwarf_seekable_stream.seekForward(len_bytes);
1949 },
19531950 }
19541951 }
1955
1956 this_offset += next_offset;
19571952 }
19581953
19591954 return error.MissingDebugInfo;
......@@ -1962,7 +1957,6 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
19621957fn scanAllCompileUnits(di: *DwarfInfo) !void {
19631958 const debug_info_end = di.debug_info.offset + di.debug_info.size;
19641959 var this_unit_offset = di.debug_info.offset;
1965 var cu_index: usize = 0;
19661960
19671961 while (this_unit_offset < debug_info_end) {
19681962 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
......@@ -2019,11 +2013,9 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
20192013 .is_64 = is_64,
20202014 .pc_range = pc_range,
20212015 .die = compile_unit_die,
2022 .index = cu_index,
20232016 });
20242017
20252018 this_unit_offset += next_offset;
2026 cu_index += 1;
20272019 }
20282020}
20292021
std/dwarf.zig+3
......@@ -241,6 +241,9 @@ pub const AT_const_expr = 0x6c;
241241pub const AT_enum_class = 0x6d;
242242pub const AT_linkage_name = 0x6e;
243243
244// DWARF 5
245pub const AT_alignment = 0x88;
246
244247pub const AT_lo_user = 0x2000; // Implementation-defined range start.
245248pub const AT_hi_user = 0x3fff; // Implementation-defined range end.
246249