From 285d216beddb9c4d8e65145e13e3e3203f4d615c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Wed, 2 Feb 2011 13:45:40 +0100 Subject: [PATCH] Debuggeri[CDB]: Add breakpoint command. Report back breakpoints with modules. --- src/libs/qtcreatorcdbext/common.cpp | 18 +++++ src/libs/qtcreatorcdbext/common.h | 1 + src/libs/qtcreatorcdbext/eventcallback.cpp | 2 +- src/libs/qtcreatorcdbext/extensioncontext.cpp | 12 +++ src/libs/qtcreatorcdbext/extensioncontext.h | 1 + src/libs/qtcreatorcdbext/gdbmihelpers.cpp | 81 +++++++++++++++++++ src/libs/qtcreatorcdbext/gdbmihelpers.h | 7 ++ src/libs/qtcreatorcdbext/qtcreatorcdbext.def | 1 + .../qtcreatorcdbext/qtcreatorcdbextension.cpp | 30 +++++++ src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 16 +--- 10 files changed, 155 insertions(+), 14 deletions(-) diff --git a/src/libs/qtcreatorcdbext/common.cpp b/src/libs/qtcreatorcdbext/common.cpp index 18f2973a229..097264a4467 100644 --- a/src/libs/qtcreatorcdbext/common.cpp +++ b/src/libs/qtcreatorcdbext/common.cpp @@ -122,3 +122,21 @@ ULONG currentProcessId(CIDebugClient *client) return currentProcessId(sysObjects.data()); 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); +} diff --git a/src/libs/qtcreatorcdbext/common.h b/src/libs/qtcreatorcdbext/common.h index f13a880a347..4d4075ab5b9 100644 --- a/src/libs/qtcreatorcdbext/common.h +++ b/src/libs/qtcreatorcdbext/common.h @@ -74,6 +74,7 @@ ULONG currentThreadId(IDebugSystemObjects *sysObjects); ULONG currentThreadId(CIDebugClient *client); ULONG currentProcessId(IDebugSystemObjects *sysObjects); ULONG currentProcessId(CIDebugClient *client); +std::string moduleNameByOffset(CIDebugSymbols *symbols, ULONG64 offset); #ifdef QTC_TRACE # define QTC_TRACE_IN dprintf(">%s\n", __FUNCTION__); diff --git a/src/libs/qtcreatorcdbext/eventcallback.cpp b/src/libs/qtcreatorcdbext/eventcallback.cpp index e2799a959eb..d04ad11a57d 100644 --- a/src/libs/qtcreatorcdbext/eventcallback.cpp +++ b/src/libs/qtcreatorcdbext/eventcallback.cpp @@ -172,7 +172,7 @@ STDMETHODIMP EventCallback::Exception( std::ostringstream str; 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()); return m_wrapped ? m_wrapped->Exception(Ex, FirstChance) : S_OK; } diff --git a/src/libs/qtcreatorcdbext/extensioncontext.cpp b/src/libs/qtcreatorcdbext/extensioncontext.cpp index 8d5b07affd4..965aac037aa 100644 --- a/src/libs/qtcreatorcdbext/extensioncontext.cpp +++ b/src/libs/qtcreatorcdbext/extensioncontext.cpp @@ -45,6 +45,7 @@ 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::breakPointStopReasonC = "breakpoint"; ExtensionContext::ExtensionContext() : m_hookedClient(0), @@ -197,6 +198,17 @@ void ExtensionContext::notifyIdleCommand(CIDebugClient *client) } else { 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 << '}'; reportLong('E', 0, "session_idle", str.str()); } diff --git a/src/libs/qtcreatorcdbext/extensioncontext.h b/src/libs/qtcreatorcdbext/extensioncontext.h index abeeb2cbe73..f844783a592 100644 --- a/src/libs/qtcreatorcdbext/extensioncontext.h +++ b/src/libs/qtcreatorcdbext/extensioncontext.h @@ -56,6 +56,7 @@ public: // Key used to report stop reason in StopReasonMap static const char *stopReasonKeyC; + static const char *breakPointStopReasonC; // pre-defined stop reasons // Map of parameters reported with the next stop as GDBMI typedef std::map<std::string, std::string> StopReasonMap; diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp index 6826df9b83a..e3c45f178ec 100644 --- a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp +++ b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp @@ -670,3 +670,84 @@ std::string widgetAt(const SymbolGroupValueContext &ctx, int x, int y, std::stri wOutput.erase(sepPos, 1); 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(); +} diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.h b/src/libs/qtcreatorcdbext/gdbmihelpers.h index 849a05faebb..54c475bd9e8 100644 --- a/src/libs/qtcreatorcdbext/gdbmihelpers.h +++ b/src/libs/qtcreatorcdbext/gdbmihelpers.h @@ -113,6 +113,13 @@ Modules getModules(CIDebugSymbols *syms, std::string *errorMessage); // Format modules as GDBMI 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 */ struct Register { diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.def b/src/libs/qtcreatorcdbext/qtcreatorcdbext.def index bc91011c9b5..ab4cf4ea5c8 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.def +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.def @@ -21,4 +21,5 @@ test stack addwatch widgetat +breakpoints KnownStructOutput diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index 45dccd50d90..59d6a3c2f2e 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -101,6 +101,7 @@ enum Command { CmdShutdownex, CmdAddWatch, CmdWidgetAt, + CmdBreakPoints, CmdTest }; @@ -158,6 +159,7 @@ static const CommandDescription commandDescriptions[] = { {"shutdownex","Unhooks output callbacks.\nNeeds to be called explicitly only in case of remote debugging.",""}, {"addwatch","Add watch expression","<iname> <expression>"}, {"widgetat","Return address of widget at position","<x> <y>"}, +{"breakpoints","List breakpoints with modules","[-h] [-v]"}, {"test","Testing command","-T type | -w watch-expression"} }; @@ -984,6 +986,34 @@ extern "C" HRESULT CALLBACK widgetat(CIDebugClient *client, PCSTR argsIn) 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) { enum Mode { Invalid, TestType, TestFixWatchExpression }; diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 3654e42a43c..660cc837d1f 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -600,20 +600,10 @@ std::string SymbolGroupValue::resolveType(const std::string &typeIn, const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size); if (!typeSize || !symParameters.ModBase) // Failed? return stripped; - ULONG index = 0; - ULONG64 base = 0; - // Convert module base address to module index - HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base); - if (FAILED(hr)) + const std::string module = moduleNameByOffset(ctx.symbols, symParameters.ModBase); + if (module.empty()) return stripped; - // Obtain module name - 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; + std::string rc = module; rc.push_back('!'); rc += stripped; return rc; -- GitLab