Exemplo n.º 1
0
        private MethodBody BuildMethodBody( ModuleInfo moduleInfo, Method method )
        {
            Debug.Assert( this.Debugger.DebugHost.CpuHook != null );
            uint[] codes = this.Debugger.DebugHost.CpuHook.GetMethodBody( method );

            uint instrAddress = method.Address;
            List<Instruction> instrs = new List<Instruction>( ( int )method.Length / 4 );
            for( int n = 0; n < codes.Length; n++ )
            {
                Instruction instr = new Instruction( instrAddress, codes[ n ] );
                instrs.Add( instr );
                instrAddress += 4;
            }
            MethodBody methodBody = new MethodBody( moduleInfo, method.Address, ( uint )method.Length, instrs.ToArray() );
            if( method.Type == MethodType.Bios )
            {
                if( method.Function.MethodName != null )
                    methodBody.Name = method.Function.MethodName;
                else
                    methodBody.Name = method.Function.ModuleName + "::" + method.Function.NID.ToString( "X8" );
                methodBody.Function = method.Function;
            }
            else
            {
                if( method.Name != null )
                    methodBody.Name = method.Name;
            }

            return methodBody;
        }
Exemplo n.º 2
0
        public bool ShowDisassembly( Method method )
        {
            if( method == null )
                throw new ArgumentNullException( "method" );

            if( _disasmDoc != null )
            {
                _disasmDoc.DisplayMethod( method );
                _disasmDoc.Activate();
            }
            else
            {
                DisassemblyDocument doc = new DisassemblyDocument( this );
                doc.DisplayMethod( method );
                doc.Show( dockPanel );
                doc.Activate();
                _disasmDoc = doc;
            }

            return true;
        }
Exemplo n.º 3
0
        private MethodBody BuildMethodBody( Method method )
        {
            Debug.Assert( Debugger.Host.CpuHook != null );
            uint[] codes = Debugger.Host.CpuHook.GetMethodBody( method );

            uint instrAddress = method.Address;
            List<Instruction> instrs = new List<Instruction>( ( int )method.Length / 4 );
            for( int n = 0; n < codes.Length; n++ )
            {
                Instruction instr = new Instruction( instrAddress, codes[ n ] );
                instrs.Add( instr );
                instrAddress += 4;
            }
            MethodBody methodBody = new MethodBody( method.Address, 4 * ( uint )method.Length, instrs.ToArray() );

            return methodBody;
        }
Exemplo n.º 4
0
 public Statement( StatementType type, Method method, int address )
 {
     this.Type = type;
     this.Method = method;
     this.Address = address;
 }
Exemplo n.º 5
0
        public void DisplayMethod( Method method )
        {
            if( _currentMethod == method )
                return;

            _currentMethod = method;
            //_rowMapping = new Dictionary<int, Row>( method.Instructions.Count );
            _rowMapping = new Dictionary<int, Row>();

            if( methodsToolStripComboBox.Items.Contains( method ) == true )
                methodsToolStripComboBox.SelectedItem = method;

            syntaxDocument.Clear();

            syntaxDocument.Text = string.Format( "{0:X8} <{1}>:", method.EntryAddress, method.Name );

            //foreach( Instruction instr in method.Instructions.Values )
            //{
            //    Row row = syntaxDocument.Add( string.Format( " {0:X8}:  {1:X8}    {2} {3}", instr.Address, instr.Code, instr.Opcode, instr.Operands ), false );
            //    _rowMapping.Add( instr.Address, row );
            //}

            syntaxDocument.UndoBuffer.Clear();

            foreach( Statement statement in _statements.Values )
            {
                this.SetStatement( statement );
            }
        }
Exemplo n.º 6
0
        public Statement AddStatement( StatementType type, Method method, int address )
        {
            Statement statement = new Statement( type, method, address );
            _statements.Add( statement.Address, statement );

            this.SetStatement( statement );

            return statement;
        }
Exemplo n.º 7
0
        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;
        }
Exemplo n.º 8
0
        private void Analyze( uint moduleId, IDebugDatabase db, byte* text, uint textLength, uint baseAddress )
        {
            // We start at the base and try to build functions
            // The logic here is similar to my dynarec

            uint methodStart = baseAddress;
            bool inDelay = false;
            uint lastBranchTarget = 0;
            InstructionType lastJumpType = InstructionType.Normal;
            uint previousTarget = 0;
            bool lastJumpRegister = false;
            //bool hasSpMod = false;

            uint address = baseAddress;
            uint* pcode = ( uint* )text;
            for( int n = 0; n < textLength / 4; n++, pcode++, address += 4 )
            {
                // addiu $sp, ... ($sp = 29)
                // 29 << 16 = 1D0000
                //bool isSpMod =
                //    ( ( *pcode & 0xFC1F0000 ) == 0x241D0000 ) ||
                //    ( ( *pcode & 0xFC1F0000 ) == 0x201D0000 );
                //if( isSpMod == true )
                //    hasSpMod = true;

                bool lastDelay = inDelay;
                inDelay = false;
                if( lastDelay == true )
                {
                    // A function may end here if there are no forward branches
                    if( lastJumpType == InstructionType.Branch )
                        continue;
                    // We don't (usually) end on JAL
                    if( lastJumpType == InstructionType.JumpAndLink )
                        continue;
                    if( lastBranchTarget > address )
                        continue;
                    // If it's a jump and it's back in to us, don't count it
                    //if( ( lastJumpType == InstructionType.Jump ) &&
                    //    ( previousTarget >= methodStart ) &&
                    //    ( previousTarget < address ) )
                    //    continue;
                    //if( ( isSpMod == true ) &&
                    //    ( lastJumpType == InstructionType.Jump ) &&
                    //    ( lastJumpRegister == false ) )
                    //{
                    //}

                    // End method
                    Method method = new Method( moduleId, MethodType.User, methodStart, address - methodStart + 4 );
                    db.AddSymbol( method );
                    methodStart = address + 4;
                    lastBranchTarget = 0;
                    //hasSpMod = false;
                    continue;
                }

                uint target;
                InstructionType type = AnalyzeJump( address, *pcode, out target );
                switch( type )
                {
                    case InstructionType.Branch:
                        if( ( target != uint.MaxValue ) &&
                            ( target > lastBranchTarget ) )
                            lastBranchTarget = target;
                        break;
                    case InstructionType.Jump:
                        lastJumpRegister = ( target == uint.MaxValue );
                        // Only treat the J as a branch if it's an absolute jump and there are other forward branches
                        if( ( lastJumpRegister == false ) &&
                            ( lastBranchTarget > target ) )
                        {
                            if( ( target != uint.MaxValue ) &&
                                ( target > lastBranchTarget ) )
                                lastBranchTarget = target;
                        }
                        break;
                    case InstructionType.JumpAndLink:
                        break;
                }
                previousTarget = target;
                inDelay = ( type != InstructionType.Normal );
                lastJumpType = type;
            }

            if( address - 4 > methodStart )
            {
                // Final end - ideally we'd never have to do this
                Method method = new Method( moduleId, MethodType.User, methodStart, address - 4 - methodStart );
                db.AddSymbol( method );
                Log.WriteLine( Verbosity.Normal, Feature.Loader, "Analyze didn't finish .text cleanly - last method: {0}", method.ToString() );
            }
        }