| ... | ... | @@ -248,56 +248,63 @@ const ComputeCompareExpected = struct { |
| 248 | 248 | const Check = struct { |
| 249 | 249 | kind: Kind, |
| 250 | 250 | payload: Payload, |
| 251 | | data: std.ArrayList(u8), |
| 252 | | actions: std.ArrayList(Action), |
| 251 | allocator: Allocator, |
| 252 | data: std.ArrayListUnmanaged(u8), |
| 253 | actions: std.ArrayListUnmanaged(Action), |
| 253 | 254 | |
| 254 | 255 | fn create(allocator: Allocator, kind: Kind) Check { |
| 255 | 256 | return .{ |
| 256 | 257 | .kind = kind, |
| 257 | 258 | .payload = .{ .none = {} }, |
| 258 | | .data = std.ArrayList(u8).init(allocator), |
| 259 | | .actions = std.ArrayList(Action).init(allocator), |
| 259 | .allocator = allocator, |
| 260 | .data = .empty, |
| 261 | .actions = .empty, |
| 260 | 262 | }; |
| 261 | 263 | } |
| 262 | 264 | |
| 263 | | fn dumpSection(allocator: Allocator, name: [:0]const u8) Check { |
| 264 | | var check = Check.create(allocator, .dump_section); |
| 265 | fn dumpSection(gpa: Allocator, name: [:0]const u8) Check { |
| 266 | var check = Check.create(gpa, .dump_section); |
| 265 | 267 | const off: u32 = @intCast(check.data.items.len); |
| 266 | | check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM"); |
| 268 | check.data.print(gpa, "{s}\x00", .{name}) catch @panic("OOM"); |
| 267 | 269 | check.payload = .{ .dump_section = off }; |
| 268 | 270 | return check; |
| 269 | 271 | } |
| 270 | 272 | |
| 271 | 273 | fn extract(check: *Check, phrase: SearchPhrase) void { |
| 272 | | check.actions.append(.{ |
| 274 | const gpa = check.allocator; |
| 275 | check.actions.append(gpa, .{ |
| 273 | 276 | .tag = .extract, |
| 274 | 277 | .phrase = phrase, |
| 275 | 278 | }) catch @panic("OOM"); |
| 276 | 279 | } |
| 277 | 280 | |
| 278 | 281 | fn exact(check: *Check, phrase: SearchPhrase) void { |
| 279 | | check.actions.append(.{ |
| 282 | const gpa = check.allocator; |
| 283 | check.actions.append(gpa, .{ |
| 280 | 284 | .tag = .exact, |
| 281 | 285 | .phrase = phrase, |
| 282 | 286 | }) catch @panic("OOM"); |
| 283 | 287 | } |
| 284 | 288 | |
| 285 | 289 | fn contains(check: *Check, phrase: SearchPhrase) void { |
| 286 | | check.actions.append(.{ |
| 290 | const gpa = check.allocator; |
| 291 | check.actions.append(gpa, .{ |
| 287 | 292 | .tag = .contains, |
| 288 | 293 | .phrase = phrase, |
| 289 | 294 | }) catch @panic("OOM"); |
| 290 | 295 | } |
| 291 | 296 | |
| 292 | 297 | fn notPresent(check: *Check, phrase: SearchPhrase) void { |
| 293 | | check.actions.append(.{ |
| 298 | const gpa = check.allocator; |
| 299 | check.actions.append(gpa, .{ |
| 294 | 300 | .tag = .not_present, |
| 295 | 301 | .phrase = phrase, |
| 296 | 302 | }) catch @panic("OOM"); |
| 297 | 303 | } |
| 298 | 304 | |
| 299 | 305 | fn computeCmp(check: *Check, phrase: SearchPhrase, expected: ComputeCompareExpected) void { |
| 300 | | check.actions.append(.{ |
| 306 | const gpa = check.allocator; |
| 307 | check.actions.append(gpa, .{ |
| 301 | 308 | .tag = .compute_cmp, |
| 302 | 309 | .phrase = phrase, |
| 303 | 310 | .expected = expected, |
| ... | ... | @@ -810,7 +817,7 @@ const MachODumper = struct { |
| 810 | 817 | return null; |
| 811 | 818 | } |
| 812 | 819 | |
| 813 | | fn dumpHeader(hdr: macho.mach_header_64, writer: anytype) !void { |
| 820 | fn dumpHeader(hdr: macho.mach_header_64, bw: *std.io.BufferedWriter) !void { |
| 814 | 821 | const cputype = switch (hdr.cputype) { |
| 815 | 822 | macho.CPU_TYPE_ARM64 => "ARM64", |
| 816 | 823 | macho.CPU_TYPE_X86_64 => "X86_64", |
| ... | ... | @@ -831,7 +838,7 @@ const MachODumper = struct { |
| 831 | 838 | else => "Unknown", |
| 832 | 839 | }; |
| 833 | 840 | |
| 834 | | try writer.print( |
| 841 | try bw.print( |
| 835 | 842 | \\header |
| 836 | 843 | \\cputype {s} |
| 837 | 844 | \\filetype {s} |
| ... | ... | @@ -846,41 +853,41 @@ const MachODumper = struct { |
| 846 | 853 | }); |
| 847 | 854 | |
| 848 | 855 | if (hdr.flags > 0) { |
| 849 | | if (hdr.flags & macho.MH_NOUNDEFS != 0) try writer.writeAll(" NOUNDEFS"); |
| 850 | | if (hdr.flags & macho.MH_INCRLINK != 0) try writer.writeAll(" INCRLINK"); |
| 851 | | if (hdr.flags & macho.MH_DYLDLINK != 0) try writer.writeAll(" DYLDLINK"); |
| 852 | | if (hdr.flags & macho.MH_BINDATLOAD != 0) try writer.writeAll(" BINDATLOAD"); |
| 853 | | if (hdr.flags & macho.MH_PREBOUND != 0) try writer.writeAll(" PREBOUND"); |
| 854 | | if (hdr.flags & macho.MH_SPLIT_SEGS != 0) try writer.writeAll(" SPLIT_SEGS"); |
| 855 | | if (hdr.flags & macho.MH_LAZY_INIT != 0) try writer.writeAll(" LAZY_INIT"); |
| 856 | | if (hdr.flags & macho.MH_TWOLEVEL != 0) try writer.writeAll(" TWOLEVEL"); |
| 857 | | if (hdr.flags & macho.MH_FORCE_FLAT != 0) try writer.writeAll(" FORCE_FLAT"); |
| 858 | | if (hdr.flags & macho.MH_NOMULTIDEFS != 0) try writer.writeAll(" NOMULTIDEFS"); |
| 859 | | if (hdr.flags & macho.MH_NOFIXPREBINDING != 0) try writer.writeAll(" NOFIXPREBINDING"); |
| 860 | | if (hdr.flags & macho.MH_PREBINDABLE != 0) try writer.writeAll(" PREBINDABLE"); |
| 861 | | if (hdr.flags & macho.MH_ALLMODSBOUND != 0) try writer.writeAll(" ALLMODSBOUND"); |
| 862 | | if (hdr.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) try writer.writeAll(" SUBSECTIONS_VIA_SYMBOLS"); |
| 863 | | if (hdr.flags & macho.MH_CANONICAL != 0) try writer.writeAll(" CANONICAL"); |
| 864 | | if (hdr.flags & macho.MH_WEAK_DEFINES != 0) try writer.writeAll(" WEAK_DEFINES"); |
| 865 | | if (hdr.flags & macho.MH_BINDS_TO_WEAK != 0) try writer.writeAll(" BINDS_TO_WEAK"); |
| 866 | | if (hdr.flags & macho.MH_ALLOW_STACK_EXECUTION != 0) try writer.writeAll(" ALLOW_STACK_EXECUTION"); |
| 867 | | if (hdr.flags & macho.MH_ROOT_SAFE != 0) try writer.writeAll(" ROOT_SAFE"); |
| 868 | | if (hdr.flags & macho.MH_SETUID_SAFE != 0) try writer.writeAll(" SETUID_SAFE"); |
| 869 | | if (hdr.flags & macho.MH_NO_REEXPORTED_DYLIBS != 0) try writer.writeAll(" NO_REEXPORTED_DYLIBS"); |
| 870 | | if (hdr.flags & macho.MH_PIE != 0) try writer.writeAll(" PIE"); |
| 871 | | if (hdr.flags & macho.MH_DEAD_STRIPPABLE_DYLIB != 0) try writer.writeAll(" DEAD_STRIPPABLE_DYLIB"); |
| 872 | | if (hdr.flags & macho.MH_HAS_TLV_DESCRIPTORS != 0) try writer.writeAll(" HAS_TLV_DESCRIPTORS"); |
| 873 | | if (hdr.flags & macho.MH_NO_HEAP_EXECUTION != 0) try writer.writeAll(" NO_HEAP_EXECUTION"); |
| 874 | | if (hdr.flags & macho.MH_APP_EXTENSION_SAFE != 0) try writer.writeAll(" APP_EXTENSION_SAFE"); |
| 875 | | if (hdr.flags & macho.MH_NLIST_OUTOFSYNC_WITH_DYLDINFO != 0) try writer.writeAll(" NLIST_OUTOFSYNC_WITH_DYLDINFO"); |
| 856 | if (hdr.flags & macho.MH_NOUNDEFS != 0) try bw.writeAll(" NOUNDEFS"); |
| 857 | if (hdr.flags & macho.MH_INCRLINK != 0) try bw.writeAll(" INCRLINK"); |
| 858 | if (hdr.flags & macho.MH_DYLDLINK != 0) try bw.writeAll(" DYLDLINK"); |
| 859 | if (hdr.flags & macho.MH_BINDATLOAD != 0) try bw.writeAll(" BINDATLOAD"); |
| 860 | if (hdr.flags & macho.MH_PREBOUND != 0) try bw.writeAll(" PREBOUND"); |
| 861 | if (hdr.flags & macho.MH_SPLIT_SEGS != 0) try bw.writeAll(" SPLIT_SEGS"); |
| 862 | if (hdr.flags & macho.MH_LAZY_INIT != 0) try bw.writeAll(" LAZY_INIT"); |
| 863 | if (hdr.flags & macho.MH_TWOLEVEL != 0) try bw.writeAll(" TWOLEVEL"); |
| 864 | if (hdr.flags & macho.MH_FORCE_FLAT != 0) try bw.writeAll(" FORCE_FLAT"); |
| 865 | if (hdr.flags & macho.MH_NOMULTIDEFS != 0) try bw.writeAll(" NOMULTIDEFS"); |
| 866 | if (hdr.flags & macho.MH_NOFIXPREBINDING != 0) try bw.writeAll(" NOFIXPREBINDING"); |
| 867 | if (hdr.flags & macho.MH_PREBINDABLE != 0) try bw.writeAll(" PREBINDABLE"); |
| 868 | if (hdr.flags & macho.MH_ALLMODSBOUND != 0) try bw.writeAll(" ALLMODSBOUND"); |
| 869 | if (hdr.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) try bw.writeAll(" SUBSECTIONS_VIA_SYMBOLS"); |
| 870 | if (hdr.flags & macho.MH_CANONICAL != 0) try bw.writeAll(" CANONICAL"); |
| 871 | if (hdr.flags & macho.MH_WEAK_DEFINES != 0) try bw.writeAll(" WEAK_DEFINES"); |
| 872 | if (hdr.flags & macho.MH_BINDS_TO_WEAK != 0) try bw.writeAll(" BINDS_TO_WEAK"); |
| 873 | if (hdr.flags & macho.MH_ALLOW_STACK_EXECUTION != 0) try bw.writeAll(" ALLOW_STACK_EXECUTION"); |
| 874 | if (hdr.flags & macho.MH_ROOT_SAFE != 0) try bw.writeAll(" ROOT_SAFE"); |
| 875 | if (hdr.flags & macho.MH_SETUID_SAFE != 0) try bw.writeAll(" SETUID_SAFE"); |
| 876 | if (hdr.flags & macho.MH_NO_REEXPORTED_DYLIBS != 0) try bw.writeAll(" NO_REEXPORTED_DYLIBS"); |
| 877 | if (hdr.flags & macho.MH_PIE != 0) try bw.writeAll(" PIE"); |
| 878 | if (hdr.flags & macho.MH_DEAD_STRIPPABLE_DYLIB != 0) try bw.writeAll(" DEAD_STRIPPABLE_DYLIB"); |
| 879 | if (hdr.flags & macho.MH_HAS_TLV_DESCRIPTORS != 0) try bw.writeAll(" HAS_TLV_DESCRIPTORS"); |
| 880 | if (hdr.flags & macho.MH_NO_HEAP_EXECUTION != 0) try bw.writeAll(" NO_HEAP_EXECUTION"); |
| 881 | if (hdr.flags & macho.MH_APP_EXTENSION_SAFE != 0) try bw.writeAll(" APP_EXTENSION_SAFE"); |
| 882 | if (hdr.flags & macho.MH_NLIST_OUTOFSYNC_WITH_DYLDINFO != 0) try bw.writeAll(" NLIST_OUTOFSYNC_WITH_DYLDINFO"); |
| 876 | 883 | } |
| 877 | 884 | |
| 878 | | try writer.writeByte('\n'); |
| 885 | try bw.writeByte('\n'); |
| 879 | 886 | } |
| 880 | 887 | |
| 881 | | fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, writer: anytype) !void { |
| 888 | fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, bw: *std.io.BufferedWriter) !void { |
| 882 | 889 | // print header first |
| 883 | | try writer.print( |
| 890 | try bw.print( |
| 884 | 891 | \\LC {d} |
| 885 | 892 | \\cmd {s} |
| 886 | 893 | \\cmdsize {d} |
| ... | ... | @@ -889,8 +896,8 @@ const MachODumper = struct { |
| 889 | 896 | switch (lc.cmd()) { |
| 890 | 897 | .SEGMENT_64 => { |
| 891 | 898 | const seg = lc.cast(macho.segment_command_64).?; |
| 892 | | try writer.writeByte('\n'); |
| 893 | | try writer.print( |
| 899 | try bw.writeByte('\n'); |
| 900 | try bw.print( |
| 894 | 901 | \\segname {s} |
| 895 | 902 | \\vmaddr {x} |
| 896 | 903 | \\vmsize {x} |
| ... | ... | @@ -905,8 +912,8 @@ const MachODumper = struct { |
| 905 | 912 | }); |
| 906 | 913 | |
| 907 | 914 | for (lc.getSections()) |sect| { |
| 908 | | try writer.writeByte('\n'); |
| 909 | | try writer.print( |
| 915 | try bw.writeByte('\n'); |
| 916 | try bw.print( |
| 910 | 917 | \\sectname {s} |
| 911 | 918 | \\addr {x} |
| 912 | 919 | \\size {x} |
| ... | ... | @@ -928,8 +935,8 @@ const MachODumper = struct { |
| 928 | 935 | .REEXPORT_DYLIB, |
| 929 | 936 | => { |
| 930 | 937 | const dylib = lc.cast(macho.dylib_command).?; |
| 931 | | try writer.writeByte('\n'); |
| 932 | | try writer.print( |
| 938 | try bw.writeByte('\n'); |
| 939 | try bw.print( |
| 933 | 940 | \\name {s} |
| 934 | 941 | \\timestamp {d} |
| 935 | 942 | \\current version {x} |
| ... | ... | @@ -944,16 +951,16 @@ const MachODumper = struct { |
| 944 | 951 | |
| 945 | 952 | .MAIN => { |
| 946 | 953 | const main = lc.cast(macho.entry_point_command).?; |
| 947 | | try writer.writeByte('\n'); |
| 948 | | try writer.print( |
| 954 | try bw.writeByte('\n'); |
| 955 | try bw.print( |
| 949 | 956 | \\entryoff {x} |
| 950 | 957 | \\stacksize {x} |
| 951 | 958 | , .{ main.entryoff, main.stacksize }); |
| 952 | 959 | }, |
| 953 | 960 | |
| 954 | 961 | .RPATH => { |
| 955 | | try writer.writeByte('\n'); |
| 956 | | try writer.print( |
| 962 | try bw.writeByte('\n'); |
| 963 | try bw.print( |
| 957 | 964 | \\path {s} |
| 958 | 965 | , .{ |
| 959 | 966 | lc.getRpathPathName(), |
| ... | ... | @@ -962,8 +969,8 @@ const MachODumper = struct { |
| 962 | 969 | |
| 963 | 970 | .UUID => { |
| 964 | 971 | const uuid = lc.cast(macho.uuid_command).?; |
| 965 | | try writer.writeByte('\n'); |
| 966 | | try writer.print("uuid {x}", .{&uuid.uuid}); |
| 972 | try bw.writeByte('\n'); |
| 973 | try bw.print("uuid {x}", .{&uuid.uuid}); |
| 967 | 974 | }, |
| 968 | 975 | |
| 969 | 976 | .DATA_IN_CODE, |
| ... | ... | @@ -971,8 +978,8 @@ const MachODumper = struct { |
| 971 | 978 | .CODE_SIGNATURE, |
| 972 | 979 | => { |
| 973 | 980 | const llc = lc.cast(macho.linkedit_data_command).?; |
| 974 | | try writer.writeByte('\n'); |
| 975 | | try writer.print( |
| 981 | try bw.writeByte('\n'); |
| 982 | try bw.print( |
| 976 | 983 | \\dataoff {x} |
| 977 | 984 | \\datasize {x} |
| 978 | 985 | , .{ llc.dataoff, llc.datasize }); |
| ... | ... | @@ -980,8 +987,8 @@ const MachODumper = struct { |
| 980 | 987 | |
| 981 | 988 | .DYLD_INFO_ONLY => { |
| 982 | 989 | const dlc = lc.cast(macho.dyld_info_command).?; |
| 983 | | try writer.writeByte('\n'); |
| 984 | | try writer.print( |
| 990 | try bw.writeByte('\n'); |
| 991 | try bw.print( |
| 985 | 992 | \\rebaseoff {x} |
| 986 | 993 | \\rebasesize {x} |
| 987 | 994 | \\bindoff {x} |
| ... | ... | @@ -1008,8 +1015,8 @@ const MachODumper = struct { |
| 1008 | 1015 | |
| 1009 | 1016 | .SYMTAB => { |
| 1010 | 1017 | const slc = lc.cast(macho.symtab_command).?; |
| 1011 | | try writer.writeByte('\n'); |
| 1012 | | try writer.print( |
| 1018 | try bw.writeByte('\n'); |
| 1019 | try bw.print( |
| 1013 | 1020 | \\symoff {x} |
| 1014 | 1021 | \\nsyms {x} |
| 1015 | 1022 | \\stroff {x} |
| ... | ... | @@ -1024,8 +1031,8 @@ const MachODumper = struct { |
| 1024 | 1031 | |
| 1025 | 1032 | .DYSYMTAB => { |
| 1026 | 1033 | const dlc = lc.cast(macho.dysymtab_command).?; |
| 1027 | | try writer.writeByte('\n'); |
| 1028 | | try writer.print( |
| 1034 | try bw.writeByte('\n'); |
| 1035 | try bw.print( |
| 1029 | 1036 | \\ilocalsym {x} |
| 1030 | 1037 | \\nlocalsym {x} |
| 1031 | 1038 | \\iextdefsym {x} |
| ... | ... | @@ -1048,8 +1055,8 @@ const MachODumper = struct { |
| 1048 | 1055 | |
| 1049 | 1056 | .BUILD_VERSION => { |
| 1050 | 1057 | const blc = lc.cast(macho.build_version_command).?; |
| 1051 | | try writer.writeByte('\n'); |
| 1052 | | try writer.print( |
| 1058 | try bw.writeByte('\n'); |
| 1059 | try bw.print( |
| 1053 | 1060 | \\platform {s} |
| 1054 | 1061 | \\minos {d}.{d}.{d} |
| 1055 | 1062 | \\sdk {d}.{d}.{d} |
| ... | ... | @@ -1065,12 +1072,12 @@ const MachODumper = struct { |
| 1065 | 1072 | blc.ntools, |
| 1066 | 1073 | }); |
| 1067 | 1074 | for (lc.getBuildVersionTools()) |tool| { |
| 1068 | | try writer.writeByte('\n'); |
| 1075 | try bw.writeByte('\n'); |
| 1069 | 1076 | switch (tool.tool) { |
| 1070 | | .CLANG, .SWIFT, .LD, .LLD, .ZIG => try writer.print("tool {s}\n", .{@tagName(tool.tool)}), |
| 1071 | | else => |x| try writer.print("tool {d}\n", .{@intFromEnum(x)}), |
| 1077 | .CLANG, .SWIFT, .LD, .LLD, .ZIG => try bw.print("tool {s}\n", .{@tagName(tool.tool)}), |
| 1078 | else => |x| try bw.print("tool {d}\n", .{@intFromEnum(x)}), |
| 1072 | 1079 | } |
| 1073 | | try writer.print( |
| 1080 | try bw.print( |
| 1074 | 1081 | \\version {d}.{d}.{d} |
| 1075 | 1082 | , .{ |
| 1076 | 1083 | tool.version >> 16, |
| ... | ... | @@ -1086,8 +1093,8 @@ const MachODumper = struct { |
| 1086 | 1093 | .VERSION_MIN_TVOS, |
| 1087 | 1094 | => { |
| 1088 | 1095 | const vlc = lc.cast(macho.version_min_command).?; |
| 1089 | | try writer.writeByte('\n'); |
| 1090 | | try writer.print( |
| 1096 | try bw.writeByte('\n'); |
| 1097 | try bw.print( |
| 1091 | 1098 | \\version {d}.{d}.{d} |
| 1092 | 1099 | \\sdk {d}.{d}.{d} |
| 1093 | 1100 | , .{ |
| ... | ... | @@ -1104,8 +1111,8 @@ const MachODumper = struct { |
| 1104 | 1111 | } |
| 1105 | 1112 | } |
| 1106 | 1113 | |
| 1107 | | fn dumpSymtab(ctx: ObjectContext, writer: anytype) !void { |
| 1108 | | try writer.writeAll(symtab_label ++ "\n"); |
| 1114 | fn dumpSymtab(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { |
| 1115 | try bw.writeAll(symtab_label ++ "\n"); |
| 1109 | 1116 | |
| 1110 | 1117 | for (ctx.symtab.items) |sym| { |
| 1111 | 1118 | const sym_name = ctx.getString(sym.n_strx); |
| ... | ... | @@ -1120,32 +1127,32 @@ const MachODumper = struct { |
| 1120 | 1127 | macho.N_STSYM => "STSYM", |
| 1121 | 1128 | else => "UNKNOWN STAB", |
| 1122 | 1129 | }; |
| 1123 | | try writer.print("{x}", .{sym.n_value}); |
| 1130 | try bw.print("{x}", .{sym.n_value}); |
| 1124 | 1131 | if (sym.n_sect > 0) { |
| 1125 | 1132 | const sect = ctx.sections.items[sym.n_sect - 1]; |
| 1126 | | try writer.print(" ({s},{s})", .{ sect.segName(), sect.sectName() }); |
| 1133 | try bw.print(" ({s},{s})", .{ sect.segName(), sect.sectName() }); |
| 1127 | 1134 | } |
| 1128 | | try writer.print(" {s} (stab) {s}\n", .{ tt, sym_name }); |
| 1135 | try bw.print(" {s} (stab) {s}\n", .{ tt, sym_name }); |
| 1129 | 1136 | } else if (sym.sect()) { |
| 1130 | 1137 | const sect = ctx.sections.items[sym.n_sect - 1]; |
| 1131 | | try writer.print("{x} ({s},{s})", .{ |
| 1138 | try bw.print("{x} ({s},{s})", .{ |
| 1132 | 1139 | sym.n_value, |
| 1133 | 1140 | sect.segName(), |
| 1134 | 1141 | sect.sectName(), |
| 1135 | 1142 | }); |
| 1136 | | if (sym.n_desc & macho.REFERENCED_DYNAMICALLY != 0) try writer.writeAll(" [referenced dynamically]"); |
| 1137 | | if (sym.weakDef()) try writer.writeAll(" weak"); |
| 1138 | | if (sym.weakRef()) try writer.writeAll(" weakref"); |
| 1143 | if (sym.n_desc & macho.REFERENCED_DYNAMICALLY != 0) try bw.writeAll(" [referenced dynamically]"); |
| 1144 | if (sym.weakDef()) try bw.writeAll(" weak"); |
| 1145 | if (sym.weakRef()) try bw.writeAll(" weakref"); |
| 1139 | 1146 | if (sym.ext()) { |
| 1140 | | if (sym.pext()) try writer.writeAll(" private"); |
| 1141 | | try writer.writeAll(" external"); |
| 1142 | | } else if (sym.pext()) try writer.writeAll(" (was private external)"); |
| 1143 | | try writer.print(" {s}\n", .{sym_name}); |
| 1147 | if (sym.pext()) try bw.writeAll(" private"); |
| 1148 | try bw.writeAll(" external"); |
| 1149 | } else if (sym.pext()) try bw.writeAll(" (was private external)"); |
| 1150 | try bw.print(" {s}\n", .{sym_name}); |
| 1144 | 1151 | } else if (sym.tentative()) { |
| 1145 | 1152 | const alignment = (sym.n_desc >> 8) & 0x0F; |
| 1146 | | try writer.print(" 0x{x:0>16} (common) (alignment 2^{d})", .{ sym.n_value, alignment }); |
| 1147 | | if (sym.ext()) try writer.writeAll(" external"); |
| 1148 | | try writer.print(" {s}\n", .{sym_name}); |
| 1153 | try bw.print(" 0x{x:0>16} (common) (alignment 2^{d})", .{ sym.n_value, alignment }); |
| 1154 | if (sym.ext()) try bw.writeAll(" external"); |
| 1155 | try bw.print(" {s}\n", .{sym_name}); |
| 1149 | 1156 | } else if (sym.undf()) { |
| 1150 | 1157 | const ordinal = @divFloor(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER); |
| 1151 | 1158 | const import_name = blk: { |
| ... | ... | @@ -1164,10 +1171,10 @@ const MachODumper = struct { |
| 1164 | 1171 | const ext = mem.lastIndexOfScalar(u8, basename, '.') orelse basename.len; |
| 1165 | 1172 | break :blk basename[0..ext]; |
| 1166 | 1173 | }; |
| 1167 | | try writer.writeAll("(undefined)"); |
| 1168 | | if (sym.weakRef()) try writer.writeAll(" weakref"); |
| 1169 | | if (sym.ext()) try writer.writeAll(" external"); |
| 1170 | | try writer.print(" {s} (from {s})\n", .{ |
| 1174 | try bw.writeAll("(undefined)"); |
| 1175 | if (sym.weakRef()) try bw.writeAll(" weakref"); |
| 1176 | if (sym.ext()) try bw.writeAll(" external"); |
| 1177 | try bw.print(" {s} (from {s})\n", .{ |
| 1171 | 1178 | sym_name, |
| 1172 | 1179 | import_name, |
| 1173 | 1180 | }); |
| ... | ... | @@ -1175,8 +1182,8 @@ const MachODumper = struct { |
| 1175 | 1182 | } |
| 1176 | 1183 | } |
| 1177 | 1184 | |
| 1178 | | fn dumpIndirectSymtab(ctx: ObjectContext, writer: anytype) !void { |
| 1179 | | try writer.writeAll(indirect_symtab_label ++ "\n"); |
| 1185 | fn dumpIndirectSymtab(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { |
| 1186 | try bw.writeAll(indirect_symtab_label ++ "\n"); |
| 1180 | 1187 | |
| 1181 | 1188 | var sects_buffer: [3]macho.section_64 = undefined; |
| 1182 | 1189 | const sects = blk: { |
| ... | ... | @@ -1214,23 +1221,23 @@ const MachODumper = struct { |
| 1214 | 1221 | break :blk @sizeOf(u64); |
| 1215 | 1222 | }; |
| 1216 | 1223 | |
| 1217 | | try writer.print("{s},{s}\n", .{ sect.segName(), sect.sectName() }); |
| 1218 | | try writer.print("nentries {d}\n", .{end - start}); |
| 1224 | try bw.print("{s},{s}\n", .{ sect.segName(), sect.sectName() }); |
| 1225 | try bw.print("nentries {d}\n", .{end - start}); |
| 1219 | 1226 | for (ctx.indsymtab.items[start..end], 0..) |index, j| { |
| 1220 | 1227 | const sym = ctx.symtab.items[index]; |
| 1221 | 1228 | const addr = sect.addr + entry_size * j; |
| 1222 | | try writer.print("0x{x} {d} {s}\n", .{ addr, index, ctx.getString(sym.n_strx) }); |
| 1229 | try bw.print("0x{x} {d} {s}\n", .{ addr, index, ctx.getString(sym.n_strx) }); |
| 1223 | 1230 | } |
| 1224 | 1231 | } |
| 1225 | 1232 | } |
| 1226 | 1233 | |
| 1227 | | fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, writer: anytype) !void { |
| 1234 | fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { |
| 1228 | 1235 | var rebases = std.ArrayList(u64).init(ctx.gpa); |
| 1229 | 1236 | defer rebases.deinit(); |
| 1230 | 1237 | try ctx.parseRebaseInfo(data, &rebases); |
| 1231 | 1238 | mem.sort(u64, rebases.items, {}, std.sort.asc(u64)); |
| 1232 | 1239 | for (rebases.items) |addr| { |
| 1233 | | try writer.print("0x{x}\n", .{addr}); |
| 1240 | try bw.print("0x{x}\n", .{addr}); |
| 1234 | 1241 | } |
| 1235 | 1242 | } |
| 1236 | 1243 | |
| ... | ... | @@ -1323,7 +1330,7 @@ const MachODumper = struct { |
| 1323 | 1330 | }; |
| 1324 | 1331 | }; |
| 1325 | 1332 | |
| 1326 | | fn dumpBindInfo(ctx: ObjectContext, data: []const u8, writer: anytype) !void { |
| 1333 | fn dumpBindInfo(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { |
| 1327 | 1334 | var bindings = std.ArrayList(Binding).init(ctx.gpa); |
| 1328 | 1335 | defer { |
| 1329 | 1336 | for (bindings.items) |*b| { |
| ... | ... | @@ -1334,15 +1341,15 @@ const MachODumper = struct { |
| 1334 | 1341 | try ctx.parseBindInfo(data, &bindings); |
| 1335 | 1342 | mem.sort(Binding, bindings.items, {}, Binding.lessThan); |
| 1336 | 1343 | for (bindings.items) |binding| { |
| 1337 | | try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); |
| 1338 | | try writer.writeAll(" ("); |
| 1344 | try bw.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); |
| 1345 | try bw.writeAll(" ("); |
| 1339 | 1346 | switch (binding.tag) { |
| 1340 | | .self => try writer.writeAll("self"), |
| 1341 | | .exe => try writer.writeAll("main executable"), |
| 1342 | | .flat => try writer.writeAll("flat lookup"), |
| 1343 | | .ord => try writer.writeAll(std.fs.path.basename(ctx.imports.items[binding.ordinal - 1])), |
| 1347 | .self => try bw.writeAll("self"), |
| 1348 | .exe => try bw.writeAll("main executable"), |
| 1349 | .flat => try bw.writeAll("flat lookup"), |
| 1350 | .ord => try bw.writeAll(std.fs.path.basename(ctx.imports.items[binding.ordinal - 1])), |
| 1344 | 1351 | } |
| 1345 | | try writer.print(") {s}\n", .{binding.name}); |
| 1352 | try bw.print(") {s}\n", .{binding.name}); |
| 1346 | 1353 | } |
| 1347 | 1354 | } |
| 1348 | 1355 | |
| ... | ... | @@ -1439,7 +1446,7 @@ const MachODumper = struct { |
| 1439 | 1446 | } |
| 1440 | 1447 | } |
| 1441 | 1448 | |
| 1442 | | fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, writer: anytype) !void { |
| 1449 | fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, bw: *std.io.BufferedWriter) !void { |
| 1443 | 1450 | const seg = ctx.getSegmentByName("__TEXT") orelse return; |
| 1444 | 1451 | |
| 1445 | 1452 | var arena = std.heap.ArenaAllocator.init(ctx.gpa); |
| ... | ... | @@ -1456,23 +1463,23 @@ const MachODumper = struct { |
| 1456 | 1463 | .@"export" => { |
| 1457 | 1464 | const info = exp.data.@"export"; |
| 1458 | 1465 | if (info.kind != .regular or info.weak) { |
| 1459 | | try writer.writeByte('['); |
| 1466 | try bw.writeByte('['); |
| 1460 | 1467 | } |
| 1461 | 1468 | switch (info.kind) { |
| 1462 | 1469 | .regular => {}, |
| 1463 | | .absolute => try writer.writeAll("ABS, "), |
| 1464 | | .tlv => try writer.writeAll("THREAD_LOCAL, "), |
| 1470 | .absolute => try bw.writeAll("ABS, "), |
| 1471 | .tlv => try bw.writeAll("THREAD_LOCAL, "), |
| 1465 | 1472 | } |
| 1466 | | if (info.weak) try writer.writeAll("WEAK"); |
| 1473 | if (info.weak) try bw.writeAll("WEAK"); |
| 1467 | 1474 | if (info.kind != .regular or info.weak) { |
| 1468 | | try writer.writeAll("] "); |
| 1475 | try bw.writeAll("] "); |
| 1469 | 1476 | } |
| 1470 | | try writer.print("{x} ", .{seg.vmaddr + info.vmoffset}); |
| 1477 | try bw.print("{x} ", .{seg.vmaddr + info.vmoffset}); |
| 1471 | 1478 | }, |
| 1472 | 1479 | else => {}, |
| 1473 | 1480 | } |
| 1474 | 1481 | |
| 1475 | | try writer.print("{s}\n", .{exp.name}); |
| 1482 | try bw.print("{s}\n", .{exp.name}); |
| 1476 | 1483 | } |
| 1477 | 1484 | } |
| 1478 | 1485 | |
| ... | ... | @@ -1616,9 +1623,9 @@ const MachODumper = struct { |
| 1616 | 1623 | } |
| 1617 | 1624 | } |
| 1618 | 1625 | |
| 1619 | | fn dumpSection(ctx: ObjectContext, sect: macho.section_64, writer: anytype) !void { |
| 1626 | fn dumpSection(ctx: ObjectContext, sect: macho.section_64, bw: *std.io.BufferedWriter) !void { |
| 1620 | 1627 | const data = ctx.data[sect.offset..][0..sect.size]; |
| 1621 | | try writer.print("{s}", .{data}); |
| 1628 | try bw.print("{s}", .{data}); |
| 1622 | 1629 | } |
| 1623 | 1630 | }; |
| 1624 | 1631 | |
| ... | ... | @@ -1632,29 +1639,29 @@ const MachODumper = struct { |
| 1632 | 1639 | var ctx = ObjectContext{ .gpa = gpa, .data = bytes, .header = hdr }; |
| 1633 | 1640 | try ctx.parse(); |
| 1634 | 1641 | |
| 1635 | | var output = std.ArrayList(u8).init(gpa); |
| 1636 | | const writer = output.writer(); |
| 1642 | var output: std.io.AllocatingWriter = undefined; |
| 1643 | const bw = output.init(gpa); |
| 1637 | 1644 | |
| 1638 | 1645 | switch (check.kind) { |
| 1639 | 1646 | .headers => { |
| 1640 | | try ObjectContext.dumpHeader(ctx.header, writer); |
| 1647 | try ObjectContext.dumpHeader(ctx.header, bw); |
| 1641 | 1648 | |
| 1642 | 1649 | var it = ctx.getLoadCommandIterator(); |
| 1643 | 1650 | var i: usize = 0; |
| 1644 | 1651 | while (it.next()) |cmd| { |
| 1645 | | try ObjectContext.dumpLoadCommand(cmd, i, writer); |
| 1646 | | try writer.writeByte('\n'); |
| 1652 | try ObjectContext.dumpLoadCommand(cmd, i, bw); |
| 1653 | try bw.writeByte('\n'); |
| 1647 | 1654 | |
| 1648 | 1655 | i += 1; |
| 1649 | 1656 | } |
| 1650 | 1657 | }, |
| 1651 | 1658 | |
| 1652 | 1659 | .symtab => if (ctx.symtab.items.len > 0) { |
| 1653 | | try ctx.dumpSymtab(writer); |
| 1660 | try ctx.dumpSymtab(bw); |
| 1654 | 1661 | } else return step.fail("no symbol table found", .{}), |
| 1655 | 1662 | |
| 1656 | 1663 | .indirect_symtab => if (ctx.symtab.items.len > 0 and ctx.indsymtab.items.len > 0) { |
| 1657 | | try ctx.dumpIndirectSymtab(writer); |
| 1664 | try ctx.dumpIndirectSymtab(bw); |
| 1658 | 1665 | } else return step.fail("no indirect symbol table found", .{}), |
| 1659 | 1666 | |
| 1660 | 1667 | .dyld_rebase, |
| ... | ... | @@ -1669,26 +1676,26 @@ const MachODumper = struct { |
| 1669 | 1676 | switch (check.kind) { |
| 1670 | 1677 | .dyld_rebase => if (lc.rebase_size > 0) { |
| 1671 | 1678 | const data = ctx.data[lc.rebase_off..][0..lc.rebase_size]; |
| 1672 | | try writer.writeAll(dyld_rebase_label ++ "\n"); |
| 1673 | | try ctx.dumpRebaseInfo(data, writer); |
| 1679 | try bw.writeAll(dyld_rebase_label ++ "\n"); |
| 1680 | try ctx.dumpRebaseInfo(data, bw); |
| 1674 | 1681 | } else return step.fail("no rebase data found", .{}), |
| 1675 | 1682 | |
| 1676 | 1683 | .dyld_bind => if (lc.bind_size > 0) { |
| 1677 | 1684 | const data = ctx.data[lc.bind_off..][0..lc.bind_size]; |
| 1678 | | try writer.writeAll(dyld_bind_label ++ "\n"); |
| 1679 | | try ctx.dumpBindInfo(data, writer); |
| 1685 | try bw.writeAll(dyld_bind_label ++ "\n"); |
| 1686 | try ctx.dumpBindInfo(data, bw); |
| 1680 | 1687 | } else return step.fail("no bind data found", .{}), |
| 1681 | 1688 | |
| 1682 | 1689 | .dyld_weak_bind => if (lc.weak_bind_size > 0) { |
| 1683 | 1690 | const data = ctx.data[lc.weak_bind_off..][0..lc.weak_bind_size]; |
| 1684 | | try writer.writeAll(dyld_weak_bind_label ++ "\n"); |
| 1685 | | try ctx.dumpBindInfo(data, writer); |
| 1691 | try bw.writeAll(dyld_weak_bind_label ++ "\n"); |
| 1692 | try ctx.dumpBindInfo(data, bw); |
| 1686 | 1693 | } else return step.fail("no weak bind data found", .{}), |
| 1687 | 1694 | |
| 1688 | 1695 | .dyld_lazy_bind => if (lc.lazy_bind_size > 0) { |
| 1689 | 1696 | const data = ctx.data[lc.lazy_bind_off..][0..lc.lazy_bind_size]; |
| 1690 | | try writer.writeAll(dyld_lazy_bind_label ++ "\n"); |
| 1691 | | try ctx.dumpBindInfo(data, writer); |
| 1697 | try bw.writeAll(dyld_lazy_bind_label ++ "\n"); |
| 1698 | try ctx.dumpBindInfo(data, bw); |
| 1692 | 1699 | } else return step.fail("no lazy bind data found", .{}), |
| 1693 | 1700 | |
| 1694 | 1701 | else => unreachable, |
| ... | ... | @@ -1700,8 +1707,8 @@ const MachODumper = struct { |
| 1700 | 1707 | const lc = cmd.cast(macho.dyld_info_command).?; |
| 1701 | 1708 | if (lc.export_size > 0) { |
| 1702 | 1709 | const data = ctx.data[lc.export_off..][0..lc.export_size]; |
| 1703 | | try writer.writeAll(exports_label ++ "\n"); |
| 1704 | | try ctx.dumpExportsTrie(data, writer); |
| 1710 | try bw.writeAll(exports_label ++ "\n"); |
| 1711 | try ctx.dumpExportsTrie(data, bw); |
| 1705 | 1712 | break :blk; |
| 1706 | 1713 | } |
| 1707 | 1714 | } |
| ... | ... | @@ -1716,7 +1723,7 @@ const MachODumper = struct { |
| 1716 | 1723 | const sectname = name[sep_index + 1 ..]; |
| 1717 | 1724 | const sect = ctx.getSectionByName(segname, sectname) orelse |
| 1718 | 1725 | return step.fail("section '{s}' not found", .{name}); |
| 1719 | | try ctx.dumpSection(sect, writer); |
| 1726 | try ctx.dumpSection(sect, bw); |
| 1720 | 1727 | }, |
| 1721 | 1728 | |
| 1722 | 1729 | else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(check.kind)}), |
| ... | ... | @@ -1850,7 +1857,7 @@ const ElfDumper = struct { |
| 1850 | 1857 | } |
| 1851 | 1858 | } |
| 1852 | 1859 | |
| 1853 | | fn dumpSymtab(ctx: ArchiveContext, writer: anytype) !void { |
| 1860 | fn dumpSymtab(ctx: ArchiveContext, bw: *std.io.BufferedWriter) !void { |
| 1854 | 1861 | var files = std.AutoHashMap(usize, []const u8).init(ctx.gpa); |
| 1855 | 1862 | defer files.deinit(); |
| 1856 | 1863 | try files.ensureUnusedCapacity(@intCast(ctx.objects.items.len)); |
| ... | ... | @@ -1875,21 +1882,21 @@ const ElfDumper = struct { |
| 1875 | 1882 | try gop.value_ptr.append(entry.name); |
| 1876 | 1883 | } |
| 1877 | 1884 | |
| 1878 | | try writer.print("{s}\n", .{archive_symtab_label}); |
| 1885 | try bw.print("{s}\n", .{archive_symtab_label}); |
| 1879 | 1886 | for (symbols.keys(), symbols.values()) |off, values| { |
| 1880 | | try writer.print("in object {s}\n", .{files.get(off).?}); |
| 1887 | try bw.print("in object {s}\n", .{files.get(off).?}); |
| 1881 | 1888 | for (values.items) |value| { |
| 1882 | | try writer.print("{s}\n", .{value}); |
| 1889 | try bw.print("{s}\n", .{value}); |
| 1883 | 1890 | } |
| 1884 | 1891 | } |
| 1885 | 1892 | } |
| 1886 | 1893 | |
| 1887 | | fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, writer: anytype) !void { |
| 1894 | fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, bw: *std.io.BufferedWriter) !void { |
| 1888 | 1895 | for (ctx.objects.items) |object| { |
| 1889 | | try writer.print("object {s}\n", .{object.name}); |
| 1896 | try bw.print("object {s}\n", .{object.name}); |
| 1890 | 1897 | const output = try parseAndDumpObject(step, check, ctx.data[object.off..][0..object.len]); |
| 1891 | 1898 | defer ctx.gpa.free(output); |
| 1892 | | try writer.print("{s}\n", .{output}); |
| 1899 | try bw.print("{s}\n", .{output}); |
| 1893 | 1900 | } |
| 1894 | 1901 | } |
| 1895 | 1902 | |
| ... | ... | @@ -1955,32 +1962,32 @@ const ElfDumper = struct { |
| 1955 | 1962 | else => {}, |
| 1956 | 1963 | }; |
| 1957 | 1964 | |
| 1958 | | var output = std.ArrayList(u8).init(gpa); |
| 1959 | | const writer = output.writer(); |
| 1965 | var output: std.io.AllocatingWriter = undefined; |
| 1966 | const bw = output.init(gpa); |
| 1960 | 1967 | |
| 1961 | 1968 | switch (check.kind) { |
| 1962 | 1969 | .headers => { |
| 1963 | | try ctx.dumpHeader(writer); |
| 1964 | | try ctx.dumpShdrs(writer); |
| 1965 | | try ctx.dumpPhdrs(writer); |
| 1970 | try ctx.dumpHeader(bw); |
| 1971 | try ctx.dumpShdrs(bw); |
| 1972 | try ctx.dumpPhdrs(bw); |
| 1966 | 1973 | }, |
| 1967 | 1974 | |
| 1968 | 1975 | .symtab => if (ctx.symtab.symbols.len > 0) { |
| 1969 | | try ctx.dumpSymtab(.symtab, writer); |
| 1976 | try ctx.dumpSymtab(.symtab, bw); |
| 1970 | 1977 | } else return step.fail("no symbol table found", .{}), |
| 1971 | 1978 | |
| 1972 | 1979 | .dynamic_symtab => if (ctx.dysymtab.symbols.len > 0) { |
| 1973 | | try ctx.dumpSymtab(.dysymtab, writer); |
| 1980 | try ctx.dumpSymtab(.dysymtab, bw); |
| 1974 | 1981 | } else return step.fail("no dynamic symbol table found", .{}), |
| 1975 | 1982 | |
| 1976 | 1983 | .dynamic_section => if (ctx.getSectionByName(".dynamic")) |shndx| { |
| 1977 | | try ctx.dumpDynamicSection(shndx, writer); |
| 1984 | try ctx.dumpDynamicSection(shndx, bw); |
| 1978 | 1985 | } else return step.fail("no .dynamic section found", .{}), |
| 1979 | 1986 | |
| 1980 | 1987 | .dump_section => { |
| 1981 | 1988 | const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0); |
| 1982 | 1989 | const shndx = ctx.getSectionByName(name) orelse return step.fail("no '{s}' section found", .{name}); |
| 1983 | | try ctx.dumpSection(shndx, writer); |
| 1990 | try ctx.dumpSection(shndx, bw); |
| 1984 | 1991 | }, |
| 1985 | 1992 | |
| 1986 | 1993 | else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(check.kind)}), |
| ... | ... | @@ -1999,76 +2006,76 @@ const ElfDumper = struct { |
| 1999 | 2006 | symtab: Symtab = .{}, |
| 2000 | 2007 | dysymtab: Symtab = .{}, |
| 2001 | 2008 | |
| 2002 | | fn dumpHeader(ctx: ObjectContext, writer: anytype) !void { |
| 2003 | | try writer.writeAll("header\n"); |
| 2004 | | try writer.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); |
| 2005 | | try writer.print("entry {x}\n", .{ctx.hdr.e_entry}); |
| 2009 | fn dumpHeader(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { |
| 2010 | try bw.writeAll("header\n"); |
| 2011 | try bw.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); |
| 2012 | try bw.print("entry {x}\n", .{ctx.hdr.e_entry}); |
| 2006 | 2013 | } |
| 2007 | 2014 | |
| 2008 | | fn dumpPhdrs(ctx: ObjectContext, writer: anytype) !void { |
| 2015 | fn dumpPhdrs(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { |
| 2009 | 2016 | if (ctx.phdrs.len == 0) return; |
| 2010 | 2017 | |
| 2011 | | try writer.writeAll("program headers\n"); |
| 2018 | try bw.writeAll("program headers\n"); |
| 2012 | 2019 | |
| 2013 | 2020 | for (ctx.phdrs, 0..) |phdr, phndx| { |
| 2014 | | try writer.print("phdr {d}\n", .{phndx}); |
| 2015 | | try writer.print("type {s}\n", .{fmtPhType(phdr.p_type)}); |
| 2016 | | try writer.print("vaddr {x}\n", .{phdr.p_vaddr}); |
| 2017 | | try writer.print("paddr {x}\n", .{phdr.p_paddr}); |
| 2018 | | try writer.print("offset {x}\n", .{phdr.p_offset}); |
| 2019 | | try writer.print("memsz {x}\n", .{phdr.p_memsz}); |
| 2020 | | try writer.print("filesz {x}\n", .{phdr.p_filesz}); |
| 2021 | | try writer.print("align {x}\n", .{phdr.p_align}); |
| 2021 | try bw.print("phdr {d}\n", .{phndx}); |
| 2022 | try bw.print("type {s}\n", .{fmtPhType(phdr.p_type)}); |
| 2023 | try bw.print("vaddr {x}\n", .{phdr.p_vaddr}); |
| 2024 | try bw.print("paddr {x}\n", .{phdr.p_paddr}); |
| 2025 | try bw.print("offset {x}\n", .{phdr.p_offset}); |
| 2026 | try bw.print("memsz {x}\n", .{phdr.p_memsz}); |
| 2027 | try bw.print("filesz {x}\n", .{phdr.p_filesz}); |
| 2028 | try bw.print("align {x}\n", .{phdr.p_align}); |
| 2022 | 2029 | |
| 2023 | 2030 | { |
| 2024 | 2031 | const flags = phdr.p_flags; |
| 2025 | | try writer.writeAll("flags"); |
| 2026 | | if (flags > 0) try writer.writeByte(' '); |
| 2032 | try bw.writeAll("flags"); |
| 2033 | if (flags > 0) try bw.writeByte(' '); |
| 2027 | 2034 | if (flags & elf.PF_R != 0) { |
| 2028 | | try writer.writeByte('R'); |
| 2035 | try bw.writeByte('R'); |
| 2029 | 2036 | } |
| 2030 | 2037 | if (flags & elf.PF_W != 0) { |
| 2031 | | try writer.writeByte('W'); |
| 2038 | try bw.writeByte('W'); |
| 2032 | 2039 | } |
| 2033 | 2040 | if (flags & elf.PF_X != 0) { |
| 2034 | | try writer.writeByte('E'); |
| 2041 | try bw.writeByte('E'); |
| 2035 | 2042 | } |
| 2036 | 2043 | if (flags & elf.PF_MASKOS != 0) { |
| 2037 | | try writer.writeAll("OS"); |
| 2044 | try bw.writeAll("OS"); |
| 2038 | 2045 | } |
| 2039 | 2046 | if (flags & elf.PF_MASKPROC != 0) { |
| 2040 | | try writer.writeAll("PROC"); |
| 2047 | try bw.writeAll("PROC"); |
| 2041 | 2048 | } |
| 2042 | | try writer.writeByte('\n'); |
| 2049 | try bw.writeByte('\n'); |
| 2043 | 2050 | } |
| 2044 | 2051 | } |
| 2045 | 2052 | } |
| 2046 | 2053 | |
| 2047 | | fn dumpShdrs(ctx: ObjectContext, writer: anytype) !void { |
| 2054 | fn dumpShdrs(ctx: ObjectContext, bw: *std.io.BufferedWriter) !void { |
| 2048 | 2055 | if (ctx.shdrs.len == 0) return; |
| 2049 | 2056 | |
| 2050 | | try writer.writeAll("section headers\n"); |
| 2057 | try bw.writeAll("section headers\n"); |
| 2051 | 2058 | |
| 2052 | 2059 | for (ctx.shdrs, 0..) |shdr, shndx| { |
| 2053 | | try writer.print("shdr {d}\n", .{shndx}); |
| 2054 | | try writer.print("name {s}\n", .{ctx.getSectionName(shndx)}); |
| 2055 | | try writer.print("type {s}\n", .{fmtShType(shdr.sh_type)}); |
| 2056 | | try writer.print("addr {x}\n", .{shdr.sh_addr}); |
| 2057 | | try writer.print("offset {x}\n", .{shdr.sh_offset}); |
| 2058 | | try writer.print("size {x}\n", .{shdr.sh_size}); |
| 2059 | | try writer.print("addralign {x}\n", .{shdr.sh_addralign}); |
| 2060 | try bw.print("shdr {d}\n", .{shndx}); |
| 2061 | try bw.print("name {s}\n", .{ctx.getSectionName(shndx)}); |
| 2062 | try bw.print("type {s}\n", .{fmtShType(shdr.sh_type)}); |
| 2063 | try bw.print("addr {x}\n", .{shdr.sh_addr}); |
| 2064 | try bw.print("offset {x}\n", .{shdr.sh_offset}); |
| 2065 | try bw.print("size {x}\n", .{shdr.sh_size}); |
| 2066 | try bw.print("addralign {x}\n", .{shdr.sh_addralign}); |
| 2060 | 2067 | // TODO dump formatted sh_flags |
| 2061 | 2068 | } |
| 2062 | 2069 | } |
| 2063 | 2070 | |
| 2064 | | fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void { |
| 2071 | fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, bw: *std.io.BufferedWriter) !void { |
| 2065 | 2072 | const shdr = ctx.shdrs[shndx]; |
| 2066 | 2073 | const strtab = ctx.getSectionContents(shdr.sh_link); |
| 2067 | 2074 | const data = ctx.getSectionContents(shndx); |
| 2068 | 2075 | const nentries = @divExact(data.len, @sizeOf(elf.Elf64_Dyn)); |
| 2069 | 2076 | const entries = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(data.ptr))[0..nentries]; |
| 2070 | 2077 | |
| 2071 | | try writer.writeAll(ElfDumper.dynamic_section_label ++ "\n"); |
| 2078 | try bw.writeAll(ElfDumper.dynamic_section_label ++ "\n"); |
| 2072 | 2079 | |
| 2073 | 2080 | for (entries) |entry| { |
| 2074 | 2081 | const key = @as(u64, @bitCast(entry.d_tag)); |
| ... | ... | @@ -2109,7 +2116,7 @@ const ElfDumper = struct { |
| 2109 | 2116 | elf.DT_NULL => "NULL", |
| 2110 | 2117 | else => "UNKNOWN", |
| 2111 | 2118 | }; |
| 2112 | | try writer.print("{s}", .{key_str}); |
| 2119 | try bw.print("{s}", .{key_str}); |
| 2113 | 2120 | |
| 2114 | 2121 | switch (key) { |
| 2115 | 2122 | elf.DT_NEEDED, |
| ... | ... | @@ -2118,7 +2125,7 @@ const ElfDumper = struct { |
| 2118 | 2125 | elf.DT_RUNPATH, |
| 2119 | 2126 | => { |
| 2120 | 2127 | const name = getString(strtab, @intCast(value)); |
| 2121 | | try writer.print(" {s}", .{name}); |
| 2128 | try bw.print(" {s}", .{name}); |
| 2122 | 2129 | }, |
| 2123 | 2130 | |
| 2124 | 2131 | elf.DT_INIT_ARRAY, |
| ... | ... | @@ -2136,7 +2143,7 @@ const ElfDumper = struct { |
| 2136 | 2143 | elf.DT_INIT, |
| 2137 | 2144 | elf.DT_FINI, |
| 2138 | 2145 | elf.DT_NULL, |
| 2139 | | => try writer.print(" {x}", .{value}), |
| 2146 | => try bw.print(" {x}", .{value}), |
| 2140 | 2147 | |
| 2141 | 2148 | elf.DT_INIT_ARRAYSZ, |
| 2142 | 2149 | elf.DT_FINI_ARRAYSZ, |
| ... | ... | @@ -2146,77 +2153,77 @@ const ElfDumper = struct { |
| 2146 | 2153 | elf.DT_RELASZ, |
| 2147 | 2154 | elf.DT_RELAENT, |
| 2148 | 2155 | elf.DT_RELACOUNT, |
| 2149 | | => try writer.print(" {d}", .{value}), |
| 2156 | => try bw.print(" {d}", .{value}), |
| 2150 | 2157 | |
| 2151 | | elf.DT_PLTREL => try writer.writeAll(switch (value) { |
| 2158 | elf.DT_PLTREL => try bw.writeAll(switch (value) { |
| 2152 | 2159 | elf.DT_REL => " REL", |
| 2153 | 2160 | elf.DT_RELA => " RELA", |
| 2154 | 2161 | else => " UNKNOWN", |
| 2155 | 2162 | }), |
| 2156 | 2163 | |
| 2157 | 2164 | elf.DT_FLAGS => if (value > 0) { |
| 2158 | | if (value & elf.DF_ORIGIN != 0) try writer.writeAll(" ORIGIN"); |
| 2159 | | if (value & elf.DF_SYMBOLIC != 0) try writer.writeAll(" SYMBOLIC"); |
| 2160 | | if (value & elf.DF_TEXTREL != 0) try writer.writeAll(" TEXTREL"); |
| 2161 | | if (value & elf.DF_BIND_NOW != 0) try writer.writeAll(" BIND_NOW"); |
| 2162 | | if (value & elf.DF_STATIC_TLS != 0) try writer.writeAll(" STATIC_TLS"); |
| 2165 | if (value & elf.DF_ORIGIN != 0) try bw.writeAll(" ORIGIN"); |
| 2166 | if (value & elf.DF_SYMBOLIC != 0) try bw.writeAll(" SYMBOLIC"); |
| 2167 | if (value & elf.DF_TEXTREL != 0) try bw.writeAll(" TEXTREL"); |
| 2168 | if (value & elf.DF_BIND_NOW != 0) try bw.writeAll(" BIND_NOW"); |
| 2169 | if (value & elf.DF_STATIC_TLS != 0) try bw.writeAll(" STATIC_TLS"); |
| 2163 | 2170 | }, |
| 2164 | 2171 | |
| 2165 | 2172 | elf.DT_FLAGS_1 => if (value > 0) { |
| 2166 | | if (value & elf.DF_1_NOW != 0) try writer.writeAll(" NOW"); |
| 2167 | | if (value & elf.DF_1_GLOBAL != 0) try writer.writeAll(" GLOBAL"); |
| 2168 | | if (value & elf.DF_1_GROUP != 0) try writer.writeAll(" GROUP"); |
| 2169 | | if (value & elf.DF_1_NODELETE != 0) try writer.writeAll(" NODELETE"); |
| 2170 | | if (value & elf.DF_1_LOADFLTR != 0) try writer.writeAll(" LOADFLTR"); |
| 2171 | | if (value & elf.DF_1_INITFIRST != 0) try writer.writeAll(" INITFIRST"); |
| 2172 | | if (value & elf.DF_1_NOOPEN != 0) try writer.writeAll(" NOOPEN"); |
| 2173 | | if (value & elf.DF_1_ORIGIN != 0) try writer.writeAll(" ORIGIN"); |
| 2174 | | if (value & elf.DF_1_DIRECT != 0) try writer.writeAll(" DIRECT"); |
| 2175 | | if (value & elf.DF_1_TRANS != 0) try writer.writeAll(" TRANS"); |
| 2176 | | if (value & elf.DF_1_INTERPOSE != 0) try writer.writeAll(" INTERPOSE"); |
| 2177 | | if (value & elf.DF_1_NODEFLIB != 0) try writer.writeAll(" NODEFLIB"); |
| 2178 | | if (value & elf.DF_1_NODUMP != 0) try writer.writeAll(" NODUMP"); |
| 2179 | | if (value & elf.DF_1_CONFALT != 0) try writer.writeAll(" CONFALT"); |
| 2180 | | if (value & elf.DF_1_ENDFILTEE != 0) try writer.writeAll(" ENDFILTEE"); |
| 2181 | | if (value & elf.DF_1_DISPRELDNE != 0) try writer.writeAll(" DISPRELDNE"); |
| 2182 | | if (value & elf.DF_1_DISPRELPND != 0) try writer.writeAll(" DISPRELPND"); |
| 2183 | | if (value & elf.DF_1_NODIRECT != 0) try writer.writeAll(" NODIRECT"); |
| 2184 | | if (value & elf.DF_1_IGNMULDEF != 0) try writer.writeAll(" IGNMULDEF"); |
| 2185 | | if (value & elf.DF_1_NOKSYMS != 0) try writer.writeAll(" NOKSYMS"); |
| 2186 | | if (value & elf.DF_1_NOHDR != 0) try writer.writeAll(" NOHDR"); |
| 2187 | | if (value & elf.DF_1_EDITED != 0) try writer.writeAll(" EDITED"); |
| 2188 | | if (value & elf.DF_1_NORELOC != 0) try writer.writeAll(" NORELOC"); |
| 2189 | | if (value & elf.DF_1_SYMINTPOSE != 0) try writer.writeAll(" SYMINTPOSE"); |
| 2190 | | if (value & elf.DF_1_GLOBAUDIT != 0) try writer.writeAll(" GLOBAUDIT"); |
| 2191 | | if (value & elf.DF_1_SINGLETON != 0) try writer.writeAll(" SINGLETON"); |
| 2192 | | if (value & elf.DF_1_STUB != 0) try writer.writeAll(" STUB"); |
| 2193 | | if (value & elf.DF_1_PIE != 0) try writer.writeAll(" PIE"); |
| 2173 | if (value & elf.DF_1_NOW != 0) try bw.writeAll(" NOW"); |
| 2174 | if (value & elf.DF_1_GLOBAL != 0) try bw.writeAll(" GLOBAL"); |
| 2175 | if (value & elf.DF_1_GROUP != 0) try bw.writeAll(" GROUP"); |
| 2176 | if (value & elf.DF_1_NODELETE != 0) try bw.writeAll(" NODELETE"); |
| 2177 | if (value & elf.DF_1_LOADFLTR != 0) try bw.writeAll(" LOADFLTR"); |
| 2178 | if (value & elf.DF_1_INITFIRST != 0) try bw.writeAll(" INITFIRST"); |
| 2179 | if (value & elf.DF_1_NOOPEN != 0) try bw.writeAll(" NOOPEN"); |
| 2180 | if (value & elf.DF_1_ORIGIN != 0) try bw.writeAll(" ORIGIN"); |
| 2181 | if (value & elf.DF_1_DIRECT != 0) try bw.writeAll(" DIRECT"); |
| 2182 | if (value & elf.DF_1_TRANS != 0) try bw.writeAll(" TRANS"); |
| 2183 | if (value & elf.DF_1_INTERPOSE != 0) try bw.writeAll(" INTERPOSE"); |
| 2184 | if (value & elf.DF_1_NODEFLIB != 0) try bw.writeAll(" NODEFLIB"); |
| 2185 | if (value & elf.DF_1_NODUMP != 0) try bw.writeAll(" NODUMP"); |
| 2186 | if (value & elf.DF_1_CONFALT != 0) try bw.writeAll(" CONFALT"); |
| 2187 | if (value & elf.DF_1_ENDFILTEE != 0) try bw.writeAll(" ENDFILTEE"); |
| 2188 | if (value & elf.DF_1_DISPRELDNE != 0) try bw.writeAll(" DISPRELDNE"); |
| 2189 | if (value & elf.DF_1_DISPRELPND != 0) try bw.writeAll(" DISPRELPND"); |
| 2190 | if (value & elf.DF_1_NODIRECT != 0) try bw.writeAll(" NODIRECT"); |
| 2191 | if (value & elf.DF_1_IGNMULDEF != 0) try bw.writeAll(" IGNMULDEF"); |
| 2192 | if (value & elf.DF_1_NOKSYMS != 0) try bw.writeAll(" NOKSYMS"); |
| 2193 | if (value & elf.DF_1_NOHDR != 0) try bw.writeAll(" NOHDR"); |
| 2194 | if (value & elf.DF_1_EDITED != 0) try bw.writeAll(" EDITED"); |
| 2195 | if (value & elf.DF_1_NORELOC != 0) try bw.writeAll(" NORELOC"); |
| 2196 | if (value & elf.DF_1_SYMINTPOSE != 0) try bw.writeAll(" SYMINTPOSE"); |
| 2197 | if (value & elf.DF_1_GLOBAUDIT != 0) try bw.writeAll(" GLOBAUDIT"); |
| 2198 | if (value & elf.DF_1_SINGLETON != 0) try bw.writeAll(" SINGLETON"); |
| 2199 | if (value & elf.DF_1_STUB != 0) try bw.writeAll(" STUB"); |
| 2200 | if (value & elf.DF_1_PIE != 0) try bw.writeAll(" PIE"); |
| 2194 | 2201 | }, |
| 2195 | 2202 | |
| 2196 | | else => try writer.print(" {x}", .{value}), |
| 2203 | else => try bw.print(" {x}", .{value}), |
| 2197 | 2204 | } |
| 2198 | | try writer.writeByte('\n'); |
| 2205 | try bw.writeByte('\n'); |
| 2199 | 2206 | } |
| 2200 | 2207 | } |
| 2201 | 2208 | |
| 2202 | | fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, writer: anytype) !void { |
| 2209 | fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, bw: *std.io.BufferedWriter) !void { |
| 2203 | 2210 | const symtab = switch (@"type") { |
| 2204 | 2211 | .symtab => ctx.symtab, |
| 2205 | 2212 | .dysymtab => ctx.dysymtab, |
| 2206 | 2213 | }; |
| 2207 | 2214 | |
| 2208 | | try writer.writeAll(switch (@"type") { |
| 2215 | try bw.writeAll(switch (@"type") { |
| 2209 | 2216 | .symtab => symtab_label, |
| 2210 | 2217 | .dysymtab => dynamic_symtab_label, |
| 2211 | 2218 | } ++ "\n"); |
| 2212 | 2219 | |
| 2213 | 2220 | for (symtab.symbols, 0..) |sym, index| { |
| 2214 | | try writer.print("{x} {x}", .{ sym.st_value, sym.st_size }); |
| 2221 | try bw.print("{x} {x}", .{ sym.st_value, sym.st_size }); |
| 2215 | 2222 | |
| 2216 | 2223 | { |
| 2217 | 2224 | if (elf.SHN_LORESERVE <= sym.st_shndx and sym.st_shndx < elf.SHN_HIRESERVE) { |
| 2218 | 2225 | if (elf.SHN_LOPROC <= sym.st_shndx and sym.st_shndx < elf.SHN_HIPROC) { |
| 2219 | | try writer.print(" LO+{d}", .{sym.st_shndx - elf.SHN_LOPROC}); |
| 2226 | try bw.print(" LO+{d}", .{sym.st_shndx - elf.SHN_LOPROC}); |
| 2220 | 2227 | } else { |
| 2221 | 2228 | const sym_ndx = switch (sym.st_shndx) { |
| 2222 | 2229 | elf.SHN_ABS => "ABS", |
| ... | ... | @@ -2224,12 +2231,12 @@ const ElfDumper = struct { |
| 2224 | 2231 | elf.SHN_LIVEPATCH => "LIV", |
| 2225 | 2232 | else => "UNK", |
| 2226 | 2233 | }; |
| 2227 | | try writer.print(" {s}", .{sym_ndx}); |
| 2234 | try bw.print(" {s}", .{sym_ndx}); |
| 2228 | 2235 | } |
| 2229 | 2236 | } else if (sym.st_shndx == elf.SHN_UNDEF) { |
| 2230 | | try writer.writeAll(" UND"); |
| 2237 | try bw.writeAll(" UND"); |
| 2231 | 2238 | } else { |
| 2232 | | try writer.print(" {x}", .{sym.st_shndx}); |
| 2239 | try bw.print(" {x}", .{sym.st_shndx}); |
| 2233 | 2240 | } |
| 2234 | 2241 | } |
| 2235 | 2242 | |
| ... | ... | @@ -2246,12 +2253,12 @@ const ElfDumper = struct { |
| 2246 | 2253 | elf.STT_NUM => "NUM", |
| 2247 | 2254 | elf.STT_GNU_IFUNC => "IFUNC", |
| 2248 | 2255 | else => if (elf.STT_LOPROC <= tt and tt < elf.STT_HIPROC) { |
| 2249 | | break :blk try writer.print(" LOPROC+{d}", .{tt - elf.STT_LOPROC}); |
| 2256 | break :blk try bw.print(" LOPROC+{d}", .{tt - elf.STT_LOPROC}); |
| 2250 | 2257 | } else if (elf.STT_LOOS <= tt and tt < elf.STT_HIOS) { |
| 2251 | | break :blk try writer.print(" LOOS+{d}", .{tt - elf.STT_LOOS}); |
| 2258 | break :blk try bw.print(" LOOS+{d}", .{tt - elf.STT_LOOS}); |
| 2252 | 2259 | } else "UNK", |
| 2253 | 2260 | }; |
| 2254 | | try writer.print(" {s}", .{sym_type}); |
| 2261 | try bw.print(" {s}", .{sym_type}); |
| 2255 | 2262 | } |
| 2256 | 2263 | |
| 2257 | 2264 | blk: { |
| ... | ... | @@ -2262,28 +2269,28 @@ const ElfDumper = struct { |
| 2262 | 2269 | elf.STB_WEAK => "WEAK", |
| 2263 | 2270 | elf.STB_NUM => "NUM", |
| 2264 | 2271 | else => if (elf.STB_LOPROC <= bind and bind < elf.STB_HIPROC) { |
| 2265 | | break :blk try writer.print(" LOPROC+{d}", .{bind - elf.STB_LOPROC}); |
| 2272 | break :blk try bw.print(" LOPROC+{d}", .{bind - elf.STB_LOPROC}); |
| 2266 | 2273 | } else if (elf.STB_LOOS <= bind and bind < elf.STB_HIOS) { |
| 2267 | | break :blk try writer.print(" LOOS+{d}", .{bind - elf.STB_LOOS}); |
| 2274 | break :blk try bw.print(" LOOS+{d}", .{bind - elf.STB_LOOS}); |
| 2268 | 2275 | } else "UNKNOWN", |
| 2269 | 2276 | }; |
| 2270 | | try writer.print(" {s}", .{sym_bind}); |
| 2277 | try bw.print(" {s}", .{sym_bind}); |
| 2271 | 2278 | } |
| 2272 | 2279 | |
| 2273 | 2280 | const sym_vis = @as(elf.STV, @enumFromInt(sym.st_other)); |
| 2274 | | try writer.print(" {s}", .{@tagName(sym_vis)}); |
| 2281 | try bw.print(" {s}", .{@tagName(sym_vis)}); |
| 2275 | 2282 | |
| 2276 | 2283 | const sym_name = switch (sym.st_type()) { |
| 2277 | 2284 | elf.STT_SECTION => ctx.getSectionName(sym.st_shndx), |
| 2278 | 2285 | else => symtab.getName(index).?, |
| 2279 | 2286 | }; |
| 2280 | | try writer.print(" {s}\n", .{sym_name}); |
| 2287 | try bw.print(" {s}\n", .{sym_name}); |
| 2281 | 2288 | } |
| 2282 | 2289 | } |
| 2283 | 2290 | |
| 2284 | | fn dumpSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void { |
| 2291 | fn dumpSection(ctx: ObjectContext, shndx: usize, bw: *std.io.BufferedWriter) !void { |
| 2285 | 2292 | const data = ctx.getSectionContents(shndx); |
| 2286 | | try writer.print("{s}", .{data}); |
| 2293 | try bw.print("{s}", .{data}); |
| 2287 | 2294 | } |
| 2288 | 2295 | |
| 2289 | 2296 | inline fn getSectionName(ctx: ObjectContext, shndx: usize) []const u8 { |
| ... | ... | @@ -2333,7 +2340,7 @@ const ElfDumper = struct { |
| 2333 | 2340 | sh_type: u32, |
| 2334 | 2341 | comptime unused_fmt_string: []const u8, |
| 2335 | 2342 | options: std.fmt.FormatOptions, |
| 2336 | | writer: anytype, |
| 2343 | bw: *std.io.BufferedWriter, |
| 2337 | 2344 | ) !void { |
| 2338 | 2345 | _ = unused_fmt_string; |
| 2339 | 2346 | _ = options; |
| ... | ... | @@ -2362,14 +2369,14 @@ const ElfDumper = struct { |
| 2362 | 2369 | elf.SHT_GNU_VERNEED => "VERNEED", |
| 2363 | 2370 | elf.SHT_GNU_VERSYM => "VERSYM", |
| 2364 | 2371 | else => if (elf.SHT_LOOS <= sh_type and sh_type < elf.SHT_HIOS) { |
| 2365 | | return try writer.print("LOOS+0x{x}", .{sh_type - elf.SHT_LOOS}); |
| 2372 | return try bw.print("LOOS+0x{x}", .{sh_type - elf.SHT_LOOS}); |
| 2366 | 2373 | } else if (elf.SHT_LOPROC <= sh_type and sh_type < elf.SHT_HIPROC) { |
| 2367 | | return try writer.print("LOPROC+0x{x}", .{sh_type - elf.SHT_LOPROC}); |
| 2374 | return try bw.print("LOPROC+0x{x}", .{sh_type - elf.SHT_LOPROC}); |
| 2368 | 2375 | } else if (elf.SHT_LOUSER <= sh_type and sh_type < elf.SHT_HIUSER) { |
| 2369 | | return try writer.print("LOUSER+0x{x}", .{sh_type - elf.SHT_LOUSER}); |
| 2376 | return try bw.print("LOUSER+0x{x}", .{sh_type - elf.SHT_LOUSER}); |
| 2370 | 2377 | } else "UNKNOWN", |
| 2371 | 2378 | }; |
| 2372 | | try writer.writeAll(name); |
| 2379 | try bw.writeAll(name); |
| 2373 | 2380 | } |
| 2374 | 2381 | |
| 2375 | 2382 | fn fmtPhType(ph_type: u32) std.fmt.Formatter(formatPhType) { |
| ... | ... | @@ -2380,7 +2387,7 @@ const ElfDumper = struct { |
| 2380 | 2387 | ph_type: u32, |
| 2381 | 2388 | comptime unused_fmt_string: []const u8, |
| 2382 | 2389 | options: std.fmt.FormatOptions, |
| 2383 | | writer: anytype, |
| 2390 | bw: *std.io.BufferedWriter, |
| 2384 | 2391 | ) !void { |
| 2385 | 2392 | _ = unused_fmt_string; |
| 2386 | 2393 | _ = options; |
| ... | ... | @@ -2398,12 +2405,12 @@ const ElfDumper = struct { |
| 2398 | 2405 | elf.PT_GNU_STACK => "GNU_STACK", |
| 2399 | 2406 | elf.PT_GNU_RELRO => "GNU_RELRO", |
| 2400 | 2407 | else => if (elf.PT_LOOS <= ph_type and ph_type < elf.PT_HIOS) { |
| 2401 | | return try writer.print("LOOS+0x{x}", .{ph_type - elf.PT_LOOS}); |
| 2408 | return try bw.print("LOOS+0x{x}", .{ph_type - elf.PT_LOOS}); |
| 2402 | 2409 | } else if (elf.PT_LOPROC <= ph_type and ph_type < elf.PT_HIPROC) { |
| 2403 | | return try writer.print("LOPROC+0x{x}", .{ph_type - elf.PT_LOPROC}); |
| 2410 | return try bw.print("LOPROC+0x{x}", .{ph_type - elf.PT_LOPROC}); |
| 2404 | 2411 | } else "UNKNOWN", |
| 2405 | 2412 | }; |
| 2406 | | try writer.writeAll(p_type); |
| 2413 | try bw.writeAll(p_type); |
| 2407 | 2414 | } |
| 2408 | 2415 | }; |
| 2409 | 2416 | |
| ... | ... | @@ -2463,12 +2470,12 @@ const WasmDumper = struct { |
| 2463 | 2470 | step: *Step, |
| 2464 | 2471 | section: std.wasm.Section, |
| 2465 | 2472 | data: []const u8, |
| 2466 | | writer: anytype, |
| 2473 | bw: *std.io.BufferedWriter, |
| 2467 | 2474 | ) !void { |
| 2468 | 2475 | var fbs = std.io.fixedBufferStream(data); |
| 2469 | 2476 | const reader = fbs.reader(); |
| 2470 | 2477 | |
| 2471 | | try writer.print( |
| 2478 | try bw.print( |
| 2472 | 2479 | \\Section {s} |
| 2473 | 2480 | \\size {d} |
| 2474 | 2481 | , .{ @tagName(section), data.len }); |
| ... | ... | @@ -2486,37 +2493,37 @@ const WasmDumper = struct { |
| 2486 | 2493 | .data, |
| 2487 | 2494 | => { |
| 2488 | 2495 | const entries = try std.leb.readUleb128(u32, reader); |
| 2489 | | try writer.print("\nentries {d}\n", .{entries}); |
| 2490 | | try parseSection(step, section, data[fbs.pos..], entries, writer); |
| 2496 | try bw.print("\nentries {d}\n", .{entries}); |
| 2497 | try parseSection(step, section, data[fbs.pos..], entries, bw); |
| 2491 | 2498 | }, |
| 2492 | 2499 | .custom => { |
| 2493 | 2500 | const name_length = try std.leb.readUleb128(u32, reader); |
| 2494 | 2501 | const name = data[fbs.pos..][0..name_length]; |
| 2495 | 2502 | fbs.pos += name_length; |
| 2496 | | try writer.print("\nname {s}\n", .{name}); |
| 2503 | try bw.print("\nname {s}\n", .{name}); |
| 2497 | 2504 | |
| 2498 | 2505 | if (mem.eql(u8, name, "name")) { |
| 2499 | | try parseDumpNames(step, reader, writer, data); |
| 2506 | try parseDumpNames(step, reader, bw, data); |
| 2500 | 2507 | } else if (mem.eql(u8, name, "producers")) { |
| 2501 | | try parseDumpProducers(reader, writer, data); |
| 2508 | try parseDumpProducers(reader, bw, data); |
| 2502 | 2509 | } else if (mem.eql(u8, name, "target_features")) { |
| 2503 | | try parseDumpFeatures(reader, writer, data); |
| 2510 | try parseDumpFeatures(reader, bw, data); |
| 2504 | 2511 | } |
| 2505 | 2512 | // TODO: Implement parsing and dumping other custom sections (such as relocations) |
| 2506 | 2513 | }, |
| 2507 | 2514 | .start => { |
| 2508 | 2515 | const start = try std.leb.readUleb128(u32, reader); |
| 2509 | | try writer.print("\nstart {d}\n", .{start}); |
| 2516 | try bw.print("\nstart {d}\n", .{start}); |
| 2510 | 2517 | }, |
| 2511 | 2518 | .data_count => { |
| 2512 | 2519 | const count = try std.leb.readUleb128(u32, reader); |
| 2513 | | try writer.print("\ncount {d}\n", .{count}); |
| 2520 | try bw.print("\ncount {d}\n", .{count}); |
| 2514 | 2521 | }, |
| 2515 | 2522 | else => {}, // skip unknown sections |
| 2516 | 2523 | } |
| 2517 | 2524 | } |
| 2518 | 2525 | |
| 2519 | | fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void { |
| 2526 | fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, bw: *std.io.BufferedWriter) !void { |
| 2520 | 2527 | var fbs = std.io.fixedBufferStream(data); |
| 2521 | 2528 | const reader = fbs.reader(); |
| 2522 | 2529 | |
| ... | ... | @@ -2529,15 +2536,15 @@ const WasmDumper = struct { |
| 2529 | 2536 | return step.fail("expected function type, found byte '{d}'", .{func_type}); |
| 2530 | 2537 | } |
| 2531 | 2538 | const params = try std.leb.readUleb128(u32, reader); |
| 2532 | | try writer.print("params {d}\n", .{params}); |
| 2539 | try bw.print("params {d}\n", .{params}); |
| 2533 | 2540 | var index: u32 = 0; |
| 2534 | 2541 | while (index < params) : (index += 1) { |
| 2535 | | _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); |
| 2542 | _ = try parseDumpType(step, std.wasm.Valtype, reader, bw); |
| 2536 | 2543 | } else index = 0; |
| 2537 | 2544 | const returns = try std.leb.readUleb128(u32, reader); |
| 2538 | | try writer.print("returns {d}\n", .{returns}); |
| 2545 | try bw.print("returns {d}\n", .{returns}); |
| 2539 | 2546 | while (index < returns) : (index += 1) { |
| 2540 | | _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); |
| 2547 | _ = try parseDumpType(step, std.wasm.Valtype, reader, bw); |
| 2541 | 2548 | } |
| 2542 | 2549 | } |
| 2543 | 2550 | }, |
| ... | ... | @@ -2555,26 +2562,26 @@ const WasmDumper = struct { |
| 2555 | 2562 | return step.fail("invalid import kind", .{}); |
| 2556 | 2563 | }; |
| 2557 | 2564 | |
| 2558 | | try writer.print( |
| 2565 | try bw.print( |
| 2559 | 2566 | \\module {s} |
| 2560 | 2567 | \\name {s} |
| 2561 | 2568 | \\kind {s} |
| 2562 | 2569 | , .{ module_name, name, @tagName(kind) }); |
| 2563 | | try writer.writeByte('\n'); |
| 2570 | try bw.writeByte('\n'); |
| 2564 | 2571 | switch (kind) { |
| 2565 | 2572 | .function => { |
| 2566 | | try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2573 | try bw.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2567 | 2574 | }, |
| 2568 | 2575 | .memory => { |
| 2569 | | try parseDumpLimits(reader, writer); |
| 2576 | try parseDumpLimits(reader, bw); |
| 2570 | 2577 | }, |
| 2571 | 2578 | .global => { |
| 2572 | | _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); |
| 2573 | | try writer.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u32, reader)}); |
| 2579 | _ = try parseDumpType(step, std.wasm.Valtype, reader, bw); |
| 2580 | try bw.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u32, reader)}); |
| 2574 | 2581 | }, |
| 2575 | 2582 | .table => { |
| 2576 | | _ = try parseDumpType(step, std.wasm.RefType, reader, writer); |
| 2577 | | try parseDumpLimits(reader, writer); |
| 2583 | _ = try parseDumpType(step, std.wasm.RefType, reader, bw); |
| 2584 | try parseDumpLimits(reader, bw); |
| 2578 | 2585 | }, |
| 2579 | 2586 | } |
| 2580 | 2587 | } |
| ... | ... | @@ -2582,28 +2589,28 @@ const WasmDumper = struct { |
| 2582 | 2589 | .function => { |
| 2583 | 2590 | var i: u32 = 0; |
| 2584 | 2591 | while (i < entries) : (i += 1) { |
| 2585 | | try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2592 | try bw.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2586 | 2593 | } |
| 2587 | 2594 | }, |
| 2588 | 2595 | .table => { |
| 2589 | 2596 | var i: u32 = 0; |
| 2590 | 2597 | while (i < entries) : (i += 1) { |
| 2591 | | _ = try parseDumpType(step, std.wasm.RefType, reader, writer); |
| 2592 | | try parseDumpLimits(reader, writer); |
| 2598 | _ = try parseDumpType(step, std.wasm.RefType, reader, bw); |
| 2599 | try parseDumpLimits(reader, bw); |
| 2593 | 2600 | } |
| 2594 | 2601 | }, |
| 2595 | 2602 | .memory => { |
| 2596 | 2603 | var i: u32 = 0; |
| 2597 | 2604 | while (i < entries) : (i += 1) { |
| 2598 | | try parseDumpLimits(reader, writer); |
| 2605 | try parseDumpLimits(reader, bw); |
| 2599 | 2606 | } |
| 2600 | 2607 | }, |
| 2601 | 2608 | .global => { |
| 2602 | 2609 | var i: u32 = 0; |
| 2603 | 2610 | while (i < entries) : (i += 1) { |
| 2604 | | _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); |
| 2605 | | try writer.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u1, reader)}); |
| 2606 | | try parseDumpInit(step, reader, writer); |
| 2611 | _ = try parseDumpType(step, std.wasm.Valtype, reader, bw); |
| 2612 | try bw.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u1, reader)}); |
| 2613 | try parseDumpInit(step, reader, bw); |
| 2607 | 2614 | } |
| 2608 | 2615 | }, |
| 2609 | 2616 | .@"export" => { |
| ... | ... | @@ -2617,25 +2624,25 @@ const WasmDumper = struct { |
| 2617 | 2624 | return step.fail("invalid export kind value '{d}'", .{kind_byte}); |
| 2618 | 2625 | }; |
| 2619 | 2626 | const index = try std.leb.readUleb128(u32, reader); |
| 2620 | | try writer.print( |
| 2627 | try bw.print( |
| 2621 | 2628 | \\name {s} |
| 2622 | 2629 | \\kind {s} |
| 2623 | 2630 | \\index {d} |
| 2624 | 2631 | , .{ name, @tagName(kind), index }); |
| 2625 | | try writer.writeByte('\n'); |
| 2632 | try bw.writeByte('\n'); |
| 2626 | 2633 | } |
| 2627 | 2634 | }, |
| 2628 | 2635 | .element => { |
| 2629 | 2636 | var i: u32 = 0; |
| 2630 | 2637 | while (i < entries) : (i += 1) { |
| 2631 | | try writer.print("table index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2632 | | try parseDumpInit(step, reader, writer); |
| 2638 | try bw.print("table index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2639 | try parseDumpInit(step, reader, bw); |
| 2633 | 2640 | |
| 2634 | 2641 | const function_indexes = try std.leb.readUleb128(u32, reader); |
| 2635 | 2642 | var function_index: u32 = 0; |
| 2636 | | try writer.print("indexes {d}\n", .{function_indexes}); |
| 2643 | try bw.print("indexes {d}\n", .{function_indexes}); |
| 2637 | 2644 | while (function_index < function_indexes) : (function_index += 1) { |
| 2638 | | try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2645 | try bw.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2639 | 2646 | } |
| 2640 | 2647 | } |
| 2641 | 2648 | }, |
| ... | ... | @@ -2648,13 +2655,13 @@ const WasmDumper = struct { |
| 2648 | 2655 | try std.leb.readUleb128(u32, reader) |
| 2649 | 2656 | else |
| 2650 | 2657 | 0; |
| 2651 | | try writer.print("memory index 0x{x}\n", .{index}); |
| 2658 | try bw.print("memory index 0x{x}\n", .{index}); |
| 2652 | 2659 | if (flags == 0) { |
| 2653 | | try parseDumpInit(step, reader, writer); |
| 2660 | try parseDumpInit(step, reader, bw); |
| 2654 | 2661 | } |
| 2655 | 2662 | |
| 2656 | 2663 | const size = try std.leb.readUleb128(u32, reader); |
| 2657 | | try writer.print("size {d}\n", .{size}); |
| 2664 | try bw.print("size {d}\n", .{size}); |
| 2658 | 2665 | try reader.skipBytes(size, .{}); // we do not care about the content of the segments |
| 2659 | 2666 | } |
| 2660 | 2667 | }, |
| ... | ... | @@ -2662,36 +2669,36 @@ const WasmDumper = struct { |
| 2662 | 2669 | } |
| 2663 | 2670 | } |
| 2664 | 2671 | |
| 2665 | | fn parseDumpType(step: *Step, comptime E: type, reader: anytype, writer: anytype) !E { |
| 2672 | fn parseDumpType(step: *Step, comptime E: type, reader: anytype, bw: *std.io.BufferedWriter) !E { |
| 2666 | 2673 | const byte = try reader.readByte(); |
| 2667 | 2674 | const tag = std.enums.fromInt(E, byte) orelse { |
| 2668 | 2675 | return step.fail("invalid wasm type value '{d}'", .{byte}); |
| 2669 | 2676 | }; |
| 2670 | | try writer.print("type {s}\n", .{@tagName(tag)}); |
| 2677 | try bw.print("type {s}\n", .{@tagName(tag)}); |
| 2671 | 2678 | return tag; |
| 2672 | 2679 | } |
| 2673 | 2680 | |
| 2674 | | fn parseDumpLimits(reader: anytype, writer: anytype) !void { |
| 2681 | fn parseDumpLimits(reader: anytype, bw: *std.io.BufferedWriter) !void { |
| 2675 | 2682 | const flags = try std.leb.readUleb128(u8, reader); |
| 2676 | 2683 | const min = try std.leb.readUleb128(u32, reader); |
| 2677 | 2684 | |
| 2678 | | try writer.print("min {x}\n", .{min}); |
| 2685 | try bw.print("min {x}\n", .{min}); |
| 2679 | 2686 | if (flags != 0) { |
| 2680 | | try writer.print("max {x}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2687 | try bw.print("max {x}\n", .{try std.leb.readUleb128(u32, reader)}); |
| 2681 | 2688 | } |
| 2682 | 2689 | } |
| 2683 | 2690 | |
| 2684 | | fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void { |
| 2691 | fn parseDumpInit(step: *Step, reader: anytype, bw: *std.io.BufferedWriter) !void { |
| 2685 | 2692 | const byte = try reader.readByte(); |
| 2686 | 2693 | const opcode = std.enums.fromInt(std.wasm.Opcode, byte) orelse { |
| 2687 | 2694 | return step.fail("invalid wasm opcode '{d}'", .{byte}); |
| 2688 | 2695 | }; |
| 2689 | 2696 | switch (opcode) { |
| 2690 | | .i32_const => try writer.print("i32.const {x}\n", .{try std.leb.readIleb128(i32, reader)}), |
| 2691 | | .i64_const => try writer.print("i64.const {x}\n", .{try std.leb.readIleb128(i64, reader)}), |
| 2692 | | .f32_const => try writer.print("f32.const {x}\n", .{@as(f32, @bitCast(try reader.readInt(u32, .little)))}), |
| 2693 | | .f64_const => try writer.print("f64.const {x}\n", .{@as(f64, @bitCast(try reader.readInt(u64, .little)))}), |
| 2694 | | .global_get => try writer.print("global.get {x}\n", .{try std.leb.readUleb128(u32, reader)}), |
| 2697 | .i32_const => try bw.print("i32.const {x}\n", .{try std.leb.readIleb128(i32, reader)}), |
| 2698 | .i64_const => try bw.print("i64.const {x}\n", .{try std.leb.readIleb128(i64, reader)}), |
| 2699 | .f32_const => try bw.print("f32.const {x}\n", .{@as(f32, @bitCast(try reader.readInt(u32, .little)))}), |
| 2700 | .f64_const => try bw.print("f64.const {x}\n", .{@as(f64, @bitCast(try reader.readInt(u64, .little)))}), |
| 2701 | .global_get => try bw.print("global.get {x}\n", .{try std.leb.readUleb128(u32, reader)}), |
| 2695 | 2702 | else => unreachable, |
| 2696 | 2703 | } |
| 2697 | 2704 | const end_opcode = try std.leb.readUleb128(u8, reader); |
| ... | ... | @@ -2701,9 +2708,9 @@ const WasmDumper = struct { |
| 2701 | 2708 | } |
| 2702 | 2709 | |
| 2703 | 2710 | /// https://webassembly.github.io/spec/core/appendix/custom.html |
| 2704 | | fn parseDumpNames(step: *Step, reader: anytype, writer: anytype, data: []const u8) !void { |
| 2711 | fn parseDumpNames(step: *Step, reader: anytype, bw: *std.io.BufferedWriter, data: []const u8) !void { |
| 2705 | 2712 | while (reader.context.pos < data.len) { |
| 2706 | | switch (try parseDumpType(step, std.wasm.NameSubsection, reader, writer)) { |
| 2713 | switch (try parseDumpType(step, std.wasm.NameSubsection, reader, bw)) { |
| 2707 | 2714 | // The module name subsection ... consists of a single name |
| 2708 | 2715 | // that is assigned to the module itself. |
| 2709 | 2716 | .module => { |
| ... | ... | @@ -2711,7 +2718,7 @@ const WasmDumper = struct { |
| 2711 | 2718 | const name_len = try std.leb.readUleb128(u32, reader); |
| 2712 | 2719 | if (size != name_len + 1) return error.BadSubsectionSize; |
| 2713 | 2720 | if (reader.context.pos + name_len > data.len) return error.UnexpectedEndOfStream; |
| 2714 | | try writer.print("name {s}\n", .{data[reader.context.pos..][0..name_len]}); |
| 2721 | try bw.print("name {s}\n", .{data[reader.context.pos..][0..name_len]}); |
| 2715 | 2722 | reader.context.pos += name_len; |
| 2716 | 2723 | }, |
| 2717 | 2724 | |
| ... | ... | @@ -2720,7 +2727,7 @@ const WasmDumper = struct { |
| 2720 | 2727 | .function, .global, .data_segment => { |
| 2721 | 2728 | const size = try std.leb.readUleb128(u32, reader); |
| 2722 | 2729 | const entries = try std.leb.readUleb128(u32, reader); |
| 2723 | | try writer.print( |
| 2730 | try bw.print( |
| 2724 | 2731 | \\size {d} |
| 2725 | 2732 | \\names {d} |
| 2726 | 2733 | \\ |
| ... | ... | @@ -2732,7 +2739,7 @@ const WasmDumper = struct { |
| 2732 | 2739 | const name = data[reader.context.pos..][0..name_len]; |
| 2733 | 2740 | reader.context.pos += name.len; |
| 2734 | 2741 | |
| 2735 | | try writer.print( |
| 2742 | try bw.print( |
| 2736 | 2743 | \\index {d} |
| 2737 | 2744 | \\name {s} |
| 2738 | 2745 | \\ |
| ... | ... | @@ -2752,9 +2759,9 @@ const WasmDumper = struct { |
| 2752 | 2759 | } |
| 2753 | 2760 | } |
| 2754 | 2761 | |
| 2755 | | fn parseDumpProducers(reader: anytype, writer: anytype, data: []const u8) !void { |
| 2762 | fn parseDumpProducers(reader: anytype, bw: *std.io.BufferedWriter, data: []const u8) !void { |
| 2756 | 2763 | const field_count = try std.leb.readUleb128(u32, reader); |
| 2757 | | try writer.print("fields {d}\n", .{field_count}); |
| 2764 | try bw.print("fields {d}\n", .{field_count}); |
| 2758 | 2765 | var current_field: u32 = 0; |
| 2759 | 2766 | while (current_field < field_count) : (current_field += 1) { |
| 2760 | 2767 | const field_name_length = try std.leb.readUleb128(u32, reader); |
| ... | ... | @@ -2762,11 +2769,11 @@ const WasmDumper = struct { |
| 2762 | 2769 | reader.context.pos += field_name_length; |
| 2763 | 2770 | |
| 2764 | 2771 | const value_count = try std.leb.readUleb128(u32, reader); |
| 2765 | | try writer.print( |
| 2772 | try bw.print( |
| 2766 | 2773 | \\field_name {s} |
| 2767 | 2774 | \\values {d} |
| 2768 | 2775 | , .{ field_name, value_count }); |
| 2769 | | try writer.writeByte('\n'); |
| 2776 | try bw.writeByte('\n'); |
| 2770 | 2777 | var current_value: u32 = 0; |
| 2771 | 2778 | while (current_value < value_count) : (current_value += 1) { |
| 2772 | 2779 | const value_length = try std.leb.readUleb128(u32, reader); |
| ... | ... | @@ -2777,18 +2784,18 @@ const WasmDumper = struct { |
| 2777 | 2784 | const version = data[reader.context.pos..][0..version_length]; |
| 2778 | 2785 | reader.context.pos += version_length; |
| 2779 | 2786 | |
| 2780 | | try writer.print( |
| 2787 | try bw.print( |
| 2781 | 2788 | \\value_name {s} |
| 2782 | 2789 | \\version {s} |
| 2783 | 2790 | , .{ value, version }); |
| 2784 | | try writer.writeByte('\n'); |
| 2791 | try bw.writeByte('\n'); |
| 2785 | 2792 | } |
| 2786 | 2793 | } |
| 2787 | 2794 | } |
| 2788 | 2795 | |
| 2789 | | fn parseDumpFeatures(reader: anytype, writer: anytype, data: []const u8) !void { |
| 2796 | fn parseDumpFeatures(reader: anytype, bw: *std.io.BufferedWriter, data: []const u8) !void { |
| 2790 | 2797 | const feature_count = try std.leb.readUleb128(u32, reader); |
| 2791 | | try writer.print("features {d}\n", .{feature_count}); |
| 2798 | try bw.print("features {d}\n", .{feature_count}); |
| 2792 | 2799 | |
| 2793 | 2800 | var index: u32 = 0; |
| 2794 | 2801 | while (index < feature_count) : (index += 1) { |
| ... | ... | @@ -2797,7 +2804,7 @@ const WasmDumper = struct { |
| 2797 | 2804 | const feature_name = data[reader.context.pos..][0..name_length]; |
| 2798 | 2805 | reader.context.pos += name_length; |
| 2799 | 2806 | |
| 2800 | | try writer.print("{c} {s}\n", .{ prefix_byte, feature_name }); |
| 2807 | try bw.print("{c} {s}\n", .{ prefix_byte, feature_name }); |
| 2801 | 2808 | } |
| 2802 | 2809 | } |
| 2803 | 2810 | }; |