forked from qt-creator/qt-creator
Debuggeri[CDB]: Add breakpoint command.
Report back breakpoints with modules.
This commit is contained in:
@@ -122,3 +122,21 @@ ULONG currentProcessId(CIDebugClient *client)
|
|||||||
return currentProcessId(sysObjects.data());
|
return currentProcessId(sysObjects.data());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string moduleNameByOffset(CIDebugSymbols *symbols, ULONG64 offset)
|
||||||
|
{
|
||||||
|
enum { BufSize = 512 };
|
||||||
|
ULONG index = 0;
|
||||||
|
ULONG64 base = 0;
|
||||||
|
// Convert module base address to module index
|
||||||
|
HRESULT hr = symbols->GetModuleByOffset(offset, 0, &index, &base);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return std::string();
|
||||||
|
// Obtain module name
|
||||||
|
char buf[BufSize];
|
||||||
|
buf[0] = '\0';
|
||||||
|
hr = symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return std::string();
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ ULONG currentThreadId(IDebugSystemObjects *sysObjects);
|
|||||||
ULONG currentThreadId(CIDebugClient *client);
|
ULONG currentThreadId(CIDebugClient *client);
|
||||||
ULONG currentProcessId(IDebugSystemObjects *sysObjects);
|
ULONG currentProcessId(IDebugSystemObjects *sysObjects);
|
||||||
ULONG currentProcessId(CIDebugClient *client);
|
ULONG currentProcessId(CIDebugClient *client);
|
||||||
|
std::string moduleNameByOffset(CIDebugSymbols *symbols, ULONG64 offset);
|
||||||
|
|
||||||
#ifdef QTC_TRACE
|
#ifdef QTC_TRACE
|
||||||
# define QTC_TRACE_IN dprintf(">%s\n", __FUNCTION__);
|
# define QTC_TRACE_IN dprintf(">%s\n", __FUNCTION__);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ STDMETHODIMP EventCallback::Exception(
|
|||||||
|
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
formatGdbmiHash(str, parameters);
|
formatGdbmiHash(str, parameters);
|
||||||
ExtensionContext::instance().setStopReason(parameters, "exception");
|
ExtensionContext::instance().setStopReason(parameters, ExtensionContext::breakPointStopReasonC);
|
||||||
ExtensionContext::instance().report('E', 0, 0, "exception", "%s", str.str().c_str());
|
ExtensionContext::instance().report('E', 0, 0, "exception", "%s", str.str().c_str());
|
||||||
return m_wrapped ? m_wrapped->Exception(Ex, FirstChance) : S_OK;
|
return m_wrapped ? m_wrapped->Exception(Ex, FirstChance) : S_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
WINDBG_EXTENSION_APIS ExtensionApis = {sizeof(WINDBG_EXTENSION_APIS), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
WINDBG_EXTENSION_APIS ExtensionApis = {sizeof(WINDBG_EXTENSION_APIS), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
const char *ExtensionContext::stopReasonKeyC = "reason";
|
const char *ExtensionContext::stopReasonKeyC = "reason";
|
||||||
|
const char *ExtensionContext::breakPointStopReasonC = "breakpoint";
|
||||||
|
|
||||||
ExtensionContext::ExtensionContext() :
|
ExtensionContext::ExtensionContext() :
|
||||||
m_hookedClient(0),
|
m_hookedClient(0),
|
||||||
@@ -197,6 +198,17 @@ void ExtensionContext::notifyIdleCommand(CIDebugClient *client)
|
|||||||
} else {
|
} else {
|
||||||
str << ",stack=" << stackInfo;
|
str << ",stack=" << stackInfo;
|
||||||
}
|
}
|
||||||
|
// Report breakpoints
|
||||||
|
const StopReasonMap::const_iterator rit = stopReasons.find(stopReasonKeyC);
|
||||||
|
if (rit != stopReasons.end() && rit->second == breakPointStopReasonC) {
|
||||||
|
const std::string breakpoints = gdbmiBreakpoints(exc.control(), exc.symbols(),
|
||||||
|
false, false, &errorMessage);
|
||||||
|
if (breakpoints.empty()) {
|
||||||
|
str << ",breakpointserror=" << gdbmiStringFormat(errorMessage);
|
||||||
|
} else {
|
||||||
|
str << ",breakpoints=" << breakpoints;
|
||||||
|
}
|
||||||
|
}
|
||||||
str << '}';
|
str << '}';
|
||||||
reportLong('E', 0, "session_idle", str.str());
|
reportLong('E', 0, "session_idle", str.str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public:
|
|||||||
|
|
||||||
// Key used to report stop reason in StopReasonMap
|
// Key used to report stop reason in StopReasonMap
|
||||||
static const char *stopReasonKeyC;
|
static const char *stopReasonKeyC;
|
||||||
|
static const char *breakPointStopReasonC; // pre-defined stop reasons
|
||||||
// Map of parameters reported with the next stop as GDBMI
|
// Map of parameters reported with the next stop as GDBMI
|
||||||
typedef std::map<std::string, std::string> StopReasonMap;
|
typedef std::map<std::string, std::string> StopReasonMap;
|
||||||
|
|
||||||
|
|||||||
@@ -670,3 +670,84 @@ std::string widgetAt(const SymbolGroupValueContext &ctx, int x, int y, std::stri
|
|||||||
wOutput.erase(sepPos, 1);
|
wOutput.erase(sepPos, 1);
|
||||||
return wStringToString(wOutput);
|
return wStringToString(wOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void formatGdbmiFlag(std::ostream &str, const char *name, bool v)
|
||||||
|
{
|
||||||
|
str << name << "=\"" << (v ? "true" : "false") << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gdbmiFormatBreakpoint(std::ostream &str,
|
||||||
|
IDebugBreakpoint *bp,
|
||||||
|
CIDebugSymbols *symbols /* = 0 */,
|
||||||
|
bool verbose, std::string *errorMessage)
|
||||||
|
{
|
||||||
|
enum { BufSize = 512 };
|
||||||
|
ULONG64 offset = 0;
|
||||||
|
ULONG flags = 0;
|
||||||
|
HRESULT hr = bp->GetFlags(&flags);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgDebugEngineComFailed("GetFlags", hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const bool deferred = (flags & DEBUG_BREAKPOINT_DEFERRED) != 0;
|
||||||
|
formatGdbmiFlag(str, ",deferred", deferred);
|
||||||
|
if (verbose) {
|
||||||
|
formatGdbmiFlag(str, ",enabled", (flags & DEBUG_BREAKPOINT_ENABLED) != 0);
|
||||||
|
formatGdbmiFlag(str, ",oneshot", (flags & DEBUG_BREAKPOINT_ONE_SHOT) != 0);
|
||||||
|
str << ",flags=\"" << flags << '"';
|
||||||
|
ULONG threadId = 0;
|
||||||
|
if (SUCCEEDED(bp->GetMatchThreadId(&threadId))) // Fails if none set
|
||||||
|
str << ",thread=\"" << threadId << '"';
|
||||||
|
ULONG passCount = 0;
|
||||||
|
if (SUCCEEDED(bp->GetPassCount(&passCount)))
|
||||||
|
str << ",passcount=\"" << passCount << '"';
|
||||||
|
}
|
||||||
|
// Offset: Fails for deferred ones
|
||||||
|
if (!deferred && SUCCEEDED(bp->GetOffset(&offset))) {
|
||||||
|
str << ",address=\"" << std::hex << std::showbase << offset
|
||||||
|
<< std::dec << std::noshowbase << '"';
|
||||||
|
if (symbols) {
|
||||||
|
const std::string module = moduleNameByOffset(symbols, offset);
|
||||||
|
if (!module.empty())
|
||||||
|
str << ",module=\"" << module << '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Expression
|
||||||
|
char buf[BufSize];
|
||||||
|
if (SUCCEEDED(bp->GetOffsetExpression(buf, BUFSIZ, 0)))
|
||||||
|
str << ",expression=\"" << gdbmiStringFormat(buf) << '"';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format breakpoints as GDBMI
|
||||||
|
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
|
||||||
|
CIDebugSymbols *symbols /* = 0 */,
|
||||||
|
bool humanReadable, bool verbose, std::string *errorMessage)
|
||||||
|
{
|
||||||
|
ULONG breakPointCount = 0;
|
||||||
|
HRESULT hr = ctrl->GetNumberBreakpoints(&breakPointCount);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
*errorMessage = msgDebugEngineComFailed("GetNumberBreakpoints", hr);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
std::ostringstream str;
|
||||||
|
str << '[';
|
||||||
|
if (humanReadable)
|
||||||
|
str << '\n';
|
||||||
|
for (ULONG i = 0; i < breakPointCount; i++) {
|
||||||
|
str << "{id=\"" << i << '"';
|
||||||
|
IDebugBreakpoint *bp = 0;
|
||||||
|
hr = ctrl->GetBreakpointByIndex(i, &bp);
|
||||||
|
if (FAILED(hr) || !bp) {
|
||||||
|
*errorMessage = msgDebugEngineComFailed("GetBreakpointByIndex", hr);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
if (!gdbmiFormatBreakpoint(str, bp, symbols, verbose, errorMessage))
|
||||||
|
return std::string();
|
||||||
|
str << '}';
|
||||||
|
if (humanReadable)
|
||||||
|
str << '\n';
|
||||||
|
}
|
||||||
|
str << ']';
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|||||||
@@ -113,6 +113,13 @@ Modules getModules(CIDebugSymbols *syms, std::string *errorMessage);
|
|||||||
// Format modules as GDBMI
|
// Format modules as GDBMI
|
||||||
std::string gdbmiModules(CIDebugSymbols *syms, bool humanReadable, std::string *errorMessage);
|
std::string gdbmiModules(CIDebugSymbols *syms, bool humanReadable, std::string *errorMessage);
|
||||||
|
|
||||||
|
// Format breakpoints as GDBMI
|
||||||
|
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
|
||||||
|
CIDebugSymbols *symbols /* = 0 */,
|
||||||
|
bool humanReadable,
|
||||||
|
bool verbose,
|
||||||
|
std::string *errorMessage);
|
||||||
|
|
||||||
/* Helpers for registers */
|
/* Helpers for registers */
|
||||||
struct Register
|
struct Register
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,4 +21,5 @@ test
|
|||||||
stack
|
stack
|
||||||
addwatch
|
addwatch
|
||||||
widgetat
|
widgetat
|
||||||
|
breakpoints
|
||||||
KnownStructOutput
|
KnownStructOutput
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ enum Command {
|
|||||||
CmdShutdownex,
|
CmdShutdownex,
|
||||||
CmdAddWatch,
|
CmdAddWatch,
|
||||||
CmdWidgetAt,
|
CmdWidgetAt,
|
||||||
|
CmdBreakPoints,
|
||||||
CmdTest
|
CmdTest
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,6 +159,7 @@ static const CommandDescription commandDescriptions[] = {
|
|||||||
{"shutdownex","Unhooks output callbacks.\nNeeds to be called explicitly only in case of remote debugging.",""},
|
{"shutdownex","Unhooks output callbacks.\nNeeds to be called explicitly only in case of remote debugging.",""},
|
||||||
{"addwatch","Add watch expression","<iname> <expression>"},
|
{"addwatch","Add watch expression","<iname> <expression>"},
|
||||||
{"widgetat","Return address of widget at position","<x> <y>"},
|
{"widgetat","Return address of widget at position","<x> <y>"},
|
||||||
|
{"breakpoints","List breakpoints with modules","[-h] [-v]"},
|
||||||
{"test","Testing command","-T type | -w watch-expression"}
|
{"test","Testing command","-T type | -w watch-expression"}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -984,6 +986,34 @@ extern "C" HRESULT CALLBACK widgetat(CIDebugClient *client, PCSTR argsIn)
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" HRESULT CALLBACK breakpoints(CIDebugClient *client, PCSTR argsIn)
|
||||||
|
{
|
||||||
|
ExtensionCommandContext exc(client);
|
||||||
|
int token;
|
||||||
|
std::string errorMessage;
|
||||||
|
bool humanReadable = false;
|
||||||
|
bool verbose = false;
|
||||||
|
StringList tokens = commandTokens<StringList>(argsIn, &token);
|
||||||
|
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
|
||||||
|
switch (tokens.front().at(1)) {
|
||||||
|
case 'h':
|
||||||
|
humanReadable = true;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokens.pop_front();
|
||||||
|
}
|
||||||
|
const std::string bp = gdbmiBreakpoints(exc.control(), exc.symbols(), humanReadable, verbose, &errorMessage);
|
||||||
|
if (bp.empty()) {
|
||||||
|
ExtensionContext::instance().report('N', token, 0, "breakpoints", errorMessage.c_str());
|
||||||
|
} else {
|
||||||
|
ExtensionContext::instance().reportLong('R', token, "breakpoints", bp);
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn)
|
extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn)
|
||||||
{
|
{
|
||||||
enum Mode { Invalid, TestType, TestFixWatchExpression };
|
enum Mode { Invalid, TestType, TestFixWatchExpression };
|
||||||
|
|||||||
@@ -600,20 +600,10 @@ std::string SymbolGroupValue::resolveType(const std::string &typeIn,
|
|||||||
const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size);
|
const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size);
|
||||||
if (!typeSize || !symParameters.ModBase) // Failed?
|
if (!typeSize || !symParameters.ModBase) // Failed?
|
||||||
return stripped;
|
return stripped;
|
||||||
ULONG index = 0;
|
const std::string module = moduleNameByOffset(ctx.symbols, symParameters.ModBase);
|
||||||
ULONG64 base = 0;
|
if (module.empty())
|
||||||
// Convert module base address to module index
|
|
||||||
HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return stripped;
|
return stripped;
|
||||||
// Obtain module name
|
std::string rc = module;
|
||||||
char buf[BufSize];
|
|
||||||
buf[0] = '\0';
|
|
||||||
hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return stripped;
|
|
||||||
|
|
||||||
std::string rc = buf;
|
|
||||||
rc.push_back('!');
|
rc.push_back('!');
|
||||||
rc += stripped;
|
rc += stripped;
|
||||||
return rc;
|
return rc;
|
||||||
|
|||||||
Reference in New Issue
Block a user