| ... | @@ -662,13 +662,19 @@ pub const DwarfSection = enum { | ... | @@ -662,13 +662,19 @@ pub const DwarfSection = enum { |
| 662 | | 662 | |
| 663 | pub const DwarfInfo = struct { | 663 | pub const DwarfInfo = struct { |
| 664 | endian: std.builtin.Endian, | 664 | endian: std.builtin.Endian, |
| 665 | // No memory is owned by the DwarfInfo | 665 | |
| | 666 | // No section memory is owned by the DwarfInfo |
| 666 | sections: [std.enums.directEnumArrayLen(DwarfSection, 0)]?[]const u8, | 667 | sections: [std.enums.directEnumArrayLen(DwarfSection, 0)]?[]const u8, |
| | 668 | |
| 667 | // Filled later by the initializer | 669 | // Filled later by the initializer |
| 668 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, | 670 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, |
| 669 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, | 671 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 670 | func_list: std.ArrayListUnmanaged(Func) = .{}, | 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 | pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 { | 678 | pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 { |
| 673 | return di.sections[@enumToInt(dwarf_section)]; | 679 | return di.sections[@enumToInt(dwarf_section)]; |
| 674 | } | 680 | } |
| ... | @@ -1434,6 +1440,7 @@ pub const DwarfInfo = struct { | ... | @@ -1434,6 +1440,7 @@ pub const DwarfInfo = struct { |
| 1434 | return getStringGeneric(di.section(.debug_line_str), offset); | 1440 | return getStringGeneric(di.section(.debug_line_str), offset); |
| 1435 | } | 1441 | } |
| 1436 | | 1442 | |
| | 1443 | |
| 1437 | fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 { | 1444 | fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 { |
| 1438 | const debug_addr = di.section(.debug_addr) orelse return badDwarf(); | 1445 | const debug_addr = di.section(.debug_addr) orelse return badDwarf(); |
| 1439 | | 1446 | |
| ... | @@ -1459,6 +1466,56 @@ pub const DwarfInfo = struct { | ... | @@ -1459,6 +1466,56 @@ pub const DwarfInfo = struct { |
| 1459 | else => badDwarf(), | 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 | /// Initialize DWARF info. The caller has the responsibility to initialize most | 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,11 +1524,8 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 1467 | try di.scanAllFunctions(allocator); | 1524 | try di.scanAllFunctions(allocator); |
| 1468 | try di.scanAllCompileUnits(allocator); | 1525 | try di.scanAllCompileUnits(allocator); |
| 1469 | | 1526 | |
| 1470 | // DEBUG | 1527 | // Unwind info is not required |
| 1471 | if (di.section(.eh_frame)) |eh_frame| { | 1528 | di.scanAllUnwindInfo(allocator) catch {}; |
| 1472 | _ = try CommonInformationEntry.parse(eh_frame, 8, .Little); | | |
| 1473 | } | | |
| 1474 | | | |
| 1475 | } | 1529 | } |
| 1476 | | 1530 | |
| 1477 | /// This function is to make it handy to comment out the return and make it | 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,74 +1549,131 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { |
| 1495 | return str[casted_offset..last :0]; | 1549 | return str[casted_offset..last :0]; |
| 1496 | } | 1550 | } |
| 1497 | | 1551 | |
| 1498 | const EhPointer = struct { | 1552 | const EhPointerContext = struct { |
| 1499 | value: union(enum) { | 1553 | // The address of the pointer field itself |
| 1500 | signed: i64, | 1554 | pc_rel_base: u64, |
| 1501 | unsigned: u64, | | |
| 1502 | }, | | |
| 1503 | relative_to: u8, | | |
| 1504 | | 1555 | |
| 1505 | // address of the encoded value | 1556 | // These relative addressing modes are only used in specific cases, and |
| 1506 | pc: u64, | 1557 | // might not be available / required in all parsing contexts |
| 1507 | | 1558 | data_rel_base: ?u64 = null, |
| 1508 | // TODO: Function to resolve the value given input state (.text start, .eh_frame_hdr start, functions start) | 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 | if (enc == EH.PE.omit) return null; | 1564 | if (enc == EH.PE.omit) return null; |
| 1513 | return EhPointer{ | 1565 | |
| 1514 | .value = switch (enc & 0x0f) { | 1566 | const value: union(enum) { |
| 1515 | EH.PE.absptr => .{ .unsigned = switch (addr_size_bytes) { | 1567 | signed: i64, |
| | 1568 | unsigned: u64, |
| | 1569 | } = switch (enc & 0x0f) { |
| | 1570 | EH.PE.absptr => .{ |
| | 1571 | .unsigned = switch (addr_size_bytes) { |
| 1516 | 2 => try reader.readInt(u16, endian), | 1572 | 2 => try reader.readInt(u16, endian), |
| 1517 | 4 => try reader.readInt(u32, endian), | 1573 | 4 => try reader.readInt(u32, endian), |
| 1518 | 8 => try reader.readInt(u64, endian), | 1574 | 8 => try reader.readInt(u64, endian), |
| 1519 | else => return error.InvalidAddrSize, | 1575 | else => return error.InvalidAddrSize, |
| 1520 | } }, | 1576 | }, |
| 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(), | | |
| 1530 | }, | 1577 | }, |
| 1531 | .relative_to = enc & 0xf0, | 1578 | EH.PE.uleb128 => .{ .unsigned = try leb.readULEB128(u64, reader) }, |
| 1532 | .pc = pc | 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 { | 1619 | pub const CommonInformationEntry = struct { |
| 1537 | length: u32, | 1620 | // Used in .eh_frame |
| 1538 | id: u32, | 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 | version: u8, | 1632 | version: u8, |
| 1540 | code_alignment_factor: u64, | | |
| 1541 | data_alignment_factor: u64, | | |
| 1542 | return_address_register: u64, | | |
| 1543 | | 1633 | |
| 1544 | // Augmented data | 1634 | code_alignment_factor: u32, |
| 1545 | lsda_pointer_enc: ?u8, | 1635 | data_alignment_factor: i32, |
| 1546 | personality_routine_pointer: ?EhPointer, | 1636 | return_address_register: u8, |
| 1547 | fde_pointer_enc: ?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 | initial_instructions: []const u8, | 1644 | initial_instructions: []const u8, |
| 1550 | | 1645 | |
| 1551 | // The returned struct references memory in `bytes`. | 1646 | pub fn isSignalFrame(self: CommonInformationEntry) bool { |
| 1552 | pub fn parse(bytes: []const u8, addr_size_bytes: u8, endian: std.builtin.Endian) !CommonInformationEntry { | 1647 | for (self.aug_str) |c| if (c == 'S') return true; |
| 1553 | if (addr_size_bytes > 8) return error.InvalidAddrSize; | 1648 | return false; |
| 1554 | if (bytes.len < 4) return badDwarf(); | 1649 | } |
| 1555 | const length = mem.readInt(u32, bytes[0..4], endian); | 1650 | |
| 1556 | const cie_bytes = bytes[4..][0..length]; | 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 | var stream = io.fixedBufferStream(cie_bytes); | 1672 | var stream = io.fixedBufferStream(cie_bytes); |
| 1559 | const reader = stream.reader(); | 1673 | const reader = stream.reader(); |
| 1560 | | 1674 | |
| 1561 | const id = try reader.readInt(u32, endian); | | |
| 1562 | if (id != 0) return badDwarf(); | | |
| 1563 | | | |
| 1564 | const version = try reader.readByte(); | 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 | var has_eh_data = false; | 1678 | var has_eh_data = false; |
| 1568 | var has_aug_data = false; | 1679 | var has_aug_data = false; |
| ... | @@ -1575,76 +1686,153 @@ const CommonInformationEntry = struct { | ... | @@ -1575,76 +1686,153 @@ const CommonInformationEntry = struct { |
| 1575 | 'z' => { | 1686 | 'z' => { |
| 1576 | if (aug_str_len != 0) return badDwarf(); | 1687 | if (aug_str_len != 0) return badDwarf(); |
| 1577 | has_aug_data = true; | 1688 | has_aug_data = true; |
| 1578 | aug_str_start = stream.pos; | | |
| 1579 | }, | 1689 | }, |
| 1580 | 'e' => { | 1690 | 'e' => { |
| 1581 | if (has_aug_data or aug_str_len != 0) return badDwarf(); | 1691 | if (has_aug_data or aug_str_len != 0) return badDwarf(); |
| 1582 | if (try reader.readByte() != 'h') return badDwarf(); | 1692 | if (try reader.readByte() != 'h') return badDwarf(); |
| 1583 | has_eh_data = true; | 1693 | has_eh_data = true; |
| 1584 | }, | 1694 | }, |
| 1585 | else => { | 1695 | else => if (has_eh_data) return badDwarf(), |
| 1586 | if (has_eh_data) return badDwarf(); | | |
| 1587 | aug_str_len += 1; | | |
| 1588 | }, | | |
| 1589 | } | 1696 | } |
| | 1697 | |
| | 1698 | aug_str_len += 1; |
| 1590 | } | 1699 | } |
| 1591 | | 1700 | |
| 1592 | if (has_eh_data) { | 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 | for (0..addr_size_bytes) |_| _ = try reader.readByte(); | 1703 | for (0..addr_size_bytes) |_| _ = try reader.readByte(); |
| 1595 | } | 1704 | } |
| 1596 | | 1705 | |
| 1597 | const code_alignment_factor = try leb.readULEB128(u64, reader); | 1706 | const code_alignment_factor = try leb.readULEB128(u32, reader); |
| 1598 | const data_alignment_factor = try leb.readULEB128(u64, reader); | 1707 | const data_alignment_factor = try leb.readILEB128(i32, reader); |
| 1599 | const return_address_register = try leb.readULEB128(u64, 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; | 1710 | var lsda_pointer_enc: u8 = EH.PE.omit; |
| 1602 | var personality_routine_pointer: ?EhPointer = null; | 1711 | var personality_enc: ?u8 = null; |
| 1603 | var fde_pointer_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 | const aug_data_len = try leb.readULEB128(usize, reader); | 1717 | const aug_data_len = try leb.readULEB128(usize, reader); |
| 1607 | const aug_data_start = stream.pos; | 1718 | const aug_data_start = stream.pos; |
| | 1719 | aug_data = cie_bytes[aug_data_start..][0..aug_data_len]; |
| 1608 | | 1720 | |
| 1609 | const aug_str = cie_bytes[aug_str_start..][0..aug_str_len]; | 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 | switch (byte) { | 1723 | switch (byte) { |
| 1612 | 'L' => { | 1724 | 'L' => { |
| 1613 | lsda_pointer_enc = try reader.readByte(); | 1725 | lsda_pointer_enc = try reader.readByte(); |
| 1614 | }, | 1726 | }, |
| 1615 | 'P' => { | 1727 | 'P' => { |
| 1616 | const personality_enc = try reader.readByte(); | 1728 | personality_enc = try reader.readByte(); |
| 1617 | personality_routine_pointer = try readEhPointer( | 1729 | personality_routine_pointer = try readEhPointer( |
| 1618 | personality_enc, | 1730 | reader, |
| 1619 | @ptrToInt(&cie_bytes[stream.pos]), | 1731 | personality_enc.?, |
| 1620 | addr_size_bytes, | 1732 | addr_size_bytes, |
| | 1733 | .{ .pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset }, |
| 1621 | endian, | 1734 | endian, |
| 1622 | reader, | | |
| 1623 | ); | 1735 | ); |
| 1624 | }, | 1736 | }, |
| 1625 | 'R' => { | 1737 | 'R' => { |
| 1626 | fde_pointer_enc = try reader.readByte(); | 1738 | fde_pointer_enc = try reader.readByte(); |
| 1627 | }, | 1739 | }, |
| | 1740 | 'S', 'B', 'G' => {}, |
| 1628 | else => return badDwarf(), | 1741 | else => return badDwarf(), |
| 1629 | } | 1742 | } |
| 1630 | } | 1743 | } |
| 1631 | | 1744 | |
| 1632 | // verify length field | 1745 | // aug_data_len can include padding so the CIE ends on an address boundary |
| 1633 | if (stream.pos != (aug_data_start + aug_data_len)) return badDwarf(); | 1746 | try stream.seekTo(aug_data_start + aug_data_len); |
| 1634 | } | 1747 | break :blk aug_str; |
| | 1748 | } else &[_]u8{}; |
| 1635 | | 1749 | |
| 1636 | const initial_instructions = cie_bytes[stream.pos..]; | 1750 | const initial_instructions = cie_bytes[stream.pos..]; |
| 1637 | return .{ | 1751 | return .{ |
| 1638 | .length = length, | 1752 | .length_offset = length_offset, |
| 1639 | .id = id, | | |
| 1640 | .version = version, | 1753 | .version = version, |
| 1641 | .code_alignment_factor = code_alignment_factor, | 1754 | .code_alignment_factor = code_alignment_factor, |
| 1642 | .data_alignment_factor = data_alignment_factor, | 1755 | .data_alignment_factor = data_alignment_factor, |
| 1643 | .return_address_register = return_address_register, | 1756 | .return_address_register = return_address_register, |
| | 1757 | .aug_str = aug_str, |
| | 1758 | .aug_data = aug_data, |
| 1644 | .lsda_pointer_enc = lsda_pointer_enc, | 1759 | .lsda_pointer_enc = lsda_pointer_enc, |
| | 1760 | .personality_enc = personality_enc, |
| 1645 | .personality_routine_pointer = personality_routine_pointer, | 1761 | .personality_routine_pointer = personality_routine_pointer, |
| 1646 | .fde_pointer_enc = fde_pointer_enc, | 1762 | .fde_pointer_enc = fde_pointer_enc, |
| 1647 | .initial_instructions = initial_instructions, | 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 | }; |