| ... | ... | @@ -10,10 +10,13 @@ const native_endian = builtin.cpu.arch.endian(); |
| 10 | 10 | var stdout_buffer: [4000]u8 = undefined; |
| 11 | 11 | |
| 12 | 12 | const Options = struct { |
| 13 | | input_path: []const u8, |
| 13 | exports: bool, |
| 14 | 14 | file_headers: bool, |
| 15 | imports: bool, |
| 16 | input_path: []const u8, |
| 15 | 17 | member_filters: []const []const u8 = &.{}, |
| 16 | 18 | member_headers: bool, |
| 19 | relocs: bool, |
| 17 | 20 | section_filters: []const []const u8 = &.{}, |
| 18 | 21 | section_headers: bool, |
| 19 | 22 | strings: bool, |
| ... | ... | @@ -30,14 +33,16 @@ pub fn main(init: std.process.Init) !void { |
| 30 | 33 | |
| 31 | 34 | var i: usize = 1; |
| 32 | 35 | |
| 33 | | var opt_input_path: ?[]const u8 = null; |
| 36 | var opt_exports: ?bool = null; |
| 34 | 37 | var opt_file_headers: ?bool = null; |
| 38 | var opt_imports: ?bool = null; |
| 39 | var opt_input_path: ?[]const u8 = null; |
| 35 | 40 | var opt_linker_member: ?std.coff.ArchiveMemberHeader.Kind = null; |
| 36 | 41 | var opt_member_headers: ?bool = null; |
| 42 | var opt_relocs: ?bool = null; |
| 37 | 43 | var opt_section_headers: ?bool = null; |
| 38 | 44 | var opt_strings: ?bool = null; |
| 39 | 45 | var opt_symbols: ?bool = null; |
| 40 | | var opt_relocs: ?bool = null; |
| 41 | 46 | var section_filters: std.ArrayList([]const u8) = .empty; |
| 42 | 47 | var member_filters: std.ArrayList([]const u8) = .empty; |
| 43 | 48 | while (i < args.len) : (i += 1) { |
| ... | ... | @@ -51,11 +56,17 @@ pub fn main(init: std.process.Init) !void { |
| 51 | 56 | opt_section_headers = true; |
| 52 | 57 | opt_symbols = true; |
| 53 | 58 | opt_relocs = true; |
| 59 | } else if (mem.eql(u8, arg, "--exports")) { |
| 60 | opt_exports = true; |
| 54 | 61 | } else if (mem.eql(u8, arg, "--file-headers")) { |
| 55 | 62 | opt_file_headers = true; |
| 63 | } else if (mem.eql(u8, arg, "--imports")) { |
| 64 | opt_imports = true; |
| 56 | 65 | } else if (mem.startsWith(u8, arg, "--linker-member")) { |
| 57 | 66 | if (mem.eql(u8, arg["--linker-member".len..], "=1")) |
| 58 | 67 | opt_linker_member = .first_linker |
| 68 | else if (mem.eql(u8, arg["--linker-member".len..], "=longnames")) |
| 69 | opt_linker_member = .longnames |
| 59 | 70 | else |
| 60 | 71 | opt_linker_member = .second_linker; |
| 61 | 72 | } else if (mem.eql(u8, arg, "--member-headers")) { |
| ... | ... | @@ -84,9 +95,12 @@ pub fn main(init: std.process.Init) !void { |
| 84 | 95 | |
| 85 | 96 | const opts: Options = .{ |
| 86 | 97 | .input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}), |
| 98 | .exports = opt_exports orelse false, |
| 87 | 99 | .file_headers = opt_file_headers orelse false, |
| 100 | .imports = opt_imports orelse false, |
| 88 | 101 | .section_filters = section_filters.items, |
| 89 | 102 | .section_headers = opt_section_headers orelse false, |
| 103 | .relocs = opt_relocs orelse false, |
| 90 | 104 | .strings = opt_strings orelse false, |
| 91 | 105 | .symbols = opt_symbols orelse false, |
| 92 | 106 | .member_filters = member_filters.items, |
| ... | ... | @@ -129,6 +143,7 @@ fn dump(gpa: std.mem.Allocator, opts: *const Options, fr: *Io.File.Reader, w: *I |
| 129 | 143 | } |
| 130 | 144 | coff: { |
| 131 | 145 | const ext = std.fs.path.extension(opts.input_path); |
| 146 | const basename = std.fs.path.basename(opts.input_path); |
| 132 | 147 | if (std.mem.eql(u8, ext, ".exe") or std.mem.eql(u8, ext, ".dll")) { |
| 133 | 148 | if (!mem.eql(u8, r.buffered()[0..2], "MZ")) break :coff; |
| 134 | 149 | try r.discardAll(std.coff.pe_pointer_offset); |
| ... | ... | @@ -141,16 +156,16 @@ fn dump(gpa: std.mem.Allocator, opts: *const Options, fr: *Io.File.Reader, w: *I |
| 141 | 156 | return error.ParseFailure; |
| 142 | 157 | } |
| 143 | 158 | |
| 144 | | try w.print("{s}: PE/COFF image\n\n", .{std.fs.path.basename(opts.input_path)}); |
| 145 | | return coff.dumpObject(gpa, opts, true, fr, w); |
| 159 | try w.print("{s}: PE/COFF image\n\n", .{basename}); |
| 160 | return coff.dumpObject(gpa, opts, true, basename, fr, w); |
| 146 | 161 | } else if (std.mem.eql(u8, ext, ".lib")) { |
| 147 | 162 | r.fill(std.coff.archive_signature.len) catch break :coff; |
| 148 | 163 | if (!mem.eql(u8, r.buffered()[0..std.coff.archive_signature.len], std.coff.archive_signature)) break :coff; |
| 149 | | try w.print("{s}: COFF archive\n\n", .{std.fs.path.basename(opts.input_path)}); |
| 164 | try w.print("{s}: COFF archive\n\n", .{basename}); |
| 150 | 165 | return coff.dumpArchive(gpa, opts, fr, w); |
| 151 | 166 | } else if (std.mem.eql(u8, ext, ".obj")) { |
| 152 | | try w.print("{s}: COFF object\n\n", .{std.fs.path.basename(opts.input_path)}); |
| 153 | | return coff.dumpObject(gpa, opts, false, fr, w); |
| 167 | try w.print("{s}: COFF object\n\n", .{basename}); |
| 168 | return coff.dumpObject(gpa, opts, false, basename, fr, w); |
| 154 | 169 | } |
| 155 | 170 | } |
| 156 | 171 | return error.UnknownFile; |
| ... | ... | @@ -242,7 +257,10 @@ const coff = struct { |
| 242 | 257 | if (!std.mem.eql(u8, &raw_header.end_of_header, std.coff.archive_end_of_header)) |
| 243 | 258 | return failParse(opts, "malformed end-of-header field in member '{s}': {x}", .{ header.name, raw_header.end_of_header }); |
| 244 | 259 | |
| 245 | | const dump_header = opts.member_headers and filterMatches(opts.member_filters, header.name); |
| 260 | const dump_header = |
| 261 | (opts.member_headers and filterMatches(opts.member_filters, header.name)) or |
| 262 | (opts.linker_member == opt_expected_kind); |
| 263 | |
| 246 | 264 | if (dump_header) |
| 247 | 265 | try dumpArchiveHeader(w, &header, @intCast(pos)); |
| 248 | 266 | |
| ... | ... | @@ -264,11 +282,12 @@ const coff = struct { |
| 264 | 282 | , .{ expected_kind, num_symbols }); |
| 265 | 283 | |
| 266 | 284 | if (opts.linker_member == .first_linker) { |
| 267 | | try w.print( |
| 268 | | \\Archives symbols ({d}): |
| 285 | try w.writeAll( |
| 286 | \\ |
| 287 | \\Archive symbols: |
| 269 | 288 | \\& Member Symbol |
| 270 | 289 | \\ |
| 271 | | , .{num_symbols}); |
| 290 | ); |
| 272 | 291 | |
| 273 | 292 | const offsets = try r.readAlloc(gpa, num_symbols * 4); |
| 274 | 293 | defer gpa.free(offsets); |
| ... | ... | @@ -320,11 +339,12 @@ const coff = struct { |
| 320 | 339 | symbol_member_indices.addOneAssumeCapacity().* = (try r.takeInt(u16, .little)) - 1; |
| 321 | 340 | |
| 322 | 341 | if (opts.linker_member == .second_linker) { |
| 323 | | try w.print( |
| 324 | | \\Archive symbols ({d} members, {d} symbols): |
| 342 | try w.writeAll( |
| 343 | \\ |
| 344 | \\Archive Symbols: |
| 325 | 345 | \\& Member Symbol |
| 326 | 346 | \\ |
| 327 | | , .{ num_members, num_symbols }); |
| 347 | ); |
| 328 | 348 | |
| 329 | 349 | pos = fr.logicalPos(); |
| 330 | 350 | var symbol_i: u32 = 0; |
| ... | ... | @@ -362,6 +382,21 @@ const coff = struct { |
| 362 | 382 | opt_longnames = try r.readAlloc(gpa, header.size); |
| 363 | 383 | if (dump_header) |
| 364 | 384 | try w.print("{t: >16} type\n", .{expected_kind}); |
| 385 | |
| 386 | if (opts.linker_member == .longnames) { |
| 387 | try w.print( |
| 388 | \\ |
| 389 | \\Longnames (0x{x} bytes): |
| 390 | \\ |
| 391 | , .{opt_longnames.?.len}); |
| 392 | |
| 393 | var lr = Io.Reader.fixed(opt_longnames.?); |
| 394 | while (try lr.takeDelimiter(0)) |str| { |
| 395 | try w.writeAll(str); |
| 396 | try w.writeByte('\n'); |
| 397 | } |
| 398 | try w.writeByte('\n'); |
| 399 | } |
| 365 | 400 | } |
| 366 | 401 | |
| 367 | 402 | opt_expected_kind = null; |
| ... | ... | @@ -390,13 +425,50 @@ const coff = struct { |
| 390 | 425 | @enumFromInt(std.mem.readInt(u16, member_sig[0..2], .little)); |
| 391 | 426 | const sig = std.mem.readInt(u16, member_sig[2..4], .little); |
| 392 | 427 | |
| 393 | | const is_import = machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff; |
| 428 | const is_imp_lib = machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff; |
| 394 | 429 | |
| 395 | | if (opts.member_headers) { |
| 430 | if (opts.member_headers or (opts.exports and is_imp_lib)) { |
| 396 | 431 | try dumpArchiveHeader(w, &header, member.offset); |
| 397 | | if (is_import) { |
| 398 | | try w.writeAll(" Import header type\n"); |
| 399 | | // TODO: Dump import header |
| 432 | if (is_imp_lib) { |
| 433 | try w.writeAll("\nImport header:\n"); |
| 434 | |
| 435 | const imp_header = try r.takeStruct(std.coff.ImportHeader, .little); |
| 436 | try dumpHeader(w, std.coff.ImportHeader, &imp_header, struct { |
| 437 | pub fn sig1(_: *const std.coff.ImportHeader, _: *Io.Writer) !void {} |
| 438 | pub fn sig2(_: *const std.coff.ImportHeader, _: *Io.Writer) !void {} |
| 439 | pub fn types(h: *const std.coff.ImportHeader, cw: *Io.Writer) !void { |
| 440 | try cw.print( |
| 441 | \\{t: >16} import_type |
| 442 | \\{t: >16} name_type |
| 443 | \\ |
| 444 | , .{ h.types.type, h.types.name_type }); |
| 445 | } |
| 446 | }); |
| 447 | |
| 448 | const sym_name = (try r.takeDelimiter(0)).?; |
| 449 | const imp_dll = (try r.takeDelimiter(0)).?; |
| 450 | const imp_name = imp_name: switch (imp_header.types.name_type) { |
| 451 | .NAME_NOPREFIX, |
| 452 | .NAME_UNDECORATE, |
| 453 | => |tag| { |
| 454 | var imp_name = std.mem.trimStart(u8, sym_name, "?@_"); |
| 455 | if (tag == .NAME_UNDECORATE) |
| 456 | imp_name = std.mem.sliceTo(imp_name, '@'); |
| 457 | break :imp_name imp_name; |
| 458 | }, |
| 459 | else => sym_name, |
| 460 | }; |
| 461 | |
| 462 | try w.print( |
| 463 | \\ symbol name | {s} |
| 464 | \\ import name | {s} |
| 465 | \\ dll | {s} |
| 466 | \\ |
| 467 | , .{ |
| 468 | sym_name, |
| 469 | imp_name, |
| 470 | imp_dll, |
| 471 | }); |
| 400 | 472 | } else { |
| 401 | 473 | try w.writeAll(" COFF object type\n"); |
| 402 | 474 | } |
| ... | ... | @@ -409,7 +481,7 @@ const coff = struct { |
| 409 | 481 | opts.symbols) |
| 410 | 482 | { |
| 411 | 483 | try w.print("{s}({s}): COFF object\n\n", .{ std.fs.path.basename(opts.input_path), header.name }); |
| 412 | | try dumpObject(gpa, opts, false, fr, w); |
| 484 | try dumpObject(gpa, opts, false, header.name, fr, w); |
| 413 | 485 | } |
| 414 | 486 | } |
| 415 | 487 | } |
| ... | ... | @@ -418,6 +490,7 @@ const coff = struct { |
| 418 | 490 | gpa: std.mem.Allocator, |
| 419 | 491 | opts: *const Options, |
| 420 | 492 | is_image: bool, |
| 493 | obj_name: []const u8, |
| 421 | 494 | fr: *Io.File.Reader, |
| 422 | 495 | w: *Io.Writer, |
| 423 | 496 | ) !void { |
| ... | ... | @@ -432,6 +505,11 @@ const coff = struct { |
| 432 | 505 | try w.writeByte('\n'); |
| 433 | 506 | } |
| 434 | 507 | |
| 508 | switch (header.machine) { |
| 509 | _ => return failParse(opts, "unknown machine type: {x}", .{header.machine}), |
| 510 | else => {}, |
| 511 | } |
| 512 | |
| 435 | 513 | if (header.size_of_optional_header > 0) opt_header: { |
| 436 | 514 | if (!opts.file_headers) { |
| 437 | 515 | try fr.seekBy(header.size_of_optional_header); |
| ... | ... | @@ -541,59 +619,65 @@ const coff = struct { |
| 541 | 619 | try w.writeByte('\n'); |
| 542 | 620 | } |
| 543 | 621 | |
| 544 | | var sections: std.ArrayList(std.coff.SectionHeader) = .empty; |
| 622 | var sections: std.ArrayList(struct { |
| 623 | header: std.coff.SectionHeader, |
| 624 | name: []const u8, |
| 625 | }) = .empty; |
| 545 | 626 | defer sections.deinit(gpa); |
| 546 | 627 | |
| 547 | | const load_sections = opts.section_headers or opts.symbols; |
| 628 | const load_sections = |
| 629 | opts.section_headers or |
| 630 | opts.symbols or |
| 631 | opts.relocs; |
| 632 | |
| 548 | 633 | if (load_sections) { |
| 549 | 634 | if (opts.section_headers) |
| 550 | | try w.writeAll( |
| 551 | | \\Section Table: |
| 635 | try w.print( |
| 636 | \\Sections ({s}): |
| 552 | 637 | \\Num Name RVA Virt Size Data Size & Data & Relocs & Lines # Relocs # Lines Flags |
| 553 | 638 | \\ |
| 554 | | ); |
| 639 | , .{obj_name}); |
| 555 | 640 | |
| 556 | 641 | try sections.resize(gpa, header.number_of_sections); |
| 557 | 642 | for (sections.items, 0..) |*section, section_i| { |
| 558 | | section.* = r.takeStruct(std.coff.SectionHeader, .little) catch |err| |
| 643 | section.header = r.takeStruct(std.coff.SectionHeader, .little) catch |err| |
| 559 | 644 | return failParse(opts, "unable to read section header {x}: {t}", .{ section_i, err }); |
| 645 | section.name = headerName(&section.header.name, string_table) catch |err| switch (err) { |
| 646 | error.Overflow, |
| 647 | error.InvalidCharacter, |
| 648 | => return failParse(opts, "unable to parse section name offset '{s}': {t}", .{ |
| 649 | section.name, |
| 650 | err, |
| 651 | }), |
| 652 | error.OutOfBounds => return failParse(opts, "section name offset '{s}' was out of bounds (>= {x})", .{ |
| 653 | section.name, |
| 654 | string_table.len, |
| 655 | }), |
| 656 | }; |
| 560 | 657 | |
| 561 | 658 | if (opts.section_headers) { |
| 562 | | const name = headerName(&section.name, string_table) catch |err| switch (err) { |
| 563 | | error.Overflow, |
| 564 | | error.InvalidCharacter, |
| 565 | | => return failParse(opts, "unable to parse section name offset '{s}': {t}", .{ |
| 566 | | section.name, |
| 567 | | err, |
| 568 | | }), |
| 569 | | error.OutOfBounds => return failParse(opts, "section name offset '{s}' was out of bounds (>= {x})", .{ |
| 570 | | section.name, |
| 571 | | string_table.len, |
| 572 | | }), |
| 573 | | }; |
| 574 | | |
| 575 | | if (!filterMatches(opts.section_filters, name)) continue; |
| 576 | | const raw_name = std.mem.sliceTo(&section.name, 0); |
| 659 | if (!filterMatches(opts.section_filters, section.name)) continue; |
| 660 | const raw_name = std.mem.sliceTo(&section.header.name, 0); |
| 577 | 661 | try w.print( |
| 578 | 662 | "{x: >3} {s: <8} {x: >8} {x: >9} {x: >9} {x: >8} {x: >8} {x: >8} {x: >8} {x: >8} {x:0>8} | ", |
| 579 | 663 | .{ |
| 580 | 664 | section_i + 1, |
| 581 | 665 | raw_name, |
| 582 | | section.virtual_address, |
| 583 | | section.virtual_size, |
| 584 | | section.size_of_raw_data, |
| 585 | | section.pointer_to_raw_data, |
| 586 | | section.pointer_to_relocations, |
| 587 | | section.pointer_to_linenumbers, |
| 588 | | section.number_of_relocations, |
| 589 | | section.number_of_linenumbers, |
| 590 | | @as(u32, @bitCast(section.flags)), |
| 666 | section.header.virtual_address, |
| 667 | section.header.virtual_size, |
| 668 | section.header.size_of_raw_data, |
| 669 | section.header.pointer_to_raw_data, |
| 670 | section.header.pointer_to_relocations, |
| 671 | section.header.pointer_to_linenumbers, |
| 672 | section.header.number_of_relocations, |
| 673 | section.header.number_of_linenumbers, |
| 674 | @as(u32, @bitCast(section.header.flags)), |
| 591 | 675 | }, |
| 592 | 676 | ); |
| 593 | 677 | |
| 594 | | try dumpFlags(w, "{s} ", std.coff.SectionHeader.Flags, &section.flags, 0); |
| 595 | | if (name.len > 8) |
| 596 | | try w.print("| {s}", .{name}); |
| 678 | try dumpFlags(w, "{s} ", std.coff.SectionHeader.Flags, &section.header.flags, 1); |
| 679 | if (section.name.len > 8) |
| 680 | try w.print("| {s}", .{section.name}); |
| 597 | 681 | |
| 598 | 682 | try w.writeByte('\n'); |
| 599 | 683 | } |
| ... | ... | @@ -602,16 +686,21 @@ const coff = struct { |
| 602 | 686 | if (opts.section_headers) try w.writeByte('\n'); |
| 603 | 687 | } |
| 604 | 688 | |
| 689 | var symbol_names: std.ArrayList([]const u8) = .empty; |
| 690 | defer symbol_names.deinit(gpa); |
| 691 | if (opts.relocs) |
| 692 | try symbol_names.ensureUnusedCapacity(gpa, header.number_of_symbols); |
| 693 | |
| 605 | 694 | if (opts.symbols) { |
| 606 | 695 | if (header.pointer_to_symbol_table > 0) { |
| 607 | 696 | fr.seekTo(file_location + header.pointer_to_symbol_table) catch |err| |
| 608 | 697 | return failParse(opts, "unable to seek to symbol table: {t}", .{err}); |
| 609 | 698 | |
| 610 | | try w.writeAll( |
| 611 | | \\Symbol Table: |
| 699 | try w.print( |
| 700 | \\Symbols ({s}): |
| 612 | 701 | \\ Ord Value Sect Type Storage Name |
| 613 | 702 | \\ |
| 614 | | ); |
| 703 | , .{obj_name}); |
| 615 | 704 | |
| 616 | 705 | const symbol_size = std.coff.Symbol.sizeOf(); |
| 617 | 706 | var symbol_i: u32 = 0; |
| ... | ... | @@ -633,10 +722,17 @@ const coff = struct { |
| 633 | 722 | const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: { |
| 634 | 723 | const index = std.mem.readInt(u32, symbol.name[4..], .little); |
| 635 | 724 | if (index >= string_table.len) |
| 636 | | return failParse(opts, "invalid name offset for symbol {x} ({x} >= {x})", .{ symbol_i, index, string_table.len }); |
| 725 | return failParse(opts, "invalid name offset for symbol {x} ({x} >= {x})", .{ |
| 726 | symbol_i, |
| 727 | index, |
| 728 | string_table.len, |
| 729 | }); |
| 637 | 730 | break :name string_table[index..]; |
| 638 | 731 | } else &symbol.name, 0); |
| 639 | 732 | |
| 733 | if (opts.relocs) |
| 734 | symbol_names.appendNTimesAssumeCapacity(name, 1 + symbol.number_of_aux_symbols); |
| 735 | |
| 640 | 736 | try w.print("{x: >4} {x:0>8} ", .{ symbol_i, symbol.value }); |
| 641 | 737 | try switch (symbol.section_number) { |
| 642 | 738 | .UNDEFINED => w.writeAll("UNDEF"), |
| ... | ... | @@ -743,18 +839,18 @@ const coff = struct { |
| 743 | 839 | std.mem.byteSwapAllFields(std.coff.SectionDefinition, &section_def); |
| 744 | 840 | |
| 745 | 841 | const section = &sections.items[section_i]; |
| 746 | | if (section_def.number_of_relocations != section.number_of_relocations) { |
| 842 | if (section_def.number_of_relocations != section.header.number_of_relocations) { |
| 747 | 843 | try w.print( |
| 748 | 844 | " !! relocation count did not match section header: {d} vs {d}", |
| 749 | | .{ section_def.number_of_relocations, section.number_of_relocations }, |
| 845 | .{ section_def.number_of_relocations, section.header.number_of_relocations }, |
| 750 | 846 | ); |
| 751 | 847 | continue; |
| 752 | 848 | } |
| 753 | 849 | |
| 754 | | if (section_def.number_of_linenumbers != section.number_of_linenumbers) { |
| 850 | if (section_def.number_of_linenumbers != section.header.number_of_linenumbers) { |
| 755 | 851 | try w.print( |
| 756 | 852 | " !! line number count did not match section header: {d} vs {d}", |
| 757 | | .{ section_def.number_of_linenumbers, section.number_of_linenumbers }, |
| 853 | .{ section_def.number_of_linenumbers, section.header.number_of_linenumbers }, |
| 758 | 854 | ); |
| 759 | 855 | continue; |
| 760 | 856 | } |
| ... | ... | @@ -786,6 +882,52 @@ const coff = struct { |
| 786 | 882 | try w.writeAll("No symbol table found\n"); |
| 787 | 883 | } |
| 788 | 884 | } |
| 885 | |
| 886 | if (opts.relocs) { |
| 887 | const relocation_size = std.coff.Relocation.sizeOf(); |
| 888 | |
| 889 | for (sections.items, 0..) |section, section_i| { |
| 890 | if (section.header.pointer_to_relocations == 0) continue; |
| 891 | |
| 892 | try w.print( |
| 893 | \\Relocs for section {x} '{s}' in {s}: |
| 894 | \\ Offset Type Symbol Name |
| 895 | \\ |
| 896 | , .{ section_i + 1, section.name, obj_name }); |
| 897 | |
| 898 | fr.seekTo(file_location + section.header.pointer_to_relocations) catch |err| |
| 899 | return failParse(opts, "unable to seek to section {x} relocation table: {t}", .{ section_i + 1, err }); |
| 900 | |
| 901 | for (0..section.header.number_of_relocations) |reloc_i| { |
| 902 | var reloc: std.coff.Relocation = undefined; |
| 903 | @memcpy(std.mem.asBytes(&reloc)[0..relocation_size], try r.take(relocation_size)); |
| 904 | if (native_endian != .little) |
| 905 | std.mem.byteSwapAllFields(std.coff.Relocation, &reloc); |
| 906 | |
| 907 | try w.print("{x:0>8} ", .{reloc.virtual_address}); |
| 908 | switch (header.machine) { |
| 909 | _ => unreachable, |
| 910 | inline else => |m| switch (m.RelocationType()) { |
| 911 | void => try w.writeAll("(unknown arch)"), |
| 912 | else => |RelocationType| try w.print( |
| 913 | "{t: <17} ", |
| 914 | .{@as(RelocationType, @enumFromInt(reloc.type))}, |
| 915 | ), |
| 916 | }, |
| 917 | } |
| 918 | |
| 919 | if (reloc.symbol_table_index >= symbol_names.items.len) |
| 920 | return failParse( |
| 921 | opts, |
| 922 | "reloc {x} in section {x} has out-of-bounds symbol index {x}", |
| 923 | .{ reloc_i, section_i + 1, reloc.symbol_table_index }, |
| 924 | ); |
| 925 | |
| 926 | try w.print("{x: >8} | {s}\n", .{ reloc.symbol_table_index, symbol_names.items[reloc.symbol_table_index] }); |
| 927 | } |
| 928 | try w.writeByte('\n'); |
| 929 | } |
| 930 | } |
| 789 | 931 | } |
| 790 | 932 | |
| 791 | 933 | fn headerName(raw: *const [8]u8, string_table: []const u8) ![]const u8 { |
| ... | ... | @@ -903,12 +1045,14 @@ const usage = |
| 903 | 1045 | \\ -h, --help Print this help and exit |
| 904 | 1046 | \\ --all-headers Alias for --file-headers --member-headers --section-headers --relocs --symbols |
| 905 | 1047 | \\ --file-headers Display file-format specific headers |
| 906 | | \\ --linker-member[=1|2] (Coff) Display contents of the specified linker member (default 2) |
| 1048 | \\ --imports Display imported symbols |
| 1049 | \\ --exports Display exported symbols |
| 1050 | \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified linker member (default 2) |
| 907 | 1051 | \\ --member-headers Display archive member headers |
| 908 | 1052 | \\ --only-member=[name] Only consider archive members that contain [name]. Can be specified multiple times. |
| 909 | 1053 | \\ --only-section=[name] Only consider sections that contain [name]. Can be specified multiple times. |
| 910 | 1054 | \\ --section-headers Display section headers |
| 911 | | \\ --strings Display string table |
| 1055 | \\ --strings Display string tables |
| 912 | 1056 | \\ --symbols Display symbol tables |
| 913 | 1057 | \\ --relocs Display relocations |
| 914 | 1058 | ; |