Skip to content

Instantly share code, notes, and snippets.

@nektro
Created August 27, 2026 01:49
Show Gist options
  • Select an option

  • Save nektro/e5d98bc1a1654989671b0dcb4817da0f to your computer and use it in GitHub Desktop.

Select an option

Save nektro/e5d98bc1a1654989671b0dcb4817da0f to your computer and use it in GitHub Desktop.
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(&section_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