UNPKG

il2cpp-dump-analyzer-mcp

Version:

Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games

392 lines 17.4 kB
"use strict"; /** * 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