From cbb82e8c5410ce769509a9a95c7cdddfcadf6501 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Sun, 16 Jul 2017 05:14:31 +0300 Subject: [PATCH] Refactor process attach into a separate function --- src/debug/netcoredbg/breakpoints.cpp | 56 ++++--- src/debug/netcoredbg/commands.cpp | 48 +++--- src/debug/netcoredbg/main.cpp | 222 ++++++++++++++++----------- src/debug/netcoredbg/modules.cpp | 6 + 4 files changed, 201 insertions(+), 131 deletions(-) diff --git a/src/debug/netcoredbg/breakpoints.cpp b/src/debug/netcoredbg/breakpoints.cpp index 072e8b4..b3ab5e3 100644 --- a/src/debug/netcoredbg/breakpoints.cpp +++ b/src/debug/netcoredbg/breakpoints.cpp @@ -117,6 +117,15 @@ HRESULT FindCurrentBreakpointId(ICorDebugThread *pThread, ULONG32 &id) return E_FAIL; } +static ULONG32 InsertBreakpoint(Breakpoint &bp) +{ + std::lock_guard lock(g_breakMutex); + ULONG32 id = g_breakIndex++; + bp.id = id; + g_breaks.insert(std::make_pair(id, std::move(bp))); + return id; +} + HRESULT DeleteBreakpoint(ULONG32 id) { std::lock_guard lock(g_breakMutex); @@ -133,7 +142,7 @@ void DeleteAllBreakpoints() g_breaks.clear(); } -HRESULT ResolveBreakpoint(ICorDebugModule *pModule, std::string filename, int linenum, Breakpoint &bp) +HRESULT ResolveBreakpoint(ICorDebugModule *pModule, Breakpoint &bp) { HRESULT Status; @@ -141,8 +150,8 @@ HRESULT ResolveBreakpoint(ICorDebugModule *pModule, std::string filename, int li ULONG32 ilOffset; std::string fullname; - IfFailRet(GetLocationInModule(pModule, filename, - linenum, + IfFailRet(GetLocationInModule(pModule, bp.fullname, + bp.linenum, ilOffset, methodToken, fullname)); @@ -163,7 +172,6 @@ HRESULT ResolveBreakpoint(ICorDebugModule *pModule, std::string filename, int li bp.methodToken = methodToken; bp.ilOffset = ilOffset; bp.fullname = fullname; - bp.linenum = linenum; bp.breakpoint = pBreakpoint.Detach(); return S_OK; @@ -180,7 +188,7 @@ HRESULT TryResolveBreakpointsForModule(ICorDebugModule *pModule) if (b.IsResolved()) continue; - if (SUCCEEDED(ResolveBreakpoint(pModule, b.fullname, b.linenum, b))) + if (SUCCEEDED(ResolveBreakpoint(pModule, b))) { return S_OK; } @@ -188,17 +196,13 @@ HRESULT TryResolveBreakpointsForModule(ICorDebugModule *pModule) return E_FAIL; } -HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id) +static HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, Breakpoint &bp, ULONG32 &id) { HRESULT Status; ToRelease domains; IfFailRet(pProcess->EnumerateAppDomains(&domains)); - Breakpoint bp; - bp.fullname = filename; - bp.linenum = linenum; - ICorDebugAppDomain *curDomain; ULONG domainsFetched; while (SUCCEEDED(domains->Next(1, &curDomain, &domainsFetched)) && domainsFetched == 1) @@ -222,23 +226,31 @@ HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filena while (SUCCEEDED(modules->Next(1, &curModule, &modulesFetched)) && modulesFetched == 1) { ToRelease pModule(curModule); - if (SUCCEEDED(ResolveBreakpoint(pModule, filename, linenum, bp))) + if (SUCCEEDED(ResolveBreakpoint(pModule, bp))) { - std::lock_guard lock(g_breakMutex); - id = g_breakIndex++; - bp.id = id; - g_breaks.insert(std::make_pair(id, std::move(bp))); + id = InsertBreakpoint(bp); return S_OK; } } } } - // Add pending breakpoint - std::lock_guard lock(g_breakMutex); - id = g_breakIndex++; - bp.id = id; - g_breaks.insert(std::make_pair(id, std::move(bp))); - return S_FALSE; -} \ No newline at end of file +} + +HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id) +{ + Breakpoint bp; + bp.fullname = filename; + bp.linenum = linenum; + + HRESULT Status = pProcess ? CreateBreakpointInProcess(pProcess, bp, id) : S_FALSE; + + if (Status == S_FALSE) + { + // Add pending breakpoint + id = InsertBreakpoint(bp); + } + + return Status; +} diff --git a/src/debug/netcoredbg/commands.cpp b/src/debug/netcoredbg/commands.cpp index e8e9505..ec06334 100644 --- a/src/debug/netcoredbg/commands.cpp +++ b/src/debug/netcoredbg/commands.cpp @@ -20,12 +20,14 @@ HRESULT GetStepRangeFromCurrentIP(ICorDebugThread *pThread, COR_DEBUG_STEP_RANGE // Breakpoints HRESULT DeleteBreakpoint(ULONG32 id); -HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id); +HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id); HRESULT PrintBreakpoint(ULONG32 id, std::string &output); // Frames HRESULT GetFrameAt(ICorDebugThread *pThread, int level, ICorDebugFrame **ppFrame); +void TerminateProcess(); + void _out_printf(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@ -118,7 +120,7 @@ bool ParseBreakpoint(const std::vector &args, std::string &filename return ok && linenum > 0; } -HRESULT BreakInsertCommand( +static HRESULT BreakInsertCommand( ICorDebugProcess *pProcess, const std::vector &args, std::string &output) @@ -127,7 +129,7 @@ HRESULT BreakInsertCommand( unsigned int linenum; ULONG32 id; if (ParseBreakpoint(args, filename, linenum) - && SUCCEEDED(CreateBreakpointInProcess(pProcess, filename, linenum, id))) + && SUCCEEDED(InsertBreakpointInProcess(pProcess, filename, linenum, id))) { PrintBreakpoint(id, output); return S_OK; @@ -185,6 +187,7 @@ static HRESULT StepCommand(ICorDebugProcess *pProcess, const std::vector &, std::string &output) { + if (!pProcess) return E_FAIL; return PrintThreadsState(pProcess, output); } @@ -192,8 +195,12 @@ static bool g_exit = false; static std::unordered_map commands { { "thread-info", ThreadInfoCommand }, - { "exec-continue", [](ICorDebugProcess *pProcess, const std::vector &, std::string &){ return pProcess->Continue(0); } }, - { "exec-interrupt", [](ICorDebugProcess *pProcess, const std::vector &, std::string &){ return pProcess->Stop(0); } }, + { "exec-continue", [](ICorDebugProcess *pProcess, const std::vector &, std::string &){ + if (!pProcess) return E_FAIL; + return pProcess->Continue(0); } }, + { "exec-interrupt", [](ICorDebugProcess *pProcess, const std::vector &, std::string &){ + if (!pProcess) return E_FAIL; + return pProcess->Stop(0); } }, { "break-insert", BreakInsertCommand }, { "break-delete", [](ICorDebugProcess *, const std::vector &args, std::string &) -> HRESULT { for (const std::string &idStr : args) @@ -209,6 +216,7 @@ static std::unordered_map commands { { "exec-next", std::bind(StepCommand, _1, _2, _3, STEP_OVER) }, { "exec-finish", std::bind(StepCommand, _1, _2, _3, STEP_OUT) }, { "stack-list-frames", [](ICorDebugProcess *pProcess, const std::vector &args, std::string &output) -> HRESULT { + if (!pProcess) return E_FAIL; HRESULT Status; ToRelease pThread; DWORD threadId = GetIntArg(args, "--thread", GetLastStoppedThreadId()); @@ -220,6 +228,7 @@ static std::unordered_map commands { return S_OK; }}, { "stack-list-variables", [](ICorDebugProcess *pProcess, const std::vector &args, std::string &output) -> HRESULT { + if (!pProcess) return E_FAIL; HRESULT Status; ToRelease pThread; DWORD threadId = GetIntArg(args, "--thread", GetLastStoppedThreadId()); @@ -233,6 +242,7 @@ static std::unordered_map commands { return S_OK; }}, { "var-create", [](ICorDebugProcess *pProcess, const std::vector &args, std::string &output) -> HRESULT { + if (!pProcess) return E_FAIL; HRESULT Status; if (args.size() < 2) @@ -251,6 +261,7 @@ static std::unordered_map commands { return CreateVar(pThread, pFrame, args.at(0), args.at(1), output); }}, { "var-list-children", [](ICorDebugProcess *pProcess, const std::vector &args, std::string &output) -> HRESULT { + if (!pProcess) return E_FAIL; HRESULT Status; int print_values = 0; @@ -294,18 +305,12 @@ static std::unordered_map commands { } return DeleteVar(args.at(0)); }}, - { "gdb-exit", [](ICorDebugProcess *pProcess, const std::vector &args, std::string &output) -> HRESULT { - HRESULT Status; + { "gdb-exit", [](ICorDebugProcess *, const std::vector &args, std::string &output) -> HRESULT { g_exit = true; - IfFailRet(pProcess->Stop(0)); - DisableAllBreakpointsAndSteppers(pProcess); + TerminateProcess(); - Status = pProcess->Terminate(0); - - WaitProcessExited(); - - return Status; + return S_OK; }} }; @@ -342,7 +347,9 @@ static bool ParseLine(const std::string &str, return true; } -void CommandLoop(ICorDebugProcess *pProcess) +extern ICorDebugProcess *g_pProcess; + +void CommandLoop() { static char inputBuffer[1024]; std::string token; @@ -372,7 +379,7 @@ void CommandLoop(ICorDebugProcess *pProcess) } std::string output; - HRESULT hr = command_it->second(pProcess, args, output); + HRESULT hr = command_it->second(g_pProcess, args, output); if (g_exit) break; if (SUCCEEDED(hr)) @@ -386,10 +393,9 @@ void CommandLoop(ICorDebugProcess *pProcess) out_printf("%s^error,msg=\"Error: 0x%08x%s%s\"\n", token.c_str(), hr, sep, output.c_str()); } } - if (SUCCEEDED(pProcess->Stop(0))) - { - DisableAllBreakpointsAndSteppers(pProcess); - pProcess->Detach(); - } + + if (!g_exit) + TerminateProcess(); + out_printf("%s^exit\n", token.c_str()); } diff --git a/src/debug/netcoredbg/main.cpp b/src/debug/netcoredbg/main.cpp index a1d74c8..fb69083 100644 --- a/src/debug/netcoredbg/main.cpp +++ b/src/debug/netcoredbg/main.cpp @@ -30,9 +30,17 @@ static std::mutex g_processMutex; static std::condition_variable g_processCV; static ICorDebugProcess *g_process = nullptr; +static void ProcessCreated(ICorDebugProcess *pProcess) +{ + std::lock_guard lock(g_processMutex); + pProcess->AddRef(); + g_process = pProcess; +} + static void NotifyProcessExited() { std::lock_guard lock(g_processMutex); + g_process->Release(); g_process = nullptr; g_processMutex.unlock(); g_processCV.notify_one(); @@ -110,6 +118,7 @@ HRESULT FindCurrentBreakpointId(ICorDebugThread *pThread, ULONG32 &id); HRESULT TryResolveBreakpointsForModule(ICorDebugModule *pModule); // Modules +void CleanupAllModules(); void SetCoreCLRPath(const std::string &coreclrPath); std::string GetModuleName(ICorDebugModule *pModule); HRESULT GetStepRangeFromCurrentIP(ICorDebugThread *pThread, COR_DEBUG_STEP_RANGE *range); @@ -143,6 +152,7 @@ static HRESULT DisableAllBreakpointsAndSteppersInAppDomain(ICorDebugAppDomain *p } } + // FIXME: Delete all or Release all? DeleteAllBreakpoints(); ToRelease steppers; @@ -388,6 +398,7 @@ public: /* [in] */ ICorDebugProcess *pProcess) { //HandleEvent(pProcess, "CreateProcess"); + ProcessCreated(pProcess); pProcess->Continue(0); return S_OK; } @@ -591,7 +602,121 @@ public: /* [in] */ ICorDebugMDA *pMDA) {return S_OK; } }; -void CommandLoop(ICorDebugProcess *pProcess); +static ToRelease g_managedCallback(new ManagedCallback()); +ICorDebugProcess *g_pProcess = nullptr; +static ICorDebug *g_pDebug = nullptr; + +void CommandLoop(); + +HRESULT DetachProcess() +{ + if (!g_pProcess || !g_pDebug) + return E_FAIL; + + if (SUCCEEDED(g_pProcess->Stop(0))) + { + DisableAllBreakpointsAndSteppers(g_pProcess); + g_pProcess->Detach(); + } + + CleanupAllModules(); + // TODO: Cleanup libcoreclr.so instance + + g_pProcess->Release(); + g_pProcess = nullptr; + + g_pDebug->Terminate(); + g_pDebug = nullptr; + + return S_OK; +} + +HRESULT TerminateProcess() +{ + if (!g_pProcess || !g_pDebug) + return E_FAIL; + + if (SUCCEEDED(g_pProcess->Stop(0))) + { + DisableAllBreakpointsAndSteppers(g_pProcess); + //pProcess->Detach(); + } + + CleanupAllModules(); + // TODO: Cleanup libcoreclr.so instance + + g_pProcess->Terminate(0); + WaitProcessExited(); + + g_pProcess->Release(); + g_pProcess = nullptr; + + g_pDebug->Terminate(); + g_pDebug = nullptr; + + return S_OK; +} + +HRESULT AttachToProcess(int pid) +{ + HRESULT Status; + + if (g_pProcess || g_pDebug) + { + std::lock_guard lock(g_processMutex); + if (g_process) + return E_FAIL; // Already attached + g_processMutex.unlock(); + + TerminateProcess(); + } + + std::string coreclrPath = GetCoreCLRPath(pid); + if (coreclrPath.empty()) + return E_INVALIDARG; // Unable to find libcoreclr.so + + SetCoreCLRPath(coreclrPath); + + WCHAR szModuleName[MAX_LONGPATH]; + MultiByteToWideChar(CP_UTF8, 0, coreclrPath.c_str(), coreclrPath.size() + 1, szModuleName, MAX_LONGPATH); + + WCHAR pBuffer[100]; + DWORD dwLength; + IfFailRet(CreateVersionStringFromModule( + pid, + szModuleName, + pBuffer, + _countof(pBuffer), + &dwLength)); + + ToRelease pCordb; + ToRelease pCorDebug; + IfFailRet(CreateDebuggingInterfaceFromVersionEx(4, pBuffer, &pCordb)); + + IfFailRet(pCordb->QueryInterface(IID_ICorDebug, (LPVOID *)&pCorDebug)); + + IfFailRet(pCorDebug->Initialize()); + + Status = pCorDebug->SetManagedHandler(g_managedCallback); + if (FAILED(Status)) + { + pCorDebug->Terminate(); + return Status; + } + + ToRelease pProcess; + Status = pCorDebug->DebugActiveProcess(pid, FALSE, &pProcess); + if (FAILED(Status)) + { + pCorDebug->Terminate(); + return Status; + } + + g_pProcess = pProcess.Detach(); + g_pDebug = pCorDebug.Detach(); + + return S_OK; +} void print_help() { @@ -647,96 +772,17 @@ int main(int argc, char *argv[]) } } - if (pidDebuggee == 0) - { - fprintf(stderr, "Error: Missing process id\n"); - return EXIT_FAILURE; - } - - std::string coreclrPath = GetCoreCLRPath(pidDebuggee); - if (coreclrPath.empty()) - { - fprintf(stderr, "Error: Unable to find libcoreclr.so\n"); - return EXIT_FAILURE; - } - - SetCoreCLRPath(coreclrPath); - - WCHAR szModuleName[MAX_LONGPATH]; - MultiByteToWideChar(CP_UTF8, 0, coreclrPath.c_str(), coreclrPath.size() + 1, szModuleName, MAX_LONGPATH); - - WCHAR pBuffer[100]; - DWORD dwLength; - HRESULT hr = CreateVersionStringFromModule( - pidDebuggee, - szModuleName, - pBuffer, - _countof(pBuffer), - &dwLength); - - if (FAILED(hr)) - { - fprintf(stderr, "CreateVersionStringFromModule failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - ToRelease pCordb; - //WCHAR szDebuggeeVersion[] = W("4.0"); - hr = CreateDebuggingInterfaceFromVersionEx(4, pBuffer, &pCordb); - - if (FAILED(hr)) - { - fprintf(stderr, "CreateDebuggingInterfaceFromVersionEx failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - ToRelease pCorDebug; - - hr = pCordb->QueryInterface(IID_ICorDebug, (LPVOID *)&pCorDebug); - if (FAILED(hr)) - { - fprintf(stderr, "QueryInterface(IID_ICorDebug) failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - hr = pCorDebug->Initialize(); - if (FAILED(hr)) - { - fprintf(stderr, "Initialize failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - hr = pCorDebug->SetManagedHandler(new ManagedCallback()); - if (FAILED(hr)) + if (pidDebuggee != 0) { - fprintf(stderr, "SetManagedHandler failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - hr = pCorDebug->CanLaunchOrAttach(pidDebuggee, FALSE); - //fprintf(stderr, "CanLaunchOrAttach : hr=%x\n", hr); - - ToRelease pProcess; - hr = pCorDebug->DebugActiveProcess( - pidDebuggee, - FALSE, - &pProcess); - if (FAILED(hr)) - { - fprintf(stderr, "DebugActiveProcess failed: hr=%x\n", hr); - return EXIT_FAILURE; - } - - { - std::lock_guard lock(g_processMutex); - g_process = pProcess; + HRESULT Status = AttachToProcess(pidDebuggee); + if (FAILED(Status)) + { + fprintf(stderr, "Error: 0x%x Failed to attach to %i\n", Status, pidDebuggee); + return EXIT_FAILURE; + } } - CommandLoop(pProcess); - - pCorDebug->Terminate(); - - // TODO: Cleanup libcoreclr.so instance + CommandLoop(); return EXIT_SUCCESS; } diff --git a/src/debug/netcoredbg/modules.cpp b/src/debug/netcoredbg/modules.cpp index 8a1e805..78a4ba1 100644 --- a/src/debug/netcoredbg/modules.cpp +++ b/src/debug/netcoredbg/modules.cpp @@ -20,6 +20,12 @@ struct ModuleInfo std::mutex g_modulesInfoMutex; std::unordered_map g_modulesInfo; +void CleanupAllModules() +{ + std::lock_guard lock(g_modulesInfoMutex); + g_modulesInfo.clear(); +} + void SetCoreCLRPath(const std::string &coreclrPath) { SymbolReader::SetCoreCLRPath(coreclrPath); -- 2.34.1