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 {
1616 input_path: []const u8,
1717 member_filters: []const []const u8 = &.{},
1818 member_headers: bool,
19 omit_elements: std.enums.EnumArray(Element, bool),
19 elements: std.enums.EnumArray(Element, bool),
2020 redact: std.enums.EnumArray(FieldKind, bool),
2121 relocs: bool,
2222 section_filters: []const []const u8 = &.{},
......@@ -39,9 +39,10 @@ const FieldKind = enum {
3939
4040const Element = enum {
4141 @"file-type",
42 @"table-header",
43 @"header-names",
42 @"header-name",
43 @"member-path",
4444 newlines,
45 @"table-header",
4546};
4647
4748pub fn main(init: std.process.Init) !void {
......@@ -57,7 +58,8 @@ pub fn main(init: std.process.Init) !void {
5758 var opt_input_path: ?[]const u8 = null;
5859 var opt_linker_member: ?std.coff.ArchiveMemberHeader.Kind = null;
5960 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;
6163 var redact: @FieldType(Options, "redact") = .initFill(false);
6264 var opt_relocs: ?bool = null;
6365 var opt_section_headers: ?bool = null;
......@@ -93,14 +95,23 @@ pub fn main(init: std.process.Init) !void {
9395 opt_linker_member = .second_linker;
9496 } else if (mem.eql(u8, arg, "--member-headers")) {
9597 opt_member_headers = true;
96 } else if (mem.startsWith(u8, arg, "--omit-element=")) {
97 const kind = arg["--omit-element=".len..];
98 if (std.meta.stringToEnum(Element, kind)) |format_kind| {
99 omit_elements.set(format_kind, true);
100 } else if (std.mem.eql(u8, kind, "all")) {
101 omit_elements = .initFill(true);
102 } else {
103 fatal("unrecognized element: {s}", .{kind});
98 } else if (mem.startsWith(u8, arg, "--elements=")) {
99 any_elements = true;
100 var split = std.mem.splitScalar(u8, arg["--elements=".len..], ',');
101 while (split.next()) |element| {
102 const kind, const add = if (element.len > 0 and element[0] == '-')
103 .{ element[1..], false }
104 else
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 }
104115 }
105116 } else if (mem.startsWith(u8, arg, "--only-member=")) {
106117 (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 {
122133 } else if (mem.eql(u8, arg, "--section-headers")) {
123134 opt_section_headers = true;
124135 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--snapshot")) {
125 omit_elements = .initFill(true);
136 elements = .initFill(false);
126137 redact = .initFill(true);
127138 } else if (mem.eql(u8, arg, "--strings")) {
128139 opt_strings = true;
......@@ -148,7 +159,7 @@ pub fn main(init: std.process.Init) !void {
148159 .linker_member = opt_linker_member,
149160 .member_filters = member_filters.items,
150161 .member_headers = opt_member_headers orelse false,
151 .omit_elements = omit_elements,
162 .elements = elements orelse .initFill(true),
152163 .redact = redact,
153164 .relocs = opt_relocs orelse false,
154165 .section_filters = section_filters.items,
......@@ -215,20 +226,26 @@ fn dump(d: *const DumpContext) !void {
215226 return error.ParseFailure;
216227 }
217228
218 if (d.element(.@"file-type"))
229 if (d.element(.@"file-type")) {
219230 try d.w.print("{s}: PE/COFF image\n\n", .{basename});
231 if (d.element(.newlines)) try d.w.writeByte('\n');
232 }
220233
221234 return coff.dumpObject(d, true, basename);
222235 } else if (std.mem.eql(u8, ext, ".lib")) {
223236 r.fill(std.coff.archive_signature.len) catch break :coff;
224237 if (!mem.eql(u8, r.buffered()[0..std.coff.archive_signature.len], std.coff.archive_signature)) break :coff;
225 if (d.element(.@"file-type"))
226 try d.w.print("{s}: COFF archive\n\n", .{basename});
238 if (d.element(.@"file-type")) {
239 try d.w.print("{s}: COFF archive\n", .{basename});
240 if (d.element(.newlines)) try d.w.writeByte('\n');
241 }
227242
228243 return coff.dumpArchive(d);
229244 } else if (std.mem.eql(u8, ext, ".obj")) {
230 if (d.element(.@"file-type"))
231 try d.w.print("{s}: COFF object\n\n", .{basename});
245 if (d.element(.@"file-type")) {
246 try d.w.print("{s}: COFF object\n", .{basename});
247 if (d.element(.newlines)) try d.w.writeByte('\n');
248 }
232249
233250 return coff.dumpObject(d, false, basename);
234251 }
......@@ -243,7 +260,7 @@ const DumpContext = struct {
243260 w: *Io.Writer,
244261
245262 fn element(self: *const DumpContext, e: Element) bool {
246 return !self.opts.omit_elements.get(e);
263 return self.opts.elements.get(e);
247264 }
248265
249266 fn redacted(self: *const DumpContext, opt_kind: ?FieldKind) bool {
......@@ -589,9 +606,19 @@ const coff = struct {
589606 d.opts.strings or
590607 d.opts.symbols)
591608 {
592 if (d.element(.@"file-type"))
593 try w.print("{s}({s}): COFF object\n\n", .{ std.fs.path.basename(d.opts.input_path), header.name });
594 try dumpObject(d, false, header.name);
609 const member_name = if (d.element(.@"member-path"))
610 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);
595622 }
596623 }
597624 }
......@@ -611,7 +638,7 @@ const coff = struct {
611638 return d.failParse("unable to read COFF header: {t}", .{err});
612639
613640 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");
615642 try dumpHeader(d, std.coff.Header, &header, struct {});
616643 if (d.element(.newlines)) try w.writeByte('\n');
617644 }
......@@ -639,7 +666,7 @@ const coff = struct {
639666 break :image_info null;
640667 }
641668
642 if (d.opts.file_headers and d.element(.@"header-names"))
669 if (d.opts.file_headers and d.element(.@"header-name"))
643670 try w.writeAll("COFF Optional Header:\n");
644671
645672 const magic: std.coff.OptionalHeader.Magic = @enumFromInt(try r.peekInt(u16, .little));
......@@ -701,7 +728,7 @@ const coff = struct {
701728 else => return d.failParse("invalid optional header magic number: {x}", .{magic}),
702729 };
703730
704 if (d.opts.file_headers and d.element(.@"header-names"))
731 if (d.opts.file_headers and d.element(.@"header-name"))
705732 try w.writeAll("Data Directories:\n");
706733
707734 for (0..num_directory_entries) |dir_i| {
......@@ -753,7 +780,7 @@ const coff = struct {
753780 \\
754781 , .{string_table.len});
755782
756 var sr = Io.Reader.fixed(string_table[4..]);
783 var sr = Io.Reader.fixed(string_table[@sizeOf(u32)..]);
757784 while (try sr.takeDelimiter(0)) |str| {
758785 try w.writeAll(str);
759786 try w.writeByte('\n');
......@@ -1631,28 +1658,29 @@ const usage =
16311658 \\Options:
16321659 \\ -h, --help Print this help and exit
16331660 \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols
1661 \\ --exports Display exported symbols
16341662 \\ --file-headers Display file-format specific headers
16351663 \\ --imports Display imported symbols
1636 \\ --exports Display exported symbols
16371664 \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2)
16381665 \\ --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.
16391676 \\ --redact=[kind] Redact the specified field kind. Intended for snapshot testing.
16401677 \\ rva Relative virtual addresses
16411678 \\ va Virtual addresses and file offsets
16421679 \\ ord Symbol ordinals / hints
16431680 \\ size Sizes and lengths
16441681 \\ 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.
16541682 \\ --relocs Display relocations
1655 \\ -s, --snapshot Alias for --redact=all --omit-format=all
1683 \\ -s, --snapshot Alias for --redact=all --elements=-all
16561684 \\ --section-headers Display section headers
16571685 \\ --strings Display string tables
16581686 \\ --symbols Display symbol tables