#include <algorithm>
#include <mutex>
#include <condition_variable>
+#include <iomanip>
#include "platform.h"
#include "debugger.h"
return S_OK;
}
+static std::string AddrToString(uint64_t addr)
+{
+ std::stringstream ss;
+ ss << "0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << addr;
+ return ss.str();
+}
+
+HRESULT PrintFrameLocation(const StackFrame &stackFrame, std::string &output)
+{
+ HRESULT Status;
+
+ std::stringstream ss;
+
+ if (!stackFrame.source.isNull())
+ {
+ ss << "file=\"" << Debugger::EscapeMIValue(stackFrame.source.name) << "\","
+ << "fullname=\"" << Debugger::EscapeMIValue(stackFrame.source.path) << "\","
+ << "line=\"" << stackFrame.line << "\","
+ << "col=\"" << stackFrame.column << "\","
+ << "end-line=\"" << stackFrame.endLine << "\","
+ << "end-col=\"" << stackFrame.endColumn << "\",";
+ }
+
+ if (stackFrame.clrAddr.methodToken != 0)
+ {
+ ss << "clr-addr={module-id=\"{" << stackFrame.moduleId << "}\","
+ << "method-token=\"0x"
+ << std::setw(8) << std::setfill('0') << std::hex << stackFrame.clrAddr.methodToken << "\","
+ << "il-offset=\"" << std::dec << stackFrame.clrAddr.ilOffset
+ << "\",native-offset=\"" << stackFrame.clrAddr.nativeOffset << "\"},";
+ }
+
+ ss << "func=\"" << stackFrame.name << "\"";
+ if (stackFrame.id != 0)
+ ss << ",addr=\"" << AddrToString(stackFrame.id) << "\"";
+
+ output = ss.str();
+
+ return stackFrame.source.isNull() ? S_FALSE : S_OK;
+}
+
+static HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output, int lowFrame, int highFrame)
+{
+ HRESULT Status;
+ std::stringstream ss;
+
+ std::vector<StackFrame> stackFrames;
+ IfFailRet(GetStackTrace(pThread, lowFrame, highFrame, stackFrames));
+
+ int currentFrame = lowFrame;
+
+ ss << "stack=[";
+ const char *sep = "";
+
+ for (const StackFrame &stackFrame : stackFrames)
+ {
+ ss << sep;
+ sep = ",";
+
+ std::string frameLocation;
+ PrintFrameLocation(stackFrame, frameLocation);
+
+ ss << "frame={level=\"" << currentFrame << "\"";
+ if (!frameLocation.empty())
+ ss << "," << frameLocation;
+ ss << "}";
+ currentFrame++;
+ }
+
+ ss << "]";
+
+ output = ss.str();
+
+ return S_OK;
+}
+
static HRESULT ThreadInfoCommand(ICorDebugProcess *pProcess, const std::vector<std::string> &, std::string &output)
{
if (!pProcess) return E_FAIL;
HRESULT DisableAllSteppers(ICorDebugProcess *pProcess);
int GetLastStoppedThreadId();
void WaitProcessExited();
+
+HRESULT PrintFrameLocation(const StackFrame &stackFrame, std::string &output);
#include <vector>
#include <list>
#include <functional>
-#include <iomanip>
#include <mutex>
#include <condition_variable>
#include <algorithm>
return S_OK;
}
-static std::string AddrToString(uint64_t addr)
-{
- std::stringstream ss;
- ss << "0x" << std::setw(2 * sizeof(void*)) << std::setfill('0') << std::hex << addr;
- return ss.str();
-}
-
-static std::string FrameAddrToString(ICorDebugFrame *pFrame)
+static uint64_t FrameAddr(ICorDebugFrame *pFrame)
{
CORDB_ADDRESS startAddr = 0;
CORDB_ADDRESS endAddr = 0;
pFrame->GetStackRange(&startAddr, &endAddr);
- return AddrToString(startAddr);
+ return startAddr;
}
-HRESULT PrintFrameLocation(ICorDebugFrame *pFrame, std::string &output)
+HRESULT GetFrameLocation(ICorDebugFrame *pFrame, StackFrame &stackFrame)
{
HRESULT Status;
+ stackFrame.id = FrameAddr(pFrame);
+
ULONG32 ilOffset;
Modules::SequencePoint sp;
- bool has_source = false;
-
- std::stringstream ss;
if (SUCCEEDED(Modules::GetFrameLocation(pFrame, ilOffset, sp)))
{
- ss << "file=\"" << GetFileName(sp.document) << "\","
- << "fullname=\"" << Debugger::EscapeMIValue(sp.document) << "\","
- << "line=\"" << sp.startLine << "\","
- << "col=\"" << sp.startColumn << "\","
- << "end-line=\"" << sp.endLine << "\","
- << "end-col=\"" << sp.endColumn << "\",";
- has_source = true;
+ stackFrame.source = Source(sp.document);
+ stackFrame.line = sp.startLine;
+ stackFrame.column = sp.startColumn;
+ stackFrame.endLine = sp.endLine;
+ stackFrame.endColumn = sp.endColumn;
}
mdMethodDef methodToken;
CorDebugMappingResult mappingResult;
IfFailRet(pILFrame->GetIP(&ilOffset, &mappingResult));
- std::string id;
- IfFailRet(Modules::GetModuleId(pModule, id));
-
- ss << "clr-addr={module-id=\"{" << id << "}\","
- << "method-token=\"0x" << std::setw(8) << std::setfill('0') << std::hex << methodToken << "\","
- << "il-offset=\"" << std::dec << ilOffset << "\",native-offset=\"" << nOffset << "\"},";
+ IfFailRet(Modules::GetModuleId(pModule, stackFrame.moduleId));
- std::string methodName;
- TypePrinter::GetMethodName(pFrame, methodName);
- ss << "func=\"" << methodName << "\",";
- ss << "addr=\"" << FrameAddrToString(pFrame) << "\"";
+ stackFrame.clrAddr.methodToken = methodToken;
+ stackFrame.clrAddr.ilOffset = ilOffset;
+ stackFrame.clrAddr.nativeOffset = nOffset;
- output = ss.str();
+ TypePrinter::GetMethodName(pFrame, stackFrame.name);
- return has_source ? S_OK : S_FALSE;
+ return stackFrame.source.isNull() ? S_FALSE : S_OK;
}
struct NativeFrame
}
}
-HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output, int lowFrame, int highFrame)
+HRESULT GetStackTrace(ICorDebugThread *pThread, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames)
{
HRESULT Status;
std::stringstream ss;
int currentFrame = -1;
- ss << "stack=[";
- const char *sep = "";
-
IfFailRet(WalkFrames(pThread, [&](
FrameType frameType,
ICorDebugFrame *pFrame,
if (currentFrame > highFrame)
return S_OK; // Todo implement fast break mechanism
- ss << sep;
- sep = ",";
-
switch(frameType)
{
case FrameUnknown:
- ss << "frame={level=\"" << currentFrame << "\",func=\"?\"}";
+ stackFrames.emplace_back(FrameAddr(pFrame), "?");
break;
case FrameNative:
- ss << "frame={level=\"" << currentFrame << "\",func=\"" << pNative->symbol << "\","
- << "file=\"" << pNative->file << "\","
- << "line=\"" << pNative->linenum << "\","
- << "addr=\"" << AddrToString(pNative->addr) << "\"}";
+ stackFrames.emplace_back(pNative->addr, pNative->symbol);
+ stackFrames.back().source = Source(pNative->file);
+ stackFrames.back().line = pNative->linenum;
break;
case FrameCLRNative:
- ss << "frame={level=\"" << currentFrame << "\",func=\"[Native Frame]\","
- << "addr=\"" << FrameAddrToString(pFrame) << "\"}";
+ stackFrames.emplace_back(FrameAddr(pFrame), "[Native Frame]");
break;
case FrameCLRInternal:
{
IfFailRet(pFrame->QueryInterface(IID_ICorDebugInternalFrame, (LPVOID*) &pInternalFrame));
CorDebugInternalFrameType frameType;
IfFailRet(pInternalFrame->GetFrameType(&frameType));
- ss << "frame={level=\"" << currentFrame << "\",func=\"[" << GetInternalTypeName(frameType) << "]\","
- << "addr=\"" << FrameAddrToString(pFrame) << "\"}";
+ std::string name = "[";
+ name += GetInternalTypeName(frameType);
+ name += "]";
+ stackFrames.emplace_back(FrameAddr(pFrame), name);
}
break;
case FrameCLRManaged:
{
- std::string frameLocation;
- PrintFrameLocation(pFrame, frameLocation);
-
- ss << "frame={level=\"" << currentFrame << "\"";
- if (!frameLocation.empty())
- ss << "," << frameLocation;
- ss << "}";
+ StackFrame stackFrame;
+ GetFrameLocation(pFrame, stackFrame);
+ stackFrames.push_back(stackFrame);
}
break;
}
return S_OK;
}));
- ss << "]";
-
- output = ss.str();
-
return S_OK;
}
// Distributed under the MIT License.
// See the LICENSE file in the project root for more information.
-HRESULT PrintFrameLocation(ICorDebugFrame *pFrame, std::string &output);
+HRESULT GetFrameLocation(ICorDebugFrame *pFrame, StackFrame &stackFrame);
HRESULT GetFrameAt(ICorDebugThread *pThread, int level, ICorDebugFrame **ppFrame);
-
HRESULT GetThreadsState(ICorDebugController *controller, std::vector<Thread> &threads);
-HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output, int lowFrame = 0, int highFrame = INT_MAX);
+HRESULT GetStackTrace(ICorDebugThread *pThread, int lowFrame, int highFrame, std::vector<StackFrame> &stackFrames);
ULONG32 times = 0;
HitBreakpoint(pThread, id, times);
- std::string output;
+ StackFrame stackFrame;
ToRelease<ICorDebugFrame> pFrame;
if (SUCCEEDED(pThread->GetActiveFrame(&pFrame)) && pFrame != nullptr)
- PrintFrameLocation(pFrame, output);
+ GetFrameLocation(pFrame, stackFrame);
DWORD threadId = 0;
pThread->GetID(&threadId);
+ std::string output;
+ PrintFrameLocation(stackFrame, output);
Debugger::Printf("*stopped,reason=\"breakpoint-hit\",thread-id=\"%i\",stopped-threads=\"all\",bkptno=\"%u\",times=\"%u\",frame={%s}\n",
(int)threadId, (unsigned int)id, (unsigned int)times, output.c_str());
/* [in] */ ICorDebugStepper *pStepper,
/* [in] */ CorDebugStepReason reason)
{
- std::string output;
+ StackFrame stackFrame;
ToRelease<ICorDebugFrame> pFrame;
HRESULT Status = S_FALSE;
if (SUCCEEDED(pThread->GetActiveFrame(&pFrame)) && pFrame != nullptr)
- Status = PrintFrameLocation(pFrame, output);
+ Status = GetFrameLocation(pFrame, stackFrame);
const bool no_source = Status == S_FALSE;
{
DWORD threadId = 0;
pThread->GetID(&threadId);
-
+ std::string output;
+ PrintFrameLocation(stackFrame, output);
Debugger::Printf("*stopped,reason=\"end-stepping-range\",thread-id=\"%i\",stopped-threads=\"all\",frame={%s}\n",
(int)threadId, output.c_str());
/* [in] */ ICorDebugThread *pThread,
/* [in] */ BOOL unhandled)
{
- std::string frameLocation;
+ StackFrame stackFrame;
ToRelease<ICorDebugFrame> pFrame;
if (SUCCEEDED(pThread->GetActiveFrame(&pFrame)) && pFrame != nullptr)
- PrintFrameLocation(pFrame, frameLocation);
+ GetFrameLocation(pFrame, stackFrame);
DWORD threadId = 0;
pThread->GetID(&threadId);
if (unhandled)
{
+ std::string frameLocation;
+ PrintFrameLocation(stackFrame, frameLocation);
ToRelease<ICorDebugValue> pExceptionValue;
std::string details = "An unhandled exception of type '" + excType + "' occurred in " + excModule;
std::string category = "clr";
#pragma once
+#include "platform.h"
#include <string>
struct Thread
Thread(int id, std::string name, bool running) : id(id), name(name), running(running) {}
};
+
+struct Source
+{
+ std::string name;
+ std::string path;
+
+ Source(std::string path = std::string()) : name(GetFileName(path)), path(path) {}
+ bool isNull() const { return name.empty() && path.empty(); }
+};
+
+struct ClrAddr
+{
+ uint32_t ilOffset;
+ uint32_t nativeOffset;
+ uint32_t methodToken;
+
+ ClrAddr() : ilOffset(0), nativeOffset(0), methodToken(0) {}
+ bool isNull() const { return methodToken == 0; }
+};
+
+struct StackFrame
+{
+ uint64_t id; // frame start address
+ std::string name;
+ Source source;
+ int line;
+ int column;
+ int endLine;
+ int endColumn;
+ std::string moduleId;
+
+ ClrAddr clrAddr;
+
+ StackFrame() :
+ id(0), line(0), column(0), endLine(0), endColumn(0) {}
+
+ StackFrame(uint64_t id, std::string name) : id(id), name(name) {}
+};