authorgravatar for ashe@kivikakk.eeAsherah Connor <ashe@kivikakk.ee> 2021-01-14 15:30:28+11:00
committergravatar for ashe@kivikakk.eeAsherah Connor <ashe@kivikakk.ee> 2021-01-14 15:30:28+11:00
log32d69d70cf5c915e2b2b0664c269f7e029d3c2f4
tree6c196923c43b7b91ecacb6d7f77938465ddc7e12
parent49ab6bb429dfb3c2ed67b6daf3b5b55033a44fd0

expose phdr, shdr parsing


3 files changed, 115 insertions(+), 99 deletions(-)

lib/std/build/emit_raw.zig+4-3
...@@ -51,9 +51,10 @@ const BinaryElfOutput = struct {...@@ -51,9 +51,10 @@ const BinaryElfOutput = struct {
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };53 };
54 const elf_hdr = try std.elf.readHeader(elf_file);54 const elf_source = std.elf.FileParseSource{ .file = elf_file };
55 const elf_hdr = try std.elf.Header.read(elf_source);
5556
56 var section_headers = elf_hdr.section_header_iterator(elf_file);57 var section_headers = elf_hdr.section_header_iterator(elf_source);
57 while (try section_headers.next()) |section| {58 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {59 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);60 const newSection = try allocator.create(BinaryElfSection);
...@@ -67,7 +68,7 @@ const BinaryElfOutput = struct {...@@ -67,7 +68,7 @@ const BinaryElfOutput = struct {
67 }68 }
68 }69 }
6970
70 var program_headers = elf_hdr.program_header_iterator(elf_file);71 var program_headers = elf_hdr.program_header_iterator(elf_source);
71 while (try program_headers.next()) |phdr| {72 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {73 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);74 const newSegment = try allocator.create(BinaryElfSegment);
lib/std/elf.zig+108-94
...@@ -334,6 +334,40 @@ pub const ET = extern enum(u16) {...@@ -334,6 +334,40 @@ pub const ET = extern enum(u16) {
334 pub const HIPROC = 0xffff;334 pub const HIPROC = 0xffff;
335};335};
336336
337pub const FileParseSource = struct {
338 file: std.fs.File,
339
340 fn readNoEof(self: FileParseSource, buf: []u8, offset: u64) !void {
341 var i: usize = 0;
342 while (i < buf.len) {
343 const len = self.file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
344 error.SystemResources => return error.SystemResources,
345 error.IsDir => return error.UnableToReadElfFile,
346 error.OperationAborted => return error.UnableToReadElfFile,
347 error.BrokenPipe => return error.UnableToReadElfFile,
348 error.Unseekable => return error.UnableToReadElfFile,
349 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
350 error.ConnectionTimedOut => return error.UnableToReadElfFile,
351 error.InputOutput => return error.FileSystem,
352 error.Unexpected => return error.Unexpected,
353 error.WouldBlock => return error.Unexpected,
354 error.NotOpenForReading => return error.Unexpected,
355 error.AccessDenied => return error.Unexpected,
356 };
357 if (len == 0) return error.UnexpectedEndOfFile;
358 i += len;
359 }
360 }
361};
362
363pub const BufferParseSource = struct {
364 buffer: []const u8,
365
366 fn readNoEof(self: BufferParseSource, buf: []u8, offset: u64) !void {
367 std.mem.copy(u8, buf, self.buffer[offset .. offset + buf.len]);
368 }
369};
370
337/// All integers are native endian.371/// All integers are native endian.
338pub const Header = struct {372pub const Header = struct {
339 endian: builtin.Endian,373 endian: builtin.Endian,
...@@ -347,20 +381,26 @@ pub const Header = struct {...@@ -347,20 +381,26 @@ pub const Header = struct {
347 shnum: u16,381 shnum: u16,
348 shstrndx: u16,382 shstrndx: u16,
349383
350 pub fn program_header_iterator(self: Header, file: File) ProgramHeaderIterator {384 pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {
351 return .{385 return ProgramHeaderIterator(@TypeOf(parse_source)){
352 .elf_header = self,386 .elf_header = self,
353 .file = file,387 .parse_source = parse_source,
354 };388 };
355 }389 }
356390
357 pub fn section_header_iterator(self: Header, file: File) SectionHeaderIterator {391 pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator {
358 return .{392 return .{
359 .elf_header = self,393 .elf_header = self,
360 .file = file,394 .parse_source = parse_source,
361 };395 };
362 }396 }
363397
398 pub fn read(parse_source: anytype) !Header {
399 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
400 try parse_source.readNoEof(&hdr_buf, 0);
401 return Header.parse(&hdr_buf);
402 }
403
364 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {404 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
365 const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);405 const hdr32 = @ptrCast(*const Elf32_Ehdr, hdr_buf);
366 const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);406 const hdr64 = @ptrCast(*const Elf64_Ehdr, hdr_buf);
...@@ -395,78 +435,74 @@ pub const Header = struct {...@@ -395,78 +435,74 @@ pub const Header = struct {
395 }435 }
396};436};
397437
398pub fn readHeader(file: File) !Header {438pub fn ProgramHeaderIterator(ParseSource: anytype) type {
399 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;439 return struct {
400 try preadNoEof(file, &hdr_buf, 0);440 elf_header: Header,
401 return Header.parse(&hdr_buf);441 parse_source: ParseSource,
402}442 index: usize = 0,
403443
404pub const ProgramHeaderIterator = struct {444 pub fn next(self: *@This()) !?Elf64_Phdr {
405 elf_header: Header,445 if (self.index >= self.elf_header.phnum) return null;
406 file: File,446 defer self.index += 1;
407 index: usize = 0,447
408448 if (self.elf_header.is_64) {
409 pub fn next(self: *ProgramHeaderIterator) !?Elf64_Phdr {449 var phdr: Elf64_Phdr = undefined;
410 if (self.index >= self.elf_header.phnum) return null;450 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
411 defer self.index += 1;451 try self.parse_source.readNoEof(mem.asBytes(&phdr), offset);
412452
413 if (self.elf_header.is_64) {453 // ELF endianness matches native endianness.
414 var phdr: Elf64_Phdr = undefined;454 if (self.elf_header.endian == std.builtin.endian) return phdr;
455
456 // Convert fields to native endianness.
457 return Elf64_Phdr{
458 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
459 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
460 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
461 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
462 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
463 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
464 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
465 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
466 };
467 }
468
469 var phdr: Elf32_Phdr = undefined;
415 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;470 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
416 try preadNoEof(self.file, mem.asBytes(&phdr), offset);471 try self.parse_source.readNoEof(mem.asBytes(&phdr), offset);
417472
418 // ELF endianness matches native endianness.473 // ELF endianness does NOT match native endianness.
419 if (self.elf_header.endian == std.builtin.endian) return phdr;474 if (self.elf_header.endian != std.builtin.endian) {
420475 // Convert fields to native endianness.
421 // Convert fields to native endianness.476 phdr = .{
477 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
478 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
479 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
480 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
481 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
482 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
483 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
484 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
485 };
486 }
487
488 // Convert 32-bit header to 64-bit.
422 return Elf64_Phdr{489 return Elf64_Phdr{
423 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),490 .p_type = phdr.p_type,
424 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),491 .p_offset = phdr.p_offset,
425 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),492 .p_vaddr = phdr.p_vaddr,
426 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),493 .p_paddr = phdr.p_paddr,
427 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),494 .p_filesz = phdr.p_filesz,
428 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),495 .p_memsz = phdr.p_memsz,
429 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),496 .p_flags = phdr.p_flags,
430 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),497 .p_align = phdr.p_align,
431 };
432 }
433
434 var phdr: Elf32_Phdr = undefined;
435 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
436 try preadNoEof(self.file, mem.asBytes(&phdr), offset);
437
438 // ELF endianness does NOT match native endianness.
439 if (self.elf_header.endian != std.builtin.endian) {
440 // Convert fields to native endianness.
441 phdr = .{
442 .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
443 .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
444 .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
445 .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
446 .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
447 .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
448 .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
449 .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
450 };498 };
451 }499 }
452500 };
453 // Convert 32-bit header to 64-bit.501}
454 return Elf64_Phdr{
455 .p_type = phdr.p_type,
456 .p_offset = phdr.p_offset,
457 .p_vaddr = phdr.p_vaddr,
458 .p_paddr = phdr.p_paddr,
459 .p_filesz = phdr.p_filesz,
460 .p_memsz = phdr.p_memsz,
461 .p_flags = phdr.p_flags,
462 .p_align = phdr.p_align,
463 };
464 }
465};
466502
467pub const SectionHeaderIterator = struct {503pub const SectionHeaderIterator = struct {
468 elf_header: Header,504 elf_header: Header,
469 file: File,505 parse_source: ParseSource,
470 index: usize = 0,506 index: usize = 0,
471507
472 pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {508 pub fn next(self: *SectionHeaderIterator) !?Elf64_Shdr {
...@@ -476,7 +512,7 @@ pub const SectionHeaderIterator = struct {...@@ -476,7 +512,7 @@ pub const SectionHeaderIterator = struct {
476 if (self.elf_header.is_64) {512 if (self.elf_header.is_64) {
477 var shdr: Elf64_Shdr = undefined;513 var shdr: Elf64_Shdr = undefined;
478 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;514 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
479 try preadNoEof(self.file, mem.asBytes(&shdr), offset);515 try self.parse_source.readNoEof(mem.asBytes(&shdr), offset);
480516
481 // ELF endianness matches native endianness.517 // ELF endianness matches native endianness.
482 if (self.elf_header.endian == std.builtin.endian) return shdr;518 if (self.elf_header.endian == std.builtin.endian) return shdr;
...@@ -498,7 +534,7 @@ pub const SectionHeaderIterator = struct {...@@ -498,7 +534,7 @@ pub const SectionHeaderIterator = struct {
498534
499 var shdr: Elf32_Shdr = undefined;535 var shdr: Elf32_Shdr = undefined;
500 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;536 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
501 try preadNoEof(self.file, mem.asBytes(&shdr), offset);537 try self.parse_source.readNoEof(mem.asBytes(&shdr), offset);
502538
503 // ELF endianness does NOT match native endianness.539 // ELF endianness does NOT match native endianness.
504 if (self.elf_header.endian != std.builtin.endian) {540 if (self.elf_header.endian != std.builtin.endian) {
...@@ -553,28 +589,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {...@@ -553,28 +589,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
553 }589 }
554}590}
555591
556fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
557 var i: usize = 0;
558 while (i < buf.len) {
559 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
560 error.SystemResources => return error.SystemResources,
561 error.IsDir => return error.UnableToReadElfFile,
562 error.OperationAborted => return error.UnableToReadElfFile,
563 error.BrokenPipe => return error.UnableToReadElfFile,
564 error.Unseekable => return error.UnableToReadElfFile,
565 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
566 error.ConnectionTimedOut => return error.UnableToReadElfFile,
567 error.InputOutput => return error.FileSystem,
568 error.Unexpected => return error.Unexpected,
569 error.WouldBlock => return error.Unexpected,
570 error.NotOpenForReading => return error.Unexpected,
571 error.AccessDenied => return error.Unexpected,
572 };
573 if (len == 0) return error.UnexpectedEndOfFile;
574 i += len;
575 }
576}
577
578pub const EI_NIDENT = 16;592pub const EI_NIDENT = 16;
579593
580pub const EI_CLASS = 4;594pub const EI_CLASS = 4;
src/test.zig+3-2
...@@ -989,8 +989,9 @@ pub const TestContext = struct {...@@ -989,8 +989,9 @@ pub const TestContext = struct {
989 var file = try tmp_dir.openFile(bin_name, .{ .read = true });989 var file = try tmp_dir.openFile(bin_name, .{ .read = true });
990 defer file.close();990 defer file.close();
991991
992 const header = try std.elf.readHeader(file);992 const elf_source = std.elf.FileParseSource{ .file = file };
993 var iterator = header.program_header_iterator(file);993 const header = try std.elf.Header.read(elf_source);
994 var iterator = header.program_header_iterator(elf_source);
994995
995 var none_loaded = true;996 var none_loaded = true;
996997