authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:37-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:27:16-04:00
log7f0b5787fb1db871501bc4b03629d68dc378e038
tree937713178e003c9cd655d655df84e8fcf1f8d1ea
parent344d0ab72c049035cacdca63094c07cd512f89cd

objdump: various fixes

- symbol filtering applies to import headers - fix missing formatting hooks - fix referencing stale memory for reloc symbol names (short names) - improved output when the user requests things that don't exist in the file

1 files changed, 49 insertions(+), 19 deletions(-)

lib/compiler/objdump.zig+49-19
......@@ -76,12 +76,14 @@ pub fn main(init: std.process.Init) !void {
7676 return Io.File.stdout().writeStreamingAll(io, usage);
7777 } else if (mem.eql(u8, arg, "--all-headers")) {
7878 opt_file_headers = true;
79 opt_linker_member = .second_linker;
7980 opt_member_headers = true;
8081 opt_section_headers = true;
8182 opt_symbols = true;
8283 opt_relocs = true;
8384 } else if (mem.eql(u8, arg, "--exports")) {
8485 opt_exports = true;
86 opt_linker_member = .second_linker;
8587 } else if (mem.eql(u8, arg, "--file-headers")) {
8688 opt_file_headers = true;
8789 } else if (mem.eql(u8, arg, "--imports")) {
......@@ -551,12 +553,21 @@ const coff = struct {
551553 const sig = std.mem.readInt(u16, member_sig[2..4], .little);
552554
553555 const is_imp_lib = machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff;
554 if (d.opts.member_headers or (d.opts.exports and is_imp_lib)) {
556 if (d.opts.member_headers)
555557 try dumpArchiveHeader(d, &header, member.offset);
556 if (is_imp_lib) {
557 try w.writeAll("\nImport header:\n");
558558
559 if (d.opts.member_headers or (d.opts.exports and is_imp_lib)) {
560 if (is_imp_lib) {
559561 const imp_header = try r.takeStruct(std.coff.ImportHeader, .little);
562 const sym_name = (try r.takeDelimiter(0)).?;
563 const imp_dll = (try r.takeDelimiter(0)).?;
564
565 if (!filterMatches(d.opts.symbol_filters, sym_name))
566 continue;
567
568 if (d.element(.@"header-name"))
569 try w.writeAll("\nImport header:\n");
570
560571 try dumpHeader(d, std.coff.ImportHeader, &imp_header, struct {
561572 pub fn sig1(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}
562573 pub fn sig2(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}
......@@ -569,8 +580,6 @@ const coff = struct {
569580 }
570581 });
571582
572 const sym_name = (try r.takeDelimiter(0)).?;
573 const imp_dll = (try r.takeDelimiter(0)).?;
574583 const imp_name = imp_name: switch (imp_header.types.name_type) {
575584 .NAME_NOPREFIX,
576585 .NAME_UNDECORATE,
......@@ -847,7 +856,7 @@ const coff = struct {
847856
848857 try dumpFlags(w, "{s}", std.coff.SectionHeader.Flags, &section.header.flags, 1);
849858 if (section.name.len > 8)
850 try w.print("| {s}", .{section.name});
859 try w.print("\n | {s}", .{section.name});
851860
852861 try w.writeByte('\n');
853862 }
......@@ -861,6 +870,10 @@ const coff = struct {
861870 section_number: std.coff.SectionNumber,
862871 }) = .empty;
863872 defer symbols.deinit(gpa);
873
874 var name_arena: std.heap.ArenaAllocator = .init(gpa);
875 defer name_arena.deinit();
876
864877 if (d.opts.relocs)
865878 try symbols.ensureUnusedCapacity(gpa, header.number_of_symbols);
866879
......@@ -893,7 +906,7 @@ const coff = struct {
893906 &.{};
894907 defer symbol_i += symbol.number_of_aux_symbols + 1;
895908
896 const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: {
909 const name = if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: {
897910 const index = std.mem.readInt(u32, symbol.name[4..], .little);
898911 if (index >= string_table.len)
899912 return d.failParse("invalid name offset for symbol {x} ({x} >= {x})", .{
......@@ -901,8 +914,8 @@ const coff = struct {
901914 index,
902915 string_table.len,
903916 });
904 break :name string_table[index..];
905 } else &symbol.name, 0);
917 break :name std.mem.sliceTo(string_table[index..], 0);
918 } else try name_arena.allocator().dupe(u8, std.mem.sliceTo(&symbol.name, 0));
906919
907920 if (d.opts.relocs)
908921 symbols.appendNTimesAssumeCapacity(.{
......@@ -1152,8 +1165,17 @@ const coff = struct {
11521165 } else &.{};
11531166 defer gpa.free(rva_index);
11541167
1155 if (d.opts.exports) {
1156 if (try seekToDataDirectory(d, rva_index, sections.items, image_info.?.data_dirs, .EXPORT)) |section_index| {
1168 if (d.opts.exports) exports: {
1169 if (try seekToDataDirectory(
1170 d,
1171 rva_index,
1172 sections.items,
1173 (image_info orelse {
1174 try w.writeAll("COFF objects do not contain an export data directory");
1175 break :exports;
1176 }).data_dirs,
1177 .EXPORT,
1178 )) |section_index| {
11571179 const export_dir = r.takeStruct(std.coff.ExportDirectoryTable, .little) catch |err|
11581180 return d.failParse("unable to read export directory: {t}", .{err});
11591181
......@@ -1239,12 +1261,15 @@ const coff = struct {
12391261 }
12401262 }
12411263
1242 if (d.opts.imports) {
1264 if (d.opts.imports) imports: {
12431265 if (try seekToDataDirectory(
12441266 d,
12451267 rva_index,
12461268 sections.items,
1247 image_info.?.data_dirs,
1269 (image_info orelse {
1270 try w.writeAll("COFF objects do not contain an import data directory");
1271 break :imports;
1272 }).data_dirs,
12481273 .IMPORT,
12491274 )) |_| {
12501275 const Entry = std.coff.ImportDirectoryEntry;
......@@ -1374,12 +1399,15 @@ const coff = struct {
13741399 }
13751400 }
13761401
1377 if (d.opts.tls) {
1402 if (d.opts.tls) tls: {
13781403 if (try seekToDataDirectory(
13791404 d,
13801405 rva_index,
13811406 sections.items,
1382 image_info.?.data_dirs,
1407 (image_info orelse {
1408 try w.writeAll("COFF objects do not contain a TLS data directory");
1409 break :tls;
1410 }).data_dirs,
13831411 .TLS,
13841412 )) |_| {
13851413 switch (image_info.?.magic) {
......@@ -1579,7 +1607,8 @@ const coff = struct {
15791607 }
15801608
15811609 fn dumpArchiveHeader(d: *const DumpContext, header: *const ArchiveHeader, pos: u32) !void {
1582 try d.w.print("Archive member at offset 0x{x}: '{s}'\n", .{ pos, header.name });
1610 if (d.element(.@"header-name"))
1611 try d.w.print("Archive member at offset 0x{x}: '{s}'\n", .{ pos, header.name });
15831612 try dumpHeader(d, ArchiveHeader, header, struct {
15841613 pub fn name(_: *const DumpContext, _: *const ArchiveHeader) !void {}
15851614 pub fn file_mode(id: *const DumpContext, h: *const ArchiveHeader) !void {
......@@ -1595,7 +1624,8 @@ const coff = struct {
15951624 std.mem.endsWith(u8, name, "_address") or
15961625 std.mem.startsWith(u8, name, "pointer_"))
15971626 return .va;
1598 if (std.mem.startsWith(u8, name, "number_"))
1627 if (std.mem.startsWith(u8, name, "number_") or
1628 std.mem.startsWith(u8, name, "size"))
15991629 return .size;
16001630 return null;
16011631 }
......@@ -1658,8 +1688,8 @@ const usage =
16581688 \\
16591689 \\Options:
16601690 \\ -h, --help Print this help and exit
1661 \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols
1662 \\ --exports Display exported symbols
1691 \\ --all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols
1692 \\ --exports Display exported symbols. In the case of COFF import libraries, display import headers.
16631693 \\ --file-headers Display file-format specific headers
16641694 \\ --imports Display imported symbols
16651695 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)