| ... | @@ -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 { |
| 39 | | 39 | |
| 40 | const Element = enum { | 40 | const 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 | }; |
| 46 | | 47 | |
| 47 | pub fn main(init: std.process.Init) !void { | 48 | pub 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 | } |
| 217 | | 228 | |
| 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 | } |
| 220 | | 233 | |
| 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 | } |
| 227 | | 242 | |
| 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 | } |
| 232 | | 249 | |
| 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, |
| 244 | | 261 | |
| 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 | } |
| 248 | | 265 | |
| 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 or | 606 | 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}); |
| 612 | | 639 | |
| 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 | } |
| 641 | | 668 | |
| 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"); |
| 644 | | 671 | |
| 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 | }; |
| 703 | | 730 | |
| 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"); |
| 706 | | 733 | |
| 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}); |
| 755 | | 782 | |
| 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 exit | 1659 | \\ -h, --help Print this help and exit |
| 1633 | \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols | 1660 | \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols |
| | 1661 | \\ --exports Display exported symbols |
| 1634 | \\ --file-headers Display file-format specific headers | 1662 | \\ --file-headers Display file-format specific headers |
| 1635 | \\ --imports Display imported symbols | 1663 | \\ --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 headers | 1665 | \\ --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 addresses | 1677 | \\ rva Relative virtual addresses |
| 1641 | \\ va Virtual addresses and file offsets | 1678 | \\ va Virtual addresses and file offsets |
| 1642 | \\ ord Symbol ordinals / hints | 1679 | \\ ord Symbol ordinals / hints |
| 1643 | \\ size Sizes and lengths | 1680 | \\ size Sizes and lengths |
| 1644 | \\ all All of the above | 1681 | \\ 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 relocations | 1682 | \\ --relocs Display relocations |
| 1655 | \\ -s, --snapshot Alias for --redact=all --omit-format=all | 1683 | \\ -s, --snapshot Alias for --redact=all --elements=-all |
| 1656 | \\ --section-headers Display section headers | 1684 | \\ --section-headers Display section headers |
| 1657 | \\ --strings Display string tables | 1685 | \\ --strings Display string tables |
| 1658 | \\ --symbols Display symbol tables | 1686 | \\ --symbols Display symbol tables |