| ... | @@ -3,6 +3,13 @@ | ... | @@ -3,6 +3,13 @@ |
| 3 | | 3 | |
| 4 | dwarf: Dwarf, | 4 | dwarf: Dwarf, |
| 5 | | 5 | |
| | 6 | /// If we encounter a `.eh_frame` section while loading the ELF module, it is stored here and may be |
| | 7 | /// used with `Dwarf.Unwind` for call stack unwinding. |
| | 8 | eh_frame: ?UnwindSection, |
| | 9 | /// If we encounter a `.debug_frame` section while loading the ELF module, it is stored here and may |
| | 10 | /// be used with `Dwarf.Unwind` for call stack unwinding. |
| | 11 | debug_frame: ?UnwindSection, |
| | 12 | |
| 6 | /// The memory-mapped ELF file, which is referenced by `dwarf`. This field is here only so that | 13 | /// The memory-mapped ELF file, which is referenced by `dwarf`. This field is here only so that |
| 7 | /// this memory can be unmapped by `ElfModule.deinit`. | 14 | /// this memory can be unmapped by `ElfModule.deinit`. |
| 8 | mapped_file: []align(std.heap.page_size_min) const u8, | 15 | mapped_file: []align(std.heap.page_size_min) const u8, |
| ... | @@ -11,10 +18,18 @@ mapped_file: []align(std.heap.page_size_min) const u8, | ... | @@ -11,10 +18,18 @@ mapped_file: []align(std.heap.page_size_min) const u8, |
| 11 | /// be unmapped by `ElfModule.deinit`. | 18 | /// be unmapped by `ElfModule.deinit`. |
| 12 | mapped_debug_file: ?[]align(std.heap.page_size_min) const u8, | 19 | mapped_debug_file: ?[]align(std.heap.page_size_min) const u8, |
| 13 | | 20 | |
| 14 | pub fn deinit(em: *ElfModule, allocator: Allocator) void { | 21 | pub const UnwindSection = struct { |
| 15 | em.dwarf.deinit(allocator); | 22 | vaddr: u64, |
| | 23 | bytes: []const u8, |
| | 24 | owned: bool, |
| | 25 | }; |
| | 26 | |
| | 27 | pub fn deinit(em: *ElfModule, gpa: Allocator) void { |
| | 28 | em.dwarf.deinit(gpa); |
| 16 | std.posix.munmap(em.mapped_file); | 29 | std.posix.munmap(em.mapped_file); |
| 17 | if (em.mapped_debug_file) |m| std.posix.munmap(m); | 30 | if (em.mapped_debug_file) |m| std.posix.munmap(m); |
| | 31 | if (em.eh_frame) |s| if (s.owned) gpa.free(s.bytes); |
| | 32 | if (em.debug_frame) |s| if (s.owned) gpa.free(s.bytes); |
| 18 | } | 33 | } |
| 19 | | 34 | |
| 20 | pub const LoadError = error{ | 35 | pub const LoadError = error{ |
| ... | @@ -98,7 +113,6 @@ pub fn load( | ... | @@ -98,7 +113,6 @@ pub fn load( |
| 98 | )[0..hdr.e_shnum]; | 113 | )[0..hdr.e_shnum]; |
| 99 | | 114 | |
| 100 | var sections: Dwarf.SectionArray = @splat(null); | 115 | var sections: Dwarf.SectionArray = @splat(null); |
| 101 | | | |
| 102 | // Combine section list. This takes ownership over any owned sections from the parent scope. | 116 | // Combine section list. This takes ownership over any owned sections from the parent scope. |
| 103 | if (parent_sections) |ps| { | 117 | if (parent_sections) |ps| { |
| 104 | for (ps, &sections) |*parent, *section_elem| { | 118 | for (ps, &sections) |*parent, *section_elem| { |
| ... | @@ -110,6 +124,12 @@ pub fn load( | ... | @@ -110,6 +124,12 @@ pub fn load( |
| 110 | } | 124 | } |
| 111 | errdefer for (sections) |opt_section| if (opt_section) |s| if (s.owned) gpa.free(s.data); | 125 | errdefer for (sections) |opt_section| if (opt_section) |s| if (s.owned) gpa.free(s.data); |
| 112 | | 126 | |
| | 127 | var eh_frame_section: ?UnwindSection = null; |
| | 128 | errdefer if (eh_frame_section) |s| if (s.owned) gpa.free(s.bytes); |
| | 129 | |
| | 130 | var debug_frame_section: ?UnwindSection = null; |
| | 131 | errdefer if (debug_frame_section) |s| if (s.owned) gpa.free(s.bytes); |
| | 132 | |
| 113 | var separate_debug_filename: ?[]const u8 = null; | 133 | var separate_debug_filename: ?[]const u8 = null; |
| 114 | var separate_debug_crc: ?u32 = null; | 134 | var separate_debug_crc: ?u32 = null; |
| 115 | | 135 | |
| ... | @@ -128,17 +148,35 @@ pub fn load( | ... | @@ -128,17 +148,35 @@ pub fn load( |
| 128 | continue; | 148 | continue; |
| 129 | } | 149 | } |
| 130 | | 150 | |
| 131 | var section_index: ?usize = null; | 151 | const section_id: union(enum) { |
| 132 | inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields, 0..) |sect, i| { | 152 | dwarf: Dwarf.Section.Id, |
| 133 | if (mem.eql(u8, "." ++ sect.name, name)) section_index = i; | 153 | eh_frame, |
| | 154 | debug_frame, |
| | 155 | } = s: { |
| | 156 | inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields) |s| { |
| | 157 | if (mem.eql(u8, "." ++ s.name, name)) { |
| | 158 | break :s .{ .dwarf = @enumFromInt(s.value) }; |
| | 159 | } |
| | 160 | } |
| | 161 | if (mem.eql(u8, ".eh_frame", name)) break :s .eh_frame; |
| | 162 | if (mem.eql(u8, ".debug_frame", name)) break :s .debug_frame; |
| | 163 | continue; |
| | 164 | }; |
| | 165 | |
| | 166 | switch (section_id) { |
| | 167 | .dwarf => |i| if (sections[@intFromEnum(i)] != null) continue, |
| | 168 | .eh_frame => if (eh_frame_section != null) continue, |
| | 169 | .debug_frame => if (debug_frame_section != null) continue, |
| 134 | } | 170 | } |
| 135 | if (section_index == null) continue; | | |
| 136 | if (sections[section_index.?] != null) continue; | | |
| 137 | | 171 | |
| 138 | if (mapped_mem.len < shdr.sh_offset + shdr.sh_size) return error.InvalidDebugInfo; | 172 | if (mapped_mem.len < shdr.sh_offset + shdr.sh_size) return error.InvalidDebugInfo; |
| 139 | const section_bytes = mapped_mem[@intCast(shdr.sh_offset)..][0..@intCast(shdr.sh_size)]; | 173 | const raw_section_bytes = mapped_mem[@intCast(shdr.sh_offset)..][0..@intCast(shdr.sh_size)]; |
| 140 | sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: { | 174 | |
| 141 | var section_reader: Reader = .fixed(section_bytes); | 175 | const section_bytes: []const u8, const section_owned: bool = section: { |
| | 176 | if ((shdr.sh_flags & elf.SHF_COMPRESSED) == 0) { |
| | 177 | break :section .{ raw_section_bytes, false }; |
| | 178 | } |
| | 179 | var section_reader: Reader = .fixed(raw_section_bytes); |
| 142 | const chdr = section_reader.takeStruct(elf.Chdr, endian) catch continue; | 180 | const chdr = section_reader.takeStruct(elf.Chdr, endian) catch continue; |
| 143 | if (chdr.ch_type != .ZLIB) continue; | 181 | if (chdr.ch_type != .ZLIB) continue; |
| 144 | | 182 | |
| ... | @@ -153,14 +191,24 @@ pub fn load( | ... | @@ -153,14 +191,24 @@ pub fn load( |
| 153 | Dwarf.invalidDebugInfoDetected(); | 191 | Dwarf.invalidDebugInfoDetected(); |
| 154 | continue; | 192 | continue; |
| 155 | } | 193 | } |
| 156 | break :blk .{ | 194 | break :section .{ try decompressed_section.toOwnedSlice(gpa), true }; |
| 157 | .data = try decompressed_section.toOwnedSlice(gpa), | | |
| 158 | .owned = true, | | |
| 159 | }; | | |
| 160 | } else .{ | | |
| 161 | .data = section_bytes, | | |
| 162 | .owned = false, | | |
| 163 | }; | 195 | }; |
| | 196 | switch (section_id) { |
| | 197 | .dwarf => |id| sections[@intFromEnum(id)] = .{ |
| | 198 | .data = section_bytes, |
| | 199 | .owned = section_owned, |
| | 200 | }, |
| | 201 | .eh_frame => eh_frame_section = .{ |
| | 202 | .vaddr = shdr.sh_addr, |
| | 203 | .bytes = section_bytes, |
| | 204 | .owned = section_owned, |
| | 205 | }, |
| | 206 | .debug_frame => debug_frame_section = .{ |
| | 207 | .vaddr = shdr.sh_addr, |
| | 208 | .bytes = section_bytes, |
| | 209 | .owned = section_owned, |
| | 210 | }, |
| | 211 | } |
| 164 | } | 212 | } |
| 165 | | 213 | |
| 166 | const missing_debug_info = | 214 | const missing_debug_info = |
| ... | @@ -305,9 +353,11 @@ pub fn load( | ... | @@ -305,9 +353,11 @@ pub fn load( |
| 305 | var dwarf: Dwarf = .{ .sections = sections }; | 353 | var dwarf: Dwarf = .{ .sections = sections }; |
| 306 | try dwarf.open(gpa, endian); | 354 | try dwarf.open(gpa, endian); |
| 307 | return .{ | 355 | return .{ |
| | 356 | .dwarf = dwarf, |
| | 357 | .eh_frame = eh_frame_section, |
| | 358 | .debug_frame = debug_frame_section, |
| 308 | .mapped_file = parent_mapped_mem orelse mapped_mem, | 359 | .mapped_file = parent_mapped_mem orelse mapped_mem, |
| 309 | .mapped_debug_file = if (parent_mapped_mem != null) mapped_mem else null, | 360 | .mapped_debug_file = if (parent_mapped_mem != null) mapped_mem else null, |
| 310 | .dwarf = dwarf, | | |
| 311 | }; | 361 | }; |
| 312 | } | 362 | } |
| 313 | | 363 | |