| ... | ... | @@ -535,15 +535,21 @@ const coff = struct { |
| 535 | 535 | opts.imports or |
| 536 | 536 | opts.tls; |
| 537 | 537 | |
| 538 | | const data_dirs, const magic = if (header.size_of_optional_header > 0) optional_header: { |
| 538 | const ImageInfo = struct { |
| 539 | data_dirs: []const std.coff.ImageDataDirectory, |
| 540 | magic: std.coff.OptionalHeader.Magic, |
| 541 | image_base: u64, |
| 542 | }; |
| 543 | |
| 544 | const image_info: ?ImageInfo = if (header.size_of_optional_header > 0) image_info: { |
| 539 | 545 | if (!opts.file_headers and !needs_data_dirs) { |
| 540 | 546 | try fr.seekBy(header.size_of_optional_header); |
| 541 | | break :optional_header .{ &.{}, null }; |
| 547 | break :image_info null; |
| 542 | 548 | } |
| 543 | 549 | |
| 544 | 550 | if (opts.file_headers) try w.writeAll("COFF Optional Header:\n"); |
| 545 | 551 | const magic: std.coff.OptionalHeader.Magic = @enumFromInt(try r.peekInt(u16, .little)); |
| 546 | | const num_directory_entries = switch (magic) { |
| 552 | const num_directory_entries, const image_base = switch (magic) { |
| 547 | 553 | inline .PE32, .@"PE32+" => |v| num_data_dirs: { |
| 548 | 554 | const OptionalHeader = if (v == .PE32) |
| 549 | 555 | std.coff.OptionalHeader.PE32 |
| ... | ... | @@ -593,7 +599,10 @@ const coff = struct { |
| 593 | 599 | try w.writeByte('\n'); |
| 594 | 600 | } |
| 595 | 601 | |
| 596 | | break :num_data_dirs optional_header.number_of_rva_and_sizes; |
| 602 | break :num_data_dirs .{ |
| 603 | optional_header.number_of_rva_and_sizes, |
| 604 | optional_header.image_base, |
| 605 | }; |
| 597 | 606 | }, |
| 598 | 607 | else => return failParse(opts, "invalid optional header magic number: {x}", .{magic}), |
| 599 | 608 | }; |
| ... | ... | @@ -614,10 +623,14 @@ const coff = struct { |
| 614 | 623 | } |
| 615 | 624 | if (opts.file_headers) try w.writeByte('\n'); |
| 616 | 625 | |
| 617 | | break :optional_header .{ known_dirs[0..@min(known_dirs.len, num_directory_entries)], magic }; |
| 626 | break :image_info .{ |
| 627 | .data_dirs = known_dirs[0..@min(known_dirs.len, num_directory_entries)], |
| 628 | .magic = magic, |
| 629 | .image_base = image_base, |
| 630 | }; |
| 618 | 631 | } else if (is_image) { |
| 619 | 632 | return failParse(opts, "image did not contain an optional header", .{}); |
| 620 | | } else .{ &.{}, null }; |
| 633 | } else null; |
| 621 | 634 | |
| 622 | 635 | // Section names in images don't use the string table, as they must fit inline in the header |
| 623 | 636 | const load_string_table = (opts.strings or !is_image) and header.pointer_to_symbol_table > 0; |
| ... | ... | @@ -1013,7 +1026,7 @@ const coff = struct { |
| 1013 | 1026 | defer gpa.free(rva_index); |
| 1014 | 1027 | |
| 1015 | 1028 | if (opts.exports) { |
| 1016 | | if (try seekToDataDirectory(opts, fr, w, rva_index, sections.items, data_dirs, .EXPORT)) |section_index| { |
| 1029 | if (try seekToDataDirectory(opts, fr, w, rva_index, sections.items, image_info.?.data_dirs, .EXPORT)) |section_index| { |
| 1017 | 1030 | const export_dir = r.takeStruct(std.coff.ExportDirectoryTable, .little) catch |err| |
| 1018 | 1031 | return failParse(opts, "unable to read export directory: {t}", .{err}); |
| 1019 | 1032 | |
| ... | ... | @@ -1056,7 +1069,7 @@ const coff = struct { |
| 1056 | 1069 | |
| 1057 | 1070 | // All the variable length fields should be contained within this directory. |
| 1058 | 1071 | // Read it entirely to avoid needing to seek per-name when iterating. |
| 1059 | | const dir = data_dirs[@intFromEnum(DIRECTORY_ENTRY.EXPORT)]; |
| 1072 | const dir = image_info.?.data_dirs[@intFromEnum(DIRECTORY_ENTRY.EXPORT)]; |
| 1060 | 1073 | const dir_end_rva = dir.virtual_address + dir.size; |
| 1061 | 1074 | const dir_loc = fr.logicalPos(); |
| 1062 | 1075 | const dir_slice = try r.readAlloc(gpa, dir.size); |
| ... | ... | @@ -1097,7 +1110,15 @@ const coff = struct { |
| 1097 | 1110 | } |
| 1098 | 1111 | |
| 1099 | 1112 | if (opts.imports) { |
| 1100 | | if (try seekToDataDirectory(opts, fr, w, rva_index, sections.items, data_dirs, .IMPORT)) |_| { |
| 1113 | if (try seekToDataDirectory( |
| 1114 | opts, |
| 1115 | fr, |
| 1116 | w, |
| 1117 | rva_index, |
| 1118 | sections.items, |
| 1119 | image_info.?.data_dirs, |
| 1120 | .IMPORT, |
| 1121 | )) |_| { |
| 1101 | 1122 | const Entry = std.coff.ImportDirectoryEntry; |
| 1102 | 1123 | var directory_entries: std.ArrayList(Entry) = .empty; |
| 1103 | 1124 | defer directory_entries.deinit(gpa); |
| ... | ... | @@ -1114,14 +1135,20 @@ const coff = struct { |
| 1114 | 1135 | } |
| 1115 | 1136 | |
| 1116 | 1137 | for (directory_entries.items) |entry| { |
| 1117 | | const name_section = sectionContainingRva(rva_index, sections.items, entry.name_rva) orelse |
| 1138 | const name_section = sectionContainingRva( |
| 1139 | rva_index, |
| 1140 | sections.items, |
| 1141 | entry.name_rva, |
| 1142 | ) orelse |
| 1118 | 1143 | return failParse( |
| 1119 | 1144 | opts, |
| 1120 | 1145 | "import directory entry name rva 0x{x} was not found in any section", |
| 1121 | 1146 | .{entry.name_rva}, |
| 1122 | 1147 | ); |
| 1123 | 1148 | |
| 1124 | | const name_loc = sections.items[name_section].rvaFileOffset(entry.name_rva) catch unreachable; |
| 1149 | const name_loc = sections.items[name_section].rvaFileOffset( |
| 1150 | entry.name_rva, |
| 1151 | ) catch unreachable; |
| 1125 | 1152 | fr.seekTo(name_loc) catch |err| |
| 1126 | 1153 | return failParse( |
| 1127 | 1154 | opts, |
| ... | ... | @@ -1161,7 +1188,7 @@ const coff = struct { |
| 1161 | 1188 | .{ ilt_loc, err }, |
| 1162 | 1189 | ); |
| 1163 | 1190 | |
| 1164 | | switch (magic.?) { |
| 1191 | switch (image_info.?.magic) { |
| 1165 | 1192 | _ => try w.writeAll("(unknown magic)"), |
| 1166 | 1193 | inline else => |m| { |
| 1167 | 1194 | const TableEntry = std.coff.ImportLookupTableEntry(m); |
| ... | ... | @@ -1230,8 +1257,79 @@ const coff = struct { |
| 1230 | 1257 | } |
| 1231 | 1258 | |
| 1232 | 1259 | if (opts.tls) { |
| 1233 | | if (try seekToDataDirectory(opts, fr, w, rva_index, sections.items, data_dirs, .TLS)) |_| { |
| 1234 | | // TODO |
| 1260 | if (try seekToDataDirectory( |
| 1261 | opts, |
| 1262 | fr, |
| 1263 | w, |
| 1264 | rva_index, |
| 1265 | sections.items, |
| 1266 | image_info.?.data_dirs, |
| 1267 | .TLS, |
| 1268 | )) |_| { |
| 1269 | switch (image_info.?.magic) { |
| 1270 | _ => try w.writeAll("(unknown magic)"), |
| 1271 | inline else => |m| { |
| 1272 | const TlsDirectoryEntry = std.coff.TlsDirectoryEntry(m); |
| 1273 | const tls_entry = r.takeStruct(TlsDirectoryEntry, .little) catch |err| |
| 1274 | return failParse(opts, "unable to read tls directory: {t}", .{err}); |
| 1275 | |
| 1276 | try w.writeAll("TLS Directory:\n"); |
| 1277 | try dumpHeader(w, TlsDirectoryEntry, &tls_entry, struct {}); |
| 1278 | |
| 1279 | try w.writeAll(" | "); |
| 1280 | if (tls_entry.characteristics.alignment == .NONE) { |
| 1281 | try w.writeAll("Alignment not specified"); |
| 1282 | } else { |
| 1283 | try w.print( |
| 1284 | "Alignment: {d}", |
| 1285 | .{tls_entry.characteristics.alignment.toByteUnits().?}, |
| 1286 | ); |
| 1287 | } |
| 1288 | |
| 1289 | try w.writeAll( |
| 1290 | \\ |
| 1291 | \\ |
| 1292 | \\TLS Callbacks: |
| 1293 | \\ Address |
| 1294 | \\ |
| 1295 | ); |
| 1296 | |
| 1297 | const callbacks_rva: u32 = @intCast(tls_entry.callbacks_va - image_info.?.image_base); |
| 1298 | const section_index = sectionContainingRva( |
| 1299 | rva_index, |
| 1300 | sections.items, |
| 1301 | callbacks_rva, |
| 1302 | ) orelse |
| 1303 | return failParse( |
| 1304 | opts, |
| 1305 | "tls callbacks rva 0x{x} was not found in any section", |
| 1306 | .{callbacks_rva}, |
| 1307 | ); |
| 1308 | |
| 1309 | const callbacks_loc = sections.items[section_index] |
| 1310 | .rvaFileOffset(callbacks_rva) catch unreachable; |
| 1311 | |
| 1312 | fr.seekTo(callbacks_loc) catch |err| |
| 1313 | return failParse( |
| 1314 | opts, |
| 1315 | "unable to seek to tls callbacks array at offset 0x{x}: {t}", |
| 1316 | .{ callbacks_loc, err }, |
| 1317 | ); |
| 1318 | |
| 1319 | while (true) { |
| 1320 | const callback_va = r.takeInt(@FieldType(TlsDirectoryEntry, "callbacks_va"), .little) catch |err| |
| 1321 | return failParse( |
| 1322 | opts, |
| 1323 | "unable to read tls callbacks array: {t}", |
| 1324 | .{err}, |
| 1325 | ); |
| 1326 | |
| 1327 | try w.print("{x: >16} \n", .{callback_va}); |
| 1328 | if (callback_va == 0) break; |
| 1329 | } |
| 1330 | try w.writeByte('\n'); |
| 1331 | }, |
| 1332 | } |
| 1235 | 1333 | } |
| 1236 | 1334 | } |
| 1237 | 1335 | } |
| ... | ... | @@ -1245,8 +1343,10 @@ const coff = struct { |
| 1245 | 1343 | data_dirs: []const std.coff.ImageDataDirectory, |
| 1246 | 1344 | entry: DIRECTORY_ENTRY, |
| 1247 | 1345 | ) !?u16 { |
| 1248 | | if (@intFromEnum(entry) < data_dirs.len) { |
| 1346 | if (@intFromEnum(entry) < data_dirs.len) blk: { |
| 1249 | 1347 | const rva = data_dirs[@intFromEnum(entry)].virtual_address; |
| 1348 | if (rva == 0) break :blk; |
| 1349 | |
| 1250 | 1350 | const section_index = sectionContainingRva(rva_index, sections, rva) orelse |
| 1251 | 1351 | return failParse( |
| 1252 | 1352 | opts, |