1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00

Embedded console / terminal support

This commit is contained in:
Brian Fiete 2024-07-23 07:56:23 +02:00
parent 60817eec48
commit 20a8e3327c
28 changed files with 2317 additions and 690 deletions

View file

@ -328,7 +328,7 @@ bool CeDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult)
return false;
}
void CeDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled)
void CeDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
{
}
@ -337,6 +337,10 @@ bool CeDebugger::Attach(int processId, BfDbgAttachFlags attachFlags)
return false;
}
void CeDebugger::GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
{
}
void CeDebugger::Run()
{
}

View file

@ -314,8 +314,9 @@ public:
virtual void OutputRawMessage(const StringImpl& msg) override;
virtual int GetAddrSize() override;
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) override;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) override;
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) override;
virtual void Run() override;
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;

View file

@ -754,7 +754,7 @@ BF_EXPORT int BF_CALLTYPE Debugger_GetAddrSize()
return gDebugger->GetAddrSize();
}
BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize, bool hotSwapEnabled)
BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char* targetPath, const char* args, const char* workingDir, void* envBlockPtr, int envBlockSize, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
{
BF_ASSERT(gDebugger == NULL);
@ -784,7 +784,7 @@ BF_EXPORT bool BF_CALLTYPE Debugger_OpenFile(const char* launchPath, const char*
envBlock.Insert(0, (uint8*)envBlockPtr, envBlockSize);
}
gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock, hotSwapEnabled);
gDebugger->OpenFile(launchPath, targetPath, args, workingDir, envBlock, hotSwapEnabled, openFileFlags);
return true;
}
@ -911,6 +911,12 @@ BF_EXPORT bool BF_CALLTYPE Debugger_Attach(int processId, BfDbgAttachFlags attac
return false;
}
BF_EXPORT void Debugger_GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
{
if (gDebugger != NULL)
gDebugger->GetStdHandles(outStdIn, outStdOut, outStdErr);
}
BF_EXPORT void BF_CALLTYPE Debugger_Run()
{
gDebugger->Run();

View file

@ -200,6 +200,14 @@ enum DbgMemoryFlags : uint8
DbgMemoryFlags_Execute = 4
};
enum DbgOpenFileFlags : uint8
{
DbgOpenFileFlag_None = 0,
DbgOpenFileFlag_RedirectStdInput = 1,
DbgOpenFileFlag_RedirectStdOutput = 2,
DbgOpenFileFlag_RedirectStdError = 4
};
class DbgModuleMemoryCache
{
public:
@ -266,8 +274,9 @@ public:
virtual void OutputRawMessage(const StringImpl& msg) = 0;
virtual int GetAddrSize() = 0;
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) = 0;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) = 0;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) = 0;
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) = 0;
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) = 0;
virtual void Run() = 0;
virtual bool HasLoadedTargetBinary() { return true; }
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;

View file

