il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
392 lines • 17.4 kB
JavaScript
;
/**
* Extract Metadata Tool Implementation
* Extracts assembly metadata, version information, and compilation flags from IL2CPP dumps
* Implements comprehensive metadata parsing with validation and error handling
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractMetadataSchema = exports.ExtractMetadataToolHandler = void 0;
exports.createExtractMetadataTool = createExtractMetadataTool;
const zod_1 = require("zod");
const fs = __importStar(require("fs"));
const base_tool_handler_1 = require("../base-tool-handler");
const mcp_response_formatter_1 = require("../../utils/mcp-response-formatter");
/**
* Extract Metadata Tool Handler
* Provides comprehensive IL2CPP metadata extraction capabilities
*/
class ExtractMetadataToolHandler extends base_tool_handler_1.BaseAnalysisToolHandler {
constructor(context) {
super({
name: 'extract_metadata',
description: 'Extract assembly metadata, version information, and compilation flags from IL2CPP dumps',
enableParameterValidation: true,
enableResponseFormatting: true,
maxExecutionTime: 60000
}, context);
this.extractionStartTime = 0;
this.content = '';
this.lines = [];
}
/**
* Validate extract metadata specific parameters
*/
async validateParameters(params) {
const errors = [];
const warnings = [];
const adjustedValues = {};
// Validate that either content or file_path is provided
if (!params.content && !params.file_path) {
errors.push('Either content or file_path parameter is required');
}
if (params.content && params.file_path) {
warnings.push('Both content and file_path provided, content will be used');
}
// Validate file_path if provided
if (params.file_path && !params.content) {
try {
if (!fs.existsSync(params.file_path)) {
errors.push(`File not found: ${params.file_path}`);
}
}
catch (error) {
errors.push(`Invalid file path: ${params.file_path}`);
}
}
// Validate max_processing_time
if (params.max_processing_time !== undefined) {
if (params.max_processing_time < 1000 || params.max_processing_time > 300000) {
adjustedValues.max_processing_time = Math.max(1000, Math.min(300000, params.max_processing_time));
warnings.push(`max_processing_time adjusted to ${adjustedValues.max_processing_time}ms (valid range: 1000-300000)`);
}
}
return {
isValid: errors.length === 0,
errors,
warnings,
adjustedValues
};
}
/**
* Execute the core metadata extraction logic
*/
async executeCore(params) {
return await this.performAnalysis(async () => {
this.extractionStartTime = Date.now();
// Load content
await this.loadContent(params);
// Validate content
if (!this.content || this.content.trim().length === 0) {
throw new Error('IL2CPP dump content is empty or invalid');
}
this.lines = this.content.split('\n');
// Extract all metadata components
const assemblies = this.extractAssemblyMetadata();
const buildInfo = this.extractBuildInformation();
const typeSystem = this.extractTypeSystemMetadata();
// Validate extracted metadata
const validationResults = this.validateMetadata(assemblies, typeSystem);
// Calculate statistics
const statistics = this.calculateStatistics(assemblies, typeSystem, validationResults);
// Check processing time limit
const processingTime = Date.now() - this.extractionStartTime;
const maxTime = params.max_processing_time || 60000;
if (processingTime > maxTime) {
throw new Error(`Metadata extraction exceeded time limit: ${processingTime}ms > ${maxTime}ms`);
}
return {
assemblies,
buildInfo,
typeSystem,
validationResults,
statistics,
extractionDate: new Date(),
sourceFile: params.file_path
};
});
}
/**
* Load content from parameters
*/
async loadContent(params) {
try {
if (params.content) {
this.content = params.content;
}
else if (params.file_path) {
this.content = await fs.promises.readFile(params.file_path, 'utf-8');
}
}
catch (error) {
throw new Error(`Failed to load IL2CPP dump: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Extract assembly metadata from image mappings
*/
extractAssemblyMetadata() {
const assemblies = [];
const imageRegex = /\/\/ Image (\d+): (.+?) - Assembly: (.+?), Version=(.+?), Culture=(.+?), PublicKeyToken=(.+?)$/;
for (const line of this.lines) {
const trimmedLine = line.trim();
const match = trimmedLine.match(imageRegex);
if (match) {
const [, imageIndexStr, imageName, assemblyName, version, culture, publicKeyToken] = match;
assemblies.push({
name: assemblyName.trim(),
version: version.trim(),
culture: culture.trim(),
publicKeyToken: publicKeyToken.trim(),
imageName: imageName.trim(),
imageIndex: parseInt(imageIndexStr),
dependencies: []
});
}
}
return assemblies;
}
/**
* Extract build and compilation information
*/
extractBuildInformation() {
const buildInfo = {};
for (const line of this.lines) {
const trimmedLine = line.trim();
// Unity version
const unityMatch = trimmedLine.match(/\/\/ Generated by Unity IL2CPP v(.+?)$/);
if (unityMatch) {
buildInfo.unityVersion = unityMatch[1].trim();
buildInfo.il2cppVersion = unityMatch[1].trim();
}
// Build configuration
const configMatch = trimmedLine.match(/\/\/ Build Configuration: (.+?)$/);
if (configMatch) {
buildInfo.buildConfiguration = configMatch[1].trim();
}
// Target platform
const platformMatch = trimmedLine.match(/\/\/ Target Platform: (.+?)$/);
if (platformMatch) {
buildInfo.targetPlatform = platformMatch[1].trim();
}
// Scripting backend
const backendMatch = trimmedLine.match(/\/\/ Scripting Backend: (.+?)$/);
if (backendMatch) {
buildInfo.scriptingBackend = backendMatch[1].trim();
}
}
return buildInfo;
}
/**
* Extract type system metadata including generics and constraints
*/
extractTypeSystemMetadata() {
const genericTypes = [];
let totalTypes = 0;
let currentNamespace = '';
for (let i = 0; i < this.lines.length; i++) {
const line = this.lines[i].trim();
// Track namespace declarations
if (line.startsWith('// Namespace:')) {
currentNamespace = line.substring('// Namespace:'.length).trim();
continue;
}
// Count all types with TypeDefIndex
if (line.includes('TypeDefIndex:')) {
totalTypes++;
// Look for generic type declarations
if (line.includes('<') && line.includes('>')) {
const typeDefMatch = line.match(/TypeDefIndex:\s*(\d+)/);
const typeDefIndex = typeDefMatch ? parseInt(typeDefMatch[1]) : 0;
// Extract generic type information
const beforeComment = line.split('//')[0].trim();
const genericMatch = beforeComment.match(/(class|interface|struct)\s+([^<\s]+)<([^>]+)>/);
if (genericMatch) {
const [, , typeName, genericParams] = genericMatch;
const parameters = genericParams.split(',').map(p => p.trim());
// Look for constraints in following lines
const constraints = [];
let j = i + 1;
while (j < this.lines.length && this.lines[j].trim().startsWith('//')) {
const constraintLine = this.lines[j].trim();
if (constraintLine.includes('where ')) {
constraints.push(constraintLine.replace('//', '').trim());
}
j++;
}
// Extract base type and interfaces
const inheritanceMatch = beforeComment.match(/:\s*(.+?)(?:\s*\/\/|$)/);
const inheritance = inheritanceMatch ? inheritanceMatch[1].trim() : '';
const parts = inheritance.split(',').map(p => p.trim()).filter(p => p.length > 0);
const baseType = parts.length > 0 && !parts[0].startsWith('I') ? parts[0] : undefined;
const interfaces = parts.filter(p => p.startsWith('I') || p !== baseType);
genericTypes.push({
name: `${typeName}<${genericParams}>`,
namespace: currentNamespace,
typeDefIndex,
genericParameters: parameters,
constraints,
baseType,
interfaces,
isGenericDefinition: true,
isGenericInstance: false
});
}
}
}
}
return {
totalTypes,
genericTypes
};
}
/**
* Validate extracted metadata for consistency and completeness
*/
validateMetadata(assemblies, typeSystem) {
const errors = [];
const warnings = [];
const suggestions = [];
// Validate assemblies
if (assemblies.length === 0) {
errors.push('No assembly metadata found in IL2CPP dump');
}
for (const assembly of assemblies) {
if (!assembly.name || assembly.name.trim().length === 0) {
errors.push(`Assembly at index ${assembly.imageIndex} has empty name`);
}
if (!assembly.version || !assembly.version.match(/^\d+\.\d+\.\d+\.\d+$/)) {
warnings.push(`Assembly ${assembly.name} has invalid version format: ${assembly.version}`);
}
}
// Validate type system
if (typeSystem.totalTypes === 0) {
warnings.push('No types found in IL2CPP dump');
}
// Check for missing assembly information
for (let i = 0; i < this.lines.length; i++) {
const line = this.lines[i].trim();
if (line.startsWith('// Image ') && !line.includes('Assembly:')) {
const imageMatch = line.match(/\/\/ Image (\d+): (.+?) -/);
if (imageMatch) {
errors.push(`Missing assembly information for image ${imageMatch[1]}`);
}
}
// Check for classes without TypeDefIndex
if (line.includes('class ') && !line.includes('TypeDefIndex:')) {
const classMatch = line.match(/class\s+([^\s{:]+)/);
if (classMatch) {
warnings.push(`Class ${classMatch[1]} missing TypeDefIndex`);
}
}
}
// Performance suggestions
if (typeSystem.genericTypes.length > 1000) {
suggestions.push('Large number of generic types detected. Consider enabling selective processing for better performance.');
}
return {
isValid: errors.length === 0,
errors,
warnings,
suggestions
};
}
/**
* Calculate processing statistics
*/
calculateStatistics(assemblies, typeSystem, validationResults) {
const processingTime = Date.now() - this.extractionStartTime;
const memoryUsage = process.memoryUsage().heapUsed;
return {
totalAssemblies: assemblies.length,
totalTypes: typeSystem.totalTypes,
totalMethods: 0, // Will be calculated in future iterations
totalFields: 0, // Will be calculated in future iterations
processingTime,
memoryUsage,
validationErrors: validationResults.errors.length,
validationWarnings: validationResults.warnings.length
};
}
/**
* Format the metadata extraction response
*/
formatResponse(result, warnings = []) {
const allWarnings = [...warnings, ...result.validationResults.warnings];
// Create comprehensive response data
const responseData = {
metadata: result,
summary: {
assemblies: result.assemblies.length,
types: result.typeSystem.totalTypes,
genericTypes: result.typeSystem.genericTypes.length,
processingTime: result.statistics.processingTime,
memoryUsage: Math.round(result.statistics.memoryUsage / 1024 / 1024 * 100) / 100, // MB
isValid: result.validationResults.isValid
},
validation: result.validationResults
};
let response = mcp_response_formatter_1.MCPResponseFormatter.formatAnalysisResults(responseData, this.config.name, { extractionDate: result.extractionDate.toISOString() }, result.statistics.processingTime);
if (allWarnings.length > 0) {
response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, allWarnings);
}
return mcp_response_formatter_1.MCPResponseFormatter.addExecutionTiming(response, this.startTime, this.config.name);
}
}
exports.ExtractMetadataToolHandler = ExtractMetadataToolHandler;
/**
* Zod schema for extract metadata tool parameters
*/
exports.extractMetadataSchema = zod_1.z.object({
content: zod_1.z.string().optional().describe("IL2CPP dump content as string"),
file_path: zod_1.z.string().optional().describe("Path to IL2CPP dump file"),
include_generic_instantiations: zod_1.z.boolean().optional().default(true).describe("Include generic type instantiations"),
include_method_signatures: zod_1.z.boolean().optional().default(true).describe("Include method signature analysis"),
include_field_offsets: zod_1.z.boolean().optional().default(true).describe("Include field offset information"),
validate_structure: zod_1.z.boolean().optional().default(true).describe("Enable metadata structure validation"),
enable_performance_tracking: zod_1.z.boolean().optional().default(true).describe("Enable performance monitoring"),
max_processing_time: zod_1.z.number().min(1000).max(300000).optional().default(60000).describe("Maximum processing time in milliseconds")
});
/**
* Factory function to create and register the extract metadata tool
*/
function createExtractMetadataTool(server, context) {
const handler = new ExtractMetadataToolHandler(context);
server.tool("extract_metadata", exports.extractMetadataSchema, async (params) => {
return await handler.execute(params);
});
return handler;
}
//# sourceMappingURL=extract-metadata-tool.js.map