authorgravatar for quae@daurnimator.comdaurnimator <quae@daurnimator.com> 2019-11-15 18:46:18+11:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-25 22:49:46-05:00
logc0cb6767451441fcc9cd3dc4fee3b4794c8b0646
treee7d23ba88d90728c3ddbd5f7053010916ee47c9c
parentf8a2dec243d9bbfed8cd21528ccd93c4f4b9163e

std: refactor std/debug.zig DwarfInfo operations to be methods


1 files changed, 490 insertions(+), 490 deletions(-)

lib/std/debug.zig+490-490
...@@ -732,50 +732,8 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt...@@ -732,50 +732,8 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
732 }732 }
733}733}
734734
735/// This function works in freestanding mode.
736/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
737pub fn printSourceAtAddressDwarf(
738 debug_info: *DwarfInfo,
739 out_stream: var,
740 address: usize,
741 tty_color: bool,
742 comptime printLineFromFile: var,
743) !void {
744 const compile_unit = findCompileUnit(debug_info, address) catch {
745 if (tty_color) {
746 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
747 } else {
748 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
749 }
750 return;
751 };
752 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
753 if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address)) |line_info| {
754 defer line_info.deinit();
755 const symbol_name = getSymbolNameDwarf(debug_info, address) orelse "???";
756 try printLineInfo(
757 out_stream,
758 line_info,
759 address,
760 symbol_name,
761 compile_unit_name,
762 tty_color,
763 printLineFromFile,
764 );
765 } else |err| switch (err) {
766 error.MissingDebugInfo, error.InvalidDebugInfo => {
767 if (tty_color) {
768 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
769 } else {
770 try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
771 }
772 },
773 else => return err,
774 }
775}
776
777pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {735pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
778 return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);736 return debug_info.printSourceAtAddress(out_stream, address, tty_color, printLineFromFileAnyOs);
779}737}
780738
781fn printLineInfo(739fn printLineInfo(
...@@ -1034,8 +992,8 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {...@@ -1034,8 +992,8 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
1034 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);992 di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
1035 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);993 di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
1036 di.func_list = ArrayList(Func).init(allocator);994 di.func_list = ArrayList(Func).init(allocator);
1037 try scanAllFunctions(di);995 try di.scanAllFunctions();
1038 try scanAllCompileUnits(di);996 try di.scanAllCompileUnits();
1039}997}
1040998
1041pub fn openElfDebugInfo(999pub fn openElfDebugInfo(
...@@ -1253,6 +1211,492 @@ pub const DwarfInfo = struct {...@@ -1253,6 +1211,492 @@ pub const DwarfInfo = struct {
1253 pub fn readString(self: *DwarfInfo) ![]u8 {1211 pub fn readString(self: *DwarfInfo) ![]u8 {
1254 return readStringRaw(self.allocator(), self.dwarf_in_stream);1212 return readStringRaw(self.allocator(), self.dwarf_in_stream);
1255 }1213 }
1214
1215 /// This function works in freestanding mode.
1216 /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
1217 pub fn printSourceAtAddress(
1218 self: *DwarfInfo,
1219 out_stream: var,
1220 address: usize,
1221 tty_color: bool,
1222 comptime printLineFromFile: var,
1223 ) !void {
1224 const compile_unit = self.findCompileUnit(address) catch {
1225 if (tty_color) {
1226 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
1227 } else {
1228 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address);
1229 }
1230 return;
1231 };
1232 const compile_unit_name = try compile_unit.die.getAttrString(self, DW.AT_name);
1233 if (self.getLineNumberInfo(compile_unit.*, address)) |line_info| {
1234 defer line_info.deinit();
1235 const symbol_name = self.getSymbolName(address) orelse "???";
1236 try printLineInfo(
1237 out_stream,
1238 line_info,
1239 address,
1240 symbol_name,
1241 compile_unit_name,
1242 tty_color,
1243 printLineFromFile,
1244 );
1245 } else |err| switch (err) {
1246 error.MissingDebugInfo, error.InvalidDebugInfo => {
1247 if (tty_color) {
1248 try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name);
1249 } else {
1250 try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name);
1251 }
1252 },
1253 else => return err,
1254 }
1255 }
1256
1257 fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
1258 for (di.func_list.toSliceConst()) |*func| {
1259 if (func.pc_range) |range| {
1260 if (address >= range.start and address < range.end) {
1261 return func.name;
1262 }
1263 }
1264 }
1265
1266 return null;
1267 }
1268
1269 fn scanAllFunctions(di: *DwarfInfo) !void {
1270 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1271 var this_unit_offset = di.debug_info.offset;
1272
1273 while (this_unit_offset < debug_info_end) {
1274 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
1275
1276 var is_64: bool = undefined;
1277 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1278 if (unit_length == 0) return;
1279 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1280
1281 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1282 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1283
1284 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);
1285
1286 const address_size = try di.dwarf_in_stream.readByte();
1287 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1288
1289 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
1290 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
1291
1292 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
1293
1294 const next_unit_pos = this_unit_offset + next_offset;
1295
1296 while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
1297 const die_obj = (try di.parseDie(abbrev_table, is_64)) orelse continue;
1298 const after_die_offset = try di.dwarf_seekable_stream.getPos();
1299
1300 switch (die_obj.tag_id) {
1301 DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
1302 const fn_name = x: {
1303 var depth: i32 = 3;
1304 var this_die_obj = die_obj;
1305 // Prenvent endless loops
1306 while (depth > 0) : (depth -= 1) {
1307 if (this_die_obj.getAttr(DW.AT_name)) |_| {
1308 const name = try this_die_obj.getAttrString(di, DW.AT_name);
1309 break :x name;
1310 } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
1311 // Follow the DIE it points to and repeat
1312 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
1313 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1314 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
1315 this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1316 } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
1317 // Follow the DIE it points to and repeat
1318 const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
1319 if (ref_offset > next_offset) return error.InvalidDebugInfo;
1320 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
1321 this_die_obj = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1322 } else {
1323 break :x null;
1324 }
1325 }
1326
1327 break :x null;
1328 };
1329
1330 const pc_range = x: {
1331 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1332 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
1333 const pc_end = switch (high_pc_value.*) {
1334 FormValue.Address => |value| value,
1335 FormValue.Const => |value| b: {
1336 const offset = try value.asUnsignedLe();
1337 break :b (low_pc + offset);
1338 },
1339 else => return error.InvalidDebugInfo,
1340 };
1341 break :x PcRange{
1342 .start = low_pc,
1343 .end = pc_end,
1344 };
1345 } else {
1346 break :x null;
1347 }
1348 } else |err| {
1349 if (err != error.MissingDebugInfo) return err;
1350 break :x null;
1351 }
1352 };
1353
1354 try di.func_list.append(Func{
1355 .name = fn_name,
1356 .pc_range = pc_range,
1357 });
1358 },
1359 else => {
1360 continue;
1361 },
1362 }
1363
1364 try di.dwarf_seekable_stream.seekTo(after_die_offset);
1365 }
1366
1367 this_unit_offset += next_offset;
1368 }
1369 }
1370
1371 fn scanAllCompileUnits(di: *DwarfInfo) !void {
1372 const debug_info_end = di.debug_info.offset + di.debug_info.size;
1373 var this_unit_offset = di.debug_info.offset;
1374
1375 while (this_unit_offset < debug_info_end) {
1376 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
1377
1378 var is_64: bool = undefined;
1379 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1380 if (unit_length == 0) return;
1381 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1382
1383 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1384 if (version < 2 or version > 5) return error.InvalidDebugInfo;
1385
1386 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);
1387
1388 const address_size = try di.dwarf_in_stream.readByte();
1389 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
1390
1391 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
1392 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
1393
1394 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
1395
1396 const compile_unit_die = try di.allocator().create(Die);
1397 compile_unit_die.* = (try di.parseDie(abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
1398
1399 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
1400
1401 const pc_range = x: {
1402 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
1403 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
1404 const pc_end = switch (high_pc_value.*) {
1405 FormValue.Address => |value| value,
1406 FormValue.Const => |value| b: {
1407 const offset = try value.asUnsignedLe();
1408 break :b (low_pc + offset);
1409 },
1410 else => return error.InvalidDebugInfo,
1411 };
1412 break :x PcRange{
1413 .start = low_pc,
1414 .end = pc_end,
1415 };
1416 } else {
1417 break :x null;
1418 }
1419 } else |err| {
1420 if (err != error.MissingDebugInfo) return err;
1421 break :x null;
1422 }
1423 };
1424
1425 try di.compile_unit_list.append(CompileUnit{
1426 .version = version,
1427 .is_64 = is_64,
1428 .pc_range = pc_range,
1429 .die = compile_unit_die,
1430 });
1431
1432 this_unit_offset += next_offset;
1433 }
1434 }
1435
1436 fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
1437 for (di.compile_unit_list.toSlice()) |*compile_unit| {
1438 if (compile_unit.pc_range) |range| {
1439 if (target_address >= range.start and target_address < range.end) return compile_unit;
1440 }
1441 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
1442 var base_address: usize = 0;
1443 if (di.debug_ranges) |debug_ranges| {
1444 try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
1445 while (true) {
1446 const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
1447 const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
1448 if (begin_addr == 0 and end_addr == 0) {
1449 break;
1450 }
1451 if (begin_addr == maxInt(usize)) {
1452 base_address = begin_addr;
1453 continue;
1454 }
1455 if (target_address >= begin_addr and target_address < end_addr) {
1456 return compile_unit;
1457 }
1458 }
1459 }
1460 } else |err| {
1461 if (err != error.MissingDebugInfo) return err;
1462 continue;
1463 }
1464 }
1465 return error.MissingDebugInfo;
1466 }
1467
1468 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1469 /// seeks in the stream and parses it.
1470 fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1471 for (di.abbrev_table_list.toSlice()) |*header| {
1472 if (header.offset == abbrev_offset) {
1473 return &header.table;
1474 }
1475 }
1476 try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
1477 try di.abbrev_table_list.append(AbbrevTableHeader{
1478 .offset = abbrev_offset,
1479 .table = try di.parseAbbrevTable(),
1480 });
1481 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1482 }
1483
1484 fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
1485 var result = AbbrevTable.init(di.allocator());
1486 while (true) {
1487 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1488 if (abbrev_code == 0) return result;
1489 try result.append(AbbrevTableEntry{
1490 .abbrev_code = abbrev_code,
1491 .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
1492 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1493 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1494 });
1495 const attrs = &result.items[result.len - 1].attrs;
1496
1497 while (true) {
1498 const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1499 const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1500 if (attr_id == 0 and form_id == 0) break;
1501 try attrs.append(AbbrevAttr{
1502 .attr_id = attr_id,
1503 .form_id = form_id,
1504 });
1505 }
1506 }
1507 }
1508
1509 fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1510 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1511 if (abbrev_code == 0) return null;
1512 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1513
1514 var result = Die{
1515 .tag_id = table_entry.tag_id,
1516 .has_children = table_entry.has_children,
1517 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1518 };
1519 try result.attrs.resize(table_entry.attrs.len);
1520 for (table_entry.attrs.toSliceConst()) |attr, i| {
1521 result.attrs.items[i] = Die.Attr{
1522 .id = attr.attr_id,
1523 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1524 };
1525 }
1526 return result;
1527 }
1528
1529 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
1530 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1531 const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
1532
1533 assert(line_info_offset < di.debug_line.size);
1534
1535 try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
1536
1537 var is_64: bool = undefined;
1538 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1539 if (unit_length == 0) {
1540 return error.MissingDebugInfo;
1541 }
1542 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1543
1544 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1545 // TODO support 3 and 5
1546 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1547
1548 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);
1549 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
1550
1551 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1552 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1553
1554 if (version >= 4) {
1555 // maximum_operations_per_instruction
1556 _ = try di.dwarf_in_stream.readByte();
1557 }
1558
1559 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1560 const line_base = try di.dwarf_in_stream.readByteSigned();
1561
1562 const line_range = try di.dwarf_in_stream.readByte();
1563 if (line_range == 0) return error.InvalidDebugInfo;
1564
1565 const opcode_base = try di.dwarf_in_stream.readByte();
1566
1567 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1568
1569 {
1570 var i: usize = 0;
1571 while (i < opcode_base - 1) : (i += 1) {
1572 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
1573 }
1574 }
1575
1576 var include_directories = ArrayList([]u8).init(di.allocator());
1577 try include_directories.append(compile_unit_cwd);
1578 while (true) {
1579 const dir = try di.readString();
1580 if (dir.len == 0) break;
1581 try include_directories.append(dir);
1582 }
1583
1584 var file_entries = ArrayList(FileEntry).init(di.allocator());
1585 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1586
1587 while (true) {
1588 const file_name = try di.readString();
1589 if (file_name.len == 0) break;
1590 const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
1591 const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
1592 const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
1593 try file_entries.append(FileEntry{
1594 .file_name = file_name,
1595 .dir_index = dir_index,
1596 .mtime = mtime,
1597 .len_bytes = len_bytes,
1598 });
1599 }
1600
1601 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
1602
1603 while (true) {
1604 const opcode = try di.dwarf_in_stream.readByte();
1605
1606 if (opcode == DW.LNS_extended_op) {
1607 const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
1608 if (op_size < 1) return error.InvalidDebugInfo;
1609 var sub_op = try di.dwarf_in_stream.readByte();
1610 switch (sub_op) {
1611 DW.LNE_end_sequence => {
1612 prog.end_sequence = true;
1613 if (try prog.checkLineMatch()) |info| return info;
1614 return error.MissingDebugInfo;
1615 },
1616 DW.LNE_set_address => {
1617 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1618 prog.address = addr;
1619 },
1620 DW.LNE_define_file => {
1621 const file_name = try di.readString();
1622 const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
1623 const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
1624 const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
1625 try file_entries.append(FileEntry{
1626 .file_name = file_name,
1627 .dir_index = dir_index,
1628 .mtime = mtime,
1629 .len_bytes = len_bytes,
1630 });
1631 },
1632 else => {
1633 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1634 try di.dwarf_seekable_stream.seekBy(fwd_amt);
1635 },
1636 }
1637 } else if (opcode >= opcode_base) {
1638 // special opcodes
1639 const adjusted_opcode = opcode - opcode_base;
1640 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
1641 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
1642 prog.line += inc_line;
1643 prog.address += inc_addr;
1644 if (try prog.checkLineMatch()) |info| return info;
1645 prog.basic_block = false;
1646 } else {
1647 switch (opcode) {
1648 DW.LNS_copy => {
1649 if (try prog.checkLineMatch()) |info| return info;
1650 prog.basic_block = false;
1651 },
1652 DW.LNS_advance_pc => {
1653 const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
1654 prog.address += arg * minimum_instruction_length;
1655 },
1656 DW.LNS_advance_line => {
1657 const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
1658 prog.line += arg;
1659 },
1660 DW.LNS_set_file => {
1661 const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
1662 prog.file = arg;
1663 },
1664 DW.LNS_set_column => {
1665 const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
1666 prog.column = arg;
1667 },
1668 DW.LNS_negate_stmt => {
1669 prog.is_stmt = !prog.is_stmt;
1670 },
1671 DW.LNS_set_basic_block => {
1672 prog.basic_block = true;
1673 },
1674 DW.LNS_const_add_pc => {
1675 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
1676 prog.address += inc_addr;
1677 },
1678 DW.LNS_fixed_advance_pc => {
1679 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
1680 prog.address += arg;
1681 },
1682 DW.LNS_set_prologue_end => {},
1683 else => {
1684 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1685 const len_bytes = standard_opcode_lengths[opcode - 1];
1686 try di.dwarf_seekable_stream.seekBy(len_bytes);
1687 },
1688 }
1689 }
1690 }
1691
1692 return error.MissingDebugInfo;
1693 }
1694
1695 fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1696 const pos = di.debug_str.offset + offset;
1697 try di.dwarf_seekable_stream.seekTo(pos);
1698 return di.readString();
1699 }
1256};1700};
12571701
1258pub const DebugInfo = switch (builtin.os) {1702pub const DebugInfo = switch (builtin.os) {
...@@ -1391,7 +1835,7 @@ const Die = struct {...@@ -1391,7 +1835,7 @@ const Die = struct {
1391 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;1835 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
1392 return switch (form_value.*) {1836 return switch (form_value.*) {
1393 FormValue.String => |value| value,1837 FormValue.String => |value| value,
1394 FormValue.StrPtr => |offset| getString(di, offset),1838 FormValue.StrPtr => |offset| di.getString(offset),
1395 else => error.InvalidDebugInfo,1839 else => error.InvalidDebugInfo,
1396 };1840 };
1397 }1841 }
...@@ -1504,12 +1948,6 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {...@@ -1504,12 +1948,6 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
1504 return buf.toSlice();1948 return buf.toSlice();
1505}1949}
15061950
1507fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1508 const pos = di.debug_str.offset + offset;
1509 try di.dwarf_seekable_stream.seekTo(pos);
1510 return di.readString();
1511}
1512
1513// TODO the noasyncs here are workarounds1951// TODO the noasyncs here are workarounds
1514fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {1952fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
1515 const buf = try allocator.alloc(u8, size);1953 const buf = try allocator.alloc(u8, size);
...@@ -1636,47 +2074,6 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1636,47 +2074,6 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1636 };2074 };
1637}2075}
16382076
1639fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
1640 var result = AbbrevTable.init(di.allocator());
1641 while (true) {
1642 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1643 if (abbrev_code == 0) return result;
1644 try result.append(AbbrevTableEntry{
1645 .abbrev_code = abbrev_code,
1646 .tag_id = try leb.readULEB128(u64, di.dwarf_in_stream),
1647 .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
1648 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
1649 });
1650 const attrs = &result.items[result.len - 1].attrs;
1651
1652 while (true) {
1653 const attr_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1654 const form_id = try leb.readULEB128(u64, di.dwarf_in_stream);
1655 if (attr_id == 0 and form_id == 0) break;
1656 try attrs.append(AbbrevAttr{
1657 .attr_id = attr_id,
1658 .form_id = form_id,
1659 });
1660 }
1661 }
1662}
1663
1664/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
1665/// seeks in the stream and parses it.
1666fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
1667 for (di.abbrev_table_list.toSlice()) |*header| {
1668 if (header.offset == abbrev_offset) {
1669 return &header.table;
1670 }
1671 }
1672 try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
1673 try di.abbrev_table_list.append(AbbrevTableHeader{
1674 .offset = abbrev_offset,
1675 .table = try parseAbbrevTable(di),
1676 });
1677 return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
1678}
1679
1680fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {2077fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
1681 for (abbrev_table.toSliceConst()) |*table_entry| {2078 for (abbrev_table.toSliceConst()) |*table_entry| {
1682 if (table_entry.abbrev_code == abbrev_code) return table_entry;2079 if (table_entry.abbrev_code == abbrev_code) return table_entry;
...@@ -1684,26 +2081,6 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con...@@ -1684,26 +2081,6 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
1684 return null;2081 return null;
1685}2082}
16862083
1687fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die {
1688 const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream);
1689 if (abbrev_code == 0) return null;
1690 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
1691
1692 var result = Die{
1693 .tag_id = table_entry.tag_id,
1694 .has_children = table_entry.has_children,
1695 .attrs = ArrayList(Die.Attr).init(di.allocator()),
1696 };
1697 try result.attrs.resize(table_entry.attrs.len);
1698 for (table_entry.attrs.toSliceConst()) |attr, i| {
1699 result.attrs.items[i] = Die.Attr{
1700 .id = attr.attr_id,
1701 .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
1702 };
1703 }
1704 return result;
1705}
1706
1707fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {2084fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo {
1708 const ofile = symbol.ofile orelse return error.MissingDebugInfo;2085 const ofile = symbol.ofile orelse return error.MissingDebugInfo;
1709 const gop = try di.ofiles.getOrPut(ofile);2086 const gop = try di.ofiles.getOrPut(ofile);
...@@ -1907,388 +2284,11 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -1907,388 +2284,11 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
1907 return error.MissingDebugInfo;2284 return error.MissingDebugInfo;
1908}2285}
19092286
1910fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
1911 const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
1912 const line_info_offset = try compile_unit.die.getAttrSecOffset(DW.AT_stmt_list);
1913
1914 assert(line_info_offset < di.debug_line.size);
1915
1916 try di.dwarf_seekable_stream.seekTo(di.debug_line.offset + line_info_offset);
1917
1918 var is_64: bool = undefined;
1919 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
1920 if (unit_length == 0) {
1921 return error.MissingDebugInfo;
1922 }
1923 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
1924
1925 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
1926 // TODO support 3 and 5
1927 if (version != 2 and version != 4) return error.InvalidDebugInfo;
1928
1929 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);
1930 const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
1931
1932 const minimum_instruction_length = try di.dwarf_in_stream.readByte();
1933 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
1934
1935 if (version >= 4) {
1936 // maximum_operations_per_instruction
1937 _ = try di.dwarf_in_stream.readByte();
1938 }
1939
1940 const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
1941 const line_base = try di.dwarf_in_stream.readByteSigned();
1942
1943 const line_range = try di.dwarf_in_stream.readByte();
1944 if (line_range == 0) return error.InvalidDebugInfo;
1945
1946 const opcode_base = try di.dwarf_in_stream.readByte();
1947
1948 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
1949
1950 {
1951 var i: usize = 0;
1952 while (i < opcode_base - 1) : (i += 1) {
1953 standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
1954 }
1955 }
1956
1957 var include_directories = ArrayList([]u8).init(di.allocator());
1958 try include_directories.append(compile_unit_cwd);
1959 while (true) {
1960 const dir = try di.readString();
1961 if (dir.len == 0) break;
1962 try include_directories.append(dir);
1963 }
1964
1965 var file_entries = ArrayList(FileEntry).init(di.allocator());
1966 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
1967
1968 while (true) {
1969 const file_name = try di.readString();
1970 if (file_name.len == 0) break;
1971 const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
1972 const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
1973 const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
1974 try file_entries.append(FileEntry{
1975 .file_name = file_name,
1976 .dir_index = dir_index,
1977 .mtime = mtime,
1978 .len_bytes = len_bytes,
1979 });
1980 }
1981
1982 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
1983
1984 while (true) {
1985 const opcode = try di.dwarf_in_stream.readByte();
1986
1987 if (opcode == DW.LNS_extended_op) {
1988 const op_size = try leb.readULEB128(u64, di.dwarf_in_stream);
1989 if (op_size < 1) return error.InvalidDebugInfo;
1990 var sub_op = try di.dwarf_in_stream.readByte();
1991 switch (sub_op) {
1992 DW.LNE_end_sequence => {
1993 prog.end_sequence = true;
1994 if (try prog.checkLineMatch()) |info| return info;
1995 return error.MissingDebugInfo;
1996 },
1997 DW.LNE_set_address => {
1998 const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
1999 prog.address = addr;
2000 },
2001 DW.LNE_define_file => {
2002 const file_name = try di.readString();
2003 const dir_index = try leb.readULEB128(usize, di.dwarf_in_stream);
2004 const mtime = try leb.readULEB128(usize, di.dwarf_in_stream);
2005 const len_bytes = try leb.readULEB128(usize, di.dwarf_in_stream);
2006 try file_entries.append(FileEntry{
2007 .file_name = file_name,
2008 .dir_index = dir_index,
2009 .mtime = mtime,
2010 .len_bytes = len_bytes,
2011 });
2012 },
2013 else => {
2014 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
2015 try di.dwarf_seekable_stream.seekBy(fwd_amt);
2016 },
2017 }
2018 } else if (opcode >= opcode_base) {
2019 // special opcodes
2020 const adjusted_opcode = opcode - opcode_base;
2021 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
2022 const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range);
2023 prog.line += inc_line;
2024 prog.address += inc_addr;
2025 if (try prog.checkLineMatch()) |info| return info;
2026 prog.basic_block = false;
2027 } else {
2028 switch (opcode) {
2029 DW.LNS_copy => {
2030 if (try prog.checkLineMatch()) |info| return info;
2031 prog.basic_block = false;
2032 },
2033 DW.LNS_advance_pc => {
2034 const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
2035 prog.address += arg * minimum_instruction_length;
2036 },
2037 DW.LNS_advance_line => {
2038 const arg = try leb.readILEB128(i64, di.dwarf_in_stream);
2039 prog.line += arg;
2040 },
2041 DW.LNS_set_file => {
2042 const arg = try leb.readULEB128(usize, di.dwarf_in_stream);
2043 prog.file = arg;
2044 },
2045 DW.LNS_set_column => {
2046 const arg = try leb.readULEB128(u64, di.dwarf_in_stream);
2047 prog.column = arg;
2048 },
2049 DW.LNS_negate_stmt => {
2050 prog.is_stmt = !prog.is_stmt;
2051 },
2052 DW.LNS_set_basic_block => {
2053 prog.basic_block = true;
2054 },
2055 DW.LNS_const_add_pc => {
2056 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
2057 prog.address += inc_addr;
2058 },
2059 DW.LNS_fixed_advance_pc => {
2060 const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
2061 prog.address += arg;
2062 },
2063 DW.LNS_set_prologue_end => {},
2064 else => {
2065 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
2066 const len_bytes = standard_opcode_lengths[opcode - 1];
2067 try di.dwarf_seekable_stream.seekBy(len_bytes);
2068 },
2069 }
2070 }
2071 }
2072
2073 return error.MissingDebugInfo;
2074}
2075
2076const Func = struct {2287const Func = struct {
2077 pc_range: ?PcRange,2288 pc_range: ?PcRange,
2078 name: ?[]u8,2289 name: ?[]u8,
2079};2290};
20802291
2081fn getSymbolNameDwarf(di: *DwarfInfo, address: u64) ?[]const u8 {
2082 for (di.func_list.toSliceConst()) |*func| {
2083 if (func.pc_range) |range| {
2084 if (address >= range.start and address < range.end) {
2085 return func.name;
2086 }
2087 }
2088 }
2089
2090 return null;
2091}
2092
2093fn scanAllFunctions(di: *DwarfInfo) !void {
2094 const debug_info_end = di.debug_info.offset + di.debug_info.size;
2095 var this_unit_offset = di.debug_info.offset;
2096
2097 while (this_unit_offset < debug_info_end) {
2098 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
2099
2100 var is_64: bool = undefined;
2101 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
2102 if (unit_length == 0) return;
2103 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
2104
2105 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
2106 if (version < 2 or version > 5) return error.InvalidDebugInfo;
2107
2108 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);
2109
2110 const address_size = try di.dwarf_in_stream.readByte();
2111 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
2112
2113 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
2114 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
2115
2116 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
2117
2118 const next_unit_pos = this_unit_offset + next_offset;
2119
2120 while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) {
2121 const die_obj = (try parseDie(di, abbrev_table, is_64)) orelse continue;
2122 const after_die_offset = try di.dwarf_seekable_stream.getPos();
2123
2124 switch (die_obj.tag_id) {
2125 DW.TAG_subprogram, DW.TAG_inlined_subroutine, DW.TAG_subroutine, DW.TAG_entry_point => {
2126 const fn_name = x: {
2127 var depth: i32 = 3;
2128 var this_die_obj = die_obj;
2129 // Prenvent endless loops
2130 while (depth > 0) : (depth -= 1) {
2131 if (this_die_obj.getAttr(DW.AT_name)) |_| {
2132 const name = try this_die_obj.getAttrString(di, DW.AT_name);
2133 break :x name;
2134 } else if (this_die_obj.getAttr(DW.AT_abstract_origin)) |ref| {
2135 // Follow the DIE it points to and repeat
2136 const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin);
2137 if (ref_offset > next_offset) return error.InvalidDebugInfo;
2138 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
2139 this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2140 } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| {
2141 // Follow the DIE it points to and repeat
2142 const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification);
2143 if (ref_offset > next_offset) return error.InvalidDebugInfo;
2144 try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset);
2145 this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2146 } else {
2147 break :x null;
2148 }
2149 }
2150
2151 break :x null;
2152 };
2153
2154 const pc_range = x: {
2155 if (die_obj.getAttrAddr(DW.AT_low_pc)) |low_pc| {
2156 if (die_obj.getAttr(DW.AT_high_pc)) |high_pc_value| {
2157 const pc_end = switch (high_pc_value.*) {
2158 FormValue.Address => |value| value,
2159 FormValue.Const => |value| b: {
2160 const offset = try value.asUnsignedLe();
2161 break :b (low_pc + offset);
2162 },
2163 else => return error.InvalidDebugInfo,
2164 };
2165 break :x PcRange{
2166 .start = low_pc,
2167 .end = pc_end,
2168 };
2169 } else {
2170 break :x null;
2171 }
2172 } else |err| {
2173 if (err != error.MissingDebugInfo) return err;
2174 break :x null;
2175 }
2176 };
2177
2178 try di.func_list.append(Func{
2179 .name = fn_name,
2180 .pc_range = pc_range,
2181 });
2182 },
2183 else => {
2184 continue;
2185 },
2186 }
2187
2188 try di.dwarf_seekable_stream.seekTo(after_die_offset);
2189 }
2190
2191 this_unit_offset += next_offset;
2192 }
2193}
2194
2195fn scanAllCompileUnits(di: *DwarfInfo) !void {
2196 const debug_info_end = di.debug_info.offset + di.debug_info.size;
2197 var this_unit_offset = di.debug_info.offset;
2198
2199 while (this_unit_offset < debug_info_end) {
2200 try di.dwarf_seekable_stream.seekTo(this_unit_offset);
2201
2202 var is_64: bool = undefined;
2203 const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
2204 if (unit_length == 0) return;
2205 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
2206
2207 const version = try di.dwarf_in_stream.readInt(u16, di.endian);
2208 if (version < 2 or version > 5) return error.InvalidDebugInfo;
2209
2210 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);
2211
2212 const address_size = try di.dwarf_in_stream.readByte();
2213 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
2214
2215 const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
2216 const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
2217
2218 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
2219
2220 const compile_unit_die = try di.allocator().create(Die);
2221 compile_unit_die.* = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
2222
2223 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
2224
2225 const pc_range = x: {
2226 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
2227 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
2228 const pc_end = switch (high_pc_value.*) {
2229 FormValue.Address => |value| value,
2230 FormValue.Const => |value| b: {
2231 const offset = try value.asUnsignedLe();
2232 break :b (low_pc + offset);
2233 },
2234 else => return error.InvalidDebugInfo,
2235 };
2236 break :x PcRange{
2237 .start = low_pc,
2238 .end = pc_end,
2239 };
2240 } else {
2241 break :x null;
2242 }
2243 } else |err| {
2244 if (err != error.MissingDebugInfo) return err;
2245 break :x null;
2246 }
2247 };
2248
2249 try di.compile_unit_list.append(CompileUnit{
2250 .version = version,
2251 .is_64 = is_64,
2252 .pc_range = pc_range,
2253 .die = compile_unit_die,
2254 });
2255
2256 this_unit_offset += next_offset;
2257 }
2258}
2259
2260fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
2261 for (di.compile_unit_list.toSlice()) |*compile_unit| {
2262 if (compile_unit.pc_range) |range| {
2263 if (target_address >= range.start and target_address < range.end) return compile_unit;
2264 }
2265 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
2266 var base_address: usize = 0;
2267 if (di.debug_ranges) |debug_ranges| {
2268 try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
2269 while (true) {
2270 const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
2271 const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
2272 if (begin_addr == 0 and end_addr == 0) {
2273 break;
2274 }
2275 if (begin_addr == maxInt(usize)) {
2276 base_address = begin_addr;
2277 continue;
2278 }
2279 if (target_address >= begin_addr and target_address < end_addr) {
2280 return compile_unit;
2281 }
2282 }
2283 }
2284 } else |err| {
2285 if (err != error.MissingDebugInfo) return err;
2286 continue;
2287 }
2288 }
2289 return error.MissingDebugInfo;
2290}
2291
2292fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {2292fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
2293 // TODO https://github.com/ziglang/zig/issues/8632293 // TODO https://github.com/ziglang/zig/issues/863
2294 const size = (T.bit_count + 7) / 8;2294 const size = (T.bit_count + 7) / 8;