#include "stdafx.h" #include #include "../BasicCompiler_Common/common.h" #include "../BasicCompiler_Common/DebugSection.h" //デバッグ用 #include "../BasicCompiler_Common/debug.h" char *OpBuffer; extern DWORD dwStepRun; HANDLE hDebugProcess; DWORD _DebugSys_dwThreadID[MAX_DEBUG_THREAD]; HANDLE array_hDebugThread[MAX_DEBUG_THREAD]; int StepCursorObpSchedule=-1; int StepCursor_BackupChar; int NextStepThreadNum; void Debugger_StepIn(void){ dwStepRun=1; } void Debugger_StepOver(void){ dwStepRun=2; } void Debugger_StepCursor(void){ char temporary[MAX_PATH]; GetTempPath(MAX_PATH,temporary); if(temporary[lstrlen(temporary)-1]!='\\') lstrcat(temporary,"\\"); lstrcat(temporary,"ab_breakpoint.tmp"); char *buffer; buffer=ReadBuffer_NonErrMsg(temporary); int i=0; char szFilePath[MAX_PATH]; i=GetOneParameter(buffer,i,szFilePath); RemoveStringQuotes(szFilePath); int iLineNum; i=GetOneParameter(buffer,i,temporary); iLineNum=atoi(temporary); ///////////////////////////////////////////////////////// // デバッグ中プロセスのネイティブバッファ領域を更新 ///////////////////////////////////////////////////////// int FileNum; const IncludedFilesRelation *pIncludedFilesRelation = NULL; const BasicSource *pNowSource = NULL; BOOST_FOREACH( const ObjectModule *pObjectModule, compiler.staticLibraries ) { const BasicSource *pSource = &pObjectModule->GetSource(); pIncludedFilesRelation = &pSource->GetIncludedFilesRelation(); for(FileNum=0;FileNumGetFileCounts();FileNum++) { if(lstrcmpi(pIncludedFilesRelation->GetFilePathFromFileNumber(FileNum).c_str(),szFilePath)==0) { pNowSource = pSource; break; } } if( FileNum == pIncludedFilesRelation->GetFileCounts() ) { pIncludedFilesRelation = NULL; } else { break; } } if( !pIncludedFilesRelation ) { return; } for(i=0;;i++){ if( pIncludedFilesRelation->GetFileNumber( i ) == FileNum || pIncludedFilesRelation->GetFileNumber( i ) == -1 ) { break; } } if( pIncludedFilesRelation->GetFileNumber( i ) == -1 ) { return; } int FileBaseLine; FileBaseLine=i; int i2; for(i2=0;;i++,i2++) { if( FileNum < pIncludedFilesRelation->GetFileNumber( i ) ) { while( FileNum != pIncludedFilesRelation->GetFileNumber( i ) ) { i++; } } if(i2==iLineNum){ extern SourceLines oldSourceLines; loop: int tempCp = GetSourceCodeIndexFromLine( pNowSource->GetBuffer(), FileBaseLine+i2 ); int i3; for(i3=0;i3<(int)oldSourceLines.size()-1;i3++){ if(oldSourceLines[i3].GetSourceCodePosition().GetPos()==tempCp) break; } if(i3==oldSourceLines.size()-1){ i2--; goto loop; } StepCursorObpSchedule=oldSourceLines[i3].GetNativeCodePos(); StepCursor_BackupChar=pobj_DBDebugSection->pobj_now->BreakStepCodeBuffer[StepCursorObpSchedule]; pobj_DBDebugSection->pobj_now->BreakStepCodeBuffer[StepCursorObpSchedule]=(char)0xCC; break; } } extern HWND hDebugWnd; SendMessage(hDebugWnd,WM_DEBUG_CONTINUE,0,0); HeapDefaultFree(buffer); } void Debugger_Stop(void){ //プロセスを終了 TerminateProcess(hDebugProcess,0); hDebugProcess=0; //デバッグダイアログを終了 extern HWND hDebugWnd; if(hDebugWnd){ DestroyWindow(hDebugWnd); } } void Debugger_Pause(void){ /////////////////////////// // デバッグを一時中断 /////////////////////////// //ターゲットプロセス内のスレッドを一時中断 int i; for(i=0;idwThreadId); else InitVarList(pde->dwThreadId); if(bExit){ //"中断" SetDlgItemText(hMainDlg,IDOK,STRING_CLOSE); extern HWND hDebuggerToolbar; SendMessage(hDebuggerToolbar,TB_SETSTATE,IDC_DEBUG_START,TBSTATE_INDETERMINATE); SendMessage(hDebuggerToolbar,TB_SETSTATE,IDC_DEBUG_STEPOVER,TBSTATE_INDETERMINATE); SendMessage(hDebuggerToolbar,TB_SETSTATE,IDC_DEBUG_STEPIN,TBSTATE_INDETERMINATE); } else{ //"継続" SetDlgItemText(hDebugWnd,IDCANCEL,STRING_CONTINUE); } while(hDebugWnd&&dwStepRun==0) Sleep(1); } void DebugMessage(char *buffer){ extern HWND hMainDlg; int pos; if(!IsWindowEnabled(GetDlgItem(hMainDlg,IDC_DEBUGLIST))){ SetDlgItemText(hMainDlg,IDC_DEBUGLIST,""); EnableWindow(GetDlgItem(hMainDlg,IDC_DEBUGLIST),1); } pos=GetWindowTextLength(GetDlgItem(hMainDlg,IDC_DEBUGLIST)); SendDlgItemMessage(hMainDlg,IDC_DEBUGLIST,EM_SETSEL,pos,pos); SendDlgItemMessage(hMainDlg,IDC_DEBUGLIST,EM_REPLACESEL,0,(LPARAM)buffer); } UserProc *GetSubFromObp(ULONG_PTR pos) { compiler.GetObjectModule().meta.GetUserProcs().Iterator_Reset(); while( compiler.GetObjectModule().meta.GetUserProcs().Iterator_HasNext() ) { UserProc *pUserProc = compiler.GetObjectModule().meta.GetUserProcs().Iterator_GetNext(); if(rva_to_real(pUserProc->GetBeginOpAddress()) <= pos && pos < rva_to_real(pUserProc->GetEndOpAddress())) { return pUserProc; } } return NULL; } void ReleaseSingleStep(DWORD dwBeforeStepRun,HANDLE hThread,CONTEXT *pContext){ //以前にシングルステップ実行をした場合 extern DWORD ImageBase; extern int MemPos_CodeSection; extern int FileSize_CodeSection; int i2; ULONG_PTR lpAccBytes; /////////////////////////// // シングルステップOFF /////////////////////////// //ユーザー指定のブレークポイントをセット WriteProcessMemory(hDebugProcess, (void *)(ULONG_PTR)(ImageBase+MemPos_CodeSection), pobj_DBDebugSection->pobj_now->BreakStepCodeBuffer, FileSize_CodeSection,&lpAccBytes); //次に実行すべき命令はユーザー指定によるブレークポイントをはずしておく if(ImageBase+MemPos_CodeSection<=EIP_RIP(*pContext)&&EIP_RIP(*pContext)pobj_now->BreakStepCodeBuffer[EIP_RIP(*pContext)-ImageBase-MemPos_CodeSection-1]){ //直前のブレークポイントがユーザー指定によるものだったとき //eip/ripを1だけ減少 EIP_RIP(*pContext)--; SetThreadContext(hThread,pContext); //ブレークポイントを解除 WriteProcessMemory(hDebugProcess,(void *)EIP_RIP(*pContext),&OpBuffer[EIP_RIP(*pContext)-ImageBase-MemPos_CodeSection],1,&lpAccBytes); extern int StepCursorObpSchedule; if(StepCursorObpSchedule==(int)(EIP_RIP(*pContext)-ImageBase-MemPos_CodeSection)){ //カーソル行までのステップ実行の場合 pobj_DBDebugSection->pobj_now->BreakStepCodeBuffer[StepCursorObpSchedule]=StepCursor_BackupChar; StepCursorObpSchedule=-1; } return; } } if(dwBeforeStepRun){ //直前にシングルステップを行った場合 if(ImageBase+MemPos_CodeSection <= EIP_RIP(*pContext) && EIP_RIP(*pContext) < ImageBase+MemPos_CodeSection+FileSize_CodeSection){ //オリジナルコード内のみ、シングルステップ用の"int 3"を考慮 EIP_RIP(*pContext)--; SetThreadContext(hThread,pContext); } //他のスレッドのサスペンドを解除 for(i2=0;i2num;i++){ ULONG_PTR lpAccBytes; WriteProcessMemory(hDebugProcess, (void *)(ULONG_PTR)(pobj_DBDebugSection->ppobj_ds[i]->dwImageBase + pobj_DBDebugSection->ppobj_ds[i]->dwRVA_RWSection), _DebugSys_dwThreadID, sizeof(DWORD)*MAX_DEBUG_THREAD, &lpAccBytes ); } } void AddThread(DWORD dwThreadId, HANDLE hThread){ int i; for(i=0;iload(program.GetOutputFilePath().c_str());*/ if(!DebugActiveProcess( program.GetAttachProcessId() )){ AttachError: DebugMessage("アタッチに失敗しました。"); return; } } else{ /*if(!pobj_DebugSection->load(program.GetOutputFilePath().c_str())){ extern BOOL bDebugCompile; bDebugCompile=1; Build(); pobj_DebugSection->load(program.GetOutputFilePath().c_str()); }*/ //スレッドを生成 extern char szDebugCmdLine[1024]; STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si,0,sizeof(STARTUPINFO)); si.cb=sizeof(STARTUPINFO); if( !compiler.IsDll() ){ //EXEファイルをデバッグ CreateProcess(program.GetOutputFilePath().c_str(),szDebugCmdLine,NULL,NULL,0,NORMAL_PRIORITY_CLASS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi); } else{ //DLLファイルをデバッグ CreateProcess(ExeFilePathForDll,szDebugCmdLine,NULL,NULL,0,NORMAL_PRIORITY_CLASS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } //デバッグ情報データベースを生成 pobj_DBDebugSection=new CDBDebugSection(); //デバッグスレッド情報(プロシージャの階層構造を管理)を生成 pobj_dti=new CDebugThreadInfo(); UserProc *pUserProc; extern DWORD dwStepRun; BOOL bFirstBreak=1; CONTEXT Context; HANDLE hMainThread; ULONG_PTR lpAccBytes; DEBUG_EVENT de; memset(&de,0,sizeof(DEBUG_EVENT)); while(WaitForDebugEvent(&de,INFINITE)){ if(de.dwDebugEventCode==LOAD_DLL_DEBUG_EVENT){ WCHAR wcBuf[MAX_PATH]; LONG_PTR lpData; wcBuf[0]=0; temporary[0]=0; if(de.u.LoadDll.lpImageName){ if(!ReadProcessMemory(hDebugProcess,de.u.LoadDll.lpImageName,&lpData,sizeof(LONG_PTR),&lpAccBytes)){ sprintf(temporary,"ロードされたDLLの名前取得(アドレス:&H%08x)に失敗しました。\r\n",(ULONG_PTR)de.u.LoadDll.lpImageName); DebugMessage(temporary); goto NextContinue; } if(!lpData) goto Attach_DllLoad; if(!ReadProcessMemory(hDebugProcess,(void *)lpData,wcBuf,sizeof(WCHAR)*MAX_PATH,&lpAccBytes)){ sprintf(temporary,"ロードされたDLLの名前取得(アドレス:&H%08x)に失敗しました。\r\n",lpData); DebugMessage(temporary); goto NextContinue; } if(de.dwThreadId,de.u.LoadDll.fUnicode) WideCharToMultiByte(CP_ACP,0,wcBuf,-1,temporary,255,NULL,NULL); else lstrcpy(temporary,(char *)wcBuf); } else{ Attach_DllLoad: //アタッチした場合 GetModuleFileNameEx(hDebugProcess,(HINSTANCE)de.u.LoadDll.lpBaseOfDll,temporary,MAX_PATH); } char temp2[1024]; sprintf(temp2,"\"%s\" をロードしました。\r\n",temporary); DebugMessage(temp2); //可能であればデバッグ情報を読みとる if(pobj_DBDebugSection->add((HMODULE)de.u.LoadDll.lpBaseOfDll)){ pobj_DBDebugSection->choice(0); Set_DebugSys_dwThreadID(); } /*if(lstrcmpi(temporary, program.GetOutputFilePath().c_str())==0){ ImageBase=(DWORD)de.u.LoadDll.lpBaseOfDll; AddThread(de.dwThreadId,hMainThread); }*/ } else if(de.dwDebugEventCode==UNLOAD_DLL_DEBUG_EVENT){ //DLLのアンロード pobj_DBDebugSection->del((HMODULE)de.u.UnloadDll.lpBaseOfDll); } else if(de.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT){ hDebugProcess=de.u.CreateProcessInfo.hProcess; hMainThread=de.u.CreateProcessInfo.hThread; if(pobj_DBDebugSection->add((HMODULE)de.u.CreateProcessInfo.lpBaseOfImage)){ pobj_DBDebugSection->choice(0); } AddThread(de.dwThreadId,de.u.CreateProcessInfo.hThread); } else if(de.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT){ AddThread(de.dwThreadId,de.u.CreateThread.hThread); } else if(de.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT){ //デバッグダイアログを終了 SendMessage(hMainDlg,WM_CLOSE_DEBUGGER,0,0); DeleteThread(de.dwThreadId); //"スレッド(&H%X)はコード &H%X で終了しました。\r\n" sprintf(temporary,STRING_DEBUG_THREADFINISH,de.dwThreadId,de.u.ExitProcess.dwExitCode); DebugMessage(temporary); //"プログラムはコード &H%X で終了しました。\r\n" sprintf(temporary,STRING_DEBUG_PROCESSFINISH,de.u.ExitProcess.dwExitCode); DebugMessage(temporary); break; } else if(de.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT){ //"スレッド(&H%X)はコード &H%X で終了しました。\r\n" sprintf(temporary,STRING_DEBUG_THREADFINISH,de.dwThreadId,de.u.ExitThread.dwExitCode); DebugMessage(temporary); //以前にシングルステップ実行をした場合 //ステップ実行を解除 if(dwStepRun){ extern HWND hDebugWnd; if(hDebugWnd) SendMessage(hDebugWnd,WM_VARLIST_CLOSE,0,0); for(i4=0;i4Reflesh(i2)){ MessageBox(hOwnerEditor,"デバッグ情報が壊れています。ターゲットファイルを再コンパイルしてください。","ActiveBasic",MB_OK|MB_ICONEXCLAMATION); break; } if(de.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_ACCESS_VIOLATION){ //"スレッド(&H%X)でアクセス違反がありました(EIP=&H%08X)。\r\n" sprintf(temporary, STRING_DEBUG_THREAD_ACCESSVIOLATION, de.dwThreadId, (ULONG_PTR)de.u.Exception.ExceptionRecord.ExceptionAddress, #ifdef _AMD64_ (ULONG_PTR)Context.Rsp #else (ULONG_PTR)Context.Esp #endif ); DebugMessage(temporary); MessageBeep(MB_ICONEXCLAMATION); ShowVarList(&de,1); break; } else if(de.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT|| de.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP){ ///////////////////////// // ブレークポイント ///////////////////////// if(de.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP){ //CPU機構のシングルステップによるブレークポイント //※シングルステップを解除 ReleaseCPUSingleStep(); } i3=dwStepRun; for(i4=0;i4pobj_now->SingleStepCodeBuffer, FileSize_CodeSection,&lpAccBytes); //次の命令語のブレーク命令は解除しておく(シングルステップ実行後のみ) //(オリジナルコード内のみ) if(i3&&ImageBase+MemPos_CodeSection<=EIP_RIP(Context)&&EIP_RIP(Context)GetBeginOpAddress())-(long)EIP_RIP(Context)){ //プロシージャの終端位置の場合はステップインを行う goto StepIn; } extern int GlobalOpBufferSize; if(ImageBase+MemPos_CodeSection<=pobj_dti->lplpObp[pobj_dti->iProcLevel]&& pobj_dti->lplpObp[pobj_dti->iProcLevel]pobj_now->SingleStepCodeBuffer, GlobalOpBufferSize, &lpAccBytes); } else{ //プロシージャを識別 pUserProc=GetSubFromObp(pobj_dti->lplpObp[pobj_dti->iProcLevel]); //シングルステップON WriteProcessMemory(hDebugProcess, (void *)rva_to_real(pUserProc->GetBeginOpAddress()), pobj_DBDebugSection->pobj_now->SingleStepCodeBuffer+pUserProc->GetBeginOpAddress(), pUserProc->GetEndOpAddress()-pUserProc->GetBeginOpAddress(), &lpAccBytes); } //次の命令語のブレーク命令は解除しておく(シングルステップ実行後のみ) //(オリジナルコード内のみ) if(i3&&ImageBase+MemPos_CodeSection<=EIP_RIP(Context)&&EIP_RIP(Context)