aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Build/Step/CheckObject.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-07-13 17:01:26 +0200
committerJakub Konka <kubkon@jakubkonka.com>2023-07-13 17:01:26 +0200
commit76dc0d516089da6cd7dfb5ee1634c7e4ccef6a4a (patch)
treed0a574e74f7d7e7e2e7043b796cb2eaa0e0104b1 /lib/std/Build/Step/CheckObject.zig
parent0627ca527ac9b973ff0823c274913d2ece8ae6be (diff)
downloadzig-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.zig143
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";
+ },
+ };
}
};