authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-05-09 23:46:12+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-05-10 00:41:05+02:00
log4d8f96dd88c97fa175952f8dd7ab548409c78b0e
tree9af4eaee9438ba5b4ceedcd3920d3d80ddf4b79c
parent72899da44bb95ebd90f5fcc5b0d3212491f94e9a

Fix minor bug in LEB128 parsing


3 files changed, 256 insertions(+), 120 deletions(-)

CMakeLists.txt+1
...@@ -487,6 +487,7 @@ set(ZIG_STD_FILES...@@ -487,6 +487,7 @@ set(ZIG_STD_FILES
487 "crypto/x25519.zig"487 "crypto/x25519.zig"
488 "cstr.zig"488 "cstr.zig"
489 "debug.zig"489 "debug.zig"
490 "debug/leb128.zig"
490 "debug/failing_allocator.zig"491 "debug/failing_allocator.zig"
491 "dwarf.zig"492 "dwarf.zig"
492 "dynamic_library.zig"493 "dynamic_library.zig"
std/debug.zig+35-120
...@@ -13,6 +13,8 @@ const ArrayList = std.ArrayList;...@@ -13,6 +13,8 @@ const ArrayList = std.ArrayList;
13const builtin = @import("builtin");13const builtin = @import("builtin");
14const maxInt = std.math.maxInt;14const maxInt = std.math.maxInt;
1515
16const leb = @import("debug/leb128.zig");
17
16pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator;18pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAllocator;
17pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;19pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
1820
...@@ -1460,7 +1462,7 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo...@@ -1460,7 +1462,7 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
1460 2 => try in_stream.readIntLittle(u16),1462 2 => try in_stream.readIntLittle(u16),
1461 4 => try in_stream.readIntLittle(u32),1463 4 => try in_stream.readIntLittle(u32),
1462 8 => try in_stream.readIntLittle(u64),1464 8 => try in_stream.readIntLittle(u64),
1463 -1 => if (signed) @bitCast(u64, try readILeb128(in_stream)) else try readULeb128(in_stream),1465 -1 => if (signed) @bitCast(u64, try leb.readILEB128(i64, in_stream)) else try leb.readULEB128(u64, in_stream),
1464 else => @compileError("Invalid size"),1466 else => @compileError("Invalid size"),
1465 },1467 },
1466 },1468 },
...@@ -1482,7 +1484,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !Form...@@ -1482,7 +1484,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !Form
1482 2 => try in_stream.readIntLittle(u16),1484 2 => try in_stream.readIntLittle(u16),
1483 4 => try in_stream.readIntLittle(u32),1485 4 => try in_stream.readIntLittle(u32),
1484 8 => try in_stream.readIntLittle(u64),1486 8 => try in_stream.readIntLittle(u64),
1485 -1 => try readULeb128(in_stream),1487 -1 => try leb.readULEB128(u64, in_stream),
1486 else => unreachable,1488 else => unreachable,
1487 },1489 },
1488 };1490 };
...@@ -1495,7 +1497,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1495,7 +1497,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1495 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),1497 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
1496 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),1498 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
1497 DW.FORM_block => x: {1499 DW.FORM_block => x: {
1498 const block_len = try readULeb128(in_stream);1500 const block_len = try leb.readULEB128(usize, in_stream);
1499 return parseFormValueBlockLen(allocator, in_stream, block_len);1501 return parseFormValueBlockLen(allocator, in_stream, block_len);
1500 },1502 },
1501 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),1503 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
...@@ -1507,7 +1509,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1507,7 +1509,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1507 return parseFormValueConstant(allocator, in_stream, signed, -1);1509 return parseFormValueConstant(allocator, in_stream, signed, -1);
1508 },1510 },
1509 DW.FORM_exprloc => {1511 DW.FORM_exprloc => {
1510 const size = try readULeb128(in_stream);1512 const size = try leb.readULEB128(usize, in_stream);
1511 const buf = try readAllocBytes(allocator, in_stream, size);1513 const buf = try readAllocBytes(allocator, in_stream, size);
1512 return FormValue{ .ExprLoc = buf };1514 return FormValue{ .ExprLoc = buf };
1513 },1515 },
...@@ -1527,7 +1529,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1527,7 +1529,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1527 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },1529 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
1528 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },1530 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1529 DW.FORM_indirect => {1531 DW.FORM_indirect => {
1530 const child_form_id = try readULeb128(in_stream);1532 const child_form_id = try leb.readULEB128(u64, in_stream);
1531 return parseFormValue(allocator, in_stream, child_form_id, is_64);1533 return parseFormValue(allocator, in_stream, child_form_id, is_64);
1532 },1534 },
1533 else => error.InvalidDebugInfo,1535 else => error.InvalidDebugInfo,
...@@ -1537,19 +1539,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1537,19 +1539,19 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1537fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {1539fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
1538 var result = AbbrevTable.init(di.allocator());1540 var result = AbbrevTable.init(di.allocator());
1539 while (true) {1541 while (true) {
1540 const abbrev_code = try readULeb128(di.dwarf_in_stream);1542 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1541 if (abbrev_code == 0) return result;1543 if (abbrev_code == 0) return result;
1542 try result.append(AbbrevTableEntry{1544 try result.append(AbbrevTableEntry{
1543 .abbrev_code = abbrev_code,1545 .abbrev_code = abbrev_code,
1544 .tag_id = try readULeb128(di.dwarf_in_stream),1546 .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
1545 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,1547 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1546 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),1548 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1547 });1549 });
1548 const attrs = &result.items[result.len - 1].attrs;1550 const attrs = &result.items[result.len - 1].attrs;
15491551
1550 while (true) {1552 while (true) {
1551 const attr_id = try readULeb128(di.dwarf_in_stream);1553 const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1552 const form_id = try readULeb128(di.dwarf_in_stream);1554 const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1553 if (attr_id == 0 and form_id == 0) break;1555 if (attr_id == 0 and form_id == 0) break;
1554 try attrs.append(AbbrevAttr{1556 try attrs.append(AbbrevAttr{
1555 .attr_id = attr_id,1557 .attr_id = attr_id,
...@@ -1583,7 +1585,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con...@@ -1583,7 +1585,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
1583}1585}
15841586
1585fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {1587fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1586 const abbrev_code = try readULeb128(di.dwarf_in_stream);1588 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1587 if (abbrev_code == 0) return null;1589 if (abbrev_code == 0) return null;
1588 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;1590 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
15891591
...@@ -1603,7 +1605,7 @@ fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Di...@@ -1603,7 +1605,7 @@ fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Di
1603}1605}
16041606
1605fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {1607fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
1606 const abbrev_code = try readULeb128(di.dwarf_in_stream);1608 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1607 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;1609 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
16081610
1609 var result = Die{1611 var result = Die{
...@@ -1716,9 +1718,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1716,9 +1718,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1716 while (true) {1718 while (true) {
1717 const file_name = readStringMem(&ptr);1719 const file_name = readStringMem(&ptr);
1718 if (file_name.len == 0) break;1720 if (file_name.len == 0) break;
1719 const dir_index = try readULeb128Mem(&ptr);1721 const dir_index = try leb.readULEB128Mem(u64, &ptr);
1720 const mtime = try readULeb128Mem(&ptr);1722 const mtime = try leb.readULEB128Mem(u64, &ptr);
1721 const len_bytes = try readULeb128Mem(&ptr);1723 const len_bytes = try leb.readULEB128Mem(u64, &ptr);
1722 try file_entries.append(FileEntry{1724 try file_entries.append(FileEntry{
1723 .file_name = file_name,1725 .file_name = file_name,
1724 .dir_index = dir_index,1726 .dir_index = dir_index,
...@@ -1732,7 +1734,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1732,7 +1734,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1732 const opcode = readByteMem(&ptr);1734 const opcode = readByteMem(&ptr);
17331735
1734 if (opcode == DW.LNS_extended_op) {1736 if (opcode == DW.LNS_extended_op) {
1735 const op_size = try readULeb128Mem(&ptr);1737 const op_size = try leb.readULEB128Mem(u64, &ptr);
1736 if (op_size < 1) return error.InvalidDebugInfo;1738 if (op_size < 1) return error.InvalidDebugInfo;
1737 var sub_op = readByteMem(&ptr);1739 var sub_op = readByteMem(&ptr);
1738 switch (sub_op) {1740 switch (sub_op) {
...@@ -1747,9 +1749,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1747,9 +1749,9 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1747 },1749 },
1748 DW.LNE_define_file => {1750 DW.LNE_define_file => {
1749 const file_name = readStringMem(&ptr);1751 const file_name = readStringMem(&ptr);
1750 const dir_index = try readULeb128Mem(&ptr);1752 const dir_index = try leb.readULEB128Mem(u64, &ptr);
1751 const mtime = try readULeb128Mem(&ptr);1753 const mtime = try leb.readULEB128Mem(u64, &ptr);
1752 const len_bytes = try readULeb128Mem(&ptr);1754 const len_bytes = try leb.readULEB128Mem(u64, &ptr);
1753 try file_entries.append(FileEntry{1755 try file_entries.append(FileEntry{
1754 .file_name = file_name,1756 .file_name = file_name,
1755 .dir_index = dir_index,1757 .dir_index = dir_index,
...@@ -1777,19 +1779,19 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1777,19 +1779,19 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1777 prog.basic_block = false;1779 prog.basic_block = false;
1778 },1780 },
1779 DW.LNS_advance_pc => {1781 DW.LNS_advance_pc => {
1780 const arg = try readULeb128Mem(&ptr);1782 const arg = try leb.readULEB128Mem(u64, &ptr);
1781 prog.address += arg * minimum_instruction_length;1783 prog.address += arg * minimum_instruction_length;
1782 },1784 },
1783 DW.LNS_advance_line => {1785 DW.LNS_advance_line => {
1784 const arg = try readILeb128Mem(&ptr);1786 const arg = try leb.readILEB128Mem(i64, &ptr);
1785 prog.line += arg;1787 prog.line += arg;
1786 },1788 },
1787 DW.LNS_set_file => {1789 DW.LNS_set_file => {
1788 const arg = try readULeb128Mem(&ptr);1790 const arg = try leb.readULEB128Mem(u64, &ptr);
1789 prog.file = arg;1791 prog.file = arg;
1790 },1792 },
1791 DW.LNS_set_column => {1793 DW.LNS_set_column => {
1792 const arg = try readULeb128Mem(&ptr);1794 const arg = try leb.readULEB128Mem(u64, &ptr);
1793 prog.column = arg;1795 prog.column = arg;
1794 },1796 },
1795 DW.LNS_negate_stmt => {1797 DW.LNS_negate_stmt => {
...@@ -1880,9 +1882,9 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1880,9 +1882,9 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1880 while (true) {1882 while (true) {
1881 const file_name = try di.readString();1883 const file_name = try di.readString();
1882 if (file_name.len == 0) break;1884 if (file_name.len == 0) break;
1883 const dir_index = try readULeb128(di.dwarf_in_stream);1885 const dir_index = try leb.readULEB128(u64, di.dwarf_in_stream);
1884 const mtime = try readULeb128(di.dwarf_in_stream);1886 const mtime = try leb.readULEB128(u64, di.dwarf_in_stream);
1885 const len_bytes = try readULeb128(di.dwarf_in_stream);1887 const len_bytes = try leb.readULEB128(u64, di.dwarf_in_stream);
1886 try file_entries.append(FileEntry{1888 try file_entries.append(FileEntry{
1887 .file_name = file_name,1889 .file_name = file_name,
1888 .dir_index = dir_index,1890 .dir_index = dir_index,
...@@ -1897,7 +1899,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1897,7 +1899,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1897 const opcode = try di.dwarf_in_stream.readByte();1899 const opcode = try di.dwarf_in_stream.readByte();
18981900
1899 if (opcode == DW.LNS_extended_op) {1901 if (opcode == DW.LNS_extended_op) {
1900 const op_size = try readULeb128(di.dwarf_in_stream);1902 const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
1901 if (op_size < 1) return error.InvalidDebugInfo;1903 if (op_size < 1) return error.InvalidDebugInfo;
1902 var sub_op = try di.dwarf_in_stream.readByte();1904 var sub_op = try di.dwarf_in_stream.readByte();
1903 switch (sub_op) {1905 switch (sub_op) {
...@@ -1912,9 +1914,9 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1912,9 +1914,9 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1912 },1914 },
1913 DW.LNE_define_file => {1915 DW.LNE_define_file => {
1914 const file_name = try di.readString();1916 const file_name = try di.readString();
1915 const dir_index = try readULeb128(di.dwarf_in_stream);1917 const dir_index = try leb.readULEB128(u64, di.dwarf_in_stream);
1916 const mtime = try readULeb128(di.dwarf_in_stream);1918 const mtime = try leb.readULEB128(u64, di.dwarf_in_stream);
1917 const len_bytes = try readULeb128(di.dwarf_in_stream);1919 const len_bytes = try leb.readULEB128(u64, di.dwarf_in_stream);
1918 try file_entries.append(FileEntry{1920 try file_entries.append(FileEntry{
1919 .file_name = file_name,1921 .file_name = file_name,
1920 .dir_index = dir_index,1922 .dir_index = dir_index,
...@@ -1943,19 +1945,19 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1943,19 +1945,19 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1943 prog.basic_block = false;1945 prog.basic_block = false;
1944 },1946 },
1945 DW.LNS_advance_pc => {1947 DW.LNS_advance_pc => {
1946 const arg = try readULeb128(di.dwarf_in_stream);1948 const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
1947 prog.address += arg * minimum_instruction_length;1949 prog.address += arg * minimum_instruction_length;
1948 },1950 },
1949 DW.LNS_advance_line => {1951 DW.LNS_advance_line => {
1950 const arg = try readILeb128(di.dwarf_in_stream);1952 const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
1951 prog.line += arg;1953 prog.line += arg;
1952 },1954 },
1953 DW.LNS_set_file => {1955 DW.LNS_set_file => {
1954 const arg = try readULeb128(di.dwarf_in_stream);1956 const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
1955 prog.file = arg;1957 prog.file = arg;
1956 },1958 },
1957 DW.LNS_set_column => {1959 DW.LNS_set_column => {
1958 const arg = try readULeb128(di.dwarf_in_stream);1960 const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
1959 prog.column = arg;1961 prog.column = arg;
1960 },1962 },
1961 DW.LNS_negate_stmt => {1963 DW.LNS_negate_stmt => {
...@@ -2240,53 +2242,6 @@ fn readStringMem(ptr: *[*]const u8) []const u8 {...@@ -2240,53 +2242,6 @@ fn readStringMem(ptr: *[*]const u8) []const u8 {
2240 return result;2242 return result;
2241}2243}
22422244
2243fn readULeb128Mem(ptr: *[*]const u8) !u64 {
2244 var result: u64 = 0;
2245 var shift: usize = 0;
2246 var i: usize = 0;
2247
2248 while (true) {
2249 const byte = ptr.*[i];
2250 i += 1;
2251
2252 var operand: u64 = undefined;
2253
2254 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2255
2256 result |= operand;
2257
2258 if ((byte & 0b10000000) == 0) {
2259 ptr.* += i;
2260 return result;
2261 }
2262
2263 shift += 7;
2264 }
2265}
2266fn readILeb128Mem(ptr: *[*]const u8) !i64 {
2267 var result: i64 = 0;
2268 var shift: usize = 0;
2269 var i: usize = 0;
2270
2271 while (true) {
2272 const byte = ptr.*[i];
2273 i += 1;
2274
2275 if (shift > @sizeOf(i64) * 8) return error.InvalidDebugInfo;
2276
2277 result |= i64(byte & 0b01111111) << @intCast(u6, shift);
2278 shift += 7;
2279
2280 if ((byte & 0b10000000) == 0) {
2281 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) {
2282 result |= -(i64(1) << @intCast(u6, shift));
2283 }
2284 ptr.* += i;
2285 return result;
2286 }
2287 }
2288}
2289
2290fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {2245fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
2291 const first_32_bits = try in_stream.readIntLittle(u32);2246 const first_32_bits = try in_stream.readIntLittle(u32);
2292 is_64.* = (first_32_bits == 0xffffffff);2247 is_64.* = (first_32_bits == 0xffffffff);
...@@ -2298,46 +2253,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool)...@@ -2298,46 +2253,6 @@ fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool)
2298 }2253 }
2299}2254}
23002255
2301fn readULeb128(in_stream: var) !u64 {
2302 var result: u64 = 0;
2303 var shift: usize = 0;
2304
2305 while (true) {
2306 const byte = try in_stream.readByte();
2307
2308 var operand: u64 = undefined;
2309
2310 if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo;
2311
2312 result |= operand;
2313
2314 if ((byte & 0b10000000) == 0) return result;
2315
2316 shift += 7;
2317 }
2318}
2319
2320fn readILeb128(in_stream: var) !i64 {
2321 var result: i64 = 0;
2322 var shift: usize = 0;
2323
2324 while (true) {
2325 const byte = try in_stream.readByte();
2326
2327 if (shift > @sizeOf(i64) * 8) return error.InvalidDebugInfo;
2328
2329 result |= i64(byte & 0b01111111) << @intCast(u6, shift);
2330 shift += 7;
2331
2332 if ((byte & 0b10000000) == 0) {
2333 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) {
2334 result |= -(i64(1) << @intCast(u6, shift));
2335 }
2336 return result;
2337 }
2338 }
2339}
2340
2341/// This should only be used in temporary test programs.2256/// This should only be used in temporary test programs.
2342pub const global_allocator = &global_fixed_allocator.allocator;2257pub const global_allocator = &global_fixed_allocator.allocator;
2343var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);2258var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]);
std/debug/leb128.zig created+220
...@@ -0,0 +1,220 @@
1const std = @import("std");
2const testing = std.testing;
3
4pub fn readULEB128(comptime T: type, in_stream: var) !T {
5 const ShiftT = @IntType(false, std.math.log2(T.bit_count));
6
7 var result: T = 0;
8 var shift: ShiftT = 0;
9
10 while (true) {
11 const byte = try in_stream.readByte();
12
13 var operand: T = undefined;
14 if (@shlWithOverflow(T, byte & 0x7f, shift, &operand))
15 return error.Overflow;
16
17 result |= operand;
18
19 if (@addWithOverflow(ShiftT, shift, 7, &shift))
20 return error.Overflow;
21
22 if ((byte & 0x80) == 0)
23 return result;
24 }
25}
26
27pub fn readULEB128Mem(comptime T: type, ptr: *[*]const u8) !T {
28 const ShiftT = @IntType(false, std.math.log2(T.bit_count));
29
30 var result: T = 0;
31 var shift: ShiftT = 0;
32 var i: usize = 0;
33
34 while (true) {
35 const byte = ptr.*[i];
36 i += 1;
37
38 var operand: T = undefined;
39 if (@shlWithOverflow(T, byte & 0x7f, shift, &operand))
40 return error.Overflow;
41
42 result |= operand;
43
44 if (@addWithOverflow(ShiftT, shift, 7, &shift))
45 return error.Overflow;
46
47 if ((byte & 0x80) == 0) {
48 ptr.* += i;
49 return result;
50 }
51 }
52}
53
54pub fn readILEB128(comptime T: type, in_stream: var) !T {
55 const ShiftT = @IntType(false, std.math.log2(T.bit_count));
56
57 var result: T = 0;
58 var shift: ShiftT = 0;
59
60 while (true) {
61 const byte = u8(try in_stream.readByte());
62
63 var operand: T = undefined;
64 if (@shlWithOverflow(T, @intCast(T, byte & 0x7f), shift, &operand))
65 return error.Overflow;
66
67 result |= operand;
68
69 if (@addWithOverflow(ShiftT, shift, 7, &shift))
70 return error.Overflow;
71
72 if ((byte & 0x80) == 0) {
73 if (shift <= ShiftT(T.bit_count - 1) and (byte & 0x40) != 0) {
74 result |= T(-1) << shift;
75 }
76 return result;
77 }
78 }
79}
80
81pub fn readILEB128Mem(comptime T: type, ptr: *[*]const u8) !T {
82 const ShiftT = @IntType(false, std.math.log2(T.bit_count));
83
84 var result: T = 0;
85 var shift: ShiftT = 0;
86 var i: usize = 0;
87
88 while (true) {
89 const byte = ptr.*[i];
90 i += 1;
91
92 var operand: T = undefined;
93 if (@shlWithOverflow(T, @intCast(T, byte & 0x7f), shift, &operand))
94 return error.Overflow;
95
96 result |= operand;
97
98 if (@addWithOverflow(ShiftT, shift, 7, &shift))
99 return error.Overflow;
100
101 if ((byte & 0x80) == 0) {
102 if (shift <= ShiftT(T.bit_count - 1) and (byte & 0x40) != 0) {
103 result |= T(-1) << shift;
104 }
105 ptr.* += i;
106 return result;
107 }
108 }
109}
110
111const OneByteReadInStream = struct {
112 const Error = error{NoError};
113 const Stream = std.io.InStream(Error);
114
115 stream: Stream,
116 str: []const u8,
117 curr: usize,
118
119 fn init(str: []const u8) @This() {
120 return @This(){
121 .stream = Stream{ .readFn = readFn },
122 .str = str,
123 .curr = 0,
124 };
125 }
126
127 fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
128 const self = @fieldParentPtr(@This(), "stream", in_stream);
129 if (self.str.len <= self.curr or dest.len == 0)
130 return 0;
131
132 dest[0] = self.str[self.curr];
133 self.curr += 1;
134 return 1;
135 }
136};
137
138fn test_read_ileb128(comptime T: type, encoded: []const u8) !T {
139 var in_stream = OneByteReadInStream.init(encoded);
140 const v1 = try readILEB128(T, &in_stream.stream);
141 var in_ptr = encoded.ptr;
142 const v2 = try readILEB128Mem(T, &in_ptr);
143 testing.expectEqual(v1, v2);
144 return v2;
145}
146
147fn test_read_uleb128(comptime T: type, encoded: []const u8) !T {
148 var in_stream = OneByteReadInStream.init(encoded);
149 const v1 = try readULEB128(T, &in_stream.stream);
150 var in_ptr = encoded.ptr;
151 const v2 = try readULEB128Mem(T, &in_ptr);
152 return v2;
153}
154
155test "deserialize signed LEB128" {
156 // Truncated
157 testing.expectError(error.EndOfStream, test_read_ileb128(i64, "\x80"));
158
159 // Overflow
160 testing.expectError(error.Overflow, test_read_ileb128(i8, "\x80\x80\x40"));
161 testing.expectError(error.Overflow, test_read_ileb128(i16, "\x80\x80\x80\x40"));
162 testing.expectError(error.Overflow, test_read_ileb128(i32, "\x80\x80\x80\x80\x40"));
163 testing.expectError(error.Overflow, test_read_ileb128(i64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40"));
164
165 // Decode SLEB128
166 testing.expect((try test_read_ileb128(i64, "\x00")) == 0);
167 testing.expect((try test_read_ileb128(i64, "\x01")) == 1);
168 testing.expect((try test_read_ileb128(i64, "\x3f")) == 63);
169 testing.expect((try test_read_ileb128(i64, "\x40")) == -64);
170 testing.expect((try test_read_ileb128(i64, "\x41")) == -63);
171 testing.expect((try test_read_ileb128(i64, "\x7f")) == -1);
172 testing.expect((try test_read_ileb128(i64, "\x80\x01")) == 128);
173 testing.expect((try test_read_ileb128(i64, "\x81\x01")) == 129);
174 testing.expect((try test_read_ileb128(i64, "\xff\x7e")) == -129);
175 testing.expect((try test_read_ileb128(i64, "\x80\x7f")) == -128);
176 testing.expect((try test_read_ileb128(i64, "\x81\x7f")) == -127);
177 testing.expect((try test_read_ileb128(i64, "\xc0\x00")) == 64);
178 testing.expect((try test_read_ileb128(i64, "\xc7\x9f\x7f")) == -12345);
179
180 // Decode unnormalized SLEB128 with extra padding bytes.
181 testing.expect((try test_read_ileb128(i64, "\x80\x00")) == 0);
182 testing.expect((try test_read_ileb128(i64, "\x80\x80\x00")) == 0);
183 testing.expect((try test_read_ileb128(i64, "\xff\x00")) == 0x7f);
184 testing.expect((try test_read_ileb128(i64, "\xff\x80\x00")) == 0x7f);
185 testing.expect((try test_read_ileb128(i64, "\x80\x81\x00")) == 0x80);
186 testing.expect((try test_read_ileb128(i64, "\x80\x81\x80\x00")) == 0x80);
187}
188
189test "deserialize unsigned LEB128" {
190 // Truncated
191 testing.expectError(error.EndOfStream, test_read_uleb128(u64, "\x80"));
192
193 // Overflow
194 testing.expectError(error.Overflow, test_read_uleb128(u8, "\x80\x80\x40"));
195 testing.expectError(error.Overflow, test_read_uleb128(u16, "\x80\x80\x80\x40"));
196 testing.expectError(error.Overflow, test_read_uleb128(u32, "\x80\x80\x80\x80\x40"));
197 testing.expectError(error.Overflow, test_read_uleb128(u64, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x40"));
198
199 // Decode ULEB128
200 testing.expect((try test_read_uleb128(u64, "\x00")) == 0);
201 testing.expect((try test_read_uleb128(u64, "\x01")) == 1);
202 testing.expect((try test_read_uleb128(u64, "\x3f")) == 63);
203 testing.expect((try test_read_uleb128(u64, "\x40")) == 64);
204 testing.expect((try test_read_uleb128(u64, "\x7f")) == 0x7f);
205 testing.expect((try test_read_uleb128(u64, "\x80\x01")) == 0x80);
206 testing.expect((try test_read_uleb128(u64, "\x81\x01")) == 0x81);
207 testing.expect((try test_read_uleb128(u64, "\x90\x01")) == 0x90);
208 testing.expect((try test_read_uleb128(u64, "\xff\x01")) == 0xff);
209 testing.expect((try test_read_uleb128(u64, "\x80\x02")) == 0x100);
210 testing.expect((try test_read_uleb128(u64, "\x81\x02")) == 0x101);
211 testing.expect((try test_read_uleb128(u64, "\x80\xc1\x80\x80\x10")) == 4294975616);
212
213 // Decode ULEB128 with extra padding bytes
214 testing.expect((try test_read_uleb128(u64, "\x80\x00")) == 0);
215 testing.expect((try test_read_uleb128(u64, "\x80\x80\x00")) == 0);
216 testing.expect((try test_read_uleb128(u64, "\xff\x00")) == 0x7f);
217 testing.expect((try test_read_uleb128(u64, "\xff\x80\x00")) == 0x7f);
218 testing.expect((try test_read_uleb128(u64, "\x80\x81\x00")) == 0x80);
219 testing.expect((try test_read_uleb128(u64, "\x80\x81\x80\x00")) == 0x80);
220}