Created
August 27, 2026 01:49
-
-
Save nektro/e5d98bc1a1654989671b0dcb4817da0f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const std = @import("std"); | |
| const builtin = @import("builtin"); | |
| const nfs = @import("nfs"); | |
| const nio = @import("nio"); | |
| const extras = @import("extras"); | |
| const json = @import("json"); | |
| pub fn main(init: std.process.Init.Minimal) !void { | |
| var gpa = std.heap.DebugAllocator(.{ .stack_trace_frames = 16 }){}; | |
| defer _ = gpa.deinit(); | |
| const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator; | |
| const stdout = nfs.stdout(); | |
| var bw = nio.BufferedWriter(4096, nfs.File).init(stdout); | |
| const elf = std.elf; | |
| const self_path = std.mem.sliceTo(init.args.vector[1], 0); | |
| const self_file = try nfs.cwd().openFile(self_path, .{}); | |
| const self_content = try self_file.mmap(); | |
| var fr: std.Io.Reader = .fixed(self_content); | |
| const header = try elf.Header.read(&fr); | |
| const shstrtab_shdr_off = try std.math.add(u64, header.shoff, try std.math.mul(u64, header.shstrndx, header.shentsize)); | |
| fr.seek = std.math.cast(usize, shstrtab_shdr_off).?; | |
| std.debug.assert(header.is_64); | |
| const _shdr = try fr.takeStruct(elf.Elf64_Shdr, header.endian); | |
| if (_shdr.sh_offset + _shdr.sh_size > self_content.len) return error.TruncatedElfFile; | |
| const shstrtab = self_content[@intCast(_shdr.sh_offset)..][0..@intCast(_shdr.sh_size)]; | |
| const Id = enum { symtab, strtab, rodata }; | |
| const Section = struct { index: usize, header: elf.Elf64_Shdr, bytes: []const u8 }; | |
| const Array = std.enums.EnumArray(Id, ?Section); | |
| var sections: Array = .initFill(null); | |
| var it = header.iterateSectionHeadersBuffer(self_content); | |
| while (try it.next()) |shdr| { | |
| if (shdr.sh_type == elf.SHT_NULL or shdr.sh_type == elf.SHT_NOBITS) continue; | |
| if (shdr.sh_name > shstrtab.len) return error.TruncatedElfFile; | |
| const name = std.mem.sliceTo(shstrtab[@intCast(shdr.sh_name)..], 0); | |
| if (it.index - 1 == 1) std.log.debug("{d} {s} {d}", .{ it.index - 1, name, shdr.sh_offset }); | |
| const section_id: Id = inline for (@typeInfo(Id).@"enum".fields) |s| (if (std.mem.eql(u8, "." ++ s.name, name)) break @enumFromInt(s.value)) else continue; | |
| std.debug.assert(sections.get(section_id) == null); | |
| if (shdr.sh_offset + shdr.sh_size > self_content.len) return error.TruncatedElfFile; | |
| const raw_section_bytes = self_content[@intCast(shdr.sh_offset)..][0..@intCast(shdr.sh_size)]; | |
| const section_bytes: []const u8 = bytes: { | |
| if ((shdr.sh_flags & elf.SHF_COMPRESSED) == 0) break :bytes raw_section_bytes; | |
| var section_reader: std.Io.Reader = .fixed(raw_section_bytes); | |
| const chdr = try section_reader.takeStruct(elf.Elf64.Chdr, header.endian); | |
| const ch_type: elf.COMPRESS, const ch_size: u64 = .{ chdr.type, chdr.size }; | |
| if (ch_type != .ZLIB) continue; // The compression algorithm is unsupported, but don't make that a hard error; the file might still be valid, and we might still be okay without this section. | |
| const buf = try allocator.alloc(u8, std.math.cast(usize, ch_size).?); | |
| var fw: std.Io.Writer = .fixed(buf); | |
| var decompress: std.compress.flate.Decompress = .init(§ion_reader, .zlib, &.{}); | |
| const n = try decompress.reader.streamRemaining(&fw); | |
| if (n != buf.len) return error.InvalidCompressedSection; // It's also an error if the data is shorter than expected. | |
| break :bytes buf; | |
| }; | |
| sections.set(section_id, .{ .index = it.index - 1, .header = shdr, .bytes = section_bytes }); | |
| } | |
| std.log.debug("", .{}); | |
| const symtab = sections.get(.symtab).?; | |
| std.debug.assert(symtab.header.sh_entsize == @sizeOf(elf.Elf64.Sym)); | |
| const symbols: []align(1) const elf.Elf64.Sym = @ptrCast(symtab.bytes); | |
| const strtab = sections.get(.strtab).?; | |
| const rodata = sections.get(.rodata).?; | |
| const phdrs: []align(1) const elf.Elf64.Phdr = @ptrCast(self_content[header.phoff..][0 .. header.phentsize * header.phnum]); | |
| const load_base = for (phdrs) |p| (if (p.type == .LOAD) break p.vaddr) else unreachable; | |
| for (symbols) |s| { | |
| if (s.size == 0) continue; | |
| if (s.shndx != rodata.index) continue; | |
| const name = std.mem.sliceTo(strtab.bytes[s.name..], 0); | |
| const size = s.size; | |
| const value = s.value - load_base; | |
| const content = self_content[value..][0..size]; | |
| try bw.print("{s} {d} {d} 0x{x} ({d} 0x{x})\n", .{ name, s.size, s.value, s.value, value, value }); | |
| try json.stringify(&bw, content, .{}); | |
| try bw.print("\n\n", .{}); | |
| } | |
| try bw.flush(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment