| ... | ... | @@ -701,9 +701,34 @@ const MachODumper = struct { |
| 701 | 701 | const ElfDumper = struct { |
| 702 | 702 | const symtab_label = "symtab"; |
| 703 | 703 | |
| 704 | | fn parseAndDump(step: *Step, bytes: []const u8, opts: Opts) ![]const u8 { |
| 705 | | _ = opts; |
| 704 | const Symtab = struct { |
| 705 | symbols: []align(1) const elf.Elf64_Sym, |
| 706 | strings: []const u8, |
| 707 | |
| 708 | fn get(st: Symtab, index: usize) ?elf.Elf64_Sym { |
| 709 | if (index >= st.symbols.len) return null; |
| 710 | return st.symbols[index]; |
| 711 | } |
| 712 | |
| 713 | fn getName(st: Symtab, index: usize) ?[]const u8 { |
| 714 | const sym = st.get(index) orelse return null; |
| 715 | assert(sym.st_name < st.strings.len); |
| 716 | return mem.sliceTo(@ptrCast(st.strings.ptr + sym.st_name), 0); |
| 717 | } |
| 718 | }; |
| 706 | 719 | |
| 720 | const Context = struct { |
| 721 | gpa: Allocator, |
| 722 | data: []const u8, |
| 723 | hdr: elf.Elf64_Ehdr, |
| 724 | shdrs: []align(1) const elf.Elf64_Shdr, |
| 725 | phdrs: []align(1) const elf.Elf64_Phdr, |
| 726 | shstrtab: []const u8, |
| 727 | symtab: ?Symtab = null, |
| 728 | dysymtab: ?Symtab = null, |
| 729 | }; |
| 730 | |
| 731 | fn parseAndDump(step: *Step, bytes: []const u8, opts: Opts) ![]const u8 { |
| 707 | 732 | const gpa = step.owner.allocator; |
| 708 | 733 | var stream = std.io.fixedBufferStream(bytes); |
| 709 | 734 | const reader = stream.reader(); |
| ... | ... | @@ -713,18 +738,124 @@ const ElfDumper = struct { |
| 713 | 738 | return error.InvalidMagicNumber; |
| 714 | 739 | } |
| 715 | 740 | |
| 741 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(bytes.ptr + hdr.e_shoff))[0..hdr.e_shnum]; |
| 742 | const phdrs = @as([*]align(1) const elf.Elf64_Phdr, @ptrCast(bytes.ptr + hdr.e_phoff))[0..hdr.e_phnum]; |
| 743 | |
| 744 | var ctx = Context{ |
| 745 | .gpa = gpa, |
| 746 | .data = bytes, |
| 747 | .hdr = hdr, |
| 748 | .shdrs = shdrs, |
| 749 | .phdrs = phdrs, |
| 750 | .shstrtab = undefined, |
| 751 | }; |
| 752 | ctx.shstrtab = getSectionContents(ctx, ctx.hdr.e_shstrndx); |
| 753 | |
| 754 | if (opts.dump_symtab) { |
| 755 | for (ctx.shdrs, 0..) |shdr, i| switch (shdr.sh_type) { |
| 756 | elf.SHT_SYMTAB, elf.SHT_DYNSYM => { |
| 757 | const raw = getSectionContents(ctx, i); |
| 758 | const nsyms = @divExact(raw.len, @sizeOf(elf.Elf64_Sym)); |
| 759 | const symbols = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw.ptr))[0..nsyms]; |
| 760 | const strings = getSectionContents(ctx, shdr.sh_link); |
| 761 | |
| 762 | switch (shdr.sh_type) { |
| 763 | elf.SHT_SYMTAB => { |
| 764 | ctx.symtab = .{ |
| 765 | .symbols = symbols, |
| 766 | .strings = strings, |
| 767 | }; |
| 768 | }, |
| 769 | elf.SHT_DYNSYM => { |
| 770 | ctx.dysymtab = .{ |
| 771 | .symbols = symbols, |
| 772 | .strings = strings, |
| 773 | }; |
| 774 | }, |
| 775 | else => unreachable, |
| 776 | } |
| 777 | }, |
| 778 | |
| 779 | else => {}, |
| 780 | }; |
| 781 | } |
| 782 | |
| 716 | 783 | var output = std.ArrayList(u8).init(gpa); |
| 717 | 784 | const writer = output.writer(); |
| 718 | 785 | |
| 719 | | try dumpHeader(hdr, writer); |
| 786 | try dumpHeader(ctx, writer); |
| 787 | try dumpShdrs(ctx, writer); |
| 720 | 788 | |
| 721 | 789 | return output.toOwnedSlice(); |
| 722 | 790 | } |
| 723 | 791 | |
| 724 | | fn dumpHeader(hdr: elf.Elf64_Ehdr, writer: anytype) !void { |
| 792 | fn getSectionName(ctx: Context, shndx: usize) []const u8 { |
| 793 | const shdr = ctx.shdrs[shndx]; |
| 794 | assert(shdr.sh_name < ctx.shstrtab.len); |
| 795 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(ctx.shstrtab.ptr + shdr.sh_name)), 0); |
| 796 | } |
| 797 | |
| 798 | fn getSectionContents(ctx: Context, shndx: usize) []const u8 { |
| 799 | const shdr = ctx.shdrs[shndx]; |
| 800 | assert(shdr.sh_offset < ctx.data.len); |
| 801 | assert(shdr.sh_offset + shdr.sh_size <= ctx.data.len); |
| 802 | return ctx.data[shdr.sh_offset..][0..shdr.sh_size]; |
| 803 | } |
| 804 | |
| 805 | fn dumpHeader(ctx: Context, writer: anytype) !void { |
| 725 | 806 | try writer.writeAll("header\n"); |
| 726 | | try writer.print("type {s}\n", .{@tagName(hdr.e_type)}); |
| 727 | | try writer.print("entry {x}\n", .{hdr.e_entry}); |
| 807 | try writer.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); |
| 808 | try writer.print("entry {x}\n", .{ctx.hdr.e_entry}); |
| 809 | } |
| 810 | |
| 811 | fn dumpShdrs(ctx: Context, writer: anytype) !void { |
| 812 | if (ctx.shdrs.len == 0) return; |
| 813 | |
| 814 | for (ctx.shdrs, 0..) |shdr, shndx| { |
| 815 | try writer.print("shdr {d}\n", .{shndx}); |
| 816 | try writer.print("name {s}\n", .{getSectionName(ctx, shndx)}); |
| 817 | try writer.print("type {s}\n", .{try fmtShType(ctx.gpa, shdr.sh_type)}); |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | fn fmtShType(gpa: Allocator, sh_type: u32) ![]const u8 { |
| 822 | return switch (sh_type) { |
| 823 | elf.SHT_NULL => "NULL", |
| 824 | elf.SHT_PROGBITS => "PROGBITS", |
| 825 | elf.SHT_SYMTAB => "SYMTAB", |
| 826 | elf.SHT_STRTAB => "STRTAB", |
| 827 | elf.SHT_RELA => "RELA", |
| 828 | elf.SHT_HASH => "HASH", |
| 829 | elf.SHT_DYNAMIC => "DYNAMIC", |
| 830 | elf.SHT_NOTE => "NOTE", |
| 831 | elf.SHT_NOBITS => "NOBITS", |
| 832 | elf.SHT_REL => "REL", |
| 833 | elf.SHT_SHLIB => "SHLIB", |
| 834 | elf.SHT_DYNSYM => "DYNSYM", |
| 835 | elf.SHT_INIT_ARRAY => "INIT_ARRAY", |
| 836 | elf.SHT_FINI_ARRAY => "FINI_ARRAY", |
| 837 | elf.SHT_PREINIT_ARRAY => "PREINIT_ARRAY", |
| 838 | elf.SHT_GROUP => "GROUP", |
| 839 | elf.SHT_SYMTAB_SHNDX => "SYMTAB_SHNDX", |
| 840 | elf.SHT_X86_64_UNWIND => "X86_64_UNWIND", |
| 841 | elf.SHT_LLVM_ADDRSIG => "LLVM_ADDRSIG", |
| 842 | elf.SHT_GNU_HASH => "GNU_HASH", |
| 843 | elf.SHT_GNU_VERDEF => "VERDEF", |
| 844 | elf.SHT_GNU_VERNEED => "VERNEED", |
| 845 | elf.SHT_GNU_VERSYM => "VERSYM", |
| 846 | else => |sht| blk: { |
| 847 | if (elf.SHT_LOOS <= sht and sht < elf.SHT_HIOS) { |
| 848 | break :blk try std.fmt.allocPrint(gpa, "LOOS+0x{x}", .{sht - elf.SHT_LOOS}); |
| 849 | } |
| 850 | if (elf.SHT_LOPROC <= sht and sht < elf.SHT_HIPROC) { |
| 851 | break :blk try std.fmt.allocPrint(gpa, "LOPROC+0x{x}", .{sht - elf.SHT_LOPROC}); |
| 852 | } |
| 853 | if (elf.SHT_LOUSER <= sht and sht < elf.SHT_HIUSER) { |
| 854 | break :blk try std.fmt.allocPrint(gpa, "LOUSER+0x{x}", .{sht - elf.SHT_LOUSER}); |
| 855 | } |
| 856 | break :blk "UNKNOWN"; |
| 857 | }, |
| 858 | }; |
| 728 | 859 | } |
| 729 | 860 | }; |
| 730 | 861 | |