diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-07-13 17:01:26 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-07-13 17:01:26 +0200 |
| commit | 76dc0d516089da6cd7dfb5ee1634c7e4ccef6a4a (patch) | |
| tree | d0a574e74f7d7e7e2e7043b796cb2eaa0e0104b1 /lib/std/Build/Step/CheckObject.zig | |
| parent | 0627ca527ac9b973ff0823c274913d2ece8ae6be (diff) | |
| download | zig-76dc0d516089da6cd7dfb5ee1634c7e4ccef6a4a.tar.gz zig-76dc0d516089da6cd7dfb5ee1634c7e4ccef6a4a.zip | |
check-object: dump some info on SHDRs
Diffstat (limited to 'lib/std/Build/Step/CheckObject.zig')
| -rw-r--r-- | lib/std/Build/Step/CheckObject.zig | 143 |
1 files changed, 137 insertions, 6 deletions
diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index d53352af80..418aa9f681 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -701,9 +701,34 @@ const MachODumper = struct { const ElfDumper = struct { const symtab_label = "symtab"; - fn parseAndDump(step: *Step, bytes: []const u8, opts: Opts) ![]const u8 { - _ = opts; + const Symtab = struct { + symbols: []align(1) const elf.Elf64_Sym, + strings: []const u8, + + fn get(st: Symtab, index: usize) ?elf.Elf64_Sym { + if (index >= st.symbols.len) return null; + return st.symbols[index]; + } + + fn getName(st: Symtab, index: usize) ?[]const u8 { + const sym = st.get(index) orelse return null; + assert(sym.st_name < st.strings.len); + return mem.sliceTo(@ptrCast(st.strings.ptr + sym.st_name), 0); + } + }; + const Context = struct { + gpa: Allocator, + data: []const u8, + hdr: elf.Elf64_Ehdr, + shdrs: []align(1) const elf.Elf64_Shdr, + phdrs: []align(1) const elf.Elf64_Phdr, + shstrtab: []const u8, + symtab: ?Symtab = null, + dysymtab: ?Symtab = null, + }; + + fn parseAndDump(step: *Step, bytes: []const u8, opts: Opts) ![]const u8 { const gpa = step.owner.allocator; var stream = std.io.fixedBufferStream(bytes); const reader = stream.reader(); @@ -713,18 +738,124 @@ const ElfDumper = struct { return error.InvalidMagicNumber; } + const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(bytes.ptr + hdr.e_shoff))[0..hdr.e_shnum]; + const phdrs = @as([*]align(1) const elf.Elf64_Phdr, @ptrCast(bytes.ptr + hdr.e_phoff))[0..hdr.e_phnum]; + + var ctx = Context{ + .gpa = gpa, + .data = bytes, + .hdr = hdr, + .shdrs = shdrs, + .phdrs = phdrs, + .shstrtab = undefined, + }; + ctx.shstrtab = getSectionContents(ctx, ctx.hdr.e_shstrndx); + + if (opts.dump_symtab) { + for (ctx.shdrs, 0..) |shdr, i| switch (shdr.sh_type) { + elf.SHT_SYMTAB, elf.SHT_DYNSYM => { + const raw = getSectionContents(ctx, i); + const nsyms = @divExact(raw.len, @sizeOf(elf.Elf64_Sym)); + const symbols = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw.ptr))[0..nsyms]; + const strings = getSectionContents(ctx, shdr.sh_link); + + switch (shdr.sh_type) { + elf.SHT_SYMTAB => { + ctx.symtab = .{ + .symbols = symbols, + .strings = strings, + }; + }, + elf.SHT_DYNSYM => { + ctx.dysymtab = .{ + .symbols = symbols, + .strings = strings, + }; + }, + else => unreachable, + } + }, + + else => {}, + }; + } + var output = std.ArrayList(u8).init(gpa); const writer = output.writer(); - try dumpHeader(hdr, writer); + try dumpHeader(ctx, writer); + try dumpShdrs(ctx, writer); return output.toOwnedSlice(); } - fn dumpHeader(hdr: elf.Elf64_Ehdr, writer: anytype) !void { + fn getSectionName(ctx: Context, shndx: usize) []const u8 { + const shdr = ctx.shdrs[shndx]; + assert(shdr.sh_name < ctx.shstrtab.len); + return mem.sliceTo(@as([*:0]const u8, @ptrCast(ctx.shstrtab.ptr + shdr.sh_name)), 0); + } + + fn getSectionContents(ctx: Context, shndx: usize) []const u8 { + const shdr = ctx.shdrs[shndx]; + assert(shdr.sh_offset < ctx.data.len); + assert(shdr.sh_offset + shdr.sh_size <= ctx.data.len); + return ctx.data[shdr.sh_offset..][0..shdr.sh_size]; + } + + fn dumpHeader(ctx: Context, writer: anytype) !void { try writer.writeAll("header\n"); - try writer.print("type {s}\n", .{@tagName(hdr.e_type)}); - try writer.print("entry {x}\n", .{hdr.e_entry}); + try writer.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); + try writer.print("entry {x}\n", .{ctx.hdr.e_entry}); + } + + fn dumpShdrs(ctx: Context, writer: anytype) !void { + if (ctx.shdrs.len == 0) return; + + for (ctx.shdrs, 0..) |shdr, shndx| { + try writer.print("shdr {d}\n", .{shndx}); + try writer.print("name {s}\n", .{getSectionName(ctx, shndx)}); + try writer.print("type {s}\n", .{try fmtShType(ctx.gpa, shdr.sh_type)}); + } + } + + fn fmtShType(gpa: Allocator, sh_type: u32) ![]const u8 { + return switch (sh_type) { + elf.SHT_NULL => "NULL", + elf.SHT_PROGBITS => "PROGBITS", + elf.SHT_SYMTAB => "SYMTAB", + elf.SHT_STRTAB => "STRTAB", + elf.SHT_RELA => "RELA", + elf.SHT_HASH => "HASH", + elf.SHT_DYNAMIC => "DYNAMIC", + elf.SHT_NOTE => "NOTE", + elf.SHT_NOBITS => "NOBITS", + elf.SHT_REL => "REL", + elf.SHT_SHLIB => "SHLIB", + elf.SHT_DYNSYM => "DYNSYM", + elf.SHT_INIT_ARRAY => "INIT_ARRAY", + elf.SHT_FINI_ARRAY => "FINI_ARRAY", + elf.SHT_PREINIT_ARRAY => "PREINIT_ARRAY", + elf.SHT_GROUP => "GROUP", + elf.SHT_SYMTAB_SHNDX => "SYMTAB_SHNDX", + elf.SHT_X86_64_UNWIND => "X86_64_UNWIND", + elf.SHT_LLVM_ADDRSIG => "LLVM_ADDRSIG", + elf.SHT_GNU_HASH => "GNU_HASH", + elf.SHT_GNU_VERDEF => "VERDEF", + elf.SHT_GNU_VERNEED => "VERNEED", + elf.SHT_GNU_VERSYM => "VERSYM", + else => |sht| blk: { + if (elf.SHT_LOOS <= sht and sht < elf.SHT_HIOS) { + break :blk try std.fmt.allocPrint(gpa, "LOOS+0x{x}", .{sht - elf.SHT_LOOS}); + } + if (elf.SHT_LOPROC <= sht and sht < elf.SHT_HIPROC) { + break :blk try std.fmt.allocPrint(gpa, "LOPROC+0x{x}", .{sht - elf.SHT_LOPROC}); + } + if (elf.SHT_LOUSER <= sht and sht < elf.SHT_HIUSER) { + break :blk try std.fmt.allocPrint(gpa, "LOUSER+0x{x}", .{sht - elf.SHT_LOUSER}); + } + break :blk "UNKNOWN"; + }, + }; } }; |
