@bcoders.gr/evm-disassembler
Version:
A comprehensive EVM bytecode disassembler and analyzer with support for multiple EVM versions
196 lines (162 loc) • 5.67 kB
JavaScript
/**
* CLI interface for EVM Disassembler
*/
const fs = require('fs');
const path = require('path');
const { EVMDisassembler } = require('./index');
// Parse command line arguments
const args = process.argv.slice(2);
// Help text
const helpText = `
EVM Bytecode Disassembler CLI
Usage: evm-disassembler [options] <bytecode|file>
Options:
-h, --help Show this help message
-v, --version Show version
-f, --format <format> Output format (text, json, assembly, markdown, csv) [default: text]
-o, --output <file> Write output to file instead of stdout
--evm <version> EVM version (homestead, byzantium, constantinople, istanbul,
berlin, london, paris, shanghai, cancun, latest) [default: latest]
--no-metadata Don't include metadata detection
--no-functions Don't perform function analysis
--no-security Don't perform security analysis
--no-stack Don't perform stack analysis
--full-metadata Don't stop at metadata boundary
--summary Show only summary (JSON format only)
Examples:
evm-disassembler 0x6080604052...
evm-disassembler contract.bin
evm-disassembler -f json -o output.json contract.bin
evm-disassembler --format assembly --evm london bytecode.txt
evm-disassembler --summary -f json contract.bin
Input can be:
- Hex bytecode string (with or without 0x prefix)
- File containing hex bytecode
- Binary file containing bytecode
`;
// Version
const packageJson = require('./package.json');
const version = packageJson.version;
// Parse arguments
let input = null;
let options = {
format: 'text',
output: null,
evmVersion: 'latest',
includeMetadata: true,
performFunctionAnalysis: true,
performSecurityAnalysis: true,
performStackAnalysis: true,
stopAtMetadata: true,
summaryOnly: false
};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case '-h':
case '--help':
console.log(helpText);
process.exit(0);
break;
case '-v':
case '--version':
console.log(`evm-disassembler v${version}`);
process.exit(0);
break;
case '-f':
case '--format':
options.format = args[++i];
break;
case '-o':
case '--output':
options.output = args[++i];
break;
case '--evm':
options.evmVersion = args[++i];
break;
case '--no-metadata':
options.includeMetadata = false;
break;
case '--no-functions':
options.performFunctionAnalysis = false;
break;
case '--no-security':
options.performSecurityAnalysis = false;
break;
case '--no-stack':
options.performStackAnalysis = false;
break;
case '--full-metadata':
options.stopAtMetadata = false;
break;
case '--summary':
options.summaryOnly = true;
break;
default:
if (arg.startsWith('-')) {
console.error(`Unknown option: ${arg}`);
console.error('Use --help for usage information');
process.exit(1);
}
input = arg;
break;
}
}
// Check if input was provided
if (!input) {
console.error('Error: No input provided');
console.error('Use --help for usage information');
process.exit(1);
}
// Main function
async function main() {
try {
let bytecode = input;
// Check if input is a file
if (fs.existsSync(input)) {
const content = fs.readFileSync(input);
// Check if it's a text file or binary
if (input.endsWith('.bin') || input.endsWith('.bytecode')) {
// Binary file - convert to hex
bytecode = content.toString('hex');
} else {
// Text file - assume it contains hex string
bytecode = content.toString('utf8').trim();
}
}
// Create disassembler
const disassembler = new EVMDisassembler({
evmVersion: options.evmVersion,
includeMetadata: options.includeMetadata,
stopAtMetadata: options.stopAtMetadata,
performStackAnalysis: options.performStackAnalysis,
performFunctionAnalysis: options.performFunctionAnalysis,
performSecurityAnalysis: options.performSecurityAnalysis
});
// Disassemble
const result = disassembler.disassemble(bytecode);
// Format output
let output;
if (options.summaryOnly && options.format === 'json') {
output = JSON.stringify(result.summary, null, 2);
} else {
output = disassembler.format(result, options.format, { pretty: true });
}
// Write output
if (options.output) {
fs.writeFileSync(options.output, output);
console.log(`Output written to: ${options.output}`);
} else {
console.log(output);
}
} catch (error) {
console.error(`Error: ${error.message}`);
if (process.env.DEBUG) {
console.error(error.stack);
}
process.exit(1);
}
}
// Run main function
main();