authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:36-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:27:16-04:00
log2c3f42724d5131d826674357cecb5731d858ad27
tree53c9fdf79662220df5dc77a60d462692a829f681
parent1c6d19b0ff6c816cf9f73507e7e4ff35b19a1e1d

objdump: rework --omit-element= as --elements= for more flexibility


1 files changed, 66 insertions(+), 38 deletions(-)

lib/compiler/objdump.zig+66-38
...@@ -16,7 +16,7 @@ const Options = struct {...@@ -16,7 +16,7 @@ const Options = struct {
16 input_path: []const u8,16 input_path: []const u8,
17 member_filters: []const []const u8 = &.{},17 member_filters: []const []const u8 = &.{},
18 member_headers: bool,18 member_headers: bool,
19 omit_elements: std.enums.EnumArray(Element, bool),19 elements: std.enums.EnumArray(Element, bool),
20 redact: std.enums.EnumArray(FieldKind, bool),20 redact: std.enums.EnumArray(FieldKind, bool),
21 relocs: bool,21 relocs: bool,
22 section_filters: []const []const u8 = &.{},22 section_filters: []const []const u8 = &.{},
...@@ -39,9 +39,10 @@ const FieldKind = enum {...@@ -39,9 +39,10 @@ const FieldKind = enum {
3939
40const Element = enum {40const Element = enum {
41 @"file-type",41 @"file-type",
42 @"table-header",42 @"header-name",
43 @"header-names",43 @"member-path",
44 newlines,44 newlines,
45 @"table-header",
45};46};
4647
47pub fn main(init: std.process.Init) !void {48pub fn main(init: std.process.Init) !void {
...@@ -57,7 +58,8 @@ pub fn main(init: std.process.Init) !void {...@@ -57,7 +58,8 @@ pub fn main(init: std.process.Init) !void {
57 var opt_input_path: ?[]const u8 = null;58 var opt_input_path: ?[]const u8 = null;
58 var opt_linker_member: ?std.coff.ArchiveMemberHeader.Kind = null;59 var opt_linker_member: ?std.coff.ArchiveMemberHeader.Kind = null;
59 var opt_member_headers: ?bool = null;60 var opt_member_headers: ?bool = null;
60 var omit_elements: @FieldType(Options, "omit_elements") = .initFill(false);61 var any_elements = false;
62 var elements: ?@FieldType(Options, "elements") = null;
61 var redact: @FieldType(Options, "redact") = .initFill(false);63 var redact: @FieldType(Options, "redact") = .initFill(false);
62 var opt_relocs: ?bool = null;64 var opt_relocs: ?bool = null;
63 var opt_section_headers: ?bool = null;65 var opt_section_headers: ?bool = null;
...@@ -93,14 +95,23 @@ pub fn main(init: std.process.Init) !void {...@@ -93,14 +95,23 @@ pub fn main(init: std.process.Init) !void {
93 opt_linker_member = .second_linker;95 opt_linker_member = .second_linker;
94 } else if (mem.eql(u8, arg, "--member-headers")) {96 } else if (mem.eql(u8, arg, "--member-headers")) {
95 opt_member_headers = true;97 opt_member_headers = true;
96 } else if (mem.startsWith(u8, arg, "--omit-element=")) {98 } else if (mem.startsWith(u8, arg, "--elements=")) {
97 const kind = arg["--omit-element=".len..];99 any_elements = true;
98 if (std.meta.stringToEnum(Element, kind)) |format_kind| {100 var split = std.mem.splitScalar(u8, arg["--elements=".len..], ',');
99 omit_elements.set(format_kind, true);101 while (split.next()) |element| {
100 } else if (std.mem.eql(u8, kind, "all")) {102 const kind, const add = if (element.len > 0 and element[0] == '-')
101 omit_elements = .initFill(true);103 .{ element[1..], false }
102 } else {104 else
103 fatal("unrecognized element: {s}", .{kind});105 .{ element, true };
106
107 if (elements == null) elements = .initFill(false);
108 if (std.meta.stringToEnum(Element, kind)) |format_kind| {
109 elements.?.set(format_kind, add);
110 } else if (std.mem.eql(u8, kind, "all")) {
111 elements.? = .initFill(add);
112 } else {
113 fatal("unrecognized element: '{s}'", .{kind});
114 }
104 }115 }
105 } else if (mem.startsWith(u8, arg, "--only-member=")) {116 } else if (mem.startsWith(u8, arg, "--only-member=")) {
106 (try member_filters.addOne(arena)).* = try arena.dupe(u8, arg["--only-member=".len..]);117 (try member_filters.addOne(arena)).* = try arena.dupe(u8, arg["--only-member=".len..]);
...@@ -122,7 +133,7 @@ pub fn main(init: std.process.Init) !void {...@@ -122,7 +133,7 @@ pub fn main(init: std.process.Init) !void {
122 } else if (mem.eql(u8, arg, "--section-headers")) {133 } else if (mem.eql(u8, arg, "--section-headers")) {
123 opt_section_headers = true;134 opt_section_headers = true;
124 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--snapshot")) {135 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--snapshot")) {
125 omit_elements = .initFill(true);136 elements = .initFill(false);
126 redact = .initFill(true);137 redact = .initFill(true);
127 } else if (mem.eql(u8, arg, "--strings")) {138 } else if (mem.eql(u8, arg, "--strings")) {
128 opt_strings = true;139 opt_strings = true;
...@@ -148,7 +159,7 @@ pub fn main(init: std.process.Init) !void {...@@ -148,7 +159,7 @@ pub fn main(init: std.process.Init) !void {
148 .linker_member = opt_linker_member,159 .linker_member = opt_linker_member,
149 .member_filters = member_filters.items,160 .member_filters = member_filters.items,
150 .member_headers = opt_member_headers orelse false,161 .member_headers = opt_member_headers orelse false,
151 .omit_elements = omit_elements,162 .elements = elements orelse .initFill(true),
152 .redact = redact,163 .redact = redact,
153 .relocs = opt_relocs orelse false,164 .relocs = opt_relocs orelse false,
154 .section_filters = section_filters.items,165 .section_filters = section_filters.items,
...@@ -215,20 +226,26 @@ fn dump(d: *const DumpContext) !void {...@@ -215,20 +226,26 @@ fn dump(d: *const DumpContext) !void {
215 return error.ParseFailure;226 return error.ParseFailure;
216 }227 }
217228
218 if (d.element(.@"file-type"))229 if (d.element(.@"file-type")) {
219 try d.w.print("{s}: PE/COFF image\n\n", .{basename});230 try d.w.print("{s}: PE/COFF image\n\n", .{basename});
231 if (d.element(.newlines)) try d.w.writeByte('\n');
232 }
220233
221 return coff.dumpObject(d, true, basename);234 return coff.dumpObject(d, true, basename);
222 } else if (std.mem.eql(u8, ext, ".lib")) {235 } else if (std.mem.eql(u8, ext, ".lib")) {
223 r.fill(std.coff.archive_signature.len) catch break :coff;236 r.fill(std.coff.archive_signature.len) catch break :coff;
224 if (!mem.eql(u8, r.buffered()[0..std.coff.archive_signature.len], std.coff.archive_signature)) break :coff;237 if (!mem.eql(u8, r.buffered()[0..std.coff.archive_signature.len], std.coff.archive_signature)) break :coff;
225 if (d.element(.@"file-type"))238 if (d.element(.@"file-type")) {
226 try d.w.print("{s}: COFF archive\n\n", .{basename});239 try d.w.print("{s}: COFF archive\n", .{basename});
240 if (d.element(.newlines)) try d.w.writeByte('\n');
241 }
227242
228 return coff.dumpArchive(d);243 return coff.dumpArchive(d);
229 } else if (std.mem.eql(u8, ext, ".obj")) {244 } else if (std.mem.eql(u8, ext, ".obj")) {
230 if (d.element(.@"file-type"))245 if (d.element(.@"file-type")) {
231 try d.w.print("{s}: COFF object\n\n", .{basename});246 try d.w.print("{s}: COFF object\n", .{basename});
247 if (d.element(.newlines)) try d.w.writeByte('\n');
248 }
232249
233 return coff.dumpObject(d, false, basename);250 return coff.dumpObject(d, false, basename);
234 }251 }
...@@ -243,7 +260,7 @@ const DumpContext = struct {...@@ -243,7 +260,7 @@ const DumpContext = struct {
243 w: *Io.Writer,260 w: *Io.Writer,
244261
245 fn element(self: *const DumpContext, e: Element) bool {262 fn element(self: *const DumpContext, e: Element) bool {
246 return !self.opts.omit_elements.get(e);263 return self.opts.elements.get(e);
247 }264 }
248265
249 fn redacted(self: *const DumpContext, opt_kind: ?FieldKind) bool {266 fn redacted(self: *const DumpContext, opt_kind: ?FieldKind) bool {
...@@ -589,9 +606,19 @@ const coff = struct {...@@ -589,9 +606,19 @@ const coff = struct {
589 d.opts.strings or606 d.opts.strings or
590 d.opts.symbols)607 d.opts.symbols)
591 {608 {
592 if (d.element(.@"file-type"))609 const member_name = if (d.element(.@"member-path"))
593 try w.print("{s}({s}): COFF object\n\n", .{ std.fs.path.basename(d.opts.input_path), header.name });610 header.name
594 try dumpObject(d, false, header.name);611 else
612 std.fs.path.basename(header.name);
613
614 if (d.element(.@"file-type")) {
615 try w.print("{s}({s}): COFF object\n", .{
616 std.fs.path.basename(d.opts.input_path),
617 member_name,
618 });
619 if (d.element(.newlines)) try w.writeByte('\n');
620 }
621 try dumpObject(d, false, member_name);
595 }622 }
596 }623 }
597 }624 }
...@@ -611,7 +638,7 @@ const coff = struct {...@@ -611,7 +638,7 @@ const coff = struct {
611 return d.failParse("unable to read COFF header: {t}", .{err});638 return d.failParse("unable to read COFF header: {t}", .{err});
612639
613 if (d.opts.file_headers) {640 if (d.opts.file_headers) {
614 if (d.element(.@"header-names")) try w.writeAll("COFF Header:\n");641 if (d.element(.@"header-name")) try w.writeAll("COFF Header:\n");
615 try dumpHeader(d, std.coff.Header, &header, struct {});642 try dumpHeader(d, std.coff.Header, &header, struct {});
616 if (d.element(.newlines)) try w.writeByte('\n');643 if (d.element(.newlines)) try w.writeByte('\n');
617 }644 }
...@@ -639,7 +666,7 @@ const coff = struct {...@@ -639,7 +666,7 @@ const coff = struct {
639 break :image_info null;666 break :image_info null;
640 }667 }
641668
642 if (d.opts.file_headers and d.element(.@"header-names"))669 if (d.opts.file_headers and d.element(.@"header-name"))
643 try w.writeAll("COFF Optional Header:\n");670 try w.writeAll("COFF Optional Header:\n");
644671
645 const magic: std.coff.OptionalHeader.Magic = @enumFromInt(try r.peekInt(u16, .little));672 const magic: std.coff.OptionalHeader.Magic = @enumFromInt(try r.peekInt(u16, .little));
...@@ -701,7 +728,7 @@ const coff = struct {...@@ -701,7 +728,7 @@ const coff = struct {
701 else => return d.failParse("invalid optional header magic number: {x}", .{magic}),728 else => return d.failParse("invalid optional header magic number: {x}", .{magic}),
702 };729 };
703730
704 if (d.opts.file_headers and d.element(.@"header-names"))731 if (d.opts.file_headers and d.element(.@"header-name"))
705 try w.writeAll("Data Directories:\n");732 try w.writeAll("Data Directories:\n");
706733
707 for (0..num_directory_entries) |dir_i| {734 for (0..num_directory_entries) |dir_i| {
...@@ -753,7 +780,7 @@ const coff = struct {...@@ -753,7 +780,7 @@ const coff = struct {
753 \\780 \\
754 , .{string_table.len});781 , .{string_table.len});
755782
756 var sr = Io.Reader.fixed(string_table[4..]);783 var sr = Io.Reader.fixed(string_table[@sizeOf(u32)..]);
757 while (try sr.takeDelimiter(0)) |str| {784 while (try sr.takeDelimiter(0)) |str| {
758 try w.writeAll(str);785 try w.writeAll(str);
759 try w.writeByte('\n');786 try w.writeByte('\n');
...@@ -1631,28 +1658,29 @@ const usage =...@@ -1631,28 +1658,29 @@ const usage =
1631 \\Options:1658 \\Options:
1632 \\ -h, --help Print this help and exit1659 \\ -h, --help Print this help and exit
1633 \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols1660 \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols
1661 \\ --exports Display exported symbols
1634 \\ --file-headers Display file-format specific headers1662 \\ --file-headers Display file-format specific headers
1635 \\ --imports Display imported symbols1663 \\ --imports Display imported symbols
1636 \\ --exports Display exported symbols
1637 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)1664 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)
1638 \\ --member-headers Display archive member headers1665 \\ --member-headers Display archive member headers
1666 \\ --elements=[e1],[e2],-[e3],... Select which formatting elements are displayed. Intended for snapshot testing.
1667 \\ file-type File type summary
1668 \\ header-name Name that precedes a header block
1669 \\ member-path Display full member paths. If removed, only basenames will be used.
1670 \\ newlines Newlines between output sections
1671 \\ table-header Table headers with column names
1672 \\ all (default) All of the above
1673 \\ --only-member=[name] Only consider archive members names that contain [name]. Can be specified multiple times.
1674 \\ --only-section=[name] Only consider section names that contain [name]. Can be specified multiple times.
1675 \\ --only-symbol=[name] Only consider symbol names that contain [name]. Can be specified multiple times.
1639 \\ --redact=[kind] Redact the specified field kind. Intended for snapshot testing.1676 \\ --redact=[kind] Redact the specified field kind. Intended for snapshot testing.
1640 \\ rva Relative virtual addresses1677 \\ rva Relative virtual addresses
1641 \\ va Virtual addresses and file offsets1678 \\ va Virtual addresses and file offsets
1642 \\ ord Symbol ordinals / hints1679 \\ ord Symbol ordinals / hints
1643 \\ size Sizes and lengths1680 \\ size Sizes and lengths
1644 \\ all All of the above1681 \\ all All of the above
1645 \\ --omit-element=[kind] Omit specific parts of the output. Intended for snapshot testing.
1646 \\ file-type File type summary
1647 \\ table-headers Table headers with column names
1648 \\ header-names Name that precedes a header block
1649 \\ newlines Newlines between output sections
1650 \\ all All of the above
1651 \\ --only-member=[name] Only consider archive members names that contain [name]. Can be specified multiple times.
1652 \\ --only-section=[name] Only consider section names that contain [name]. Can be specified multiple times.
1653 \\ --only-symbol=[name] Only consider symbol names that contain [name]. Can be specified multiple times.
1654 \\ --relocs Display relocations1682 \\ --relocs Display relocations
1655 \\ -s, --snapshot Alias for --redact=all --omit-format=all1683 \\ -s, --snapshot Alias for --redact=all --elements=-all
1656 \\ --section-headers Display section headers1684 \\ --section-headers Display section headers
1657 \\ --strings Display string tables1685 \\ --strings Display string tables
1658 \\ --symbols Display symbol tables1686 \\ --symbols Display symbol tables