objcopy: delete most of it

this code is not up to zig project standards

tracked by #24522

oh, and fix not adjusting buffer seek position in std.fs.File.Reader
This commit is contained in:
Andrew Kelley 2025-07-20 16:43:47 -07:00
parent f2a3ac7c05
commit f1576ef14c
5 changed files with 240 additions and 1142 deletions

File diff suppressed because it is too large Load Diff

View File

@ -482,6 +482,7 @@ pub const Header = struct {
is_64: bool,
endian: std.builtin.Endian,
os_abi: OSABI,
/// The meaning of this value depends on `os_abi`.
abi_version: u8,
type: ET,
machine: EM,
@ -494,205 +495,135 @@ pub const Header = struct {
shnum: u16,
shstrndx: u16,
pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
return ProgramHeaderIterator(@TypeOf(parse_source)){
.elf_header = self,
.parse_source = parse_source,
pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator {
return .{
.elf_header = h,
.file_reader = file_reader,
};
}
pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {
return SectionHeaderIterator(@TypeOf(parse_source)){
.elf_header = self,
.parse_source = parse_source,
pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator {
return .{
.elf_header = h,
.file_reader = file_reader,
};
}
pub fn read(parse_source: anytype) !Header {
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
try parse_source.seekableStream().seekTo(0);
try parse_source.deprecatedReader().readNoEof(&hdr_buf);
return Header.parse(&hdr_buf);
}
pub const ReadError = std.Io.Reader.Error || error{
InvalidElfMagic,
InvalidElfVersion,
InvalidElfClass,
InvalidElfEndian,
};
pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf));
const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf));
if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
pub fn read(r: *std.Io.Reader) ReadError!Header {
const buf = try r.peek(@sizeOf(Elf64_Ehdr));
const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
ELFCLASS32 => false,
ELFCLASS64 => true,
else => return error.InvalidElfClass,
};
if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
const endian: std.builtin.Endian = switch (buf[EI_DATA]) {
ELFDATA2LSB => .little,
ELFDATA2MSB => .big,
else => return error.InvalidElfEndian,
};
const need_bswap = endian != native_endian;
return switch (buf[EI_CLASS]) {
ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
else => return error.InvalidElfClass,
};
}
pub fn init(hdr: anytype, endian: std.builtin.Endian) Header {
// Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.
comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive);
const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]);
// The meaning of this value depends on `os_abi` so just make it available as `u8`.
const abi_version = hdr32.e_ident[EI_ABIVERSION];
const @"type" = if (need_bswap) blk: {
comptime assert(!@typeInfo(ET).@"enum".is_exhaustive);
const value = @intFromEnum(hdr32.e_type);
break :blk @as(ET, @enumFromInt(@byteSwap(value)));
} else hdr32.e_type;
const machine = if (need_bswap) blk: {
comptime assert(!@typeInfo(EM).@"enum".is_exhaustive);
const value = @intFromEnum(hdr32.e_machine);
break :blk @as(EM, @enumFromInt(@byteSwap(value)));
} else hdr32.e_machine;
return @as(Header, .{
.is_64 = is_64,
return .{
.is_64 = switch (@TypeOf(hdr)) {
Elf32_Ehdr => false,
Elf64_Ehdr => true,
else => @compileError("bad type"),
},
.endian = endian,
.os_abi = os_abi,
.abi_version = abi_version,
.type = @"type",
.machine = machine,
.entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
.phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
.shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
.phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
.phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
.shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
.shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
.shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
});
.os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]),
.abi_version = hdr.e_ident[EI_ABIVERSION],
.type = hdr.e_type,
.machine = hdr.e_machine,
.entry = hdr.e_entry,
.phoff = hdr.e_phoff,
.shoff = hdr.e_shoff,
.phentsize = hdr.e_phentsize,
.phnum = hdr.e_phnum,
.shentsize = hdr.e_shentsize,
.shnum = hdr.e_shnum,
.shstrndx = hdr.e_shstrndx,
};
}
};
pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
return struct {
elf_header: Header,
parse_source: ParseSource,
index: usize = 0,
pub const ProgramHeaderIterator = struct {
elf_header: Header,
file_reader: *std.fs.File.Reader,
index: usize = 0,
pub fn next(self: *@This()) !?Elf64_Phdr {
if (self.index >= self.elf_header.phnum) return null;
defer self.index += 1;
pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr {
if (it.index >= it.elf_header.phnum) return null;
defer it.index += 1;
if (self.elf_header.is_64) {
var phdr: Elf64_Phdr = undefined;
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
try self.parse_source.seekableStream().seekTo(offset);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
// ELF endianness matches native endianness.
if (self.elf_header.endian == native_endian) return phdr;
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf64_Phdr, &phdr);
return phdr;
}
var phdr: Elf32_Phdr = undefined;
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
try self.parse_source.seekableStream().seekTo(offset);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
// ELF endianness does NOT match native endianness.
if (self.elf_header.endian != native_endian) {
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf32_Phdr, &phdr);
}
// Convert 32-bit header to 64-bit.
return Elf64_Phdr{
.p_type = phdr.p_type,
.p_offset = phdr.p_offset,
.p_vaddr = phdr.p_vaddr,
.p_paddr = phdr.p_paddr,
.p_filesz = phdr.p_filesz,
.p_memsz = phdr.p_memsz,
.p_flags = phdr.p_flags,
.p_align = phdr.p_align,
};
if (it.elf_header.is_64) {
const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index;
try it.file_reader.seekTo(offset);
const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian);
return phdr;
}
};
}
pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
return struct {
elf_header: Header,
parse_source: ParseSource,
index: usize = 0,
pub fn next(self: *@This()) !?Elf64_Shdr {
if (self.index >= self.elf_header.shnum) return null;
defer self.index += 1;
if (self.elf_header.is_64) {
var shdr: Elf64_Shdr = undefined;
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
try self.parse_source.seekableStream().seekTo(offset);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
// ELF endianness matches native endianness.
if (self.elf_header.endian == native_endian) return shdr;
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf64_Shdr, &shdr);
return shdr;
}
var shdr: Elf32_Shdr = undefined;
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
try self.parse_source.seekableStream().seekTo(offset);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
// ELF endianness does NOT match native endianness.
if (self.elf_header.endian != native_endian) {
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf32_Shdr, &shdr);
}
// Convert 32-bit header to 64-bit.
return Elf64_Shdr{
.sh_name = shdr.sh_name,
.sh_type = shdr.sh_type,
.sh_flags = shdr.sh_flags,
.sh_addr = shdr.sh_addr,
.sh_offset = shdr.sh_offset,
.sh_size = shdr.sh_size,
.sh_link = shdr.sh_link,
.sh_info = shdr.sh_info,
.sh_addralign = shdr.sh_addralign,
.sh_entsize = shdr.sh_entsize,
};
}
};
}
fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
if (is_64) {
if (need_bswap) {
return @byteSwap(int_64);
} else {
return int_64;
}
} else {
return int32(need_bswap, int_32, @TypeOf(int_64));
const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index;
try it.file_reader.seekTo(offset);
const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian);
return .{
.p_type = phdr.p_type,
.p_offset = phdr.p_offset,
.p_vaddr = phdr.p_vaddr,
.p_paddr = phdr.p_paddr,
.p_filesz = phdr.p_filesz,
.p_memsz = phdr.p_memsz,
.p_flags = phdr.p_flags,
.p_align = phdr.p_align,
};
}
}
};
fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
if (need_bswap) {
return @byteSwap(int_32);
} else {
return int_32;
pub const SectionHeaderIterator = struct {
elf_header: Header,
file_reader: *std.fs.File.Reader,
index: usize = 0,
pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr {
if (it.index >= it.elf_header.shnum) return null;
defer it.index += 1;
if (it.elf_header.is_64) {
try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index);
const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian);
return shdr;
}
try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index);
const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian);
return .{
.sh_name = shdr.sh_name,
.sh_type = shdr.sh_type,
.sh_flags = shdr.sh_flags,
.sh_addr = shdr.sh_addr,
.sh_offset = shdr.sh_offset,
.sh_size = shdr.sh_size,
.sh_link = shdr.sh_link,
.sh_info = shdr.sh_info,
.sh_addralign = shdr.sh_addralign,
.sh_entsize = shdr.sh_entsize,
};
}
}
};
pub const ELFCLASSNONE = 0;
pub const ELFCLASS32 = 1;

