aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libs/qtcreatorcdbext/eventcallback.cpp45
-rw-r--r--src/libs/qtcreatorcdbext/extensioncontext.h2
-rw-r--r--src/libs/qtcreatorcdbext/gdbmihelpers.cpp95
-rw-r--r--src/libs/qtcreatorcdbext/gdbmihelpers.h11
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp3
5 files changed, 120 insertions, 36 deletions
diff --git a/src/libs/qtcreatorcdbext/eventcallback.cpp b/src/libs/qtcreatorcdbext/eventcallback.cpp
index 1e98bd4d3f0..d7e25b4d00e 100644
--- a/src/libs/qtcreatorcdbext/eventcallback.cpp
+++ b/src/libs/qtcreatorcdbext/eventcallback.cpp
@@ -50,6 +50,8 @@ enum { winExceptionCppException = 0xe06d7363,
winExceptionAppInitFailed = 0xc0000143
};
+typedef ExtensionContext::StopReasonMap StopReasonMap;
+
/*!
\class IDebugEventCallbacks
@@ -109,20 +111,41 @@ STDMETHODIMP EventCallback::GetInterestMask(THIS_ __out PULONG mask)
return S_OK;
}
-STDMETHODIMP EventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT b)
+// Fill a map with parameters to be reported for a breakpoint stop.
+static StopReasonMap breakPointStopReasonParameters(PDEBUG_BREAKPOINT b)
{
- // Breakpoint hit - Set the stop reason parameters on the extension context.
- typedef ExtensionContext::StopReasonMap StopReasonMap;
- typedef ExtensionContext::StopReasonMap::value_type StopReasonMapValue;
+ typedef StopReasonMap::value_type StopReasonMapValue;
+ StopReasonMap rc;
ULONG uId = 0;
- ULONG64 address = 0;
- StopReasonMap stopReason;
- if (SUCCEEDED(b->GetId(&uId)))
- stopReason.insert(StopReasonMapValue(std::string("breakpointId"), toString(uId)));
- if (SUCCEEDED(b->GetOffset(&address)))
- stopReason.insert(StopReasonMapValue(std::string("breakpointAddress"), toString(address)));
- ExtensionContext::instance().setStopReason(stopReason, ExtensionContext::breakPointStopReasonC);
+ if (FAILED(b->GetId(&uId)))
+ return rc;
+ rc.insert(StopReasonMapValue(std::string("breakpointId"), toString(uId)));
+ const std::pair<ULONG64, ULONG> memoryRange = breakPointMemoryRange(b);
+ if (!memoryRange.first)
+ return rc;
+ rc.insert(StopReasonMapValue(std::string("breakpointAddress"), toString(memoryRange.first)));
+ // Report the memory for data breakpoints allowing for watching for changed bits
+ // on the client side.
+ if (!memoryRange.second)
+ return rc;
+ // Try to grab a IDataSpace from somewhere to get the memory
+ if (CIDebugClient *client = ExtensionContext::instance().hookedClient()) {
+ IInterfacePointer<CIDebugDataSpaces> dataSpaces(client);
+ if (dataSpaces) {
+ const std::wstring memoryHex = memoryToHexW(dataSpaces.data(), memoryRange.first, memoryRange.second);
+ if (!memoryHex.empty())
+ rc.insert(StopReasonMapValue("memory", wStringToString(memoryHex)));
+ } // dataSpaces
+ } // client
+ return rc;
+}
+
+STDMETHODIMP EventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT b)
+{
+ // Breakpoint hit - Set the stop reason parameters on the extension context.
+ ExtensionContext::instance().setStopReason(breakPointStopReasonParameters(b),
+ ExtensionContext::breakPointStopReasonC);
return m_wrapped ? m_wrapped->Breakpoint(b) : S_OK;
}
diff --git a/src/libs/qtcreatorcdbext/extensioncontext.h b/src/libs/qtcreatorcdbext/extensioncontext.h
index f844783a592..5b98ac374d7 100644
--- a/src/libs/qtcreatorcdbext/extensioncontext.h
+++ b/src/libs/qtcreatorcdbext/extensioncontext.h
@@ -107,6 +107,8 @@ public:
// Execute a function call and record the output.
bool call(const std::string &functionCall, std::wstring *output, std::string *errorMessage);
+ CIDebugClient *hookedClient() const { return m_hookedClient; }
+
private:
bool isInitialized() const;
diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp
index fc3b747e5d0..f08dc8f3075 100644
--- a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp
+++ b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp
@@ -550,7 +550,9 @@ std::string gdbmiRegisters(CIDebugRegisters *regs,
return str.str();
}
-std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length, std::string *errorMessage)
+// Read memory and return allocated array
+unsigned char *readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
+ std::string *errorMessage = 0)
{
unsigned char *buffer = new unsigned char[length];
std::fill(buffer, buffer + length, 0);
@@ -558,22 +560,43 @@ std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
const HRESULT hr = ds->ReadVirtual(address, buffer, length, &received);
if (FAILED(hr)) {
delete [] buffer;
- std::ostringstream estr;
- estr << "Cannot read " << length << " bytes from " << address << ": "
- << msgDebugEngineComFailed("ReadVirtual", hr);
- *errorMessage = estr.str();
- return std::string();
+ if (errorMessage) {
+ std::ostringstream estr;
+ estr << "Cannot read " << length << " bytes from " << address << ": "
+ << msgDebugEngineComFailed("ReadVirtual", hr);
+ *errorMessage = estr.str();
+ }
+ return 0;
}
- if (received < length) {
+ if (received < length && errorMessage) {
std::ostringstream estr;
estr << "Warning: Received only " << received << " bytes of " << length << " requested at " << address << '.';
*errorMessage = estr.str();
}
+ return buffer;
+}
- std::ostringstream str;
- base64Encode(str, buffer, length);
- delete [] buffer;
- return str.str();
+std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
+ std::string *errorMessage /* = 0 */)
+{
+ if (const unsigned char *buffer = readMemory(ds, address, length, errorMessage)) {
+ std::ostringstream str;
+ base64Encode(str, buffer, length);
+ delete [] buffer;
+ return str.str();
+ }
+ return std::string();
+}
+
+std::wstring memoryToHexW(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
+ std::string *errorMessage /* = 0 */)
+{
+ if (const unsigned char *buffer = readMemory(ds, address, length, errorMessage)) {
+ const std::wstring hex = dataToHexW(buffer, buffer + length);
+ delete [] buffer;
+ return hex;
+ }
+ return std::wstring();
}
// Format stack as GDBMI
@@ -676,13 +699,29 @@ static inline void formatGdbmiFlag(std::ostream &str, const char *name, bool v)
str << name << "=\"" << (v ? "true" : "false") << '"';
}
+std::pair<ULONG64, ULONG> breakPointMemoryRange(IDebugBreakpoint *bp)
+{
+ // Get address. Can fail for deferred breakpoints.
+ std::pair<ULONG64, ULONG> result = std::pair<ULONG64, ULONG>(0, 0);
+ if (FAILED(bp->GetOffset(&result.first)) || result.first == 0)
+ return result;
+ // Fill 'size' only for data breakpoints
+ ULONG breakType = DEBUG_BREAKPOINT_CODE;
+ ULONG cpuType = 0;
+ if (FAILED(bp->GetType(&breakType, &cpuType)) || breakType != DEBUG_BREAKPOINT_DATA)
+ return result;
+ ULONG accessType = 0;
+ bp->GetDataParameters(&result.second, &accessType);
+ return result;
+}
+
static bool gdbmiFormatBreakpoint(std::ostream &str,
IDebugBreakpoint *bp,
CIDebugSymbols *symbols /* = 0 */,
+ CIDebugDataSpaces *dataSpaces /* = 0 */,
unsigned verbose, std::string *errorMessage)
{
enum { BufSize = 512 };
- ULONG64 offset = 0;
ULONG flags = 0;
ULONG id = 0;
if (SUCCEEDED(bp->GetId(&id)))
@@ -706,15 +745,26 @@ static bool gdbmiFormatBreakpoint(std::ostream &str,
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 << '"';
- }
- }
+ if (!deferred) {
+ const std::pair<ULONG64, ULONG> memoryRange = breakPointMemoryRange(bp);
+ if (memoryRange.first) {
+ str << ",address=\"" << std::hex << std::showbase << memoryRange.first
+ << std::dec << std::noshowbase << '"';
+ // Resolve module to be specified in next run for speed-up.
+ if (symbols) {
+ const std::string module = moduleNameByOffset(symbols, memoryRange.first);
+ if (!module.empty())
+ str << ",module=\"" << module << '"';
+ } // symbols
+ // Report the memory of watchpoints for comparing bitfields
+ if (dataSpaces && memoryRange.second > 0) {
+ str << ",size=\"" << memoryRange.second << '"';
+ const std::wstring memoryHex = memoryToHexW(dataSpaces, memoryRange.first, memoryRange.second);
+ if (!memoryHex.empty())
+ str << ",memory=\"" << gdbmiWStringFormat(memoryHex) << '"';
+ }
+ } // Got address
+ } // !deferred
// Expression
if (verbose > 1) {
char buf[BufSize];
@@ -727,6 +777,7 @@ static bool gdbmiFormatBreakpoint(std::ostream &str,
// Format breakpoints as GDBMI
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
CIDebugSymbols *symbols /* = 0 */,
+ CIDebugDataSpaces *dataSpaces /* = 0 */,
bool humanReadable, unsigned verbose, std::string *errorMessage)
{
ULONG breakPointCount = 0;
@@ -747,7 +798,7 @@ std::string gdbmiBreakpoints(CIDebugControl *ctrl,
*errorMessage = msgDebugEngineComFailed("GetBreakpointByIndex", hr);
return std::string();
}
- if (!gdbmiFormatBreakpoint(str, bp, symbols, verbose, errorMessage))
+ if (!gdbmiFormatBreakpoint(str, bp, symbols, dataSpaces, verbose, errorMessage))
return std::string();
str << '}';
if (humanReadable)
diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.h b/src/libs/qtcreatorcdbext/gdbmihelpers.h
index 4b77cc74919..7df20ad42e3 100644
--- a/src/libs/qtcreatorcdbext/gdbmihelpers.h
+++ b/src/libs/qtcreatorcdbext/gdbmihelpers.h
@@ -113,9 +113,14 @@ Modules getModules(CIDebugSymbols *syms, std::string *errorMessage);
// Format modules as GDBMI
std::string gdbmiModules(CIDebugSymbols *syms, bool humanReadable, std::string *errorMessage);
+// Helper for breakpoints. Return the memory range of a breakpoint
+// as pair(address, size). size is !=0 for data breakpoints.
+std::pair<ULONG64, ULONG> breakPointMemoryRange(IDebugBreakpoint *bp);
+
// Format breakpoints as GDBMI
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
CIDebugSymbols *symbols /* = 0 */,
+ CIDebugDataSpaces *dataSpaces /* = 0 */,
bool humanReadable,
unsigned verbose,
std::string *errorMessage);
@@ -158,8 +163,10 @@ std::string gdbmiRegisters(CIDebugRegisters *regs,
unsigned flags,
std::string *errorMessage);
-std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length, std::string *errorMessage);
-
+std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
+ std::string *errorMessage = 0);
+std::wstring memoryToHexW(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
+ std::string *errorMessage = 0);
// Stack helpers
StackFrames getStackTrace(CIDebugControl *debugControl, CIDebugSymbols *debugSymbols,
unsigned maxFrames, std::string *errorMessage);
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index 16b27585776..ae8c565be66 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -1043,7 +1043,8 @@ extern "C" HRESULT CALLBACK breakpoints(CIDebugClient *client, PCSTR argsIn)
}
tokens.pop_front();
}
- const std::string bp = gdbmiBreakpoints(exc.control(), exc.symbols(), humanReadable, verbose, &errorMessage);
+ const std::string bp = gdbmiBreakpoints(exc.control(), exc.symbols(), exc.dataSpaces(),
+ humanReadable, verbose, &errorMessage);
if (bp.empty()) {
ExtensionContext::instance().report('N', token, 0, "breakpoints", errorMessage.c_str());
} else {