@ -79,6 +79,11 @@ static void FilterThreadName(String& name)
}
}
static bool IsHandleValid(HANDLE handle)
{
return (handle != NULL) && (handle != INVALID_HANDLE_VALUE);
}
//////////////////////////////////////////////////////////////////////////
WdBreakpointCondition::~WdBreakpointCondition()
@ -508,6 +513,9 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
mOrigStepType = StepType_None;
mLastValidStepIntoPC = 0;
mActiveSymSrvRequest = NULL;
mStdInputPipe = INVALID_HANDLE_VALUE;
mStdOutputPipe = INVALID_HANDLE_VALUE;
mStdErrorPipe = INVALID_HANDLE_VALUE;
mStoredReturnValueAddr = 0;
#ifdef BF_DBG_32
@ -528,6 +536,8 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
mDbgProcessId = 0;
mDbgHeapData = NULL;
mIsPartialCallStack = true;
mHotSwapEnabled = false;
mOpenFileFlags = DbgOpenFileFlag_None;
for (int i = 0; i < 4; i++)
{
@ -919,7 +929,7 @@ void WinDebugger::DebugThreadProc()
if (!IsMiniDumpDebugger())
{
if (!DoOpenFile(mLaunchPath, mArgs, mWorkingDir, mEnvBlock))
if (!DoOpenFile(mLaunchPath, mArgs, mWorkingDir, mEnvBlock, mOpenFileFlags))
{
if (mDbgProcessId != 0)
OutputRawMessage("error Unable to attach to process");
@ -1005,7 +1015,7 @@ bool WinDebugger::CanOpen(const StringImpl& fileName, DebuggerResult* outResult)
return canRead;
}
void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled)
void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags)
{
BF_ASSERT(!mIsRunning);
mLaunchPath = launchPath;
@ -1014,6 +1024,7 @@ void WinDebugger::OpenFile(const StringImpl& launchPath, const StringImpl& targe
mWorkingDir = workingDir;
mEnvBlock = envBlock;
mHotSwapEnabled = hotSwapEnabled;
mOpenFileFlags = openFileFlags;
mDebugTarget = new DebugTarget(this);
}
@ -1059,6 +1070,29 @@ bool WinDebugger::Attach(int processId, BfDbgAttachFlags attachFlags)
return true;
}
void WinDebugger::GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
{
AutoCrit autoCrit(mDebugManager->mCritSect);
if ((outStdIn != NULL) && (IsHandleValid(mStdInputPipe)))
{
*outStdIn = BfpFile_GetFromHandle((intptr)mStdInputPipe, NULL);
mStdInputPipe = 0;
}
if ((outStdOut != NULL) && (IsHandleValid(mStdOutputPipe)))
{
*outStdOut = BfpFile_GetFromHandle((intptr)mStdOutputPipe, NULL);
mStdOutputPipe = 0;
}
if ((outStdErr != NULL) && (IsHandleValid(mStdErrorPipe)))
{
*outStdErr = BfpFile_GetFromHandle((intptr)mStdErrorPipe, NULL);
mStdErrorPipe = 0;
}
}
void WinDebugger::Run()
{
mIsRunning = true;
@ -1262,7 +1296,50 @@ String WinDebugger::GetDbgAllocInfo()
return result;
}
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock)
static bool CreatePipeWithSecurityAttributes(HANDLE& hReadPipe, HANDLE& hWritePipe, SECURITY_ATTRIBUTES* lpPipeAttributes, int32 nSize)
{
hReadPipe = 0;
hWritePipe = 0;
bool ret = ::CreatePipe(&hReadPipe, &hWritePipe, lpPipeAttributes, nSize);
if (!ret || (hReadPipe == INVALID_HANDLE_VALUE) || (hWritePipe == INVALID_HANDLE_VALUE))
return false;
return true;
}
static bool CreatePipe(HANDLE& parentHandle, HANDLE& childHandle, bool parentInputs)
{
SECURITY_ATTRIBUTES securityAttributesParent = { 0 };
securityAttributesParent.bInheritHandle = 1;
HANDLE hTmp = INVALID_HANDLE_VALUE;
if (parentInputs)
CreatePipeWithSecurityAttributes(childHandle, hTmp, &securityAttributesParent, 0);
else
CreatePipeWithSecurityAttributes(hTmp, childHandle, &securityAttributesParent, 0);
HANDLE dupHandle = 0;
// Duplicate the parent handle to be non-inheritable so that the child process
// doesn't have access. This is done for correctness sake, exact reason is unclear.
// One potential theory is that child process can do something brain dead like
// closing the parent end of the pipe and there by getting into a blocking situation
// as parent will not be draining the pipe at the other end anymore.
if (!::DuplicateHandle(GetCurrentProcess(), hTmp,
GetCurrentProcess(), &dupHandle,
0, false, DUPLICATE_SAME_ACCESS))
{
return false;
}
parentHandle = dupHandle;
if (hTmp != INVALID_HANDLE_VALUE)
::CloseHandle(hTmp);
return true;
}
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, DbgOpenFileFlags openFileFlags)
{
BP_ZONE("WinDebugger::DoOpenFile");
@ -1274,6 +1351,33 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
si.cb = sizeof(si);
ZeroMemory(&mProcessInfo, sizeof(mProcessInfo));
DWORD flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_DEFAULT_ERROR_MODE;
BOOL inheritHandles = false;
// set up the streams
if ((openFileFlags & (DbgOpenFileFlag_RedirectStdInput | DbgOpenFileFlag_RedirectStdOutput | DbgOpenFileFlag_RedirectStdError)) != 0)
{
if ((openFileFlags & DbgOpenFileFlag_RedirectStdInput) != 0)
CreatePipe(mStdInputPipe, si.hStdInput, true);
else if (::GetConsoleWindow() != NULL)
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
else
si.hStdInput = INVALID_HANDLE_VALUE;
if ((openFileFlags & DbgOpenFileFlag_RedirectStdOutput) != 0)
CreatePipe(mStdOutputPipe, si.hStdOutput, false);
else
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if ((openFileFlags & DbgOpenFileFlag_RedirectStdError) != 0)
CreatePipe(mStdErrorPipe, si.hStdError, false);
else
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
flags |= CREATE_NO_WINDOW;
si.dwFlags = STARTF_USESTDHANDLES;
inheritHandles = true;
}
if (mDbgProcessId != 0)
{
BOOL success = ::DebugActiveProcess(mDbgProcessId);
@ -1287,8 +1391,7 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
BP_ZONE("DoOpenFile_CreateProcessW");
UTF16String envW;
DWORD flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_DEFAULT_ERROR_MODE;
void* envPtr = NULL;
if (!envBlock.IsEmpty())
{
@ -1318,11 +1421,34 @@ bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args,
cmdLine += args;
}
BOOL worked = CreateProcessW(NULL, (WCHAR*)UTF8Decode(cmdLine).c_str(), NULL, NULL, FALSE,
BOOL worked = CreateProcessW(NULL, (WCHAR*)UTF8Decode(cmdLine).c_str(), NULL, NULL, inheritHandles,
flags, envPtr, (WCHAR*)UTF8Decode(workingDir).c_str(), &si, &mProcessInfo);
if ((openFileFlags & DbgOpenFileFlag_RedirectStdInput) != 0)
::CloseHandle(si.hStdInput);
if ((openFileFlags & DbgOpenFileFlag_RedirectStdOutput) != 0)
::CloseHandle(si.hStdOutput);
if ((openFileFlags & DbgOpenFileFlag_RedirectStdError) != 0)
::CloseHandle(si.hStdError);
if (!worked)
{
if (IsHandleValid(mStdInputPipe))
{
::CloseHandle(mStdInputPipe);
mStdInputPipe = 0;
}
if (IsHandleValid(mStdOutputPipe))
{
::CloseHandle(mStdOutputPipe);
mStdOutputPipe = 0;
}
if (IsHandleValid(mStdErrorPipe))
{
::CloseHandle(mStdErrorPipe);
mStdErrorPipe = 0;
}
auto lastError = ::GetLastError();
if (lastError == ERROR_DIRECTORY)
{
@ -1503,6 +1629,18 @@ void WinDebugger::Detach()
mBreakpointAddrMap.Clear();
gDebugUpdateCnt = 0;
if (IsHandleValid(mStdInputPipe))
::CloseHandle(mStdInputPipe);
mStdInputPipe = INVALID_HANDLE_VALUE;
if (IsHandleValid(mStdOutputPipe))
::CloseHandle(mStdOutputPipe);
mStdOutputPipe = INVALID_HANDLE_VALUE;
if (IsHandleValid(mStdErrorPipe))
::CloseHandle(mStdErrorPipe);
mStdErrorPipe = INVALID_HANDLE_VALUE;
}
Profiler* WinDebugger::StartProfiling()
@ -2926,13 +3064,33 @@ static BOOL CALLBACK WdEnumWindowsProc(HWND hwnd, LPARAM lParam)
if (processId != ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId)
return TRUE;
SetForegroundWindow(hwnd);
while (true)
{
HWND parentHWnd = GetParent(hwnd);
if (parentHWnd != NULL)
{
hwnd = parentHWnd;
continue;
}
SetForegroundWindow(hwnd);
break;
}
return TRUE;
}
void WinDebugger::ForegroundTarget()
{
HWND hwnd = ::GetForegroundWindow();
if (hwnd != INVALID_HANDLE_VALUE)
{
DWORD processId = 0;
GetWindowThreadProcessId(hwnd, &processId);
if (processId == ((WinDebugger*)gDebugger)->mProcessInfo.dwProcessId)
return; // Already good
}
EnumWindows(WdEnumWindowsProc, 0);
}

View file

@ -389,6 +389,7 @@ public:
String mArgs;
String mWorkingDir;
bool mHotSwapEnabled;
DbgOpenFileFlags mOpenFileFlags;
Array<uint8> mEnvBlock;
DebugTarget* mEmptyDebugTarget;
DebugTarget* mDebugTarget;
@ -400,6 +401,11 @@ public:
DWORD mDbgProcessId;
HANDLE mDbgProcessHandle;
HANDLE mDbgThreadHandle;
HANDLE mStdInputPipe;
HANDLE mStdOutputPipe;
HANDLE mStdErrorPipe;
bool mIsDebuggerWaiting;
bool mWantsDebugContinue;
bool mNeedsRehupBreakpoints;
@ -553,7 +559,7 @@ public:
void ModuleChanged(DbgModule* dbgModule);
bool DoUpdate();
void DebugThreadProc();
bool DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock);
bool DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, DbgOpenFileFlags openFileFlags);
DbgTypedValue GetRegister(const StringImpl& regName, DbgLanguage language, CPURegisters* registers, Array<RegForm>* regForms = NULL);
void FixupLineData(DbgCompileUnit* compileUnit);
@ -581,8 +587,9 @@ public:
virtual void OutputRawMessage(const StringImpl& msg) override;
virtual int GetAddrSize() override;
virtual bool CanOpen(const StringImpl& fileName, DebuggerResult* outResult) override;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled) override;
virtual void OpenFile(const StringImpl& launchPath, const StringImpl& targetPath, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock, bool hotSwapEnabled, DbgOpenFileFlags openFileFlags) override;
virtual bool Attach(int processId, BfDbgAttachFlags attachFlags) override;
virtual void GetStdHandles(BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) override;
virtual void Run() override;
virtual bool HasLoadedTargetBinary() override;
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;