authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-12-02 18:35:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-12-02 18:36:18-05:00
loga40d160a5ca7fe50680578541c40038e280272ce
treeb00fa8b07250e734b19c764bcc0ce7d0161a0373
parent6f5e7ee09c9269cfcc454cde88960987054ee031
signaturelock-open Commit is signed but in an unrecognized format.

introduce std.io.SeekableStream

Relevant #764 dwarf debug info is modified to use this instead of std.os.File directly to make it easier for bare metal projects to take advantage of debug info parsing

6 files changed, 228 insertions(+), 134 deletions(-)

CMakeLists.txt+1
......@@ -491,6 +491,7 @@ set(ZIG_STD_FILES
491491 "heap.zig"
492492 "index.zig"
493493 "io.zig"
494 "io/seekable_stream.zig"
494495 "json.zig"
495496 "lazy_init.zig"
496497 "linked_list.zig"
std/debug/index.zig+110-108
......@@ -284,7 +284,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
284284 const mod_index = for (di.sect_contribs) |sect_contrib| {
285285 if (sect_contrib.Section > di.coff.sections.len) continue;
286286 // Remember that SectionContribEntry.Section is 1-based.
287 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1];
287 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
288288
289289 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
290290 const vaddr_end = vaddr_start + sect_contrib.Size;
......@@ -872,9 +872,14 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
872872 return list.toOwnedSlice();
873873}
874874
875fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
875pub fn openDwarfDebugInfo(
876 allocator: *mem.Allocator,
877 dwarf_seekable_stream: *DwarfSeekableStream,
878 dwarf_in_stream: *DwarfInStream,
879) !DebugInfo {
876880 var di = DebugInfo{
877 .self_exe_file = undefined,
881 .dwarf_seekable_stream = dwarf_seekable_stream,
882 .dwarf_in_stream = dwarf_in_stream,
878883 .elf = undefined,
879884 .debug_info = undefined,
880885 .debug_abbrev = undefined,
......@@ -884,10 +889,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
884889 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
885890 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
886891 };
887 di.self_exe_file = try os.openSelfExe();
888 errdefer di.self_exe_file.close();
889
890 try di.elf.openFile(allocator, di.self_exe_file);
892 try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream);
891893 errdefer di.elf.close();
892894
893895 di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
......@@ -899,6 +901,27 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
899901 return di;
900902}
901903
904fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
905 const S = struct {
906 var self_exe_file: os.File = undefined;
907 var self_exe_seekable_stream: os.File.SeekableStream = undefined;
908 var self_exe_in_stream: os.File.InStream = undefined;
909 };
910 S.self_exe_file = try os.openSelfExe();
911 errdefer S.self_exe_file.close();
912
913 S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
914 S.self_exe_in_stream = S.self_exe_file.inStream();
915
916 return openDwarfDebugInfo(
917 allocator,
918 // TODO https://github.com/ziglang/zig/issues/764
919 @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
920 // TODO https://github.com/ziglang/zig/issues/764
921 @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
922 );
923}
924
902925pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr {
903926 var file_stream = elf.in_file.inStream();
904927 const in = &file_stream.stream;
......@@ -1053,6 +1076,9 @@ const MachOFile = struct {
10531076 sect_debug_line: ?*const macho.section_64,
10541077};
10551078
1079pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
1080pub const DwarfInStream = io.InStream(anyerror);
1081
10561082pub const DebugInfo = switch (builtin.os) {
10571083 builtin.Os.macosx => struct {
10581084 symbols: []const MachoSymbol,
......@@ -1077,7 +1103,8 @@ pub const DebugInfo = switch (builtin.os) {
10771103 modules: []Module,
10781104 },
10791105 builtin.Os.linux => struct {
1080 self_exe_file: os.File,
1106 dwarf_seekable_stream: *DwarfSeekableStream,
1107 dwarf_in_stream: *DwarfInStream,
10811108 elf: elf.Elf,
10821109 debug_info: *elf.SectionHeader,
10831110 debug_abbrev: *elf.SectionHeader,
......@@ -1092,13 +1119,10 @@ pub const DebugInfo = switch (builtin.os) {
10921119 }
10931120
10941121 pub fn readString(self: *DebugInfo) ![]u8 {
1095 var in_file_stream = self.self_exe_file.inStream();
1096 const in_stream = &in_file_stream.stream;
1097 return readStringRaw(self.allocator(), in_stream);
1122 return readStringRaw(self.allocator(), self.dwarf_in_stream);
10981123 }
10991124
11001125 pub fn close(self: *DebugInfo) void {
1101 self.self_exe_file.close();
11021126 self.elf.close();
11031127 }
11041128 },
......@@ -1206,11 +1230,11 @@ const Die = struct {
12061230 };
12071231 }
12081232
1209 fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 {
1233 fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 {
12101234 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
12111235 return switch (form_value.*) {
12121236 FormValue.String => |value| value,
1213 FormValue.StrPtr => |offset| getString(st, offset),
1237 FormValue.StrPtr => |offset| getString(di, offset),
12141238 else => error.InvalidDebugInfo,
12151239 };
12161240 }
......@@ -1321,10 +1345,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
13211345 return buf.toSlice();
13221346}
13231347
1324fn getString(st: *DebugInfo, offset: u64) ![]u8 {
1325 const pos = st.debug_str.offset + offset;
1326 try st.self_exe_file.seekTo(pos);
1327 return st.readString();
1348fn getString(di: *DebugInfo, offset: u64) ![]u8 {
1349 const pos = di.debug_str.offset + offset;
1350 try di.dwarf_seekable_stream.seekTo(pos);
1351 return di.readString();
13281352}
13291353
13301354fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
......@@ -1371,14 +1395,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type
13711395 return parseFormValueRefLen(allocator, in_stream, block_len);
13721396}
13731397
1374const ParseFormValueError = error{
1375 EndOfStream,
1376 InvalidDebugInfo,
1377 EndOfFile,
1378 OutOfMemory,
1379} || std.os.File.ReadError;
1380
1381fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
1398fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
13821399 return switch (form_id) {
13831400 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
13841401 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
......@@ -1428,25 +1445,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
14281445 };
14291446}
14301447
1431fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
1432 const in_file = st.self_exe_file;
1433 var in_file_stream = in_file.inStream();
1434 const in_stream = &in_file_stream.stream;
1435 var result = AbbrevTable.init(st.allocator());
1448fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable {
1449 var result = AbbrevTable.init(di.allocator());
14361450 while (true) {
1437 const abbrev_code = try readULeb128(in_stream);
1451 const abbrev_code = try readULeb128(di.dwarf_in_stream);
14381452 if (abbrev_code == 0) return result;
14391453 try result.append(AbbrevTableEntry{
14401454 .abbrev_code = abbrev_code,
1441 .tag_id = try readULeb128(in_stream),
1442 .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
1443 .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
1455 .tag_id = try readULeb128(di.dwarf_in_stream),
1456 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1457 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
14441458 });
14451459 const attrs = &result.items[result.len - 1].attrs;
14461460
14471461 while (true) {
1448 const attr_id = try readULeb128(in_stream);
1449 const form_id = try readULeb128(in_stream);
1462 const attr_id = try readULeb128(di.dwarf_in_stream);
1463 const form_id = try readULeb128(di.dwarf_in_stream);
14501464 if (attr_id == 0 and form_id == 0) break;
14511465 try attrs.append(AbbrevAttr{
14521466 .attr_id = attr_id,
......@@ -1458,18 +1472,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
14581472
14591473/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
14601474/// seeks in the stream and parses it.
1461fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
1462 for (st.abbrev_table_list.toSlice()) |*header| {
1475fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
1476 for (di.abbrev_table_list.toSlice()) |*header| {
14631477 if (header.offset == abbrev_offset) {
14641478 return &header.table;
14651479 }
14661480 }
1467 try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
1468 try st.abbrev_table_list.append(AbbrevTableHeader{
1481 try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
1482 try di.abbrev_table_list.append(AbbrevTableHeader{
14691483 .offset = abbrev_offset,
1470 .table = try parseAbbrevTable(st),
1484 .table = try parseAbbrevTable(di),
14711485 });
1472 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
1486 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
14731487}
14741488
14751489fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
......@@ -1479,23 +1493,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
14791493 return null;
14801494}
14811495
1482fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1483 const in_file = st.self_exe_file;
1484 var in_file_stream = in_file.inStream();
1485 const in_stream = &in_file_stream.stream;
1486 const abbrev_code = try readULeb128(in_stream);
1496fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1497 const abbrev_code = try readULeb128(di.dwarf_in_stream);
14871498 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
14881499
14891500 var result = Die{
14901501 .tag_id = table_entry.tag_id,
14911502 .has_children = table_entry.has_children,
1492 .attrs = ArrayList(Die.Attr).init(st.allocator()),
1503 .attrs = ArrayList(Die.Attr).init(di.allocator()),
14931504 };
14941505 try result.attrs.resize(table_entry.attrs.len);
14951506 for (table_entry.attrs.toSliceConst()) |attr, i| {
14961507 result.attrs.items[i] = Die.Attr{
14971508 .id = attr.attr_id,
1498 .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
1509 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
14991510 };
15001511 }
15011512 return result;
......@@ -1702,19 +1713,15 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
17021713fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
17031714 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
17041715
1705 const in_file = di.self_exe_file;
17061716 const debug_line_end = di.debug_line.offset + di.debug_line.size;
17071717 var this_offset = di.debug_line.offset;
17081718 var this_index: usize = 0;
17091719
1710 var in_file_stream = in_file.inStream();
1711 const in_stream = &in_file_stream.stream;
1712
17131720 while (this_offset < debug_line_end) : (this_index += 1) {
1714 try in_file.seekTo(this_offset);
1721 try di.dwarf_seekable_stream.seekTo(this_offset);
17151722
17161723 var is_64: bool = undefined;
1717 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
1724 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
17181725 if (unit_length == 0) return error.MissingDebugInfo;
17191726 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
17201727
......@@ -1723,35 +1730,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
17231730 continue;
17241731 }
17251732
1726 const version = try in_stream.readInt(di.elf.endian, u16);
1733 const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
17271734 // TODO support 3 and 5
17281735 if (version != 2 and version != 4) return error.InvalidDebugInfo;
17291736
1730 const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32);
1731 const prog_start_offset = (try in_file.getPos()) + prologue_length;
1737 const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
1738 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
17321739
1733 const minimum_instruction_length = try in_stream.readByte();
1740 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
17341741 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
17351742
17361743 if (version >= 4) {
17371744 // maximum_operations_per_instruction
1738 _ = try in_stream.readByte();
1745 _ = try di.dwarf_in_stream.readByte();
17391746 }
17401747
1741 const default_is_stmt = (try in_stream.readByte()) != 0;
1742 const line_base = try in_stream.readByteSigned();
1748 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1749 const line_base = try di.dwarf_in_stream.readByteSigned();
17431750
1744 const line_range = try in_stream.readByte();
1751 const line_range = try di.dwarf_in_stream.readByte();
17451752 if (line_range == 0) return error.InvalidDebugInfo;
17461753
1747 const opcode_base = try in_stream.readByte();
1754 const opcode_base = try di.dwarf_in_stream.readByte();
17481755
17491756 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
17501757
17511758 {
17521759 var i: usize = 0;
17531760 while (i < opcode_base - 1) : (i += 1) {
1754 standard_opcode_lengths[i] = try in_stream.readByte();
1761 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
17551762 }
17561763 }
17571764
......@@ -1769,9 +1776,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
17691776 while (true) {
17701777 const file_name = try di.readString();
17711778 if (file_name.len == 0) break;
1772 const dir_index = try readULeb128(in_stream);
1773 const mtime = try readULeb128(in_stream);
1774 const len_bytes = try readULeb128(in_stream);
1779 const dir_index = try readULeb128(di.dwarf_in_stream);
1780 const mtime = try readULeb128(di.dwarf_in_stream);
1781 const len_bytes = try readULeb128(di.dwarf_in_stream);
17751782 try file_entries.append(FileEntry{
17761783 .file_name = file_name,
17771784 .dir_index = dir_index,
......@@ -1780,15 +1787,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
17801787 });
17811788 }
17821789
1783 try in_file.seekTo(prog_start_offset);
1790 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
17841791
17851792 while (true) {
1786 const opcode = try in_stream.readByte();
1793 const opcode = try di.dwarf_in_stream.readByte();
17871794
17881795 if (opcode == DW.LNS_extended_op) {
1789 const op_size = try readULeb128(in_stream);
1796 const op_size = try readULeb128(di.dwarf_in_stream);
17901797 if (op_size < 1) return error.InvalidDebugInfo;
1791 var sub_op = try in_stream.readByte();
1798 var sub_op = try di.dwarf_in_stream.readByte();
17921799 switch (sub_op) {
17931800 DW.LNE_end_sequence => {
17941801 prog.end_sequence = true;
......@@ -1796,14 +1803,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
17961803 return error.MissingDebugInfo;
17971804 },
17981805 DW.LNE_set_address => {
1799 const addr = try in_stream.readInt(di.elf.endian, usize);
1806 const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize);
18001807 prog.address = addr;
18011808 },
18021809 DW.LNE_define_file => {
18031810 const file_name = try di.readString();
1804 const dir_index = try readULeb128(in_stream);
1805 const mtime = try readULeb128(in_stream);
1806 const len_bytes = try readULeb128(in_stream);
1811 const dir_index = try readULeb128(di.dwarf_in_stream);
1812 const mtime = try readULeb128(di.dwarf_in_stream);
1813 const len_bytes = try readULeb128(di.dwarf_in_stream);
18071814 try file_entries.append(FileEntry{
18081815 .file_name = file_name,
18091816 .dir_index = dir_index,
......@@ -1813,7 +1820,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
18131820 },
18141821 else => {
18151822 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1816 try in_file.seekForward(fwd_amt);
1823 try di.dwarf_seekable_stream.seekForward(fwd_amt);
18171824 },
18181825 }
18191826 } else if (opcode >= opcode_base) {
......@@ -1832,19 +1839,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
18321839 prog.basic_block = false;
18331840 },
18341841 DW.LNS_advance_pc => {
1835 const arg = try readULeb128(in_stream);
1842 const arg = try readULeb128(di.dwarf_in_stream);
18361843 prog.address += arg * minimum_instruction_length;
18371844 },
18381845 DW.LNS_advance_line => {
1839 const arg = try readILeb128(in_stream);
1846 const arg = try readILeb128(di.dwarf_in_stream);
18401847 prog.line += arg;
18411848 },
18421849 DW.LNS_set_file => {
1843 const arg = try readULeb128(in_stream);
1850 const arg = try readULeb128(di.dwarf_in_stream);
18441851 prog.file = arg;
18451852 },
18461853 DW.LNS_set_column => {
1847 const arg = try readULeb128(in_stream);
1854 const arg = try readULeb128(di.dwarf_in_stream);
18481855 prog.column = arg;
18491856 },
18501857 DW.LNS_negate_stmt => {
......@@ -1858,14 +1865,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
18581865 prog.address += inc_addr;
18591866 },
18601867 DW.LNS_fixed_advance_pc => {
1861 const arg = try in_stream.readInt(di.elf.endian, u16);
1868 const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
18621869 prog.address += arg;
18631870 },
18641871 DW.LNS_set_prologue_end => {},
18651872 else => {
18661873 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
18671874 const len_bytes = standard_opcode_lengths[opcode - 1];
1868 try in_file.seekForward(len_bytes);
1875 try di.dwarf_seekable_stream.seekForward(len_bytes);
18691876 },
18701877 }
18711878 }
......@@ -1877,36 +1884,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
18771884 return error.MissingDebugInfo;
18781885}
18791886
1880fn scanAllCompileUnits(st: *DebugInfo) !void {
1881 const debug_info_end = st.debug_info.offset + st.debug_info.size;
1882 var this_unit_offset = st.debug_info.offset;
1887fn scanAllCompileUnits(di: *DebugInfo) !void {
1888 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1889 var this_unit_offset = di.debug_info.offset;
18831890 var cu_index: usize = 0;
18841891
1885 var in_file_stream = st.self_exe_file.inStream();
1886 const in_stream = &in_file_stream.stream;
1887
18881892 while (this_unit_offset < debug_info_end) {
1889 try st.self_exe_file.seekTo(this_unit_offset);
1893 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
18901894
18911895 var is_64: bool = undefined;
1892 const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
1896 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
18931897 if (unit_length == 0) return;
18941898 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
18951899
1896 const version = try in_stream.readInt(st.elf.endian, u16);
1900 const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16);
18971901 if (version < 2 or version > 5) return error.InvalidDebugInfo;
18981902
1899 const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
1903 const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32);
19001904
1901 const address_size = try in_stream.readByte();
1905 const address_size = try di.dwarf_in_stream.readByte();
19021906 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
19031907
1904 const compile_unit_pos = try st.self_exe_file.getPos();
1905 const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset);
1908 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
1909 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
19061910
1907 try st.self_exe_file.seekTo(compile_unit_pos);
1911 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
19081912
1909 const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
1913 const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
19101914
19111915 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
19121916
......@@ -1934,7 +1938,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
19341938 }
19351939 };
19361940
1937 try st.compile_unit_list.append(CompileUnit{
1941 try di.compile_unit_list.append(CompileUnit{
19381942 .version = version,
19391943 .is_64 = is_64,
19401944 .pc_range = pc_range,
......@@ -1947,20 +1951,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
19471951 }
19481952}
19491953
1950fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
1951 var in_file_stream = st.self_exe_file.inStream();
1952 const in_stream = &in_file_stream.stream;
1953 for (st.compile_unit_list.toSlice()) |*compile_unit| {
1954fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit {
1955 for (di.compile_unit_list.toSlice()) |*compile_unit| {
19541956 if (compile_unit.pc_range) |range| {
19551957 if (target_address >= range.start and target_address < range.end) return compile_unit;
19561958 }
19571959 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
19581960 var base_address: usize = 0;
1959 if (st.debug_ranges) |debug_ranges| {
1960 try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
1961 if (di.debug_ranges) |debug_ranges| {
1962 try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
19611963 while (true) {
1962 const begin_addr = try in_stream.readIntLe(usize);
1963 const end_addr = try in_stream.readIntLe(usize);
1964 const begin_addr = try di.dwarf_in_stream.readIntLe(usize);
1965 const end_addr = try di.dwarf_in_stream.readIntLe(usize);
19641966 if (begin_addr == 0 and end_addr == 0) {
19651967 break;
19661968 }
std/elf.zig+24-21
......@@ -353,7 +353,8 @@ pub const SectionHeader = struct {
353353};
354354
355355pub const Elf = struct {
356 in_file: os.File,
356 seekable_stream: *io.SeekableStream(anyerror, anyerror),
357 in_stream: *io.InStream(anyerror),
357358 auto_close_stream: bool,
358359 is_64: bool,
359360 endian: builtin.Endian,
......@@ -370,19 +371,24 @@ pub const Elf = struct {
370371
371372 /// Call close when done.
372373 pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
373 try elf.prealloc_file.open(path);
374 try elf.openFile(allocator, *elf.prealloc_file);
375 elf.auto_close_stream = true;
374 @compileError("TODO implement");
376375 }
377376
378377 /// Call close when done.
379378 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
380 elf.allocator = allocator;
381 elf.in_file = file;
382 elf.auto_close_stream = false;
379 @compileError("TODO implement");
380 }
383381
384 var file_stream = elf.in_file.inStream();
385 const in = &file_stream.stream;
382 pub fn openStream(
383 elf: *Elf,
384 allocator: *mem.Allocator,
385 seekable_stream: *io.SeekableStream(anyerror, anyerror),
386 in: *io.InStream(anyerror),
387 ) !void {
388 elf.auto_close_stream = false;
389 elf.allocator = allocator;
390 elf.seekable_stream = seekable_stream;
391 elf.in_stream = in;
386392
387393 var magic: [4]u8 = undefined;
388394 try in.readNoEof(magic[0..]);
......@@ -404,7 +410,7 @@ pub const Elf = struct {
404410 if (version_byte != 1) return error.InvalidFormat;
405411
406412 // skip over padding
407 try elf.in_file.seekForward(9);
413 try seekable_stream.seekForward(9);
408414
409415 elf.file_type = switch (try in.readInt(elf.endian, u16)) {
410416 1 => FileType.Relocatable,
......@@ -441,7 +447,7 @@ pub const Elf = struct {
441447 }
442448
443449 // skip over flags
444 try elf.in_file.seekForward(4);
450 try seekable_stream.seekForward(4);
445451
446452 const header_size = try in.readInt(elf.endian, u16);
447453 if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
......@@ -461,12 +467,12 @@ pub const Elf = struct {
461467 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
462468 const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
463469
464 const stream_end = try elf.in_file.getEndPos();
470 const stream_end = try seekable_stream.getEndPos();
465471 if (stream_end < end_sh or stream_end < end_ph) {
466472 return error.InvalidFormat;
467473 }
468474
469 try elf.in_file.seekTo(elf.section_header_offset);
475 try seekable_stream.seekTo(elf.section_header_offset);
470476
471477 elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
472478 errdefer elf.allocator.free(elf.section_headers);
......@@ -521,26 +527,23 @@ pub const Elf = struct {
521527 pub fn close(elf: *Elf) void {
522528 elf.allocator.free(elf.section_headers);
523529
524 if (elf.auto_close_stream) elf.in_file.close();
530 if (elf.auto_close_stream) elf.prealloc_file.close();
525531 }
526532
527533 pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
528 var file_stream = elf.in_file.inStream();
529 const in = &file_stream.stream;
530
531534 section_loop: for (elf.section_headers) |*elf_section| {
532535 if (elf_section.sh_type == SHT_NULL) continue;
533536
534537 const name_offset = elf.string_section.offset + elf_section.name;
535 try elf.in_file.seekTo(name_offset);
538 try elf.seekable_stream.seekTo(name_offset);
536539
537540 for (name) |expected_c| {
538 const target_c = try in.readByte();
541 const target_c = try elf.in_stream.readByte();
539542 if (target_c == 0 or expected_c != target_c) continue :section_loop;
540543 }
541544
542545 {
543 const null_byte = try in.readByte();
546 const null_byte = try elf.in_stream.readByte();
544547 if (null_byte == 0) return elf_section;
545548 }
546549 }
......@@ -549,7 +552,7 @@ pub const Elf = struct {
549552 }
550553
551554 pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
552 try elf.in_file.seekTo(elf_section.offset);
555 try elf.seekable_stream.seekTo(elf_section.offset);
553556 }
554557};
555558
std/io.zig+2
......@@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File {
3232 return File.openHandle(handle);
3333}
3434
35pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
36
3537pub fn InStream(comptime ReadError: type) type {
3638 return struct {
3739 const Self = @This();
std/io/seekable_stream.zig created+32
......@@ -0,0 +1,32 @@
1const std = @import("../index.zig");
2const InStream = std.io.InStream;
3
4pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
5 return struct {
6 const Self = @This();
7 pub const SeekError = SeekErrorType;
8 pub const GetSeekPosError = GetSeekPosErrorType;
9
10 seekToFn: fn (self: *Self, pos: usize) SeekError!void,
11 seekForwardFn: fn (self: *Self, pos: isize) SeekError!void,
12
13 getPosFn: fn (self: *Self) GetSeekPosError!usize,
14 getEndPosFn: fn (self: *Self) GetSeekPosError!usize,
15
16 pub fn seekTo(self: *Self, pos: usize) SeekError!void {
17 return self.seekToFn(self, pos);
18 }
19
20 pub fn seekForward(self: *Self, amt: isize) SeekError!void {
21 return self.seekForwardFn(self, amt);
22 }
23
24 pub fn getEndPos(self: *Self) GetSeekPosError!usize {
25 return self.getEndPosFn(self);
26 }
27
28 pub fn getPos(self: *Self) GetSeekPosError!usize {
29 return self.getPosFn(self);
30 }
31 };
32}
std/os/file.zig+59-5
......@@ -228,7 +228,14 @@ pub const File = struct {
228228 return os.isTty(self.handle);
229229 }
230230
231 pub fn seekForward(self: File, amount: isize) !void {
231 pub const SeekError = error{
232 /// TODO make this error impossible to get
233 Overflow,
234 Unseekable,
235 Unexpected,
236 };
237
238 pub fn seekForward(self: File, amount: isize) SeekError!void {
232239 switch (builtin.os) {
233240 Os.linux, Os.macosx, Os.ios, Os.freebsd => {
234241 const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
......@@ -259,7 +266,7 @@ pub const File = struct {
259266 }
260267 }
261268
262 pub fn seekTo(self: File, pos: usize) !void {
269 pub fn seekTo(self: File, pos: usize) SeekError!void {
263270 switch (builtin.os) {
264271 Os.linux, Os.macosx, Os.ios, Os.freebsd => {
265272 const ipos = try math.cast(isize, pos);
......@@ -293,7 +300,14 @@ pub const File = struct {
293300 }
294301 }
295302
296 pub fn getPos(self: File) !usize {
303 pub const GetSeekPosError = error{
304 Overflow,
305 SystemResources,
306 Unseekable,
307 Unexpected,
308 };
309
310 pub fn getPos(self: File) GetSeekPosError!usize {
297311 switch (builtin.os) {
298312 Os.linux, Os.macosx, Os.ios, Os.freebsd => {
299313 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
......@@ -323,13 +337,13 @@ pub const File = struct {
323337 }
324338
325339 assert(pos >= 0);
326 return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
340 return math.cast(usize, pos);
327341 },
328342 else => @compileError("unsupported OS"),
329343 }
330344 }
331345
332 pub fn getEndPos(self: File) !usize {
346 pub fn getEndPos(self: File) GetSeekPosError!usize {
333347 if (is_posix) {
334348 const stat = try os.posixFStat(self.handle);
335349 return @intCast(usize, stat.size);
......@@ -431,6 +445,18 @@ pub const File = struct {
431445 };
432446 }
433447
448 pub fn seekableStream(file: File) SeekableStream {
449 return SeekableStream{
450 .file = file,
451 .stream = SeekableStream.Stream{
452 .seekToFn = SeekableStream.seekToFn,
453 .seekForwardFn = SeekableStream.seekForwardFn,
454 .getPosFn = SeekableStream.getPosFn,
455 .getEndPosFn = SeekableStream.getEndPosFn,
456 },
457 };
458 }
459
434460 /// Implementation of io.InStream trait for File
435461 pub const InStream = struct {
436462 file: File,
......@@ -458,4 +484,32 @@ pub const File = struct {
458484 return self.file.write(bytes);
459485 }
460486 };
487
488 /// Implementation of io.SeekableStream trait for File
489 pub const SeekableStream = struct {
490 file: File,
491 stream: Stream,
492
493 pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
494
495 pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void {
496 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
497 return self.file.seekTo(pos);
498 }
499
500 pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void {
501 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
502 return self.file.seekForward(amt);
503 }
504
505 pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
506 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
507 return self.file.getEndPos();
508 }
509
510 pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
511 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
512 return self.file.getPos();
513 }
514 };
461515};