public static LoadResults LoadMDSPath(string path) { var ret = new LoadResults { MdsPath = path }; //ret.MdfPath = Path.ChangeExtension(path, ".mdf"); try { if (!File.Exists(path)) { throw new MDSParseException("Malformed MDS format: nonexistent MDS file!"); } AFile mdsf; using (var infMDS = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) mdsf = new MDS_Format().Parse(infMDS); ret.ParsedMDSFile = mdsf; ret.Valid = true; } catch (MDSParseException ex) { ret.FailureException = ex; } return(ret); }
private void arraysListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.AddedItems.Count == 1) { ExpressionInfo expressionInfo = (ExpressionInfo)e.AddedItems[0]; LoadResults result = LoadArray(expressionInfo.Expression, false); SetupControls(expressionInfo); switch (result) { case LoadResults.LargeArray: LargeArrayHandler largeArrayHandler = new LargeArrayHandler(expressionInfo.Expression.DataMembers.Count, 2000, 40000); largeArrayHandler.LoadArrayRequest += largeArrayHandler_LoadArrayRequest; mainPanel.Children.Add(largeArrayHandler); break; case LoadResults.NotSupported: break; case LoadResults.Exception: Label errorLabel = new Label { Content = string.Format("Error rendering array '{0}'\r\n\r\n'{1}'", expressionInfo.Name, _lastLoadException.Message) }; mainPanel.Children.Clear(); mainPanel.Children.Add(errorLabel); break; } } }
public static LoadResults LoadCCDPath(string path) { var ret = new LoadResults { CcdPath = path, ImgPath = Path.ChangeExtension(path, ".img"), SubPath = Path.ChangeExtension(path, ".sub") }; try { if (!File.Exists(path)) { throw new CCDParseException("Malformed CCD format: nonexistent CCD file!"); } CCDFile ccdf; using (var infCCD = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) ccdf = new CCD_Format().ParseFrom(infCCD); ret.ParsedCCDFile = ccdf; ret.Valid = true; } catch (CCDParseException ex) { ret.FailureException = ex; } return(ret); }
public void SwitchToGame(Games.GameInformation game) { Log.WriteLine(Verbosity.Critical, Feature.General, "Instance: switching to game " + game.Parameters.Title); #if XMB _xmb.Disable(); #else #endif _bios.Game = game; LoadResults results = _bios.Load(); }
public LoadResults Load() { if (_game == null) { _gameSetEvent.WaitOne(); } LoadResults results = _kernel.LoadGame(); _loaded = true; _gameSetEvent.Set(); return(results); }
public static LoadResults LoadCCDPath(string path) { LoadResults ret = new LoadResults(); ret.CcdPath = path; ret.ImgPath = Path.ChangeExtension(path, ".img"); ret.SubPath = Path.ChangeExtension(path, ".sub"); try { if (!File.Exists(path)) { throw new CCDParseException("Malformed CCD format: nonexistent CCD file!"); } if (!File.Exists(ret.ImgPath)) { throw new CCDParseException("Malformed CCD format: nonexistent IMG file!"); } if (!File.Exists(ret.SubPath)) { throw new CCDParseException("Malformed CCD format: nonexistent SUB file!"); } //quick check of .img and .sub sizes long imgLen = new FileInfo(ret.ImgPath).Length; long subLen = new FileInfo(ret.SubPath).Length; if (imgLen % 2352 != 0) { throw new CCDParseException("Malformed CCD format: IMG file length not multiple of 2352"); } ret.NumImgSectors = (int)(imgLen / 2352); if (subLen != ret.NumImgSectors * 96) { throw new CCDParseException("Malformed CCD format: SUB file length not matching IMG"); } CCDFile ccdf; using (var infCCD = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) ccdf = new CCD_Format().ParseFrom(infCCD); ret.ParsedCCDFile = ccdf; ret.Valid = true; } catch (CCDParseException ex) { ret.FailureException = ex; } return(ret); }
static void Main(string[] args) { //string path = @"C:\Dev\Noxa.Emulation\UMD Images"; string path = @"F:\UMD Images"; string resultDir = Path.Combine(path, "Reports"); foreach (string umdPath in Directory.GetFiles(path, "*.iso")) { Console.WriteLine("-------------------------------------------------------------------------------"); Console.WriteLine("- UMD ISO: " + Path.GetFileName(umdPath)); Console.WriteLine("-------------------------------------------------------------------------------"); try { TestHost host = new TestHost(); host.CreateInstance(); TestInstance instance = host.CurrentInstance as TestInstance; instance.Umd.Load(umdPath, false); GameInformation game = GameLoader.FindGame(instance.Umd); Console.WriteLine(string.Format("Loading game {0} ({1})", game.Parameters.Title, game.Parameters.DiscID)); LoadResults results = instance.SwitchToGame(game); if (results.Successful == true) { Console.WriteLine("Imports: {0}, Exports: {1}", results.Imports.Count, results.Exports.Count); GameLoader.GenerateReport(instance, game, results, resultDir); } else { Console.WriteLine("!!!! Failed to load"); } instance.Destroy(); } catch (Exception ex) { Console.WriteLine("Exception while processing: " + ex.ToString()); Debugger.Break(); } Console.WriteLine(""); GC.Collect(); } }
public LoadResults LoadGame() { // Clear everything (needed?) Emulator.LightReset(); // Get bootstream Debug.Assert(Bios.BootStream == null); string filePath; Bios.BootStream = GameLoader.FindBootStream(Bios.Game, out filePath); Debug.Assert(Bios.BootStream != null); LoadParameters loadParams = new LoadParameters(); loadParams.FilePath = filePath; loadParams.Path = Bios.Game.Folder; #if DEBUG loadParams.AppendDatabase = true; #endif LoadResults results = Bios.Loader.LoadModule(ModuleType.Boot, Bios.BootStream, loadParams); Debug.Assert(results.Successful == true); if (results.Successful == false) { Log.WriteLine(Verbosity.Critical, Feature.Bios, "load of game failed"); Bios.Game = null; return(results); } this.CurrentPath = Bios.Game.Folder; this.Cpu.SetupGame(Bios.Game, Bios.BootStream); // Start modules foreach (Module module in Bios._modules) { module.Start(); } Log.WriteLine(Verbosity.Normal, Feature.Bios, "game loaded"); return(results); }
private bool FixupDelayedImports( Kernel kernel, LoadResults results ) { int fixupCount = 0; foreach( KModule previous in kernel.UserModules ) { if( previous.LoadResults.MissingImports.Count == 0 ) continue; LinkedListEntry<DelayedImport> e = previous.LoadResults.MissingImports.HeadEntry; while( e != null ) { LinkedListEntry<DelayedImport> next = e.Next; DelayedImport import = e.Value; if( results.ExportNames.Contains( import.StubImport.ModuleName ) == true ) { // Find export StubExport myExport = null; foreach( StubExport export in results.Exports ) { if( export.NID == import.StubImport.NID ) { myExport = export; break; } } if( myExport != null ) { previous.LoadResults.MissingImports.Remove( e ); fixupCount++; // Fixup Log.WriteLine( Verbosity.Verbose, Feature.Loader, "Fixing up module {0} delayed import 0x{1:X8}; value={2:X8}", previous.Name, import.StubImport.NID, myExport.Address ); Debug.Assert( myExport.Type == import.StubImport.Type ); if( myExport.Type == StubType.Function ) { BiosFunction function = import.StubImport.Function; // TODO: Change function module, etc? // Perform fixup uint* pcode = ( uint* )kernel.MemorySystem.Translate( function.StubAddress ); { // j {target} // nop *( pcode + 0 ) = ( uint )( ( 2 << 26 ) | ( ( myExport.Address >> 2 ) & 0x03FFFFFF ) ); *( pcode + 1 ) = ( uint )0; } } else { throw new NotImplementedException( "Cannot handle fixups of variable imports" ); } } } e = next; } } return true; }
public LoadResults LoadModule( ModuleType type, Stream moduleStream, LoadParameters parameters ) { Elf32_Shdr*[] allocSections = new Elf32_Shdr*[ 256 ]; Elf32_Shdr*[] relocSections = new Elf32_Shdr*[ 256 ]; int allocSectionsCount = 0; int relocSectionsCount = 0; LoadResults results = new LoadResults(); results.Successful = false; results.Imports = new List<StubImport>(); results.Exports = new List<StubExport>(); results.ExportNames = new List<string>(); results.MissingImports = new FastLinkedList<DelayedImport>(); Debug.Assert( moduleStream != null ); Debug.Assert( moduleStream.CanRead == true ); if( ( moduleStream == null ) || ( moduleStream.CanRead == false ) ) return results; Kernel kernel = _bios._kernel; ICpu cpu = kernel.Cpu; MemorySystem memory = kernel.MemorySystem; IntPtr pbuffer = IntPtr.Zero; try { // Load the entire module in to memory - nasty, but it works int length = ( int )moduleStream.Length; byte[] mbuffer = new byte[ length ]; moduleStream.Read( mbuffer, 0, length ); pbuffer = Marshal.AllocHGlobal( length ); Debug.Assert( pbuffer != IntPtr.Zero ); Marshal.Copy( mbuffer, 0, pbuffer, length ); mbuffer = null; byte* buffer = ( byte* )pbuffer.ToPointer(); // Get header Elf32_Ehdr* header = ( Elf32_Ehdr* )buffer; //Debug.Assert( header->e_magic == Elf32_Ehdr.Magic ); if( header->e_magic != Elf32_Ehdr.Magic ) { Log.WriteLine( Verbosity.Critical, Feature.Loader, "Module header does not match: {0:X8} != {1:X8}", header->e_magic, Elf32_Ehdr.Magic ); return results; } Debug.Assert( header->e_machine == Elf32_Ehdr.MachineMips ); if( header->e_machine != Elf32_Ehdr.MachineMips ) return results; /*switch( type ) { case ModuleType.Boot: //Debug.Assert( header->e_type == ELF_EXEC_TYPE ); break; case ModuleType.Prx: //Debug.Assert( header->e_type == ELF_PRX_TYPE ); break; }*/ results.EntryAddress = header->e_entry; bool needsRelocation = ( ( header->e_entry < 0x08000000 ) || ( header->e_type == ElfType.Prx ) ); // p-hdrs //for( int n = 0; n < header->e_phnum; n++ ) //{ // Elf32_Phdr* phdr = ( Elf32_Phdr* )( buffer + header->e_phoff + ( header->e_phentsize * n ) ); //} // 0x08900000 //uint defaultLoad = 0x08880000; uint defaultLoad = 0x08800000; //uint defaultLoad = uint.MaxValue; // s-hdrs uint lextents = defaultLoad; uint extents = 0; for( int n = 0; n < header->e_shnum; n++ ) { Elf32_Shdr* shdr = ( Elf32_Shdr* )( buffer + header->e_shoff + ( header->e_shentsize * n ) ); if( ( shdr->sh_flags & ShFlags.Allocate ) == ShFlags.Allocate ) { allocSections[ allocSectionsCount++ ] = shdr; if( ( shdr->sh_addr > 0 ) && ( shdr->sh_addr < lextents ) ) lextents = shdr->sh_addr; uint upperBound = shdr->sh_addr + shdr->sh_size; if( upperBound > extents ) extents = upperBound; } if( ( shdr->sh_type == ShType.SHT_REL ) || ( shdr->sh_type == ShType.SHT_PRXRELOC ) ) relocSections[ relocSectionsCount++ ] = shdr; } uint bssSize = this.GetBssSize( buffer ); extents += bssSize; // Module info Elf32_Shdr* moduleInfoShdr = FindSection( buffer, ".rodata.sceModuleInfo" ); Debug.Assert( moduleInfoShdr != null ); PspModuleInfo* moduleInfo = ( PspModuleInfo* )( buffer + moduleInfoShdr->sh_offset ); results.GlobalPointer = moduleInfo->gp; results.Name = new string( &moduleInfo->name ); // See if this module is already implemented BiosModule existing = _bios.FindModule( results.Name ); if( existing != null ) { Log.WriteLine( Verbosity.Normal, Feature.Loader, "attempting to load module {0} with BIOS implementation; ignoring", results.Name ); results.Successful = true; results.Ignored = true; return results; } else Log.WriteLine( Verbosity.Normal, Feature.Loader, "adding new module {0}", results.Name ); uint baseAddress = 0; KMemoryBlock moduleBlock = null; if( needsRelocation == true ) { if( type == ModuleType.Boot ) baseAddress = defaultLoad; else { // Find the next block in RAM moduleBlock = kernel.Partitions[ 2 ].Allocate( string.Format( "Module {0}", results.Name ), KAllocType.Low, 0, extents ); baseAddress = moduleBlock.Address; } results.EntryAddress += baseAddress; results.LowerBounds = baseAddress; results.UpperBounds = baseAddress + extents; } else { Debug.Assert( type == ModuleType.Boot ); results.LowerBounds = lextents; //0x08900000; results.UpperBounds = extents; } // Allocate space taken by module if( type == ModuleType.Boot ) { Debug.Assert( moduleBlock == null ); moduleBlock = kernel.Partitions[ 2 ].Allocate( string.Format( "Module {0}", results.Name ), KAllocType.Specific, results.LowerBounds, results.UpperBounds - results.LowerBounds ); } else { // Should be done above Debug.Assert( moduleBlock != null ); } Debug.Assert( moduleBlock != null ); // Allocate sections in memory for( int n = 0; n < allocSectionsCount; n++ ) { Elf32_Shdr* shdr = allocSections[ n ]; uint address = baseAddress + shdr->sh_addr; byte* pdest = memory.Translate( address ); switch( shdr->sh_type ) { case ShType.SHT_NOBITS: // Write zeros? MemorySystem.ZeroMemory( pdest, shdr->sh_size ); break; default: case ShType.SHT_PROGBITS: MemorySystem.CopyMemory( buffer + shdr->sh_offset, pdest, shdr->sh_size ); break; } } // Zero out BSS if present if( bssSize > 0 ) { Elf32_Shdr* bssShdr = FindSection( buffer, ".bss" ); Debug.Assert( bssShdr != null ); if( bssShdr != null ) { uint address = baseAddress + bssShdr->sh_addr; byte* pdest = memory.Translate( address ); MemorySystem.ZeroMemory( pdest, bssSize ); } } // Perform relocations if( needsRelocation == true ) { List<HiReloc> hiRelocs = new List<HiReloc>( 10 ); uint Elf32_RelSize = ( uint )sizeof( Elf32_Rel ); // Find symbol table Elf32_Shdr* symtabShdr = FindSection( buffer, ".symtab" ); byte* symtab = null; if( symtabShdr != null ) symtab = buffer + symtabShdr->sh_offset; // Gather relocations for( int n = 0; n < header->e_shnum; n++ ) { Elf32_Shdr* shdr = ( Elf32_Shdr* )( buffer + header->e_shoff + ( header->e_shentsize * n ) ); if( ( shdr->sh_type != ShType.SHT_REL ) && ( shdr->sh_type != ShType.SHT_PRXRELOC ) ) continue; hiRelocs.Clear(); Elf32_Shdr* targetHdr = ( Elf32_Shdr* )( buffer + header->e_shoff + ( header->e_shentsize * shdr->sh_info ) ); // If the target is not allocated, do not perform the relocation if( ( targetHdr->sh_flags & ShFlags.Allocate ) != ShFlags.Allocate ) continue; uint count = shdr->sh_size / Elf32_RelSize; for( uint m = 0; m < count; m++ ) { Elf32_Rel* reloc = ( Elf32_Rel* )( buffer + shdr->sh_offset + ( sizeof( Elf32_Rel ) * m ) ); //uint rtype = ELF32_R_TYPE( reloc->r_info ); //uint symbolIndex = ELF32_R_SYM( reloc->r_info ); RelType rtype = ( RelType )( reloc->r_info & 0xFF ); uint symbolIndex = reloc->r_info >> 8; uint offset = reloc->r_offset; if( rtype == RelType.None ) continue; uint basea = baseAddress; offset += baseAddress; if( shdr->sh_type == ShType.SHT_REL ) { // Elf style - use symbol table Elf32_Sym* sym = null; if( symbolIndex != 0 ) { Debug.Assert( symtab != null ); sym = ( Elf32_Sym* )( symtab + ( sizeof( Elf32_Sym ) * symbolIndex ) ); basea += sym->st_value; } } else if( shdr->sh_type == ShType.SHT_PRXRELOC ) { // PRX style - crazy! uint offsetHeaderN = symbolIndex & 0xFF; uint valueHeaderN = ( symbolIndex >> 8 ) & 0xFF; Debug.Assert( offsetHeaderN < header->e_phnum ); Debug.Assert( valueHeaderN < header->e_phnum ); Elf32_Phdr* offsetHeader = ( Elf32_Phdr* )( buffer + header->e_phoff + ( header->e_phentsize * offsetHeaderN ) ); Elf32_Phdr* valueHeader = ( Elf32_Phdr* )( buffer + header->e_phoff + ( header->e_phentsize * valueHeaderN ) ); basea += valueHeader->p_vaddr; offset += offsetHeader->p_vaddr; } uint* pcode = ( uint* )memory.Translate( offset ); Debug.Assert( pcode != null ); switch( rtype ) { case RelType.MipsHi16: { HiReloc hiReloc = new HiReloc(); hiReloc.Value = basea; hiReloc.CodePointer = ( uint* )pcode; hiRelocs.Add( hiReloc ); } break; case RelType.MipsLo16: { uint code = *pcode; uint vallo = ( ( code & 0x0000FFFF ) ^ 0x00008000 ) - 0x00008000; while( hiRelocs.Count > 0 ) { HiReloc hiReloc = hiRelocs[ hiRelocs.Count - 1 ]; hiRelocs.RemoveAt( hiRelocs.Count - 1 ); Debug.Assert( hiReloc.Value == basea ); uint value2 = *hiReloc.CodePointer; uint temp = ( ( value2 & 0x0000FFFF ) << 16 ) + vallo; temp += basea; temp = ( ( temp >> 16 ) + ( ( ( temp & 0x00008000 ) != 0 ) ? ( uint )1 : ( uint )0 ) ) & 0x0000FFFF; value2 = ( uint )( ( value2 & ~0x0000FFFF ) | temp ); //Debug.WriteLine( string.Format( " Updating memory at 0x{0:X8} to {1:X8} (from previous HI16)", hiReloc.Address, value2 ) ); *hiReloc.CodePointer = value2; } *pcode = ( uint )( ( code & ~0x0000FFFF ) | ( ( basea + vallo ) & 0x0000FFFF ) ); } break; case RelType.Mips26: { uint code = *pcode; uint addr = ( code & 0x03FFFFFF ) << 2; addr += basea; *pcode = ( code & unchecked( ( uint )~0x03FFFFFF ) ) | ( addr >> 2 ); } break; case RelType.Mips32: *pcode += basea; break; } } Debug.Assert( hiRelocs.Count == 0 ); // Finish off hi relocs? } } IDebugDatabase db = null; if( parameters.AppendDatabase == true ) { Debug.Assert( Diag.Instance.Database != null ); db = Diag.Instance.Database; db.BeginUpdate(); } // Assign ID now so we can use it for symbols/etc uint moduleId = _bios._kernel.AllocateID(); results.ModuleID = moduleId; int variableExportCount = 0; int functionExportCount = 0; // Get exports uint PspModuleExportSize = ( uint )sizeof( PspModuleExport ); uint pexports = moduleInfo->exports + ( ( needsRelocation == true ) ? baseAddress : 0 ); uint exportCount = ( moduleInfo->exp_end - moduleInfo->exports ) / PspModuleExportSize; for( uint n = 0; n < exportCount; n++ ) { PspModuleExport* ex = ( PspModuleExport* )memory.Translate( pexports + ( PspModuleExportSize * n ) ); string name = null; if( ex->name != 0x0 ) name = kernel.ReadString( ex->name ); // Ignore null names? if( ex->name == 0x0 ) continue; results.ExportNames.Add( name ); uint* pnid = ( uint* )memory.Translate( ex->exports ); uint* pvalue = ( uint* )memory.Translate( ex->exports + ( ( uint )( ex->func_count + ex->var_count ) * 4 ) ); for( int m = 0; m < ( ex->func_count + ex->var_count ); m++ ) { uint nid = *( pnid + m ); uint value = *( pvalue + m ); StubExport stubExport = new StubExport(); if( m < ex->func_count ) { stubExport.Type = StubType.Function; Log.WriteLine( Verbosity.Verbose, Feature.Loader, "export func {0} 0x{1:X8}: {2:X8}", name, nid, value ); functionExportCount++; } else { stubExport.Type = StubType.Variable; Log.WriteLine( Verbosity.Verbose, Feature.Loader, "export var {0} 0x{1:X8}: {2:X8}", name, nid, value ); variableExportCount++; } stubExport.ModuleName = name; stubExport.NID = nid; stubExport.Address = value; results.Exports.Add( stubExport ); } } int nidGoodCount = 0; int nidNotFoundCount = 0; int nidNotImplementedCount = 0; int moduleNotFoundCount = 0; List<string> missingModules = new List<string>(); // Get imports uint PspModuleImportSize = ( uint )sizeof( PspModuleImport ); uint pimports = moduleInfo->imports + ( ( needsRelocation == true ) ? baseAddress : 0 ); uint importCount = ( moduleInfo->imp_end - moduleInfo->imports ) / PspModuleImportSize; for( uint n = 0; n < importCount; n++ ) { PspModuleImport* im = ( PspModuleImport* )memory.Translate( pimports + ( PspModuleImportSize * n ) ); string name = null; if( im->name != 0x0 ) name = kernel.ReadString( im->name ); Debug.Assert( name != null ); BiosModule module = _bios.FindModule( name ); if( module == null ) missingModules.Add( name ); uint* pnid = ( uint* )memory.Translate( im->nids ); uint* pfuncs = ( uint* )memory.Translate( im->funcs ); // Functions & variables at the same time for( int m = 0; m < ( im->func_count + im->var_count ); m++ ) { uint nid = *( pnid + m ); uint* pcode = ( pfuncs + ( m * 2 ) ); BiosFunction function = _bios.FindFunction( nid ); StubImport stubImport = new StubImport(); if( module == null ) { stubImport.Result = StubReferenceResult.ModuleNotFound; moduleNotFoundCount++; results.MissingImports.Enqueue( new DelayedImport( stubImport ) ); } else if( function == null ) { Log.WriteLine( Verbosity.Normal, Feature.Loader, "{0} 0x{1:X8} not found (NID not present)", name, nid ); stubImport.Result = StubReferenceResult.NidNotFound; nidNotFoundCount++; results.MissingImports.Enqueue( new DelayedImport( stubImport ) ); } else if( function.IsImplemented == false ) { Log.WriteLine( Verbosity.Normal, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3} (NI)", name, nid, ( uint )pcode, function.Name ); stubImport.Result = StubReferenceResult.NidNotImplemented; nidNotImplementedCount++; } else { Log.WriteLine( Verbosity.Verbose, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3}", name, nid, ( uint )pcode, function.Name ); stubImport.Result = StubReferenceResult.Success; nidGoodCount++; } // Create dummy when needed if( function == null ) { function = new BiosFunction( module, nid ); _bios.RegisterFunction( function ); } if( m < im->func_count ) stubImport.Type = StubType.Function; else stubImport.Type = StubType.Variable; stubImport.ModuleName = name; stubImport.Function = function; stubImport.NID = nid; stubImport.Address = ( uint )pcode; results.Imports.Add( stubImport ); function.StubAddress = ( uint )( im->funcs + ( m * 2 ) * 4 ); // Perform fixup { uint syscall = cpu.RegisterSyscall( nid ); *( pcode + 1 ) = ( uint )( ( syscall << 6 ) | 0xC ); } // Add to debug database if( db != null ) { Method method = new Method( moduleId, MethodType.Bios, function.StubAddress, 8, new BiosFunctionToken( stubImport.Function ) ); db.AddSymbol( method ); } } } // If symbols are present, use those to add methods and variables // Otherwise, we need to try to figure them out (good luck!) if( db != null ) { // Find symbol table Elf32_Shdr* symtabShdr = FindSection( buffer, ".symtab" ); if( ( symtabShdr != null ) && ( symtabShdr->sh_size > 0x100 ) ) { byte* strtab = FindSectionAddress( buffer, symtabShdr->sh_link ); int symbolCount = ( int )symtabShdr->sh_size / sizeof( Elf32_Sym ); byte* symtab = buffer + symtabShdr->sh_offset; byte* p = symtab; for( int n = 0; n < symbolCount; n++, p += sizeof( Elf32_Sym ) ) { Elf32_Sym* sym = ( Elf32_Sym* )p; uint symType = sym->st_info & ( uint )0xF; if( ( symType != 0x1 ) && ( symType != 0x2 ) ) continue; if( sym->st_size == 0 ) continue; Elf32_Shdr* shdr = FindSection( buffer, sym->st_shndx ); Debug.Assert( shdr != null ); string name = null; if( sym->st_name != 0 ) name = this.GetName( strtab, ( int )sym->st_name ); uint address = baseAddress + sym->st_value; if( needsRelocation == true ) address += shdr->sh_addr; Symbol symbol = null; if( symType == 0x1 ) { // OBJECT symbol = new Variable( moduleId, address, sym->st_size, name ); } else if( symType == 0x2 ) { // FUNC symbol = new Method( moduleId, MethodType.User, address, sym->st_size, name ); } if( symbol != null ) db.AddSymbol( symbol ); } results.HadSymbols = true; Log.WriteLine( Verbosity.Verbose, Feature.Loader, "Found {0} methods and {1} variables in the symbol table", db.MethodCount, db.VariableCount ); } else { // No symbol table found - try to build the symbols Elf32_Shdr* textShdr = FindSection( buffer, ".text" ); Debug.Assert( textShdr != null ); uint textAddress = baseAddress + textShdr->sh_addr; byte* text = memory.TranslateMainMemory( ( int )textAddress ); uint size = textShdr->sh_size; this.Analyze( moduleId, db, text, size, textAddress ); Log.WriteLine( Verbosity.Verbose, Feature.Loader, "Found {0} methods by analysis", db.MethodCount ); } // End update, started above db.EndUpdate(); //foreach( Method method in db.GetMethods() ) // Debug.WriteLine( method.ToString() ); } #if DEBUG // Print stats Log.WriteLine( Verbosity.Critical, Feature.Loader, "Load complete: {0}/{1} ({2}%) NIDs good; {3} not implemented, {4} not found, {5} in missing modules = {6} total", nidGoodCount, results.Imports.Count - moduleNotFoundCount, ( nidGoodCount / ( float )( results.Imports.Count - moduleNotFoundCount ) ) * 100.0f, nidNotImplementedCount, nidNotFoundCount, moduleNotFoundCount, results.Imports.Count ); if( missingModules.Count > 0 ) { Log.WriteLine( Verbosity.Normal, Feature.Loader, "{0} missing modules (contain {1} NIDs ({2}% of total)):", missingModules.Count, moduleNotFoundCount, ( moduleNotFoundCount / ( float )results.Imports.Count ) * 100.0f ); foreach( string moduleName in missingModules ) Log.WriteLine( Verbosity.Normal, Feature.Loader, "\t\t{0}", moduleName ); } if( ( functionExportCount > 0 ) || ( variableExportCount > 0 ) ) Log.WriteLine( Verbosity.Critical, Feature.Loader, "Exported {0} functions and {1} variables", functionExportCount, variableExportCount ); #endif results.Successful = true; if( results.Successful == true ) { // If we export things, go back and find previously loaded modules that may need fixing up if( ( functionExportCount > 0 ) || ( variableExportCount > 0 ) ) { bool fixupResult = this.FixupDelayedImports( kernel, results ); Debug.Assert( fixupResult == true ); } // If we are the boot load - we do some special stuff like run start, etc // If we are a PRX, all that is taken care of for us by the user code making calls if( type == ModuleType.Boot ) { KModule module = new KModule( kernel, new BiosModule( results.Name, results.Exports.ToArray() ) ); module.UID = moduleId; module.LoadParameters = parameters; module.LoadResults = results; kernel.UserModules.Add( module ); Debug.Assert( kernel.MainModule == null ); kernel.MainModule = module; kernel.AddHandle( module ); // Allocate room for args KMemoryBlock argsBlock = kernel.Partitions[ 2 ].Allocate( string.Format( "Module {0} args", results.Name ), KAllocType.High, 0, 0xFF ); // 256b of args - enough? // Set arguments - we put these right below user space, and right above the stack uint args = 0; uint argp = argsBlock.Address; string arg0 = parameters.Path.AbsolutePath.Replace( '\\', '/' ) + "/"; args += ( uint )arg0.Length + 1; kernel.WriteString( argp, arg0 ); uint envp = argp;// + args; // write envp?? // What we do here simulates what the modulemgr does - it creates a user mode thread that // runs module_start (_start, etc) and then exits when complete. // NOTE: If we are a PRX, the entry address will correspond to module_start, so we don't need to do anything! // Create a thread KThread thread = new KThread( kernel, module, kernel.Partitions[ 2 ], "kmodule_thread", results.EntryAddress, 0, KThreadAttributes.User, 0x4000 ); thread.GlobalPointer = results.GlobalPointer; kernel.AddHandle( thread ); thread.Start( args, argp ); // Setup handler so that we get the callback when the thread ends and we can kill it cpu.SetContextSafetyCallback( thread.ContextID, new ContextSafetyDelegate( this.KmoduleThreadEnd ), ( int )thread.UID ); Log.WriteLine( Verbosity.Verbose, Feature.Loader, "starting kmodule loading thread with UID {0:X}", thread.UID ); // Schedule so that our thread runs kernel.Schedule(); // If debugging, set start breakpoint if( Diag.IsAttached == true ) Diag.Instance.Client.OnBootModuleLoaded( results.EntryAddress ); if( Diag.IsAttached == true ) Diag.Instance.Client.OnModuleLoaded(); //kernel.MemorySystem.DumpMainMemory( "startup.bin" ); } } } finally { if( pbuffer != IntPtr.Zero ) Marshal.FreeHGlobal( pbuffer ); } return results; }
/// <summary> /// Generate a load report XML file and write it to the disk. /// </summary> /// <param name="instance">The current emulation instance.</param> /// <param name="game">The game being loaded.</param> /// <param name="results">The results of the load.</param> /// <param name="outputPath">The path to write the result data to.</param> public static void GenerateReport(IEmulationInstance instance, GameInformation game, LoadResults results, string outputPath) { Debug.Assert(game != null); if (game == null) { return; } Debug.Assert(results != null); if (results == null) { return; } XmlDocument doc = new XmlDocument(); doc.AppendChild(doc.CreateXmlDeclaration("1.0", null, "yes")); XmlElement root = doc.CreateElement("loadResults"); root.SetAttribute("successful", results.Successful.ToString()); XmlElement gameRoot = doc.CreateElement("game"); gameRoot.SetAttribute("type", game.GameType.ToString()); //gameRoot.SetAttribute( "path", EscapeFilePath( game.Folder.AbsolutePath ) ); { XmlElement sfoRoot = doc.CreateElement("parameters"); if (game.Parameters.Title != null) { sfoRoot.SetAttribute("title", game.Parameters.Title); } if (game.Parameters.SystemVersion != new Version()) { sfoRoot.SetAttribute("systemVersion", game.Parameters.SystemVersion.ToString()); } if (game.Parameters.GameVersion != new Version()) { sfoRoot.SetAttribute("gameVersion", game.Parameters.GameVersion.ToString()); } if (game.Parameters.DiscID != null) { sfoRoot.SetAttribute("discId", game.Parameters.DiscID); } if (game.Parameters.Region >= 0) { sfoRoot.SetAttribute("region", game.Parameters.Region.ToString("X")); } if (game.Parameters.Language != null) { sfoRoot.SetAttribute("language", game.Parameters.Language); } sfoRoot.SetAttribute("category", game.Parameters.Category.ToString()); gameRoot.AppendChild(sfoRoot); } root.AppendChild(gameRoot); XmlElement biosRoot = doc.CreateElement("bios"); { IComponent factory = Activator.CreateInstance(instance.Bios.Factory) as IComponent; if (factory != null) { biosRoot.SetAttribute("name", factory.Name); biosRoot.SetAttribute("version", factory.Version.ToString()); biosRoot.SetAttribute("build", factory.Build.ToString()); if (factory.Author != null) { biosRoot.SetAttribute("author", factory.Author); } if (factory.Website != null) { biosRoot.SetAttribute("website", factory.Website); } } } root.AppendChild(biosRoot); XmlElement importsRoot = doc.CreateElement("imports"); foreach (StubImport import in results.Imports) { XmlElement importRoot = doc.CreateElement("import"); importRoot.SetAttribute("result", import.Result.ToString()); importRoot.SetAttribute("module", import.ModuleName); importRoot.SetAttribute("nid", string.Format("{0:X8}", import.NID)); if (import.Function != null) { XmlElement functionRoot = doc.CreateElement("function"); functionRoot.SetAttribute("name", import.Function.Name); functionRoot.SetAttribute("isImplemented", import.Function.IsImplemented.ToString()); //functionRoot.SetAttribute( "hasNative", ( import.Function.NativeMethod != IntPtr.Zero ) ? true.ToString() : false.ToString() ); importRoot.AppendChild(functionRoot); } importsRoot.AppendChild(importRoot); } root.AppendChild(importsRoot); doc.AppendChild(root); string fileName; if (game.GameType == GameType.Eboot) { string title = game.Parameters.Title; title = title.Replace("\n", ""); // All it takes is one moron fileName = string.Format("LoadResult-Eboot-{0}.xml", title); } else { fileName = string.Format("LoadResult-{0}.xml", game.Parameters.DiscID); } using (FileStream stream = File.Open(Path.Combine(outputPath, fileName), FileMode.Create)) doc.Save(stream); }
public LoadResults LoadModule(ModuleType type, Stream moduleStream, LoadParameters parameters) { Elf32_Shdr *[] allocSections = new Elf32_Shdr *[256]; Elf32_Shdr *[] relocSections = new Elf32_Shdr *[256]; int allocSectionsCount = 0; int relocSectionsCount = 0; LoadResults results = new LoadResults(); results.Successful = false; results.Imports = new List <StubImport>(); results.Exports = new List <StubExport>(); results.ExportNames = new List <string>(); results.MissingImports = new FastLinkedList <DelayedImport>(); Debug.Assert(moduleStream != null); Debug.Assert(moduleStream.CanRead == true); if ((moduleStream == null) || (moduleStream.CanRead == false)) { return(results); } Kernel kernel = _bios._kernel; ICpu cpu = kernel.Cpu; MemorySystem memory = kernel.MemorySystem; IntPtr pbuffer = IntPtr.Zero; try { // Load the entire module in to memory - nasty, but it works int length = ( int )moduleStream.Length; byte[] mbuffer = new byte[length]; moduleStream.Read(mbuffer, 0, length); pbuffer = Marshal.AllocHGlobal(length); Debug.Assert(pbuffer != IntPtr.Zero); Marshal.Copy(mbuffer, 0, pbuffer, length); mbuffer = null; byte *buffer = ( byte * )pbuffer.ToPointer(); // Get header Elf32_Ehdr *header = ( Elf32_Ehdr * )buffer; //Debug.Assert( header->e_magic == Elf32_Ehdr.Magic ); if (header->e_magic != Elf32_Ehdr.Magic) { Log.WriteLine(Verbosity.Critical, Feature.Loader, "Module header does not match: {0:X8} != {1:X8}", header->e_magic, Elf32_Ehdr.Magic); return(results); } Debug.Assert(header->e_machine == Elf32_Ehdr.MachineMips); if (header->e_machine != Elf32_Ehdr.MachineMips) { return(results); } /*switch( type ) * { * case ModuleType.Boot: * //Debug.Assert( header->e_type == ELF_EXEC_TYPE ); * break; * case ModuleType.Prx: * //Debug.Assert( header->e_type == ELF_PRX_TYPE ); * break; * }*/ results.EntryAddress = header->e_entry; bool needsRelocation = ( (header->e_entry < 0x08000000) || (header->e_type == ElfType.Prx)); // p-hdrs //for( int n = 0; n < header->e_phnum; n++ ) //{ // Elf32_Phdr* phdr = ( Elf32_Phdr* )( buffer + header->e_phoff + ( header->e_phentsize * n ) ); //} // 0x08900000 //uint defaultLoad = 0x08880000; uint defaultLoad = 0x08800000; //uint defaultLoad = uint.MaxValue; // s-hdrs uint lextents = defaultLoad; uint extents = 0; for (int n = 0; n < header->e_shnum; n++) { Elf32_Shdr *shdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * n)); if ((shdr->sh_flags & ShFlags.Allocate) == ShFlags.Allocate) { allocSections[allocSectionsCount++] = shdr; if ((shdr->sh_addr > 0) && (shdr->sh_addr < lextents)) { lextents = shdr->sh_addr; } uint upperBound = shdr->sh_addr + shdr->sh_size; if (upperBound > extents) { extents = upperBound; } } if ((shdr->sh_type == ShType.SHT_REL) || (shdr->sh_type == ShType.SHT_PRXRELOC)) { relocSections[relocSectionsCount++] = shdr; } } uint bssSize = this.GetBssSize(buffer); extents += bssSize; // Module info Elf32_Shdr *moduleInfoShdr = FindSection(buffer, ".rodata.sceModuleInfo"); Debug.Assert(moduleInfoShdr != null); PspModuleInfo *moduleInfo = ( PspModuleInfo * )(buffer + moduleInfoShdr->sh_offset); results.GlobalPointer = moduleInfo->gp; results.Name = new string( &moduleInfo->name ); // See if this module is already implemented BiosModule existing = _bios.FindModule(results.Name); if (existing != null) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "attempting to load module {0} with BIOS implementation; ignoring", results.Name); results.Successful = true; results.Ignored = true; return(results); } else { Log.WriteLine(Verbosity.Normal, Feature.Loader, "adding new module {0}", results.Name); } uint baseAddress = 0; KMemoryBlock moduleBlock = null; if (needsRelocation == true) { if (type == ModuleType.Boot) { baseAddress = defaultLoad; } else { // Find the next block in RAM moduleBlock = kernel.Partitions[2].Allocate(string.Format("Module {0}", results.Name), KAllocType.Low, 0, extents); baseAddress = moduleBlock.Address; } results.EntryAddress += baseAddress; results.LowerBounds = baseAddress; results.UpperBounds = baseAddress + extents; } else { Debug.Assert(type == ModuleType.Boot); results.LowerBounds = lextents; //0x08900000; results.UpperBounds = extents; } // Allocate space taken by module if (type == ModuleType.Boot) { Debug.Assert(moduleBlock == null); moduleBlock = kernel.Partitions[2].Allocate(string.Format("Module {0}", results.Name), KAllocType.Specific, results.LowerBounds, results.UpperBounds - results.LowerBounds); } else { // Should be done above Debug.Assert(moduleBlock != null); } Debug.Assert(moduleBlock != null); // Allocate sections in memory for (int n = 0; n < allocSectionsCount; n++) { Elf32_Shdr *shdr = allocSections[n]; uint address = baseAddress + shdr->sh_addr; byte * pdest = memory.Translate(address); switch (shdr->sh_type) { case ShType.SHT_NOBITS: // Write zeros? MemorySystem.ZeroMemory(pdest, shdr->sh_size); break; default: case ShType.SHT_PROGBITS: MemorySystem.CopyMemory(buffer + shdr->sh_offset, pdest, shdr->sh_size); break; } } // Zero out BSS if present if (bssSize > 0) { Elf32_Shdr *bssShdr = FindSection(buffer, ".bss"); Debug.Assert(bssShdr != null); if (bssShdr != null) { uint address = baseAddress + bssShdr->sh_addr; byte *pdest = memory.Translate(address); MemorySystem.ZeroMemory(pdest, bssSize); } } // Perform relocations if (needsRelocation == true) { List <HiReloc> hiRelocs = new List <HiReloc>(10); uint Elf32_RelSize = ( uint )sizeof(Elf32_Rel); // Find symbol table Elf32_Shdr *symtabShdr = FindSection(buffer, ".symtab"); byte * symtab = null; if (symtabShdr != null) { symtab = buffer + symtabShdr->sh_offset; } // Gather relocations for (int n = 0; n < header->e_shnum; n++) { Elf32_Shdr *shdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * n)); if ((shdr->sh_type != ShType.SHT_REL) && (shdr->sh_type != ShType.SHT_PRXRELOC)) { continue; } hiRelocs.Clear(); Elf32_Shdr *targetHdr = ( Elf32_Shdr * )(buffer + header->e_shoff + (header->e_shentsize * shdr->sh_info)); // If the target is not allocated, do not perform the relocation if ((targetHdr->sh_flags & ShFlags.Allocate) != ShFlags.Allocate) { continue; } uint count = shdr->sh_size / Elf32_RelSize; for (uint m = 0; m < count; m++) { Elf32_Rel *reloc = ( Elf32_Rel * )(buffer + shdr->sh_offset + (sizeof(Elf32_Rel) * m)); //uint rtype = ELF32_R_TYPE( reloc->r_info ); //uint symbolIndex = ELF32_R_SYM( reloc->r_info ); RelType rtype = ( RelType )(reloc->r_info & 0xFF); uint symbolIndex = reloc->r_info >> 8; uint offset = reloc->r_offset; if (rtype == RelType.None) { continue; } uint basea = baseAddress; offset += baseAddress; if (shdr->sh_type == ShType.SHT_REL) { // Elf style - use symbol table Elf32_Sym *sym = null; if (symbolIndex != 0) { Debug.Assert(symtab != null); sym = ( Elf32_Sym * )(symtab + (sizeof(Elf32_Sym) * symbolIndex)); basea += sym->st_value; } } else if (shdr->sh_type == ShType.SHT_PRXRELOC) { // PRX style - crazy! uint offsetHeaderN = symbolIndex & 0xFF; uint valueHeaderN = (symbolIndex >> 8) & 0xFF; Debug.Assert(offsetHeaderN < header->e_phnum); Debug.Assert(valueHeaderN < header->e_phnum); Elf32_Phdr *offsetHeader = ( Elf32_Phdr * )(buffer + header->e_phoff + (header->e_phentsize * offsetHeaderN)); Elf32_Phdr *valueHeader = ( Elf32_Phdr * )(buffer + header->e_phoff + (header->e_phentsize * valueHeaderN)); basea += valueHeader->p_vaddr; offset += offsetHeader->p_vaddr; } uint *pcode = ( uint * )memory.Translate(offset); Debug.Assert(pcode != null); switch (rtype) { case RelType.MipsHi16: { HiReloc hiReloc = new HiReloc(); hiReloc.Value = basea; hiReloc.CodePointer = ( uint * )pcode; hiRelocs.Add(hiReloc); } break; case RelType.MipsLo16: { uint code = *pcode; uint vallo = ((code & 0x0000FFFF) ^ 0x00008000) - 0x00008000; while (hiRelocs.Count > 0) { HiReloc hiReloc = hiRelocs[hiRelocs.Count - 1]; hiRelocs.RemoveAt(hiRelocs.Count - 1); Debug.Assert(hiReloc.Value == basea); uint value2 = *hiReloc.CodePointer; uint temp = ((value2 & 0x0000FFFF) << 16) + vallo; temp += basea; temp = ((temp >> 16) + (((temp & 0x00008000) != 0) ? ( uint )1 : ( uint )0)) & 0x0000FFFF; value2 = ( uint )((value2 & ~0x0000FFFF) | temp); //Debug.WriteLine( string.Format( " Updating memory at 0x{0:X8} to {1:X8} (from previous HI16)", hiReloc.Address, value2 ) ); *hiReloc.CodePointer = value2; } *pcode = ( uint )((code & ~0x0000FFFF) | ((basea + vallo) & 0x0000FFFF)); } break; case RelType.Mips26: { uint code = *pcode; uint addr = (code & 0x03FFFFFF) << 2; addr += basea; *pcode = (code & unchecked (( uint )~0x03FFFFFF)) | (addr >> 2); } break; case RelType.Mips32: *pcode += basea; break; } } Debug.Assert(hiRelocs.Count == 0); // Finish off hi relocs? } } IDebugDatabase db = null; if (parameters.AppendDatabase == true) { Debug.Assert(Diag.Instance.Database != null); db = Diag.Instance.Database; db.BeginUpdate(); } // Assign ID now so we can use it for symbols/etc uint moduleId = _bios._kernel.AllocateID(); results.ModuleID = moduleId; int variableExportCount = 0; int functionExportCount = 0; // Get exports uint PspModuleExportSize = ( uint )sizeof(PspModuleExport); uint pexports = moduleInfo->exports + ((needsRelocation == true) ? baseAddress : 0); uint exportCount = (moduleInfo->exp_end - moduleInfo->exports) / PspModuleExportSize; for (uint n = 0; n < exportCount; n++) { PspModuleExport *ex = ( PspModuleExport * )memory.Translate(pexports + (PspModuleExportSize * n)); string name = null; if (ex->name != 0x0) { name = kernel.ReadString(ex->name); } // Ignore null names? if (ex->name == 0x0) { continue; } results.ExportNames.Add(name); uint *pnid = ( uint * )memory.Translate(ex->exports); uint *pvalue = ( uint * )memory.Translate(ex->exports + (( uint )(ex->func_count + ex->var_count) * 4)); for (int m = 0; m < (ex->func_count + ex->var_count); m++) { uint nid = *(pnid + m); uint value = *(pvalue + m); StubExport stubExport = new StubExport(); if (m < ex->func_count) { stubExport.Type = StubType.Function; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "export func {0} 0x{1:X8}: {2:X8}", name, nid, value); functionExportCount++; } else { stubExport.Type = StubType.Variable; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "export var {0} 0x{1:X8}: {2:X8}", name, nid, value); variableExportCount++; } stubExport.ModuleName = name; stubExport.NID = nid; stubExport.Address = value; results.Exports.Add(stubExport); } } int nidGoodCount = 0; int nidNotFoundCount = 0; int nidNotImplementedCount = 0; int moduleNotFoundCount = 0; List <string> missingModules = new List <string>(); // Get imports uint PspModuleImportSize = ( uint )sizeof(PspModuleImport); uint pimports = moduleInfo->imports + ((needsRelocation == true) ? baseAddress : 0); uint importCount = (moduleInfo->imp_end - moduleInfo->imports) / PspModuleImportSize; for (uint n = 0; n < importCount; n++) { PspModuleImport *im = ( PspModuleImport * )memory.Translate(pimports + (PspModuleImportSize * n)); string name = null; if (im->name != 0x0) { name = kernel.ReadString(im->name); } Debug.Assert(name != null); BiosModule module = _bios.FindModule(name); if (module == null) { missingModules.Add(name); } uint *pnid = ( uint * )memory.Translate(im->nids); uint *pfuncs = ( uint * )memory.Translate(im->funcs); // Functions & variables at the same time for (int m = 0; m < (im->func_count + im->var_count); m++) { uint nid = *(pnid + m); uint *pcode = (pfuncs + (m * 2)); BiosFunction function = _bios.FindFunction(nid); StubImport stubImport = new StubImport(); if (module == null) { stubImport.Result = StubReferenceResult.ModuleNotFound; moduleNotFoundCount++; results.MissingImports.Enqueue(new DelayedImport(stubImport)); } else if (function == null) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "{0} 0x{1:X8} not found (NID not present)", name, nid); stubImport.Result = StubReferenceResult.NidNotFound; nidNotFoundCount++; results.MissingImports.Enqueue(new DelayedImport(stubImport)); } else if (function.IsImplemented == false) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3} (NI)", name, nid, ( uint )pcode, function.Name); stubImport.Result = StubReferenceResult.NidNotImplemented; nidNotImplementedCount++; } else { Log.WriteLine(Verbosity.Verbose, Feature.Loader, "0x{1:X8} found and patched at 0x{2:X8} -> {0}::{3}", name, nid, ( uint )pcode, function.Name); stubImport.Result = StubReferenceResult.Success; nidGoodCount++; } // Create dummy when needed if (function == null) { function = new BiosFunction(module, nid); _bios.RegisterFunction(function); } if (m < im->func_count) { stubImport.Type = StubType.Function; } else { stubImport.Type = StubType.Variable; } stubImport.ModuleName = name; stubImport.Function = function; stubImport.NID = nid; stubImport.Address = ( uint )pcode; results.Imports.Add(stubImport); function.StubAddress = ( uint )(im->funcs + (m * 2) * 4); // Perform fixup { uint syscall = cpu.RegisterSyscall(nid); *(pcode + 1) = ( uint )((syscall << 6) | 0xC); } // Add to debug database if (db != null) { Method method = new Method(moduleId, MethodType.Bios, function.StubAddress, 8, new BiosFunctionToken(stubImport.Function)); db.AddSymbol(method); } } } // If symbols are present, use those to add methods and variables // Otherwise, we need to try to figure them out (good luck!) if (db != null) { // Find symbol table Elf32_Shdr *symtabShdr = FindSection(buffer, ".symtab"); if ((symtabShdr != null) && (symtabShdr->sh_size > 0x100)) { byte *strtab = FindSectionAddress(buffer, symtabShdr->sh_link); int symbolCount = ( int )symtabShdr->sh_size / sizeof(Elf32_Sym); byte *symtab = buffer + symtabShdr->sh_offset; byte *p = symtab; for (int n = 0; n < symbolCount; n++, p += sizeof(Elf32_Sym)) { Elf32_Sym *sym = ( Elf32_Sym * )p; uint symType = sym->st_info & ( uint )0xF; if ((symType != 0x1) && (symType != 0x2)) { continue; } if (sym->st_size == 0) { continue; } Elf32_Shdr *shdr = FindSection(buffer, sym->st_shndx); Debug.Assert(shdr != null); string name = null; if (sym->st_name != 0) { name = this.GetName(strtab, ( int )sym->st_name); } uint address = baseAddress + sym->st_value; if (needsRelocation == true) { address += shdr->sh_addr; } Symbol symbol = null; if (symType == 0x1) { // OBJECT symbol = new Variable(moduleId, address, sym->st_size, name); } else if (symType == 0x2) { // FUNC symbol = new Method(moduleId, MethodType.User, address, sym->st_size, name); } if (symbol != null) { db.AddSymbol(symbol); } } results.HadSymbols = true; Log.WriteLine(Verbosity.Verbose, Feature.Loader, "Found {0} methods and {1} variables in the symbol table", db.MethodCount, db.VariableCount); } else { // No symbol table found - try to build the symbols Elf32_Shdr *textShdr = FindSection(buffer, ".text"); Debug.Assert(textShdr != null); uint textAddress = baseAddress + textShdr->sh_addr; byte *text = memory.TranslateMainMemory(( int )textAddress); uint size = textShdr->sh_size; this.Analyze(moduleId, db, text, size, textAddress); Log.WriteLine(Verbosity.Verbose, Feature.Loader, "Found {0} methods by analysis", db.MethodCount); } // End update, started above db.EndUpdate(); //foreach( Method method in db.GetMethods() ) // Debug.WriteLine( method.ToString() ); } #if DEBUG // Print stats Log.WriteLine(Verbosity.Critical, Feature.Loader, "Load complete: {0}/{1} ({2}%) NIDs good; {3} not implemented, {4} not found, {5} in missing modules = {6} total", nidGoodCount, results.Imports.Count - moduleNotFoundCount, (nidGoodCount / ( float )(results.Imports.Count - moduleNotFoundCount)) * 100.0f, nidNotImplementedCount, nidNotFoundCount, moduleNotFoundCount, results.Imports.Count); if (missingModules.Count > 0) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "{0} missing modules (contain {1} NIDs ({2}% of total)):", missingModules.Count, moduleNotFoundCount, (moduleNotFoundCount / ( float )results.Imports.Count) * 100.0f); foreach (string moduleName in missingModules) { Log.WriteLine(Verbosity.Normal, Feature.Loader, "\t\t{0}", moduleName); } } if ((functionExportCount > 0) || (variableExportCount > 0)) { Log.WriteLine(Verbosity.Critical, Feature.Loader, "Exported {0} functions and {1} variables", functionExportCount, variableExportCount); } #endif results.Successful = true; if (results.Successful == true) { // If we export things, go back and find previously loaded modules that may need fixing up if ((functionExportCount > 0) || (variableExportCount > 0)) { bool fixupResult = this.FixupDelayedImports(kernel, results); Debug.Assert(fixupResult == true); } // If we are the boot load - we do some special stuff like run start, etc // If we are a PRX, all that is taken care of for us by the user code making calls if (type == ModuleType.Boot) { KModule module = new KModule(kernel, new BiosModule(results.Name, results.Exports.ToArray())); module.UID = moduleId; module.LoadParameters = parameters; module.LoadResults = results; kernel.UserModules.Add(module); Debug.Assert(kernel.MainModule == null); kernel.MainModule = module; kernel.AddHandle(module); // Allocate room for args KMemoryBlock argsBlock = kernel.Partitions[2].Allocate(string.Format("Module {0} args", results.Name), KAllocType.High, 0, 0xFF); // 256b of args - enough? // Set arguments - we put these right below user space, and right above the stack uint args = 0; uint argp = argsBlock.Address; string arg0 = parameters.Path.AbsolutePath.Replace('\\', '/') + "/"; args += ( uint )arg0.Length + 1; kernel.WriteString(argp, arg0); uint envp = argp; // + args; // write envp?? // What we do here simulates what the modulemgr does - it creates a user mode thread that // runs module_start (_start, etc) and then exits when complete. // NOTE: If we are a PRX, the entry address will correspond to module_start, so we don't need to do anything! // Create a thread KThread thread = new KThread(kernel, module, kernel.Partitions[2], "kmodule_thread", results.EntryAddress, 0, KThreadAttributes.User, 0x4000); thread.GlobalPointer = results.GlobalPointer; kernel.AddHandle(thread); thread.Start(args, argp); // Setup handler so that we get the callback when the thread ends and we can kill it cpu.SetContextSafetyCallback(thread.ContextID, new ContextSafetyDelegate(this.KmoduleThreadEnd), ( int )thread.UID); Log.WriteLine(Verbosity.Verbose, Feature.Loader, "starting kmodule loading thread with UID {0:X}", thread.UID); // Schedule so that our thread runs kernel.Schedule(); // If debugging, set start breakpoint if (Diag.IsAttached == true) { Diag.Instance.Client.OnBootModuleLoaded(results.EntryAddress); } if (Diag.IsAttached == true) { Diag.Instance.Client.OnModuleLoaded(); } //kernel.MemorySystem.DumpMainMemory( "startup.bin" ); } } } finally { if (pbuffer != IntPtr.Zero) { Marshal.FreeHGlobal(pbuffer); } } return(results); }
private bool FixupDelayedImports(Kernel kernel, LoadResults results) { int fixupCount = 0; foreach (KModule previous in kernel.UserModules) { if (previous.LoadResults.MissingImports.Count == 0) { continue; } LinkedListEntry <DelayedImport> e = previous.LoadResults.MissingImports.HeadEntry; while (e != null) { LinkedListEntry <DelayedImport> next = e.Next; DelayedImport import = e.Value; if (results.ExportNames.Contains(import.StubImport.ModuleName) == true) { // Find export StubExport myExport = null; foreach (StubExport export in results.Exports) { if (export.NID == import.StubImport.NID) { myExport = export; break; } } if (myExport != null) { previous.LoadResults.MissingImports.Remove(e); fixupCount++; // Fixup Log.WriteLine(Verbosity.Verbose, Feature.Loader, "Fixing up module {0} delayed import 0x{1:X8}; value={2:X8}", previous.Name, import.StubImport.NID, myExport.Address); Debug.Assert(myExport.Type == import.StubImport.Type); if (myExport.Type == StubType.Function) { BiosFunction function = import.StubImport.Function; // TODO: Change function module, etc? // Perform fixup uint *pcode = ( uint * )kernel.MemorySystem.Translate(function.StubAddress); { // j {target} // nop *(pcode + 0) = ( uint )((2 << 26) | ((myExport.Address >> 2) & 0x03FFFFFF)); *(pcode + 1) = ( uint )0; } } else { throw new NotImplementedException("Cannot handle fixups of variable imports"); } } } e = next; } } return(true); }
private int LoadModule(IMediaFile file, Stream stream, int flags, int option) { // Load! LoadParameters loadParams = new LoadParameters(); if (file != null) { loadParams.Path = file.Parent; loadParams.FilePath = file.AbsolutePath; string fileName = file.Name.ToLowerInvariant(); foreach (string blacklisted in _moduleBlacklist) { if (fileName == blacklisted) { // Module is blacklisted - ignore Log.WriteLine(Verbosity.Normal, Feature.Bios, "LoadModule: module is blacklisted, ignoring"); return(FakeModuleUID); } } } #if DEBUG loadParams.AppendDatabase = true; #endif // Check to see if it's one we have a decoded version of string kernelLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string prxLocation = Path.Combine(kernelLocation, "PRX"); string lookasidePrx = Path.Combine(prxLocation, file.Name); if (File.Exists(lookasidePrx) == true) { // Load ours instead Log.WriteLine(Verbosity.Normal, Feature.Bios, "LoadModule: lookaside prx found at {0}", lookasidePrx); stream = File.OpenRead(lookasidePrx); } Debug.Assert(stream != null); if (stream == null) { Log.WriteLine(Verbosity.Critical, Feature.Bios, "LoadModule: unable to load module {0}", file.Name); return(-1); } // Quick check to make sure it isn't encrypted before sending off to loader byte[] magicBytes = new byte[4]; stream.Read(magicBytes, 0, 4); stream.Seek(-4, SeekOrigin.Current); // 0x7E, 0x50, 0x53, 0x50 = ~PSP bool encrypted = ( (magicBytes[0] == 0x7E) && (magicBytes[1] == 0x50) && (magicBytes[2] == 0x53) && (magicBytes[3] == 0x50)); //Debug::Assert( encrypted == false ); if (encrypted == true) { Log.WriteLine(Verbosity.Critical, Feature.Bios, "LoadModule: module {0} is encrypted - unable to load", file.Name); // We spoof the caller in to thinking we worked right... by just returning 0 ^_^ KModule fakemod = new KModule(_kernel, null); fakemod.LoadParameters = loadParams; _kernel.AddHandle(fakemod); if (Diag.IsAttached == true) { Diag.Instance.Client.OnModuleLoaded(); } return(( int )fakemod.UID); } LoadResults results = _kernel.Bios._loader.LoadModule(ModuleType.Prx, stream, loadParams); //Debug.Assert( results.Successful == true ); if (results.Successful == false) { Log.WriteLine(Verbosity.Critical, Feature.Bios, "LoadModule: loader failed"); return(FakeModuleUID); } if (results.Ignored == true) { // Faked Log.WriteLine(Verbosity.Normal, Feature.Bios, "LoadModule: ignoring module"); return(FakeModuleUID); } // Create a local representation of the module BiosModule module = new BiosModule(results.Name, results.Exports.ToArray()); _kernel.Bios._metaModules.Add(module); _kernel.Bios._metaModuleLookup.Add(module.Name, module); KModule kmod = new KModule(_kernel, module); kmod.UID = results.ModuleID; kmod.LoadParameters = loadParams; kmod.LoadResults = results; _kernel.UserModules.Add(kmod); _kernel.AddHandle(kmod); if (Diag.IsAttached == true) { Diag.Instance.Client.OnModuleLoaded(); } return(( int )kmod.UID); }