| ... | ... | @@ -1580,7 +1580,7 @@ pub const DwarfInfo = struct { |
| 1580 | 1580 | if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture; |
| 1581 | 1581 | if (context.pc == 0) return; |
| 1582 | 1582 | |
| 1583 | | // TODO: Handle signal frame (ie. use_prev_instr in libunwind) |
| 1583 | // TODO: Handle unwinding from a signal frame (ie. use_prev_instr in libunwind) |
| 1584 | 1584 | |
| 1585 | 1585 | // Find the FDE and CIE |
| 1586 | 1586 | var cie: CommonInformationEntry = undefined; |
| ... | ... | @@ -1594,7 +1594,14 @@ pub const DwarfInfo = struct { |
| 1594 | 1594 | |
| 1595 | 1595 | if (di.eh_frame_hdr) |header| { |
| 1596 | 1596 | mapped_pc = context.pc; |
| 1597 | | try header.findEntry(context.isValidMemory, @intFromPtr(di.section(.eh_frame_hdr).?.ptr), mapped_pc, &cie, &fde); |
| 1597 | try header.findEntry( |
| 1598 | context.isValidMemory, |
| 1599 | null, // TODO: Check di for this |
| 1600 | @intFromPtr(di.section(.eh_frame_hdr).?.ptr), |
| 1601 | mapped_pc, |
| 1602 | &cie, |
| 1603 | &fde, |
| 1604 | ); |
| 1598 | 1605 | } else { |
| 1599 | 1606 | mapped_pc = context.pc - module_base_address; |
| 1600 | 1607 | const index = std.sort.binarySearch(FrameDescriptionEntry, mapped_pc, di.fde_list.items, {}, struct { |
| ... | ... | @@ -1821,9 +1828,28 @@ pub const ExceptionFrameHeader = struct { |
| 1821 | 1828 | }; |
| 1822 | 1829 | } |
| 1823 | 1830 | |
| 1831 | fn isValidPtr( |
| 1832 | self: ExceptionFrameHeader, |
| 1833 | ptr: usize, |
| 1834 | isValidMemory: *const fn (address: usize) bool, |
| 1835 | eh_frame_len: ?usize, |
| 1836 | ) bool { |
| 1837 | if (eh_frame_len) |len| { |
| 1838 | return ptr >= self.eh_frame_ptr and ptr < self.eh_frame_ptr + len; |
| 1839 | } else { |
| 1840 | return isValidMemory(ptr); |
| 1841 | } |
| 1842 | } |
| 1843 | |
| 1844 | /// Find an entry by binary searching the eh_frame_hdr section. |
| 1845 | /// |
| 1846 | /// Since the length of the eh_frame section (`eh_frame_len`) may not be known by the caller, |
| 1847 | /// `isValidMemory` will be called before accessing any memory referenced by |
| 1848 | /// the header entries. If `eh_frame_len` is provided, then these checks can be skipped. |
| 1824 | 1849 | pub fn findEntry( |
| 1825 | 1850 | self: ExceptionFrameHeader, |
| 1826 | 1851 | isValidMemory: *const fn (address: usize) bool, |
| 1852 | eh_frame_len: ?usize, |
| 1827 | 1853 | eh_frame_hdr_ptr: usize, |
| 1828 | 1854 | pc: usize, |
| 1829 | 1855 | cie: *CommonInformationEntry, |
| ... | ... | @@ -1855,7 +1881,7 @@ pub const ExceptionFrameHeader = struct { |
| 1855 | 1881 | |
| 1856 | 1882 | try stream.seekTo(left * entry_size); |
| 1857 | 1883 | |
| 1858 | | // Read past pc_begin |
| 1884 | // Read past the pc_begin field of the entry |
| 1859 | 1885 | _ = try readEhPointer(reader, self.table_enc, @sizeOf(usize), .{ |
| 1860 | 1886 | .pc_rel_base = @intFromPtr(&self.entries[stream.pos]), |
| 1861 | 1887 | .follow_indirect = true, |
| ... | ... | @@ -1868,24 +1894,29 @@ pub const ExceptionFrameHeader = struct { |
| 1868 | 1894 | .data_rel_base = eh_frame_hdr_ptr, |
| 1869 | 1895 | }, builtin.cpu.arch.endian()) orelse return badDwarf()) orelse return badDwarf(); |
| 1870 | 1896 | |
| 1871 | | // TODO: Should this also do isValidMemory(fde_ptr) + 11 (worst case header size)? |
| 1897 | // Verify the length fields of the FDE header are readable |
| 1898 | if (!self.isValidPtr(fde_ptr, isValidMemory, eh_frame_len) or fde_ptr < self.eh_frame_ptr) return badDwarf(); |
| 1872 | 1899 | |
| 1873 | | // The length of the .eh_frame section is unknown at this point, since .eh_frame_hdr only provides the start |
| 1874 | | if (!isValidMemory(fde_ptr) or fde_ptr < self.eh_frame_ptr) return badDwarf(); |
| 1875 | | const eh_frame = @ptrFromInt([*]const u8, self.eh_frame_ptr)[0..math.maxInt(usize)]; |
| 1876 | | const fde_offset = fde_ptr - self.eh_frame_ptr; |
| 1900 | var fde_entry_header_len: usize = 4; |
| 1901 | if (!self.isValidPtr(fde_ptr + 3, isValidMemory, eh_frame_len)) return badDwarf(); |
| 1902 | if (self.isValidPtr(fde_ptr + 11, isValidMemory, eh_frame_len)) fde_entry_header_len = 12; |
| 1877 | 1903 | |
| 1904 | // Even if eh_frame_len is not specified, all ranges accssed are checked by isValidPtr |
| 1905 | const eh_frame = @ptrFromInt([*]const u8, self.eh_frame_ptr)[0..eh_frame_len orelse math.maxInt(u32)]; |
| 1906 | |
| 1907 | const fde_offset = fde_ptr - self.eh_frame_ptr; |
| 1878 | 1908 | var eh_frame_stream = io.fixedBufferStream(eh_frame); |
| 1879 | 1909 | try eh_frame_stream.seekTo(fde_offset); |
| 1880 | 1910 | |
| 1881 | 1911 | const fde_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian()); |
| 1882 | | if (!isValidMemory(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]))) return badDwarf(); |
| 1912 | if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); |
| 1883 | 1913 | if (fde_entry_header.type != .fde) return badDwarf(); |
| 1884 | 1914 | |
| 1915 | // CIEs always come before FDEs (the offset is a subtration), so we can assume this memory is readable |
| 1885 | 1916 | const cie_offset = fde_entry_header.type.fde; |
| 1886 | 1917 | try eh_frame_stream.seekTo(cie_offset); |
| 1887 | 1918 | const cie_entry_header = try EntryHeader.read(&eh_frame_stream, builtin.cpu.arch.endian()); |
| 1888 | | if (!isValidMemory(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]))) return badDwarf(); |
| 1919 | if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); |
| 1889 | 1920 | if (cie_entry_header.type != .cie) return badDwarf(); |
| 1890 | 1921 | |
| 1891 | 1922 | cie.* = try CommonInformationEntry.parse( |