| ... | ... | @@ -662,13 +662,19 @@ pub const DwarfSection = enum { |
| 662 | 662 | |
| 663 | 663 | pub const DwarfInfo = struct { |
| 664 | 664 | endian: std.builtin.Endian, |
| 665 | | // No memory is owned by the DwarfInfo |
| 665 | |
| 666 | // No section memory is owned by the DwarfInfo |
| 666 | 667 | sections: [std.enums.directEnumArrayLen(DwarfSection, 0)]?[]const u8, |
| 668 | |
| 667 | 669 | // Filled later by the initializer |
| 668 | 670 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, |
| 669 | 671 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 670 | 672 | func_list: std.ArrayListUnmanaged(Func) = .{}, |
| 671 | 673 | |
| 674 | cie_map: std.AutoArrayHashMapUnmanaged(u64, CommonInformationEntry) = .{}, |
| 675 | // Sorted by start_pc |
| 676 | fde_list: std.ArrayListUnmanaged(FrameDescriptionEntry) = .{}, |
| 677 | |
| 672 | 678 | pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 { |
| 673 | 679 | return di.sections[@enumToInt(dwarf_section)]; |
| 674 | 680 | } |
| ... | ... | @@ -1434,6 +1440,7 @@ pub const DwarfInfo = struct { |
| 1434 | 1440 | return getStringGeneric(di.section(.debug_line_str), offset); |
| 1435 | 1441 | } |
| 1436 | 1442 | |
| 1443 | |
| 1437 | 1444 | fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 { |
| 1438 | 1445 | const debug_addr = di.section(.debug_addr) orelse return badDwarf(); |
| 1439 | 1446 | |
| ... | ... | @@ -1459,6 +1466,56 @@ pub const DwarfInfo = struct { |
| 1459 | 1466 | else => badDwarf(), |
| 1460 | 1467 | }; |
| 1461 | 1468 | } |
| 1469 | |
| 1470 | pub fn scanAllUnwindInfo(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 1471 | var has_eh_frame_hdr = false; |
| 1472 | if (di.section(.eh_frame)) |eh_frame_hdr| { |
| 1473 | has_eh_frame_hdr = true; |
| 1474 | |
| 1475 | // TODO: Parse this section |
| 1476 | _ = eh_frame_hdr; |
| 1477 | } |
| 1478 | |
| 1479 | if (di.section(.eh_frame)) |eh_frame| { |
| 1480 | var stream = io.fixedBufferStream(eh_frame); |
| 1481 | const reader = stream.reader(); |
| 1482 | |
| 1483 | while (stream.pos < stream.buffer.len) { |
| 1484 | const length_offset = stream.pos; |
| 1485 | var length: u64 = try reader.readInt(u32, di.endian); |
| 1486 | if (length == 0) break; |
| 1487 | |
| 1488 | var is_64 = length == math.maxInt(u32); |
| 1489 | if (is_64) { |
| 1490 | length = try reader.readInt(u64, di.endian); |
| 1491 | } |
| 1492 | |
| 1493 | const entry_bytes = eh_frame[stream.pos..][0..length]; |
| 1494 | const id = try reader.readInt(u32, di.endian); |
| 1495 | |
| 1496 | // TODO: Get section_offset here (pass in from headers) |
| 1497 | |
| 1498 | if (id == 0) { |
| 1499 | const cie = try CommonInformationEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, length_offset, @sizeOf(usize), di.endian); |
| 1500 | try di.cie_map.put(allocator, length_offset, cie); |
| 1501 | } else { |
| 1502 | const cie_offset = stream.pos - 4 - id; |
| 1503 | const cie = di.cie_map.get(cie_offset) orelse return badDwarf(); |
| 1504 | const fde = try FrameDescriptionEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, cie, @sizeOf(usize), di.endian); |
| 1505 | try di.fde_list.append(allocator, fde); |
| 1506 | } |
| 1507 | } |
| 1508 | |
| 1509 | // TODO: Avoiding sorting if has_eh_frame_hdr exists |
| 1510 | std.sort.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct { |
| 1511 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { |
| 1512 | _ = ctx; |
| 1513 | return a.pc_begin < b.pc_begin; |
| 1514 | } |
| 1515 | }.lessThan); |
| 1516 | } |
| 1517 | } |
| 1518 | |
| 1462 | 1519 | }; |
| 1463 | 1520 | |
| 1464 | 1521 | /// Initialize DWARF info. The caller has the responsibility to initialize most |
| ... | ... | @@ -1467,11 +1524,8 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 1467 | 1524 | try di.scanAllFunctions(allocator); |
| 1468 | 1525 | try di.scanAllCompileUnits(allocator); |
| 1469 | 1526 | |
| 1470 | | // DEBUG |
| 1471 | | if (di.section(.eh_frame)) |eh_frame| { |
| 1472 | | _ = try CommonInformationEntry.parse(eh_frame, 8, .Little); |
| 1473 | | } |
| 1474 | | |
| 1527 | // Unwind info is not required |
| 1528 | di.scanAllUnwindInfo(allocator) catch {}; |
| 1475 | 1529 | } |
| 1476 | 1530 | |
| 1477 | 1531 | /// This function is to make it handy to comment out the return and make it |
| ... | ... | @@ -1495,74 +1549,131 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { |
| 1495 | 1549 | return str[casted_offset..last :0]; |
| 1496 | 1550 | } |
| 1497 | 1551 | |
| 1498 | | const EhPointer = struct { |
| 1499 | | value: union(enum) { |
| 1500 | | signed: i64, |
| 1501 | | unsigned: u64, |
| 1502 | | }, |
| 1503 | | relative_to: u8, |
| 1552 | const EhPointerContext = struct { |
| 1553 | // The address of the pointer field itself |
| 1554 | pc_rel_base: u64, |
| 1504 | 1555 | |
| 1505 | | // address of the encoded value |
| 1506 | | pc: u64, |
| 1507 | | |
| 1508 | | // TODO: Function to resolve the value given input state (.text start, .eh_frame_hdr start, functions start) |
| 1556 | // These relative addressing modes are only used in specific cases, and |
| 1557 | // might not be available / required in all parsing contexts |
| 1558 | data_rel_base: ?u64 = null, |
| 1559 | text_rel_base: ?u64 = null, |
| 1560 | function_rel_base: ?u64 = null, |
| 1509 | 1561 | }; |
| 1510 | 1562 | |
| 1511 | | fn readEhPointer(enc: u8, pc: usize, addr_size_bytes: u8, endian: std.builtin.Endian, reader: anytype) !?EhPointer { |
| 1563 | fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerContext, endian: std.builtin.Endian) !?u64 { |
| 1512 | 1564 | if (enc == EH.PE.omit) return null; |
| 1513 | | return EhPointer{ |
| 1514 | | .value = switch (enc & 0x0f) { |
| 1515 | | EH.PE.absptr => .{ .unsigned = switch (addr_size_bytes) { |
| 1565 | |
| 1566 | const value: union(enum) { |
| 1567 | signed: i64, |
| 1568 | unsigned: u64, |
| 1569 | } = switch (enc & 0x0f) { |
| 1570 | EH.PE.absptr => .{ |
| 1571 | .unsigned = switch (addr_size_bytes) { |
| 1516 | 1572 | 2 => try reader.readInt(u16, endian), |
| 1517 | 1573 | 4 => try reader.readInt(u32, endian), |
| 1518 | 1574 | 8 => try reader.readInt(u64, endian), |
| 1519 | 1575 | else => return error.InvalidAddrSize, |
| 1520 | | } }, |
| 1521 | | EH.PE.uleb128 => .{ .unsigned = try leb.readULEB128(u64, reader) }, |
| 1522 | | EH.PE.udata2 => .{ .unsigned = try reader.readInt(u16, endian) }, |
| 1523 | | EH.PE.udata4 => .{ .unsigned = try reader.readInt(u32, endian) }, |
| 1524 | | EH.PE.udata8 => .{ .unsigned = try reader.readInt(u64, endian) }, |
| 1525 | | EH.PE.sleb128 => .{ .signed = try leb.readILEB128(i64, reader) }, |
| 1526 | | EH.PE.sdata2 => .{ .signed = try reader.readInt(i16, endian) }, |
| 1527 | | EH.PE.sdata4 => .{ .signed = try reader.readInt(i32, endian) }, |
| 1528 | | EH.PE.sdata8 => .{ .signed = try reader.readInt(i64, endian) }, |
| 1529 | | else => return badDwarf(), |
| 1576 | }, |
| 1530 | 1577 | }, |
| 1531 | | .relative_to = enc & 0xf0, |
| 1532 | | .pc = pc |
| 1578 | EH.PE.uleb128 => .{ .unsigned = try leb.readULEB128(u64, reader) }, |
| 1579 | EH.PE.udata2 => .{ .unsigned = try reader.readInt(u16, endian) }, |
| 1580 | EH.PE.udata4 => .{ .unsigned = try reader.readInt(u32, endian) }, |
| 1581 | EH.PE.udata8 => .{ .unsigned = try reader.readInt(u64, endian) }, |
| 1582 | EH.PE.sleb128 => .{ .signed = try leb.readILEB128(i64, reader) }, |
| 1583 | EH.PE.sdata2 => .{ .signed = try reader.readInt(i16, endian) }, |
| 1584 | EH.PE.sdata4 => .{ .signed = try reader.readInt(i32, endian) }, |
| 1585 | EH.PE.sdata8 => .{ .signed = try reader.readInt(i64, endian) }, |
| 1586 | else => return badDwarf(), |
| 1533 | 1587 | }; |
| 1588 | |
| 1589 | const relative_to = enc & 0xf0; |
| 1590 | var base = switch (relative_to) { |
| 1591 | EH.PE.pcrel => ctx.pc_rel_base, |
| 1592 | EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified, |
| 1593 | EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified, |
| 1594 | EH.PE.funcrel => ctx.function_rel_base orelse return error.PointerBaseNotSpecified, |
| 1595 | EH.PE.indirect => { |
| 1596 | switch (addr_size_bytes) { |
| 1597 | 2 => return @intToPtr(*const u16, value.unsigned).*, |
| 1598 | 4 => return @intToPtr(*const u32, value.unsigned).*, |
| 1599 | 8 => return @intToPtr(*const u64, value.unsigned).*, |
| 1600 | else => return error.UnsupportedAddrSize, |
| 1601 | } |
| 1602 | }, |
| 1603 | else => null, |
| 1604 | }; |
| 1605 | |
| 1606 | if (base) |b| { |
| 1607 | return switch (value) { |
| 1608 | .signed => |s| @intCast(u64, s + @intCast(i64, b)), |
| 1609 | .unsigned => |u| u + b, |
| 1610 | }; |
| 1611 | } else { |
| 1612 | return switch (value) { |
| 1613 | .signed => |s| @intCast(u64, s), |
| 1614 | .unsigned => |u| u, |
| 1615 | }; |
| 1616 | } |
| 1534 | 1617 | } |
| 1535 | 1618 | |
| 1536 | | const CommonInformationEntry = struct { |
| 1537 | | length: u32, |
| 1538 | | id: u32, |
| 1619 | pub const CommonInformationEntry = struct { |
| 1620 | // Used in .eh_frame |
| 1621 | pub const eh_id = 0; |
| 1622 | |
| 1623 | // Used in .debug_frame (DWARF32) |
| 1624 | pub const dwarf32_id = std.math.maxInt(u32); |
| 1625 | |
| 1626 | // Used in .debug_frame (DWARF64) |
| 1627 | pub const dwarf64_id = std.math.maxInt(u64); |
| 1628 | |
| 1629 | // Offset of the length field of this entry in the eh_frame section. |
| 1630 | // This is the key that FDEs use to reference CIEs. |
| 1631 | length_offset: u64, |
| 1539 | 1632 | version: u8, |
| 1540 | | code_alignment_factor: u64, |
| 1541 | | data_alignment_factor: u64, |
| 1542 | | return_address_register: u64, |
| 1543 | 1633 | |
| 1544 | | // Augmented data |
| 1545 | | lsda_pointer_enc: ?u8, |
| 1546 | | personality_routine_pointer: ?EhPointer, |
| 1547 | | fde_pointer_enc: ?u8, |
| 1634 | code_alignment_factor: u32, |
| 1635 | data_alignment_factor: i32, |
| 1636 | return_address_register: u8, |
| 1548 | 1637 | |
| 1638 | aug_str: []const u8, |
| 1639 | aug_data: []const u8, |
| 1640 | lsda_pointer_enc: u8, |
| 1641 | personality_enc: ?u8, |
| 1642 | personality_routine_pointer: ?u64, |
| 1643 | fde_pointer_enc: u8, |
| 1549 | 1644 | initial_instructions: []const u8, |
| 1550 | 1645 | |
| 1551 | | // The returned struct references memory in `bytes`. |
| 1552 | | pub fn parse(bytes: []const u8, addr_size_bytes: u8, endian: std.builtin.Endian) !CommonInformationEntry { |
| 1553 | | if (addr_size_bytes > 8) return error.InvalidAddrSize; |
| 1554 | | if (bytes.len < 4) return badDwarf(); |
| 1555 | | const length = mem.readInt(u32, bytes[0..4], endian); |
| 1556 | | const cie_bytes = bytes[4..][0..length]; |
| 1646 | pub fn isSignalFrame(self: CommonInformationEntry) bool { |
| 1647 | for (self.aug_str) |c| if (c == 'S') return true; |
| 1648 | return false; |
| 1649 | } |
| 1650 | |
| 1651 | pub fn addressesSignedWithBKey(self: CommonInformationEntry) bool { |
| 1652 | for (self.aug_str) |c| if (c == 'B') return true; |
| 1653 | return false; |
| 1654 | } |
| 1655 | |
| 1656 | pub fn mteTaggedFrame(self: CommonInformationEntry) bool { |
| 1657 | for (self.aug_str) |c| if (c == 'G') return true; |
| 1658 | return false; |
| 1659 | } |
| 1660 | |
| 1661 | // The returned struct references memory backed by cie_bytes |
| 1662 | pub fn parse( |
| 1663 | cie_bytes: []const u8, |
| 1664 | section_base: u64, |
| 1665 | section_offset: u64, |
| 1666 | length_offset: u64, |
| 1667 | addr_size_bytes: u8, |
| 1668 | endian: std.builtin.Endian, |
| 1669 | ) !CommonInformationEntry { |
| 1670 | if (addr_size_bytes > 8) return error.UnsupportedAddrSize; |
| 1557 | 1671 | |
| 1558 | 1672 | var stream = io.fixedBufferStream(cie_bytes); |
| 1559 | 1673 | const reader = stream.reader(); |
| 1560 | 1674 | |
| 1561 | | const id = try reader.readInt(u32, endian); |
| 1562 | | if (id != 0) return badDwarf(); |
| 1563 | | |
| 1564 | 1675 | const version = try reader.readByte(); |
| 1565 | | if (version != 1) return badDwarf(); |
| 1676 | if (version != 1 and version != 3) return error.UnsupportedDwarfVersion; |
| 1566 | 1677 | |
| 1567 | 1678 | var has_eh_data = false; |
| 1568 | 1679 | var has_aug_data = false; |
| ... | ... | @@ -1575,76 +1686,153 @@ const CommonInformationEntry = struct { |
| 1575 | 1686 | 'z' => { |
| 1576 | 1687 | if (aug_str_len != 0) return badDwarf(); |
| 1577 | 1688 | has_aug_data = true; |
| 1578 | | aug_str_start = stream.pos; |
| 1579 | 1689 | }, |
| 1580 | 1690 | 'e' => { |
| 1581 | 1691 | if (has_aug_data or aug_str_len != 0) return badDwarf(); |
| 1582 | 1692 | if (try reader.readByte() != 'h') return badDwarf(); |
| 1583 | 1693 | has_eh_data = true; |
| 1584 | 1694 | }, |
| 1585 | | else => { |
| 1586 | | if (has_eh_data) return badDwarf(); |
| 1587 | | aug_str_len += 1; |
| 1588 | | }, |
| 1695 | else => if (has_eh_data) return badDwarf(), |
| 1589 | 1696 | } |
| 1697 | |
| 1698 | aug_str_len += 1; |
| 1590 | 1699 | } |
| 1591 | 1700 | |
| 1592 | 1701 | if (has_eh_data) { |
| 1593 | | // legacy data created by older versions of gcc - ignored here |
| 1702 | // legacy data created by older versions of gcc - unsupported here |
| 1594 | 1703 | for (0..addr_size_bytes) |_| _ = try reader.readByte(); |
| 1595 | 1704 | } |
| 1596 | 1705 | |
| 1597 | | const code_alignment_factor = try leb.readULEB128(u64, reader); |
| 1598 | | const data_alignment_factor = try leb.readULEB128(u64, reader); |
| 1599 | | const return_address_register = try leb.readULEB128(u64, reader); |
| 1706 | const code_alignment_factor = try leb.readULEB128(u32, reader); |
| 1707 | const data_alignment_factor = try leb.readILEB128(i32, reader); |
| 1708 | const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader); |
| 1600 | 1709 | |
| 1601 | | var lsda_pointer_enc: ?u8 = null; |
| 1602 | | var personality_routine_pointer: ?EhPointer = null; |
| 1603 | | var fde_pointer_enc: ?u8 = null; |
| 1710 | var lsda_pointer_enc: u8 = EH.PE.omit; |
| 1711 | var personality_enc: ?u8 = null; |
| 1712 | var personality_routine_pointer: ?u64 = null; |
| 1713 | var fde_pointer_enc: u8 = EH.PE.absptr; |
| 1604 | 1714 | |
| 1605 | | if (has_aug_data) { |
| 1715 | var aug_data: []const u8 = &[_]u8{}; |
| 1716 | const aug_str = if (has_aug_data) blk: { |
| 1606 | 1717 | const aug_data_len = try leb.readULEB128(usize, reader); |
| 1607 | 1718 | const aug_data_start = stream.pos; |
| 1719 | aug_data = cie_bytes[aug_data_start..][0..aug_data_len]; |
| 1608 | 1720 | |
| 1609 | 1721 | const aug_str = cie_bytes[aug_str_start..][0..aug_str_len]; |
| 1610 | | for (aug_str) |byte| { |
| 1722 | for (aug_str[1..]) |byte| { |
| 1611 | 1723 | switch (byte) { |
| 1612 | 1724 | 'L' => { |
| 1613 | 1725 | lsda_pointer_enc = try reader.readByte(); |
| 1614 | 1726 | }, |
| 1615 | 1727 | 'P' => { |
| 1616 | | const personality_enc = try reader.readByte(); |
| 1728 | personality_enc = try reader.readByte(); |
| 1617 | 1729 | personality_routine_pointer = try readEhPointer( |
| 1618 | | personality_enc, |
| 1619 | | @ptrToInt(&cie_bytes[stream.pos]), |
| 1730 | reader, |
| 1731 | personality_enc.?, |
| 1620 | 1732 | addr_size_bytes, |
| 1733 | .{ .pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset }, |
| 1621 | 1734 | endian, |
| 1622 | | reader, |
| 1623 | 1735 | ); |
| 1624 | 1736 | }, |
| 1625 | 1737 | 'R' => { |
| 1626 | 1738 | fde_pointer_enc = try reader.readByte(); |
| 1627 | 1739 | }, |
| 1740 | 'S', 'B', 'G' => {}, |
| 1628 | 1741 | else => return badDwarf(), |
| 1629 | 1742 | } |
| 1630 | 1743 | } |
| 1631 | 1744 | |
| 1632 | | // verify length field |
| 1633 | | if (stream.pos != (aug_data_start + aug_data_len)) return badDwarf(); |
| 1634 | | } |
| 1745 | // aug_data_len can include padding so the CIE ends on an address boundary |
| 1746 | try stream.seekTo(aug_data_start + aug_data_len); |
| 1747 | break :blk aug_str; |
| 1748 | } else &[_]u8{}; |
| 1635 | 1749 | |
| 1636 | 1750 | const initial_instructions = cie_bytes[stream.pos..]; |
| 1637 | 1751 | return .{ |
| 1638 | | .length = length, |
| 1639 | | .id = id, |
| 1752 | .length_offset = length_offset, |
| 1640 | 1753 | .version = version, |
| 1641 | 1754 | .code_alignment_factor = code_alignment_factor, |
| 1642 | 1755 | .data_alignment_factor = data_alignment_factor, |
| 1643 | 1756 | .return_address_register = return_address_register, |
| 1757 | .aug_str = aug_str, |
| 1758 | .aug_data = aug_data, |
| 1644 | 1759 | .lsda_pointer_enc = lsda_pointer_enc, |
| 1760 | .personality_enc = personality_enc, |
| 1645 | 1761 | .personality_routine_pointer = personality_routine_pointer, |
| 1646 | 1762 | .fde_pointer_enc = fde_pointer_enc, |
| 1647 | 1763 | .initial_instructions = initial_instructions, |
| 1648 | 1764 | }; |
| 1649 | 1765 | } |
| 1650 | 1766 | }; |
| 1767 | |
| 1768 | pub const FrameDescriptionEntry = struct { |
| 1769 | // Offset into eh_frame where the CIE for this FDE is stored |
| 1770 | cie_length_offset: u64, |
| 1771 | |
| 1772 | pc_begin: u64, |
| 1773 | pc_range: u64, |
| 1774 | lsda_pointer: ?u64, |
| 1775 | aug_data: []const u8, |
| 1776 | instructions: []const u8, |
| 1777 | |
| 1778 | pub fn parse( |
| 1779 | fde_bytes: []const u8, |
| 1780 | section_base: u64, |
| 1781 | section_offset: u64, |
| 1782 | cie: CommonInformationEntry, |
| 1783 | addr_size_bytes: u8, |
| 1784 | endian: std.builtin.Endian, |
| 1785 | ) !FrameDescriptionEntry { |
| 1786 | if (addr_size_bytes > 8) return error.InvalidAddrSize; |
| 1787 | |
| 1788 | var stream = io.fixedBufferStream(fde_bytes); |
| 1789 | const reader = stream.reader(); |
| 1790 | |
| 1791 | const pc_begin = try readEhPointer( |
| 1792 | reader, |
| 1793 | cie.fde_pointer_enc, |
| 1794 | addr_size_bytes, |
| 1795 | .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset }, |
| 1796 | endian, |
| 1797 | ) orelse return badDwarf(); |
| 1798 | |
| 1799 | const pc_range = try readEhPointer( |
| 1800 | reader, |
| 1801 | cie.fde_pointer_enc & 0x0f, |
| 1802 | addr_size_bytes, |
| 1803 | .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset }, |
| 1804 | endian, |
| 1805 | ) orelse return badDwarf(); |
| 1806 | |
| 1807 | var aug_data: []const u8 = &[_]u8{}; |
| 1808 | const lsda_pointer = if (cie.aug_str.len > 0) blk: { |
| 1809 | const aug_data_len = try leb.readULEB128(u64, reader); |
| 1810 | const aug_data_start = stream.pos; |
| 1811 | aug_data = fde_bytes[aug_data_start..][0..aug_data_len]; |
| 1812 | |
| 1813 | const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit) |
| 1814 | try readEhPointer( |
| 1815 | reader, |
| 1816 | cie.lsda_pointer_enc & 0x0f, |
| 1817 | addr_size_bytes, |
| 1818 | .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) }, |
| 1819 | endian, |
| 1820 | ) |
| 1821 | else |
| 1822 | null; |
| 1823 | |
| 1824 | try stream.seekTo(aug_data_start + aug_data_len); |
| 1825 | break :blk lsda_pointer; |
| 1826 | } else null; |
| 1827 | |
| 1828 | const instructions = fde_bytes[stream.pos..]; |
| 1829 | return .{ |
| 1830 | .cie_length_offset = cie.length_offset, |
| 1831 | .pc_begin = pc_begin, |
| 1832 | .pc_range = pc_range, |
| 1833 | .lsda_pointer = lsda_pointer, |
| 1834 | .aug_data = aug_data, |
| 1835 | .instructions = instructions, |
| 1836 | }; |
| 1837 | } |
| 1838 | }; |