|
| 1 | +'use strict' |
| 2 | + |
| 3 | +var fs = require('fs') |
| 4 | +var path = require('path') |
| 5 | + |
| 6 | +module.exports = getTargetArch |
| 7 | + |
| 8 | +// DWORD for offset of PE signature; see |
| 9 | +// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#ms-dos-stub-image-only |
| 10 | +var SIGNATURE_OFFSET_OFFSET = 0x3c |
| 11 | + |
| 12 | +function getTargetArch(path, callback) { |
| 13 | + fs.open(path, 'r', function(err, fd) { |
| 14 | + if (err) return callback(err) |
| 15 | + readMagic(fd, function(err, archName, archCode) { |
| 16 | + fs.close(fd) |
| 17 | + callback(err, archName, archCode) |
| 18 | + }) |
| 19 | + }) |
| 20 | +} |
| 21 | + |
| 22 | +function readMagic(fd, callback) { |
| 23 | + var buffer = Buffer.alloc(4) |
| 24 | + fs.read(fd, buffer, 0, 2, 0, function(err, bytesRead) { |
| 25 | + if (err) return callback(err) |
| 26 | + if (bytesRead !== 2) return callback(new Error('failed to read MZ magic')) |
| 27 | + var magic = buffer.readInt16BE() |
| 28 | + var bigEndian = null |
| 29 | + if (magic === 0x5a4d) |
| 30 | + bigEndian = true |
| 31 | + else if (magic === 0x4d5a) |
| 32 | + bigEndian = false |
| 33 | + else |
| 34 | + return callback(new Error('not a DOS-MZ file')) |
| 35 | + readTargetArch(fd, bigEndian, callback) |
| 36 | + }) |
| 37 | +} |
| 38 | + |
| 39 | +function readTargetArch(fd, bigEndian, callback) { |
| 40 | + var buffer = Buffer.alloc(4) |
| 41 | + fs.read(fd, buffer, 0, 4, SIGNATURE_OFFSET_OFFSET, function(err, bytesRead) { |
| 42 | + if (err) return callback(err) |
| 43 | + if (bytesRead !== 4) return callback(new Error('failed to read PE signature offset')) |
| 44 | + var signatureOffset = bigEndian ? buffer.readUInt32BE() : buffer.readUInt32LE() |
| 45 | + var targetArchOffset = signatureOffset + 4 |
| 46 | + fs.read(fd, buffer, 0, 2, targetArchOffset, function(err, bytesRead) { |
| 47 | + if (err) return callback(err) |
| 48 | + if (bytesRead !== 2) return callback(new Error('failed to read PE architecture field')) |
| 49 | + var targetArchCode = bigEndian ? buffer.readUInt16BE() : buffer.readUInt16LE() |
| 50 | + var targetArchName = architectureNameByCode(targetArchCode) |
| 51 | + callback(null, targetArchName, targetArchCode) |
| 52 | + }) |
| 53 | + }) |
| 54 | +} |
| 55 | + |
| 56 | +// see https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types |
| 57 | +function architectureNameByCode(code) { |
| 58 | + switch (code) { |
| 59 | + case 0x0: |
| 60 | + return 'UNKNOWN' |
| 61 | + case 0x1d3: |
| 62 | + return 'AM33' |
| 63 | + case 0x8664: |
| 64 | + return 'AMD64' |
| 65 | + case 0x1c0: |
| 66 | + return 'ARM' |
| 67 | + case 0xaa64: |
| 68 | + return 'ARM64' |
| 69 | + case 0x1c4: |
| 70 | + return 'ARMNT' |
| 71 | + case 0xebc: |
| 72 | + return 'EBC' |
| 73 | + case 0x14c: |
| 74 | + return 'I386' |
| 75 | + case 0x200: |
| 76 | + return 'IA64' |
| 77 | + case 0x9041: |
| 78 | + return 'M32R' |
| 79 | + case 0x266: |
| 80 | + return 'MIPS16' |
| 81 | + case 0x366: |
| 82 | + return 'MIPSFPU' |
| 83 | + case 0x466: |
| 84 | + return 'MIPSFPU16' |
| 85 | + case 0x1f0: |
| 86 | + return 'POWERPC' |
| 87 | + case 0x1f1: |
| 88 | + return 'POWERPCFP' |
| 89 | + case 0x166: |
| 90 | + return 'R4000' |
| 91 | + case 0x5032: |
| 92 | + return 'RISCV32' |
| 93 | + case 0x5064: |
| 94 | + return 'RISCV64' |
| 95 | + case 0x5128: |
| 96 | + return 'RISCV128' |
| 97 | + case 0x1a2: |
| 98 | + return 'SH3' |
| 99 | + case 0x1a3: |
| 100 | + return 'SH3DSP' |
| 101 | + case 0x1a6: |
| 102 | + return 'SH4' |
| 103 | + case 0x1a8: |
| 104 | + return 'SH5' |
| 105 | + case 0x1c2: |
| 106 | + return 'THUMB' |
| 107 | + case 0x169: |
| 108 | + return 'WCEMIPSV2' |
| 109 | + default: |
| 110 | + return null |
| 111 | + } |
| 112 | +} |
0 commit comments