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 {...@@ -76,12 +76,14 @@ pub fn main(init: std.process.Init) !void {
76 return Io.File.stdout().writeStreamingAll(io, usage);76 return Io.File.stdout().writeStreamingAll(io, usage);
77 } else if (mem.eql(u8, arg, "--all-headers")) {77 } else if (mem.eql(u8, arg, "--all-headers")) {
78 opt_file_headers = true;78 opt_file_headers = true;
79 opt_linker_member = .second_linker;
79 opt_member_headers = true;80 opt_member_headers = true;
80 opt_section_headers = true;81 opt_section_headers = true;
81 opt_symbols = true;82 opt_symbols = true;
82 opt_relocs = true;83 opt_relocs = true;
83 } else if (mem.eql(u8, arg, "--exports")) {84 } else if (mem.eql(u8, arg, "--exports")) {
84 opt_exports = true;85 opt_exports = true;
86 opt_linker_member = .second_linker;
85 } else if (mem.eql(u8, arg, "--file-headers")) {87 } else if (mem.eql(u8, arg, "--file-headers")) {
86 opt_file_headers = true;88 opt_file_headers = true;
87 } else if (mem.eql(u8, arg, "--imports")) {89 } else if (mem.eql(u8, arg, "--imports")) {
...@@ -551,12 +553,21 @@ const coff = struct {...@@ -551,12 +553,21 @@ const coff = struct {
551 const sig = std.mem.readInt(u16, member_sig[2..4], .little);553 const sig = std.mem.readInt(u16, member_sig[2..4], .little);
552554
553 const is_imp_lib = machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff;555 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)
555 try dumpArchiveHeader(d, &header, member.offset);557 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) {
559 const imp_header = try r.takeStruct(std.coff.ImportHeader, .little);561 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
560 try dumpHeader(d, std.coff.ImportHeader, &imp_header, struct {571 try dumpHeader(d, std.coff.ImportHeader, &imp_header, struct {
561 pub fn sig1(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}572 pub fn sig1(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}
562 pub fn sig2(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}573 pub fn sig2(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {}
...@@ -569,8 +580,6 @@ const coff = struct {...@@ -569,8 +580,6 @@ const coff = struct {
569 }580 }
570 });581 });
571582
572 const sym_name = (try r.takeDelimiter(0)).?;
573 const imp_dll = (try r.takeDelimiter(0)).?;
574 const imp_name = imp_name: switch (imp_header.types.name_type) {583 const imp_name = imp_name: switch (imp_header.types.name_type) {
575 .NAME_NOPREFIX,584 .NAME_NOPREFIX,
576 .NAME_UNDECORATE,585 .NAME_UNDECORATE,
...@@ -847,7 +856,7 @@ const coff = struct {...@@ -847,7 +856,7 @@ const coff = struct {
847856
848 try dumpFlags(w, "{s}", std.coff.SectionHeader.Flags, &section.header.flags, 1);857 try dumpFlags(w, "{s}", std.coff.SectionHeader.Flags, &section.header.flags, 1);
849 if (section.name.len > 8)858 if (section.name.len > 8)
850 try w.print("| {s}", .{section.name});859 try w.print("\n | {s}", .{section.name});
851860
852 try w.writeByte('\n');861 try w.writeByte('\n');
853 }862 }
...@@ -861,6 +870,10 @@ const coff = struct {...@@ -861,6 +870,10 @@ const coff = struct {
861 section_number: std.coff.SectionNumber,870 section_number: std.coff.SectionNumber,
862 }) = .empty;871 }) = .empty;
863 defer symbols.deinit(gpa);872 defer symbols.deinit(gpa);
873
874 var name_arena: std.heap.ArenaAllocator = .init(gpa);
875 defer name_arena.deinit();
876
864 if (d.opts.relocs)877 if (d.opts.relocs)
865 try symbols.ensureUnusedCapacity(gpa, header.number_of_symbols);878 try symbols.ensureUnusedCapacity(gpa, header.number_of_symbols);
866879
...@@ -893,7 +906,7 @@ const coff = struct {...@@ -893,7 +906,7 @@ const coff = struct {
893 &.{};906 &.{};
894 defer symbol_i += symbol.number_of_aux_symbols + 1;907 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: {
897 const index = std.mem.readInt(u32, symbol.name[4..], .little);910 const index = std.mem.readInt(u32, symbol.name[4..], .little);
898 if (index >= string_table.len)911 if (index >= string_table.len)
899 return d.failParse("invalid name offset for symbol {x} ({x} >= {x})", .{912 return d.failParse("invalid name offset for symbol {x} ({x} >= {x})", .{
...@@ -901,8 +914,8 @@ const coff = struct {...@@ -901,8 +914,8 @@ const coff = struct {
901 index,914 index,
902 string_table.len,915 string_table.len,
903 });916 });
904 break :name string_table[index..];917 break :name std.mem.sliceTo(string_table[index..], 0);
905 } else &symbol.name, 0);918 } else try name_arena.allocator().dupe(u8, std.mem.sliceTo(&symbol.name, 0));
906919
907 if (d.opts.relocs)920 if (d.opts.relocs)
908 symbols.appendNTimesAssumeCapacity(.{921 symbols.appendNTimesAssumeCapacity(.{
...@@ -1152,8 +1165,17 @@ const coff = struct {...@@ -1152,8 +1165,17 @@ const coff = struct {
1152 } else &.{};1165 } else &.{};
1153 defer gpa.free(rva_index);1166 defer gpa.free(rva_index);
11541167
1155 if (d.opts.exports) {1168 if (d.opts.exports) exports: {
1156 if (try seekToDataDirectory(d, rva_index, sections.items, image_info.?.data_dirs, .EXPORT)) |section_index| {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| {
1157 const export_dir = r.takeStruct(std.coff.ExportDirectoryTable, .little) catch |err|1179 const export_dir = r.takeStruct(std.coff.ExportDirectoryTable, .little) catch |err|
1158 return d.failParse("unable to read export directory: {t}", .{err});1180 return d.failParse("unable to read export directory: {t}", .{err});
11591181
...@@ -1239,12 +1261,15 @@ const coff = struct {...@@ -1239,12 +1261,15 @@ const coff = struct {
1239 }1261 }
1240 }1262 }
12411263
1242 if (d.opts.imports) {1264 if (d.opts.imports) imports: {
1243 if (try seekToDataDirectory(1265 if (try seekToDataDirectory(
1244 d,1266 d,
1245 rva_index,1267 rva_index,
1246 sections.items,1268 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,
1248 .IMPORT,1273 .IMPORT,
1249 )) |_| {1274 )) |_| {
1250 const Entry = std.coff.ImportDirectoryEntry;1275 const Entry = std.coff.ImportDirectoryEntry;
...@@ -1374,12 +1399,15 @@ const coff = struct {...@@ -1374,12 +1399,15 @@ const coff = struct {
1374 }1399 }
1375 }1400 }
13761401
1377 if (d.opts.tls) {1402 if (d.opts.tls) tls: {
1378 if (try seekToDataDirectory(1403 if (try seekToDataDirectory(
1379 d,1404 d,
1380 rva_index,1405 rva_index,
1381 sections.items,1406 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,
1383 .TLS,1411 .TLS,
1384 )) |_| {1412 )) |_| {
1385 switch (image_info.?.magic) {1413 switch (image_info.?.magic) {
...@@ -1579,7 +1607,8 @@ const coff = struct {...@@ -1579,7 +1607,8 @@ const coff = struct {
1579 }1607 }
15801608
1581 fn dumpArchiveHeader(d: *const DumpContext, header: *const ArchiveHeader, pos: u32) !void {1609 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 });
1583 try dumpHeader(d, ArchiveHeader, header, struct {1612 try dumpHeader(d, ArchiveHeader, header, struct {
1584 pub fn name(_: *const DumpContext, _: *const ArchiveHeader) !void {}1613 pub fn name(_: *const DumpContext, _: *const ArchiveHeader) !void {}
1585 pub fn file_mode(id: *const DumpContext, h: *const ArchiveHeader) !void {1614 pub fn file_mode(id: *const DumpContext, h: *const ArchiveHeader) !void {
...@@ -1595,7 +1624,8 @@ const coff = struct {...@@ -1595,7 +1624,8 @@ const coff = struct {
1595 std.mem.endsWith(u8, name, "_address") or1624 std.mem.endsWith(u8, name, "_address") or
1596 std.mem.startsWith(u8, name, "pointer_"))1625 std.mem.startsWith(u8, name, "pointer_"))
1597 return .va;1626 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"))
1599 return .size;1629 return .size;
1600 return null;1630 return null;
1601 }1631 }
...@@ -1658,8 +1688,8 @@ const usage =...@@ -1658,8 +1688,8 @@ const usage =
1658 \\1688 \\
1659 \\Options:1689 \\Options:
1660 \\ -h, --help Print this help and exit1690 \\ -h, --help Print this help and exit
1661 \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols1691 \\ --all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols
1662 \\ --exports Display exported symbols1692 \\ --exports Display exported symbols. In the case of COFF import libraries, display import headers.
1663 \\ --file-headers Display file-format specific headers1693 \\ --file-headers Display file-format specific headers
1664 \\ --imports Display imported symbols1694 \\ --imports Display imported symbols
1665 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)1695 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)