View File

@ -1228,14 +1228,12 @@ pub const Reader = struct {
pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
switch (r.mode) {
.positional, .positional_reading => {
// TODO: make += operator allow any integer types
r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
},
.streaming, .streaming_reading => {
const seek_err = r.seek_err orelse e: {
if (posix.lseek_CUR(r.file.handle, offset)) |_| {
// TODO: make += operator allow any integer types
r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
return;
} else |err| {
r.seek_err = err;
@ -1251,6 +1249,8 @@ pub const Reader = struct {
r.pos += n;
remaining -= n;
}
r.interface.seek = 0;
r.interface.end = 0;
},
.failure => return r.seek_err.?,
}
@ -1259,7 +1259,7 @@ pub const Reader = struct {
pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
switch (r.mode) {
.positional, .positional_reading => {
r.pos = offset;
setPosAdjustingBuffer(r, offset);
},
.streaming, .streaming_reading => {
if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
@ -1268,12 +1268,22 @@ pub const Reader = struct {
r.seek_err = err;
return err;
};
r.pos = offset;
setPosAdjustingBuffer(r, offset);
},
.failure => return r.seek_err.?,
}
}
fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) {
r.interface.seek = 0;
r.interface.end = 0;
} else {
r.interface.seek += @intCast(offset - r.pos);
}
r.pos = offset;
}
/// Number of slices to store on the stack, when trying to send as many byte
/// vectors through the underlying read calls as possible.
const max_buffers_len = 16;

View File

@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void {
test_step.dependOn(&run_cmd.step);
}
// Unwinding through a C shared library without a frame pointer (libc)
//
// getcontext version: libc
//
// Unwind info type:
// - ELF: DWARF .eh_frame + .debug_frame
// - MachO: __unwind_info encodings:
// - x86_64: STACK_IMMD, STACK_IND
// - aarch64: FRAMELESS, DWARF
{
const c_shared_lib = b.addLibrary(.{
.linkage = .dynamic,
.name = "c_shared_lib",
.root_module = b.createModule(.{
.root_source_file = null,
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = false,
}),
});
// https://github.com/ziglang/zig/issues/24522
//// Unwinding through a C shared library without a frame pointer (libc)
////
//// getcontext version: libc
////
//// Unwind info type:
//// - ELF: DWARF .eh_frame + .debug_frame
//// - MachO: __unwind_info encodings:
//// - x86_64: STACK_IMMD, STACK_IND
//// - aarch64: FRAMELESS, DWARF
//{
// const c_shared_lib = b.addLibrary(.{
// .linkage = .dynamic,
// .name = "c_shared_lib",
// .root_module = b.createModule(.{
// .root_source_file = null,
// .target = target,
// .optimize = optimize,
// .link_libc = true,
// .strip = false,
// }),
// });
if (target.result.os.tag == .windows)
c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
// if (target.result.os.tag == .windows)
// c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
c_shared_lib.root_module.addCSourceFile(.{
.file = b.path("shared_lib.c"),
.flags = &.{"-fomit-frame-pointer"},
});
// c_shared_lib.root_module.addCSourceFile(.{
// .file = b.path("shared_lib.c"),
// .flags = &.{"-fomit-frame-pointer"},
// });
const exe = b.addExecutable(.{
.name = "shared_lib_unwind",
.root_module = b.createModule(.{
.root_source_file = b.path("shared_lib_unwind.zig"),
.target = target,
.optimize = optimize,
.unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
.omit_frame_pointer = true,
}),
// zig objcopy doesn't support incremental binaries
.use_llvm = true,
});
// const exe = b.addExecutable(.{
// .name = "shared_lib_unwind",
// .root_module = b.createModule(.{
// .root_source_file = b.path("shared_lib_unwind.zig"),
// .target = target,
// .optimize = optimize,
// .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
// .omit_frame_pointer = true,
// }),
// // zig objcopy doesn't support incremental binaries
// .use_llvm = true,
// });
exe.linkLibrary(c_shared_lib);
// exe.linkLibrary(c_shared_lib);
const run_cmd = b.addRunArtifact(exe);
test_step.dependOn(&run_cmd.step);
// const run_cmd = b.addRunArtifact(exe);
// test_step.dependOn(&run_cmd.step);
// Separate debug info ELF file
if (target.result.ofmt == .elf) {
const filename = b.fmt("{s}_stripped", .{exe.out_filename});
const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
.basename = filename, // set the name for the debuglink
.compress_debug = true,
.strip = .debug,
.extract_to_separate_file = true,
});
// // Separate debug info ELF file
// if (target.result.ofmt == .elf) {
// const filename = b.fmt("{s}_stripped", .{exe.out_filename});
// const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
// .basename = filename, // set the name for the debuglink
// .compress_debug = true,
// .strip = .debug,
// .extract_to_separate_file = true,
// });
const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
run_stripped.addFileArg(stripped_exe.getOutput());
test_step.dependOn(&run_stripped.step);
}
}
// const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
// run_stripped.addFileArg(stripped_exe.getOutput());
// test_step.dependOn(&run_stripped.step);
// }
//}
// Unwinding without libc/posix
//

View File

@ -310,7 +310,8 @@ pub fn main() !void {
build_all_path, libc_so_path, @errorName(err),
});
};
const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]);
var stream: std.Io.Reader = .fixed(elf_bytes);
const header = try elf.Header.read(&stream);
const parse: Parse = .{
.arena = arena,