return E_FAIL;
}
-void Debugger::InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint)
+void ManagedDebugger::InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint)
{
m_breakpoints.InsertExceptionBreakpoint(name, breakpoint);
}
return S_OK;
}
-HRESULT Debugger::SetBreakpoints(
+HRESULT ManagedDebugger::SetBreakpoints(
std::string filename,
const std::vector<int> &lines,
std::vector<Breakpoint> &breakpoints)
}
}
-HRESULT Debugger::SetupStep(ICorDebugThread *pThread, Debugger::StepType stepType)
-{
- HRESULT Status;
-
- ToRelease<ICorDebugStepper> pStepper;
- IfFailRet(pThread->CreateStepper(&pStepper));
-
- CorDebugIntercept mask = (CorDebugIntercept)(INTERCEPT_ALL & ~(INTERCEPT_SECURITY | INTERCEPT_CLASS_INIT));
- IfFailRet(pStepper->SetInterceptMask(mask));
-
- CorDebugUnmappedStop stopMask = STOP_NONE;
- IfFailRet(pStepper->SetUnmappedStopMask(stopMask));
-
- ToRelease<ICorDebugStepper2> pStepper2;
- IfFailRet(pStepper->QueryInterface(IID_ICorDebugStepper2, (LPVOID *)&pStepper2));
-
- IfFailRet(pStepper2->SetJMC(IsJustMyCode()));
-
- if (stepType == STEP_OUT)
- {
- IfFailRet(pStepper->StepOut());
- return S_OK;
- }
-
- BOOL bStepIn = stepType == STEP_IN;
-
- COR_DEBUG_STEP_RANGE range;
- if (SUCCEEDED(m_modules.GetStepRangeFromCurrentIP(pThread, &range)))
- {
- IfFailRet(pStepper->StepRange(bStepIn, &range, 1));
- } else {
- IfFailRet(pStepper->Step(bStepIn));
- }
-
- return S_OK;
-}
-
-HRESULT Debugger::StepCommand(int threadId,
- StepType stepType)
-{
- HRESULT Status;
- ToRelease<ICorDebugThread> pThread;
- IfFailRet(m_pProcess->GetThread(threadId, &pThread));
- DisableAllSteppers(m_pProcess);
- IfFailRet(SetupStep(pThread, stepType));
- IfFailRet(m_pProcess->Continue(0));
- return S_OK;
-}
-
-HRESULT Debugger::Continue()
-{
- if (!m_pProcess)
- return E_FAIL;
- return m_pProcess->Continue(0);
-}
-
-HRESULT Debugger::Pause()
-{
- if (!m_pProcess)
- return E_FAIL;
- HRESULT Status = m_pProcess->Stop(0);
- if (Status == S_OK)
- m_protocol->EmitStoppedEvent(StoppedEvent(StopPause, 0));
- return Status;
-}
-
-HRESULT Debugger::GetThreads(std::vector<Thread> &threads)
-{
- if (!m_pProcess)
- return E_FAIL;
- return GetThreadsState(m_pProcess, threads);
-}
-
-HRESULT Debugger::GetStackTrace(int threadId, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames)
-{
- HRESULT Status;
- if (!m_pProcess)
- return E_FAIL;
- ToRelease<ICorDebugThread> pThread;
- IfFailRet(m_pProcess->GetThread(threadId, &pThread));
- return GetStackTrace(pThread, lowFrame, highFrame, stackFrames);
-}
-
HRESULT MIProtocol::StepCommand(const std::vector<std::string> &args,
std::string &output,
Debugger::StepType stepType)
class ManagedCallback;
class Protocol;
+class Debugger;
enum ValueKind
{
STEP_OUT
};
+ virtual ~Debugger() {}
+
+ virtual bool IsJustMyCode() = 0;
+ virtual void SetJustMyCode(bool enable) = 0;
+
+ virtual HRESULT RunProcess(std::string fileExec, std::vector<std::string> execArgs) = 0;
+
+ virtual HRESULT AttachToProcess(int pid) = 0;
+ virtual HRESULT DetachFromProcess() = 0;
+ virtual HRESULT TerminateProcess() = 0;
+
+ virtual int GetLastStoppedThreadId() = 0;
+
+ virtual HRESULT Continue() = 0;
+ virtual HRESULT Pause() = 0;
+ virtual HRESULT GetThreads(std::vector<Thread> &threads) = 0;
+ virtual HRESULT SetBreakpoints(std::string filename, const std::vector<int> &lines, std::vector<Breakpoint> &breakpoints) = 0;
+ virtual void InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint) = 0;
+ virtual HRESULT GetStackTrace(int threadId, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames) = 0;
+ virtual HRESULT StepCommand(int threadId, StepType stepType) = 0;
+ virtual HRESULT GetScopes(uint64_t frameId, std::vector<Scope> &scopes) = 0;
+ virtual HRESULT GetVariables(uint32_t variablesReference, VariablesFilter filter, int start, int count, std::vector<Variable> &variables) = 0;
+ virtual int GetNamedVariables(uint32_t variablesReference) = 0;
+ virtual HRESULT Evaluate(uint64_t frameId, const std::string &expression, Variable &variable) = 0;
+};
+
+class ManagedDebugger : public Debugger
+{
private:
friend class ManagedCallback;
enum ProcessAttachedState
HRESULT GetStackTrace(ICorDebugThread *pThread, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames);
HRESULT GetFrameLocation(ICorDebugFrame *pFrame, int threadId, uint32_t level, StackFrame &stackFrame);
public:
- Debugger();
- ~Debugger();
-
- bool IsJustMyCode() { return m_justMyCode; }
- void SetJustMyCode(bool enable) { m_justMyCode = enable; }
+ ManagedDebugger();
+ ~ManagedDebugger() override;
void SetProtocol(Protocol *protocol) { m_protocol = protocol; }
- HRESULT RunProcess(std::string fileExec, std::vector<std::string> execArgs);
+ bool IsJustMyCode() override { return m_justMyCode; }
+ void SetJustMyCode(bool enable) override { m_justMyCode = enable; }
- HRESULT AttachToProcess(int pid);
- HRESULT DetachFromProcess();
- HRESULT TerminateProcess();
+ HRESULT RunProcess(std::string fileExec, std::vector<std::string> execArgs) override;
- int GetLastStoppedThreadId();
+ HRESULT AttachToProcess(int pid) override;
+ HRESULT DetachFromProcess() override;
+ HRESULT TerminateProcess() override;
- HRESULT Continue();
- HRESULT Pause();
- HRESULT GetThreads(std::vector<Thread> &threads);
- HRESULT SetBreakpoints(std::string filename, const std::vector<int> &lines, std::vector<Breakpoint> &breakpoints);
- void InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint);
- HRESULT GetStackTrace(int threadId, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames);
- HRESULT StepCommand(int threadId, StepType stepType);
- HRESULT GetScopes(uint64_t frameId, std::vector<Scope> &scopes);
- HRESULT GetVariables(uint32_t variablesReference, VariablesFilter filter, int start, int count, std::vector<Variable> &variables);
- int GetNamedVariables(uint32_t variablesReference);
- HRESULT Evaluate(uint64_t frameId, const std::string &expression, Variable &variable);
+ int GetLastStoppedThreadId() override;
+
+ HRESULT Continue() override;
+ HRESULT Pause() override;
+ HRESULT GetThreads(std::vector<Thread> &threads) override;
+ HRESULT SetBreakpoints(std::string filename, const std::vector<int> &lines, std::vector<Breakpoint> &breakpoints) override;
+ void InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint) override;
+ HRESULT GetStackTrace(int threadId, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames) override;
+ HRESULT StepCommand(int threadId, StepType stepType) override;
+ HRESULT GetScopes(uint64_t frameId, std::vector<Scope> &scopes) override;
+ HRESULT GetVariables(uint32_t variablesReference, VariablesFilter filter, int start, int count, std::vector<Variable> &variables) override;
+ int GetNamedVariables(uint32_t variablesReference) override;
+ HRESULT Evaluate(uint64_t frameId, const std::string &expression, Variable &variable) override;
};
class Protocol
std::unordered_map<std::string, Variable> m_vars;
std::unordered_map<std::string, std::unordered_map<int32_t, int> > m_breakpoints;
public:
- void SetDebugger(Debugger *debugger) { m_debugger = debugger; m_debugger->SetProtocol(this); }
+ void SetDebugger(Debugger *debugger) { m_debugger = debugger; }
static std::string EscapeMIValue(const std::string &str);
MIProtocol() : m_exit(false), m_varCounter(0) {}
return startAddr;
}
-HRESULT Debugger::GetFrameLocation(ICorDebugFrame *pFrame, int threadId, uint32_t level, StackFrame &stackFrame)
+HRESULT ManagedDebugger::GetFrameLocation(ICorDebugFrame *pFrame, int threadId, uint32_t level, StackFrame &stackFrame)
{
HRESULT Status;
}
}
-HRESULT Debugger::GetStackTrace(ICorDebugThread *pThread, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames)
+HRESULT ManagedDebugger::GetStackTrace(ICorDebugThread *pThread, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames)
{
HRESULT Status;
std::stringstream ss;
#undef __out
-void Debugger::NotifyProcessCreated()
+void ManagedDebugger::NotifyProcessCreated()
{
std::lock_guard<std::mutex> lock(m_processAttachedMutex);
m_processAttachedState = ProcessAttached;
}
-void Debugger::NotifyProcessExited()
+void ManagedDebugger::NotifyProcessExited()
{
std::lock_guard<std::mutex> lock(m_processAttachedMutex);
m_processAttachedState = ProcessUnattached;
m_processAttachedCV.notify_one();
}
-void Debugger::WaitProcessExited()
+void ManagedDebugger::WaitProcessExited()
{
std::unique_lock<std::mutex> lock(m_processAttachedMutex);
if (m_processAttachedState != ProcessUnattached)
return S_OK;
}
-HRESULT Debugger::DisableAllSteppers(ICorDebugProcess *pProcess)
+HRESULT ManagedDebugger::DisableAllSteppers(ICorDebugProcess *pProcess)
{
HRESULT Status;
return S_OK;
}
-void Debugger::SetLastStoppedThread(ICorDebugThread *pThread)
+void ManagedDebugger::SetLastStoppedThread(ICorDebugThread *pThread)
{
DWORD threadId = 0;
pThread->GetID(&threadId);
m_lastStoppedThreadId = threadId;
}
-int Debugger::GetLastStoppedThreadId()
+int ManagedDebugger::GetLastStoppedThreadId()
{
std::lock_guard<std::mutex> lock(m_lastStoppedThreadIdMutex);
return m_lastStoppedThreadId;
class ManagedCallback : public ICorDebugManagedCallback, ICorDebugManagedCallback2
{
ULONG m_refCount;
- Debugger &m_debugger;
+ ManagedDebugger &m_debugger;
public:
void HandleEvent(ICorDebugController *controller, const std::string &eventName)
controller->Continue(0);
}
- ManagedCallback(Debugger &debugger) : m_refCount(1), m_debugger(debugger) {}
+ ManagedCallback(ManagedDebugger &debugger) : m_refCount(1), m_debugger(debugger) {}
virtual ~ManagedCallback() {}
// IUnknown
// case DEBUG_EXCEPTION_UNHANDLED: cbTypeName = "UNHANDLED"; break;
// default: cbTypeName = "?"; break;
// }
- // Debugger::Printf("*stopped,reason=\"exception-received2\",exception-stage=\"%s\"\n",
+ // ManagedDebugger::Printf("*stopped,reason=\"exception-received2\",exception-stage=\"%s\"\n",
// cbTypeName);
pAppDomain->Continue(0);
return S_OK;
/* [in] */ ICorDebugMDA *pMDA) { HandleEvent(pController, "MDANotification"); return S_OK; }
};
-Debugger::Debugger() :
+ManagedDebugger::ManagedDebugger() :
m_processAttachedState(ProcessUnattached),
m_evaluator(m_modules),
m_breakpoints(m_modules),
{
}
-Debugger::~Debugger()
+ManagedDebugger::~ManagedDebugger()
{
}
-VOID Debugger::StartupCallback(IUnknown *pCordb, PVOID parameter, HRESULT hr)
+HRESULT ManagedDebugger::SetupStep(ICorDebugThread *pThread, Debugger::StepType stepType)
{
- Debugger *self = static_cast<Debugger*>(parameter);
+ HRESULT Status;
+
+ ToRelease<ICorDebugStepper> pStepper;
+ IfFailRet(pThread->CreateStepper(&pStepper));
+
+ CorDebugIntercept mask = (CorDebugIntercept)(INTERCEPT_ALL & ~(INTERCEPT_SECURITY | INTERCEPT_CLASS_INIT));
+ IfFailRet(pStepper->SetInterceptMask(mask));
+
+ CorDebugUnmappedStop stopMask = STOP_NONE;
+ IfFailRet(pStepper->SetUnmappedStopMask(stopMask));
+
+ ToRelease<ICorDebugStepper2> pStepper2;
+ IfFailRet(pStepper->QueryInterface(IID_ICorDebugStepper2, (LPVOID *)&pStepper2));
+
+ IfFailRet(pStepper2->SetJMC(IsJustMyCode()));
+
+ if (stepType == STEP_OUT)
+ {
+ IfFailRet(pStepper->StepOut());
+ return S_OK;
+ }
+
+ BOOL bStepIn = stepType == STEP_IN;
+
+ COR_DEBUG_STEP_RANGE range;
+ if (SUCCEEDED(m_modules.GetStepRangeFromCurrentIP(pThread, &range)))
+ {
+ IfFailRet(pStepper->StepRange(bStepIn, &range, 1));
+ } else {
+ IfFailRet(pStepper->Step(bStepIn));
+ }
+
+ return S_OK;
+}
+
+HRESULT ManagedDebugger::StepCommand(int threadId, StepType stepType)
+{
+ HRESULT Status;
+ ToRelease<ICorDebugThread> pThread;
+ IfFailRet(m_pProcess->GetThread(threadId, &pThread));
+ DisableAllSteppers(m_pProcess);
+ IfFailRet(SetupStep(pThread, stepType));
+ IfFailRet(m_pProcess->Continue(0));
+ return S_OK;
+}
+
+HRESULT ManagedDebugger::Continue()
+{
+ if (!m_pProcess)
+ return E_FAIL;
+ return m_pProcess->Continue(0);
+}
+
+HRESULT ManagedDebugger::Pause()
+{
+ if (!m_pProcess)
+ return E_FAIL;
+ HRESULT Status = m_pProcess->Stop(0);
+ if (Status == S_OK)
+ m_protocol->EmitStoppedEvent(StoppedEvent(StopPause, 0));
+ return Status;
+}
+
+HRESULT ManagedDebugger::GetThreads(std::vector<Thread> &threads)
+{
+ if (!m_pProcess)
+ return E_FAIL;
+ return GetThreadsState(m_pProcess, threads);
+}
+
+HRESULT ManagedDebugger::GetStackTrace(int threadId, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames)
+{
+ HRESULT Status;
+ if (!m_pProcess)
+ return E_FAIL;
+ ToRelease<ICorDebugThread> pThread;
+ IfFailRet(m_pProcess->GetThread(threadId, &pThread));
+ return GetStackTrace(pThread, lowFrame, highFrame, stackFrames);
+}
+
+VOID ManagedDebugger::StartupCallback(IUnknown *pCordb, PVOID parameter, HRESULT hr)
+{
+ ManagedDebugger *self = static_cast<ManagedDebugger*>(parameter);
std::unique_lock<std::mutex> lock(self->m_startupMutex);
return result;
}
-HRESULT Debugger::Startup(IUnknown *punk, int pid)
+HRESULT ManagedDebugger::Startup(IUnknown *punk, int pid)
{
HRESULT Status;
return S_OK;
}
-HRESULT Debugger::RunProcess(std::string fileExec, std::vector<std::string> execArgs)
+HRESULT ManagedDebugger::RunProcess(std::string fileExec, std::vector<std::string> execArgs)
{
static const auto startupCallbackWaitTimeout = std::chrono::milliseconds(5000);
HRESULT Status;
HANDLE resumeHandle;
IfFailRet(CreateProcessForLaunch(&cmd[0], bSuspendProcess, lpEnvironment, lpCurrentDirectory, &m_processId, &resumeHandle));
- IfFailRet(RegisterForRuntimeStartup(m_processId, Debugger::StartupCallback, this, &m_unregisterToken));
+ IfFailRet(RegisterForRuntimeStartup(m_processId, ManagedDebugger::StartupCallback, this, &m_unregisterToken));
// Resume the process so that StartupCallback can run
IfFailRet(ResumeProcess(resumeHandle));
CloseResumeHandle(resumeHandle);
- // Wait for Debugger::StartupCallback to complete
+ // Wait for ManagedDebugger::StartupCallback to complete
- // FIXME: if the process exits too soon the Debugger::StartupCallback()
+ // FIXME: if the process exits too soon the ManagedDebugger::StartupCallback()
// is never called (bug in dbgshim?).
// The workaround is to wait with timeout.
auto now = std::chrono::system_clock::now();
return m_startupResult;
}
-HRESULT Debugger::CheckNoProcess()
+HRESULT ManagedDebugger::CheckNoProcess()
{
if (m_pProcess || m_pDebug)
{
return S_OK;
}
-HRESULT Debugger::DetachFromProcess()
+HRESULT ManagedDebugger::DetachFromProcess()
{
if (!m_pProcess || !m_pDebug)
return E_FAIL;
return S_OK;
}
-HRESULT Debugger::TerminateProcess()
+HRESULT ManagedDebugger::TerminateProcess()
{
if (!m_pProcess || !m_pDebug)
return E_FAIL;
return S_OK;
}
-void Debugger::Cleanup()
+void ManagedDebugger::Cleanup()
{
m_modules.CleanupAllModules();
m_evaluator.Cleanup();
// TODO: Cleanup libcoreclr.so instance
}
-HRESULT Debugger::AttachToProcess(int pid)
+HRESULT ManagedDebugger::AttachToProcess(int pid)
{
HRESULT Status;
}
}
- Debugger debugger;
-
+ ManagedDebugger debugger;
MIProtocol protocol;
+
protocol.SetDebugger(&debugger);
+ debugger.SetProtocol(&protocol);
if (pidDebuggee != 0)
{
return S_OK;
}
-int Debugger::GetNamedVariables(uint32_t variablesReference)
+int ManagedDebugger::GetNamedVariables(uint32_t variablesReference)
{
return m_variables.GetNamedVariables(variablesReference);
}
return it->second.namedVariables;
}
-HRESULT Debugger::GetVariables(
+HRESULT ManagedDebugger::GetVariables(
uint32_t variablesReference,
VariablesFilter filter,
int start,
return S_OK;
}
-HRESULT Debugger::GetScopes(uint64_t frameId, std::vector<Scope> &scopes)
+HRESULT ManagedDebugger::GetScopes(uint64_t frameId, std::vector<Scope> &scopes)
{
return m_variables.GetScopes(m_pProcess, frameId, scopes);
}
return S_OK;
}
-HRESULT Debugger::Evaluate(uint64_t frameId, const std::string &expression, Variable &variable)
+HRESULT ManagedDebugger::Evaluate(uint64_t frameId, const std::string &expression, Variable &variable)
{
return m_variables.Evaluate(m_pProcess, frameId, expression, variable);
}