Esempio n. 1
0
void KImageModule::Unload(void)
{
    SymUnloadModule(m_hProcess, m_symbolbase);
    SymCleanup(m_hProcess);

	if ( m_image.ModuleName )
		UnMapAndLoad(& m_image);
} 
Esempio n. 2
0
void DelImages (void)
{
    PIMAGE_INFO     pImage, pNextImage;

    pNextImage = pProcessHead->pImageHead;
    pProcessHead->pImageHead = NULL;
    while (pNextImage) {
        pImage = pNextImage;
        pNextImage=pImage->pImageNext;
        SymUnloadModule( pProcessCurrent->hProcess, (ULONG)pImage->lpBaseOfImage );
        pProcessCurrent->pImageByIndex[ pImage->index ] = NULL;
        free(pImage);
        }
}
Esempio n. 3
0
void DelImage (PSZ pszName, PVOID BaseOfDll, ULONG ProcessId)
{
    PIMAGE_INFO     pImage, *pp;

    pp = &pProcessHead->pImageHead;
    while (pImage = *pp) {
        if (!_stricmp(pImage->szImagePath, pszName)){
            *pp = pImage->pImageNext;
            SymUnloadModule( pProcessCurrent->hProcess, (ULONG)pImage->lpBaseOfImage );
            pProcessCurrent->pImageByIndex[ pImage->index ] = NULL;
            free(pImage);
            }
        else {
            pp = &pImage->pImageNext;
            }
        }

    return;
}
Esempio n. 4
0
/*
==================
Sym_Shutdown
==================
*/
void Sym_Shutdown( void ) {
	SymUnloadModule( GetCurrentProcess(), lastAllocationBase );
	SymCleanup( GetCurrentProcess() );
	lastAllocationBase = -1;
}
Esempio n. 5
0
static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
{
    union {
        char	bufferA[256];
        WCHAR	buffer[256];
    } u;
    DWORD       cont = DBG_CONTINUE;

    dbg_curr_pid = de->dwProcessId;
    dbg_curr_tid = de->dwThreadId;

    if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
        dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
    else
        dbg_curr_thread = NULL;

    switch (de->dwDebugEventCode)
    {
    case EXCEPTION_DEBUG_EVENT:
        if (!dbg_curr_thread)
        {
            WINE_ERR("%04x:%04x: not a registered process or thread (perhaps a 16 bit one ?)\n",
                     de->dwProcessId, de->dwThreadId);
            break;
        }

        WINE_TRACE("%04x:%04x: exception code=%08x\n",
                   de->dwProcessId, de->dwThreadId,
                   de->u.Exception.ExceptionRecord.ExceptionCode);

        if (dbg_curr_process->continue_on_first_exception)
        {
            dbg_curr_process->continue_on_first_exception = FALSE;
            if (!DBG_IVAR(BreakOnAttach)) break;
        }
        if (dbg_fetch_context())
        {
            cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
                                        de->u.Exception.dwFirstChance);
            if (cont && dbg_curr_thread)
            {
                SetThreadContext(dbg_curr_thread->handle, &dbg_context);
            }
        }
        break;

    case CREATE_PROCESS_DEBUG_EVENT:
        dbg_curr_process = dbg_add_process(&be_process_active_io, de->dwProcessId,
                                           de->u.CreateProcessInfo.hProcess);
        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Couldn't create process\n");
            break;
        }
        fetch_module_name(de->u.CreateProcessInfo.lpImageName,
                          de->u.CreateProcessInfo.fUnicode,
                          de->u.CreateProcessInfo.lpBaseOfImage,
                          u.buffer, sizeof(u.buffer) / sizeof(WCHAR), TRUE);

        WINE_TRACE("%04x:%04x: create process '%s'/%p @%p (%u<%u>)\n",
                   de->dwProcessId, de->dwThreadId,
                   wine_dbgstr_w(u.buffer),
                   de->u.CreateProcessInfo.lpImageName,
                   de->u.CreateProcessInfo.lpStartAddress,
                   de->u.CreateProcessInfo.dwDebugInfoFileOffset,
                   de->u.CreateProcessInfo.nDebugInfoSize);
        dbg_set_process_name(dbg_curr_process, u.buffer);

        if (!dbg_init(dbg_curr_process->handle, u.buffer, FALSE))
            dbg_printf("Couldn't initiate DbgHelp\n");
        if (!dbg_load_module(dbg_curr_process->handle, de->u.CreateProcessInfo.hFile, u.buffer,
                             (DWORD_PTR)de->u.CreateProcessInfo.lpBaseOfImage, 0))
            dbg_printf("couldn't load main module (%u)\n", GetLastError());

        WINE_TRACE("%04x:%04x: create thread I @%p\n",
                   de->dwProcessId, de->dwThreadId, de->u.CreateProcessInfo.lpStartAddress);

        dbg_curr_thread = dbg_add_thread(dbg_curr_process,
                                         de->dwThreadId,
                                         de->u.CreateProcessInfo.hThread,
                                         de->u.CreateProcessInfo.lpThreadLocalBase);
        if (!dbg_curr_thread)
        {
            WINE_ERR("Couldn't create thread\n");
            break;
        }
        dbg_init_current_process();
        dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
        break;

    case EXIT_PROCESS_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: exit process (%d)\n",
                   de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);

        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Unknown process\n");
            break;
        }
        tgt_process_active_close_process(dbg_curr_process, FALSE);
        dbg_printf("Process of pid=%04x has terminated\n", de->dwProcessId);
        break;

    case CREATE_THREAD_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: create thread D @%p\n",
                   de->dwProcessId, de->dwThreadId, de->u.CreateThread.lpStartAddress);

        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Unknown process\n");
            break;
        }
        if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
        {
            WINE_TRACE("Thread already listed, skipping\n");
            break;
        }

        dbg_curr_thread = dbg_add_thread(dbg_curr_process,
                                         de->dwThreadId,
                                         de->u.CreateThread.hThread,
                                         de->u.CreateThread.lpThreadLocalBase);
        if (!dbg_curr_thread)
        {
            WINE_ERR("Couldn't create thread\n");
            break;
        }
        dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
        break;

    case EXIT_THREAD_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: exit thread (%d)\n",
                   de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);

        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }
        /* FIXME: remove break point set on thread startup */
        dbg_del_thread(dbg_curr_thread);
        break;

    case LOAD_DLL_DEBUG_EVENT:
        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }
        fetch_module_name(de->u.LoadDll.lpImageName,
                          de->u.LoadDll.fUnicode,
                          de->u.LoadDll.lpBaseOfDll,
                          u.buffer, sizeof(u.buffer) / sizeof(WCHAR), FALSE);

        WINE_TRACE("%04x:%04x: loads DLL %s @%p (%u<%u>)\n",
                   de->dwProcessId, de->dwThreadId,
                   wine_dbgstr_w(u.buffer), de->u.LoadDll.lpBaseOfDll,
                   de->u.LoadDll.dwDebugInfoFileOffset,
                   de->u.LoadDll.nDebugInfoSize);
        dbg_load_module(dbg_curr_process->handle, de->u.LoadDll.hFile, u.buffer,
                        (DWORD_PTR)de->u.LoadDll.lpBaseOfDll, 0);
        break_set_xpoints(FALSE);
        break_check_delayed_bp();
        break_set_xpoints(TRUE);
        if (DBG_IVAR(BreakOnDllLoad))
        {
            dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
                       dbg_W2A(u.buffer, -1), (unsigned long)de->u.LoadDll.lpBaseOfDll);
            if (dbg_fetch_context()) cont = 0;
        }
        break;

    case UNLOAD_DLL_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: unload DLL @%p\n",
                   de->dwProcessId, de->dwThreadId,
                   de->u.UnloadDll.lpBaseOfDll);
        break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
        SymUnloadModule(dbg_curr_process->handle,
                        (unsigned long)de->u.UnloadDll.lpBaseOfDll);
        break;

    case OUTPUT_DEBUG_STRING_EVENT:
        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }

        memory_get_string(dbg_curr_process,
                          de->u.DebugString.lpDebugStringData, TRUE,
                          de->u.DebugString.fUnicode, u.bufferA, sizeof(u.bufferA));
        WINE_TRACE("%04x:%04x: output debug string (%s)\n",
                   de->dwProcessId, de->dwThreadId, u.bufferA);
        break;

    case RIP_EVENT:
        WINE_TRACE("%04x:%04x: rip error=%u type=%u\n",
                   de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
                   de->u.RipInfo.dwType);
        break;

    default:
        WINE_TRACE("%04x:%04x: unknown event (%x)\n",
                   de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
    }
    if (!cont) return TRUE;  /* stop execution */
    ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
    return FALSE;  /* continue execution */
}
Esempio n. 6
0
void
AddImage(
    PSZ   pszName,
    PVOID BaseOfDll,
    ULONG SizeOfImage,
    ULONG CheckSum,
    ULONG ProcessId,
    PSZ   pszModuleName,
    BOOL  ForceSymbolLoad
    )
{
    PIMAGE_INFO         pImageNew;
    PIMAGE_INFO         *pp;
    UCHAR               index = 0;
    PSZ                 pszBaseName;
    PCHAR               KernelBaseFileName;
    HANDLE              KernelBaseFileHandle;
    DWORD               BytesWritten;
    IMAGEHLP_MODULE     mi;
    CHAR                buf[256];
    ULONG               LoadAddress;


    if (pszName == NULL) {
        return;
    }

    if ((_stricmp( pszName, KERNEL_IMAGE_NAME ) == 0) ||
        (_stricmp( pszName, KERNEL_IMAGE_NAME_MP ) == 0)) {
        //
        // rename the image if necessary
        //
        if (GetModnameFromImage( (ULONG)BaseOfDll, NULL, buf )) {
            strcpy( pszName, buf );
        }
        pszModuleName = "NT";
    }

    if (_stricmp( pszName, HAL_IMAGE_FILE_NAME ) == 0) {
        //
        // rename the image if necessary
        //
        if (GetModnameFromImage( (ULONG)BaseOfDll, NULL, buf )) {
            strcpy( pszName, buf );
        }
        pszModuleName = "HAL";
    }

    pszBaseName = strchr(pszName,'\0');
    while (pszBaseName > pszName) {
        if (pszBaseName[-1] == '\\' || pszBaseName[-1] == '/' || pszBaseName[-1] == ':') {
            pszName = pszBaseName;
            break;
        } else {
            pszBaseName -= 1;
        }
    }

    //
    //  search for existing image with same checksum at same base address
    //      if found, remove symbols, but leave image structure intact
    //

    pp = &pProcessCurrent->pImageHead;
    while (pImageNew = *pp) {
        if (pImageNew->lpBaseOfImage == BaseOfDll) {

            if (fVerboseOutput) {
                dprintf("%s: force unload of %s\n", DebuggerName, pImageNew->szImagePath);
            }
            SymUnloadModule( pProcessCurrent->hProcess, (ULONG)pImageNew->lpBaseOfImage );
            break;

        } else if (pImageNew->lpBaseOfImage > BaseOfDll) {

            pImageNew = NULL;
            break;

        }

        pp = &pImageNew->pImageNext;
    }

    //  if not found, allocate and fill new image structure

    if (!pImageNew) {
        for (index=0; index<pProcessCurrent->MaxIndex; index++) {
            if (pProcessCurrent->pImageByIndex[ index ] == NULL) {
                pImageNew = calloc(sizeof(IMAGE_INFO),1);
                break;
            }
        }

        if (!pImageNew) {
            DWORD NewMaxIndex;
            PIMAGE_INFO *NewImageByIndex;

            NewMaxIndex = pProcessCurrent->MaxIndex + 32;
            if (NewMaxIndex < 0x100) {
                NewImageByIndex = calloc( NewMaxIndex,  sizeof( *NewImageByIndex ) );
            } else {
                NewImageByIndex = NULL;
            }
            if (NewImageByIndex == NULL) {
                dprintf("%s: No room for %s image record.\n",
                        DebuggerName,
                        pszName );
                return;
            }

            if (pProcessCurrent->pImageByIndex) {
                memcpy( NewImageByIndex,
                        pProcessCurrent->pImageByIndex,
                        pProcessCurrent->MaxIndex * sizeof( *NewImageByIndex )
                      );
                free( pProcessCurrent->pImageByIndex );
            }

            pProcessCurrent->pImageByIndex = NewImageByIndex;
            index = (UCHAR) pProcessCurrent->MaxIndex;
            pProcessCurrent->MaxIndex = NewMaxIndex;
            pImageNew = calloc(sizeof(IMAGE_INFO),1);
            if (!pImageNew) {
                dprintf("%s: Unable to allocate memory for %s symbols.\n",
                        DebuggerName, pszName);
                return;
            }
        }

        pImageNew->pImageNext = *pp;
        *pp = pImageNew;

        pImageNew->index = index;
        pProcessCurrent->pImageByIndex[ index ] = pImageNew;
    }

    //
    //  pImageNew has either the unloaded structure or the newly created one
    //
    pImageNew->lpBaseOfImage = BaseOfDll;
    pImageNew->dwCheckSum = CheckSum;
    pImageNew->dwSizeOfImage = SizeOfImage;
    pImageNew->GoodCheckSum = TRUE;
    strcpy( pImageNew->szImagePath, pszName );

    LoadAddress = SymLoadModule(
        pProcessCurrent->hProcess,
        NULL,
        pImageNew->szImagePath,
        pszModuleName,
        (ULONG)pImageNew->lpBaseOfImage,
        pImageNew->dwSizeOfImage
        );

    if (!LoadAddress) {
        DelImage( pszName, 0, 0 );
        return;
    }

    if (!pImageNew->lpBaseOfImage) {
        pImageNew->lpBaseOfImage = (PVOID)LoadAddress;
    }

    if (ForceSymbolLoad) {
        SymLoadModule(
            pProcessCurrent->hProcess,
            NULL,
            NULL,
            NULL,
            (ULONG)pImageNew->lpBaseOfImage,
            0
            );
    }

    if (SymGetModuleInfo( pProcessCurrent->hProcess, (ULONG)pImageNew->lpBaseOfImage, &mi )) {
        pImageNew->dwSizeOfImage = mi.ImageSize;
        strcpy( pImageNew->szImagePath, mi.ImageName );
        strcpy( pImageNew->szDebugPath, mi.LoadedImageName );
    } else {
        DelImage( pszName, 0, 0 );
        return;
    }

    if (pszModuleName) {
        strcpy( pImageNew->szModuleName, pszModuleName );
    } else {
        CreateModuleNameFromPath( pImageNew->szImagePath, pImageNew->szModuleName );
    }

    if (fVerboseOutput) {
        dprintf( "%s ModLoad: %08lx %08lx   %-8s\n",
                 DebuggerName,
                 pImageNew->lpBaseOfImage,
                 (ULONG)(pImageNew->lpBaseOfImage) + pImageNew->dwSizeOfImage,
                 pImageNew->szImagePath
                 );
    }
}
Esempio n. 7
0
PPROFBLK SetupProfiling(LPCTSTR ptchFileName)
{
		PVOID	ImageBase;
		PPROFBLK pProfBlk;
		PPROFBLK pPrevProfBlk;
		ULONG	 ulBlkOff;
		LPCSTR  ptchImageName;
	    TCHAR	atchImageName [256];
    	PIMAGE_NT_HEADERS  pImageNtHeader;
		IMAGEHLP_MODULE	 ModuleInfo;

	    // Skip directory name
	    if ( (ptchImageName = strrchr(ptchFileName, '\\')) )
	        ptchImageName++;
	    else
	        ptchImageName = (PTCHAR)ptchFileName;

		// Make uppercase copy
	    _strupr (strcpy (atchImageName, ptchImageName));

		// Don't profile CAP
	    if ( !strcmp (atchImageName, CAPDLL) )
	        return NULL;

		// Search prof blk list for matching image name
		pPrevProfBlk = NULL;
		ulBlkOff = ulLocProfBlkOff;

	    while (ulBlkOff != 0) 
	    {
    		pPrevProfBlk = MKPPROFBLK(ulBlkOff);

			// If found image, no need to set up new block
			if (!strcmp((PCHAR)pPrevProfBlk->atchImageName, atchImageName))
				return FALSE;

			ulBlkOff = pPrevProfBlk->ulNxtBlk;
		}

		try // Accessing new block can cause an access fault
			// which will extend the allocation 
		{
			// Place block at next available offset
			pProfBlk = MKPPROFBLK(*pulProfBlkBase);

			// Fill in initial values
			pProfBlk->ImageBase =0;
		    pProfBlk->CodeStart = 0;
		    pProfBlk->CodeLength = 0;
			pProfBlk->iSymCnt = 0;
			pProfBlk->State = BLKSTATE_ASSIGNED;
			pProfBlk->ulNxtBlk = 0;
		    strcpy ((TCHAR *) pProfBlk->atchImageName, atchImageName);

			// Link to previous block or initial block offset
			if (pPrevProfBlk)
				pPrevProfBlk->ulNxtBlk = *pulProfBlkBase;
			else
				ulLocProfBlkOff = *pulProfBlkBase;

			// Load module symbols
			ImageBase = GetModuleHandle(ptchImageName);
			SymLoadModule(hThisProcess, NULL, (LPSTR)ptchFileName,
												 (LPSTR)ptchImageName, (DWORD)ImageBase, 0);
			if (ImageBase != NULL)
			{
		 		pProfBlk->ImageBase = ImageBase;

				// Get code start address
				if ((pImageNtHeader = ImageNtHeader(ImageBase)) != NULL)
				{
					pProfBlk->CodeStart = (PULONG)((TCHAR *)ImageBase +
													 pImageNtHeader->OptionalHeader.BaseOfCode);
	  			}
				else
				{
					// If can't get code start, use imagebase as next best guess
					pProfBlk->CodeStart = ImageBase;
				}

	#if defined(MIPS) && !defined(MIPS_VC40_INTERFACE)

				// Enumerate symbols to find adress of _penter
		    	fPenterFound = FALSE;
				SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase,
									 FindPenterCallback, (PVOID)pProfBlk);

	#endif // MIPS && !MIPS_VC40_INTERFACE

				// Get module info for symbols count
				SymGetModuleInfo(hThisProcess, (DWORD)ImageBase, &ModuleInfo);
				pProfBlk->iSymCnt = ModuleInfo.NumSyms;

				// Determine location for symbols and symbol names
				pProfSymb = (PSYMINFO)(&pProfBlk->atchImageName[strlen(atchImageName) + 1]);
				pProfBlk->ulSym = (PTCHAR)pProfSymb - (PTCHAR)pulProfBlkBase;
				pcProfSymbName = (PTCHAR)&pProfSymb[ModuleInfo.NumSyms];

				// Now enumerate symbols to build up symbol table
				ulMaxSymbAddr = (ULONG)pProfBlk->CodeStart;
				SymEnumerateSymbols(hThisProcess, (DWORD)ImageBase,
									 SymbolEnumCallback, (PVOID)pProfBlk);

				// Set symbol range based on max symbol address	encountered
				if (ulMaxSymbAddr > (ULONG)pProfBlk->CodeStart)
					pProfBlk->CodeLength = ulMaxSymbAddr - (ULONG)pProfBlk->CodeStart;

				// Update pointer to available space
				*pulProfBlkBase = (ULONG)(pcProfSymbName - (PTCHAR)pulProfBlkBase);

				// Unload the module
				SymUnloadModule(hThisProcess, (DWORD)ImageBase);

				// Do any requested import/export patching
	        	PatchDll (ptchPatchImports, ptchPatchCallers, bCallersToPatch,
	                       atchImageName, ImageBase);
			}
			else
			{	
				// No symbols - Update offset to next free space
				*pulProfBlkBase = (ULONG)&pProfBlk->atchImageName[strlen(atchImageName) + 1]
									-(ULONG)pulProfBlkBase;
			} // ImageBase != NULL

		}
		//
		// + : transfer control to the handler (EXCEPTION_EXECUTE_HANDLER)
		// 0 : continue search                 (EXCEPTION_CONTINUE_SEARCH)
		// - : dismiss exception & continue    (EXCEPTION_CONTINUE_EXECUTION)
		//
		except ( AccessXcptFilter (GetExceptionCode(), GetExceptionInformation(), COMMIT_SIZE))
		{
		    // Should never get here since filter never returns
		    // EXCEPTION_EXECUTE_HANDLER.
		    CapDbgPrint ("CAP:  DoDllInitializations() - *LOGIC ERROR* - "
		              "Inside the EXCEPT: (xcpt=0x%lx)\n", GetExceptionCode());
		} // end of TRY/EXCEPT

		return pProfBlk;
}
Esempio n. 8
0
int getDebugInfo(char* fname)
{
	HANDLE Self;
	DWORD moduleAddr;
	IMAGEHLP_MODULE moduleInfo;

	namesSize = 1;

	maxDebug = CodeSize + 10000;
	hasDebug = calloc(maxDebug, sizeof(int));
	names    = calloc(MAX_NAMES_SIZE,1);
	nonCode    = calloc(MAX_NONCODE_SIZE,sizeof(Sym));
	nonCodeCount = 0;

	Self = GetCurrentProcess();

	SymSetOptions(SYMOPT_LOAD_LINES);

	if(!SymInitialize(Self,NULL,FALSE)) {
		printf("Failed to initialize Sym \n");
		return -1;
	}

	printf("Trying to load with base = %08X\n",imageBase);
//	moduleAddr = SymLoadModule(Self,NULL,fname,NULL,imageBase+BASE_SHIFT,0);
	moduleAddr = SymLoadModule(Self,NULL,fname,NULL,0,0);

    if(!moduleAddr) {
		printf("Error: %n",GetLastError());
		return -1;
	}

	moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE);

	if(SymGetModuleInfo(Self,moduleAddr,&moduleInfo)) {
		printf("ImageSize		: %d \n",moduleInfo.ImageSize);
		printf("NumSyms			: %d \n",moduleInfo.NumSyms);
		
		printf("SymType			: ");
		switch (moduleInfo.SymType) {
			case SymNone : printf("No symbols are loaded \n"); 
							break;
			case SymCoff : printf("COFF symbols \n"); 
							break;
			case SymCv	 : printf("CodeView symbols \n");
							break;
			case SymPdb  : printf("pdb file \n");
							break;
			case SymExport : printf("Symbols generated from a DLL's export table\n");
							break;
			case SymDeferred : printf("The library has not yet attempted to load symbols.\n"); 
							break;
			case SymSym : printf(".SYM file \n");
							break;
			default:  printf("Unknown value for SymType : %d\n",moduleInfo.SymType);
		}
		printf("ModuleName		: %s\n",moduleInfo.ModuleName);
		printf("ImageName		: %s\n",moduleInfo.ImageName);
		printf("LoadedImageName	: %s\n",moduleInfo.LoadedImageName); 
		printf("LoadedImageBase : %08X\n",moduleInfo.BaseOfImage);


	}

	SymEnumerateSymbols(Self,moduleAddr,SymbolEnumumeration,NULL);

	SymUnloadModule(Self,moduleAddr);
	SymCleanup(Self);

	return 0;
}