summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-01-04 12:40:52 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-01-04 12:40:52 +0100
commitb7df5467d8b0d1540014c13b49f60e8827b7aa2a (patch)
tree419d2851014f5a76349e18b1eea8766c11a18cd2
parentd9ec7dd0a6da5384f2ddd7738a5d7fe40d30aad0 (diff)
downloadqt-creator-b7df5467d8b0d1540014c13b49f60e8827b7aa2a.tar.gz
Debugger[New CDB]: Split up long extension messages.
To accommodate the limitation of output line width of CDB.
-rw-r--r--src/libs/qtcreatorcdbext/eventcallback.cpp4
-rw-r--r--src/libs/qtcreatorcdbext/extensioncontext.cpp37
-rw-r--r--src/libs/qtcreatorcdbext/extensioncontext.h16
-rw-r--r--src/libs/qtcreatorcdbext/outputcallback.cpp2
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp50
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupnode.cpp6
-rw-r--r--src/plugins/debugger/cdb2/cdbengine2.cpp20
-rw-r--r--src/plugins/debugger/cdb2/cdbengine2.h1
8 files changed, 87 insertions, 49 deletions
diff --git a/src/libs/qtcreatorcdbext/eventcallback.cpp b/src/libs/qtcreatorcdbext/eventcallback.cpp
index 6fb65d7f67..68b129487f 100644
--- a/src/libs/qtcreatorcdbext/eventcallback.cpp
+++ b/src/libs/qtcreatorcdbext/eventcallback.cpp
@@ -173,7 +173,7 @@ STDMETHODIMP EventCallback::Exception(
std::ostringstream str;
formatGdbmiHash(str, parameters);
ExtensionContext::instance().setStopReason(parameters, "exception");
- ExtensionContext::instance().report('E', 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;
}
@@ -222,7 +222,7 @@ STDMETHODIMP EventCallback::ExitProcess(
__in ULONG ExitCode
)
{
- ExtensionContext::instance().report('E', 0, eventContextC, "Process exited (%lu)",
+ ExtensionContext::instance().report('E', 0, 0, eventContextC, "Process exited (%lu)",
ExitCode);
const HRESULT hr = m_wrapped ? m_wrapped->ExitProcess(ExitCode) : S_OK;
// Remotely debugged process exited, there is no session-inactive notification.
diff --git a/src/libs/qtcreatorcdbext/extensioncontext.cpp b/src/libs/qtcreatorcdbext/extensioncontext.cpp
index a6f633987e..2c32a1775e 100644
--- a/src/libs/qtcreatorcdbext/extensioncontext.cpp
+++ b/src/libs/qtcreatorcdbext/extensioncontext.cpp
@@ -37,6 +37,8 @@
#include "outputcallback.h"
#include "stringutils.h"
+#include <algorithm>
+
// wdbgexts.h declares 'extern WINDBG_EXTENSION_APIS ExtensionApis;'
// and it's inline functions rely on its existence.
WINDBG_EXTENSION_APIS ExtensionApis = {sizeof(WINDBG_EXTENSION_APIS), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -167,7 +169,7 @@ void ExtensionContext::notifyIdle()
// Format
std::ostringstream str;
formatGdbmiHash(str, stopReasons);
- report('E', 0, "session_idle", "%s", str.str().c_str());
+ reportLong('E', 0, "session_idle", str.str());
m_stopReason.clear();
}
@@ -176,16 +178,16 @@ void ExtensionContext::notifyState(ULONG Notify)
const ULONG ex = executionStatus();
switch (Notify) {
case DEBUG_NOTIFY_SESSION_ACTIVE:
- report('E', 0, "session_active", "%u", ex);
+ report('E', 0, 0, "session_active", "%u", ex);
break;
case DEBUG_NOTIFY_SESSION_ACCESSIBLE: // Meaning, commands accepted
- report('E', 0, "session_accessible", "%u", ex);
+ report('E', 0, 0, "session_accessible", "%u", ex);
break;
case DEBUG_NOTIFY_SESSION_INACCESSIBLE:
- report('E', 0, "session_inaccessible", "%u", ex);
+ report('E', 0, 0, "session_inaccessible", "%u", ex);
break;
case DEBUG_NOTIFY_SESSION_INACTIVE:
- report('E', 0, "session_inactive", "%u", ex);
+ report('E', 0, 0, "session_inactive", "%u", ex);
discardSymbolGroup();
// We lost the debuggee, at this point restore output.
if (ex & DEBUG_STATUS_NO_DEBUGGEE)
@@ -218,12 +220,13 @@ void ExtensionContext::discardSymbolGroup()
m_symbolGroup.reset();
}
-bool ExtensionContext::report(char code, int token, const char *serviceName, PCSTR Format, ...)
+bool ExtensionContext::report(char code, int token, int remainingChunks, const char *serviceName, PCSTR Format, ...)
{
if (!isInitialized())
return false;
// '<qtcreatorcdbext>|R|<token>|<serviceName>|<one-line-output>'.
- m_control->Output(DEBUG_OUTPUT_NORMAL, "<qtcreatorcdbext>|%c|%d|%s|", code, token, serviceName);
+ m_control->Output(DEBUG_OUTPUT_NORMAL, "<qtcreatorcdbext>|%c|%d|%d|%s|",
+ code, token, remainingChunks, serviceName);
va_list Args;
va_start(Args, Format);
m_control->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args);
@@ -232,6 +235,26 @@ bool ExtensionContext::report(char code, int token, const char *serviceName, PCS
return true;
}
+bool ExtensionContext::reportLong(char code, int token, const char *serviceName, const std::string &message)
+{
+ const std::string::size_type size = message.size();
+ if (size < outputChunkSize)
+ return report(code, token, 0, serviceName, "%s", message.c_str());
+ // Split up
+ std::string::size_type chunkCount = size / outputChunkSize;
+ if (size % outputChunkSize)
+ chunkCount++;
+ std::string::size_type pos = 0;
+ for (int remaining = int(chunkCount) - 1; remaining >= 0 ; remaining--) {
+ std::string::size_type nextPos = pos + outputChunkSize; // No consistent std::min/std::max in VS8/10
+ if (nextPos > size)
+ nextPos = size;
+ report(code, token, remaining, serviceName, "%s", message.substr(pos, nextPos - pos).c_str());
+ pos = nextPos;
+ }
+ return true;
+}
+
// Exported C-functions
extern "C" {
diff --git a/src/libs/qtcreatorcdbext/extensioncontext.h b/src/libs/qtcreatorcdbext/extensioncontext.h
index 1f7d6c56f4..4a7ee97682 100644
--- a/src/libs/qtcreatorcdbext/extensioncontext.h
+++ b/src/libs/qtcreatorcdbext/extensioncontext.h
@@ -68,11 +68,17 @@ public:
// Undo hooking.
void unhookCallbacks();
- // Report output in standardized format understood by Qt Creator.
- // '<qtcreatorcdbext>|R|<token>|<serviceName>|<one-line-output>'.
- // Char code is 'R' command reply, 'N' command fail, 'E' event notification
- bool report(char code, int token, const char *serviceName, PCSTR Format, ...);
-
+ // CDB has a limitation on output, so, long messages need to be split (empirically ca 10KB)
+ static const size_t outputChunkSize = 10240;
+ /* Report output in standardized format understood by Qt Creator.
+ * '<qtcreatorcdbext>|R|<token>|remainingChunks|<serviceName>|<one-line-output>'.
+ * Char code is 'R' command reply, 'N' command fail, 'E' event notification,
+ * 'X' exception, error. If the message is larger than outputChunkSize,
+ * it needs to be split up in chunks, remainingChunks needs to indicate the number
+ * of the following chunks (0 for just one chunk). */
+ bool report(char code, int remainingChunks, int token, const char *serviceName, PCSTR Format, ...);
+ // Convenience for reporting potentially long messages in chunks
+ bool reportLong(char code, int token, const char *serviceName, const std::string &message);
ULONG executionStatus() const;
// Call from notify handler, tell engine about state.
void notifyState(ULONG Notify);
diff --git a/src/libs/qtcreatorcdbext/outputcallback.cpp b/src/libs/qtcreatorcdbext/outputcallback.cpp
index 0ebe99f52b..5b01ffa46c 100644
--- a/src/libs/qtcreatorcdbext/outputcallback.cpp
+++ b/src/libs/qtcreatorcdbext/outputcallback.cpp
@@ -97,6 +97,6 @@ STDMETHODIMP OutputCallback::Output(
// Base encode as GDBMI is not really made for wide chars
std::ostringstream str;
base64Encode(str, reinterpret_cast<const unsigned char *>(text), sizeof(wchar_t) * std::wcslen(text));
- ExtensionContext::instance().report('E', 0, "debuggee_output", str.str().c_str());
+ ExtensionContext::instance().report('E', 0, 0, "debuggee_output", str.str().c_str());
return S_OK;
}
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index f2d87dd4cd..96a96d8802 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -235,9 +235,9 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
commandTokens<StringList>(args, &token);
if (const ULONG pid = currentProcessId(client)) {
- ExtensionContext::instance().report('R', token, "pid", "%u", pid);
+ ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
} else {
- ExtensionContext::instance().report('N', token, "pid", "0");
+ ExtensionContext::instance().report('N', token, 0, "pid", "0");
}
return S_OK;
}
@@ -277,7 +277,7 @@ extern "C" HRESULT CALLBACK expandlocals(CIDebugClient *client, PCSTR args)
symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), frame, &errorMessage);
if (!symGroup) {
- ExtensionContext::instance().report('N', token, "expandlocals", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "expandlocals", errorMessage.c_str());
return S_OK;
}
@@ -285,7 +285,7 @@ extern "C" HRESULT CALLBACK expandlocals(CIDebugClient *client, PCSTR args)
symGroup->expandListRunComplexDumpers(inames, SymbolGroupValueContext(exc.dataSpaces(), exc.symbols()), &errorMessage) :
symGroup->expandList(inames, &errorMessage);
- ExtensionContext::instance().report('R', token, "expandlocals", "%u/%u %s",
+ ExtensionContext::instance().report('R', token, 0, "expandlocals", "%u/%u %s",
succeeded, unsigned(inames.size()), errorMessage.c_str());
return S_OK;
}
@@ -403,9 +403,9 @@ extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
int token;
const std::string output = commmandLocals(exc, args, &token, &errorMessage);
if (output.empty()) {
- ExtensionContext::instance().report('N', token, "locals", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "locals", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "locals", "%s", output.c_str());
+ ExtensionContext::instance().reportLong('R', token, "locals", output);
}
return S_OK;
}
@@ -454,9 +454,9 @@ extern "C" HRESULT CALLBACK dumplocal(CIDebugClient *client, PCSTR argsIn)
int token = 0;
const std::string value = dumplocalHelper(exc,argsIn, &token, &errorMessage);
if (value.empty()) {
- ExtensionContext::instance().report('N', token, "dumplocal", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "dumplocal", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "dumplocal", value.c_str());
+ ExtensionContext::instance().reportLong('R', token, "dumplocal", value);
}
return S_OK;
}
@@ -483,9 +483,9 @@ extern "C" HRESULT CALLBACK typecast(CIDebugClient *client, PCSTR args)
errorMessage = singleLineUsage(commandDescriptions[CmdTypecast]);
}
if (symGroup != 0 && symGroup->typeCast(iname, desiredType, &errorMessage)) {
- ExtensionContext::instance().report('R', token, "typecast", "OK");
+ ExtensionContext::instance().report('R', token, 0, "typecast", "OK");
} else {
- ExtensionContext::instance().report('N', token, "typecast", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "typecast", errorMessage.c_str());
}
return S_OK;
}
@@ -513,9 +513,9 @@ extern "C" HRESULT CALLBACK addsymbol(CIDebugClient *client, PCSTR args)
errorMessage = singleLineUsage(commandDescriptions[CmdAddsymbol]);
}
if (symGroup != 0 && symGroup->addSymbol(name, iname, &errorMessage)) {
- ExtensionContext::instance().report('R', token, "addsymbol", "OK");
+ ExtensionContext::instance().report('R', token, 0, "addsymbol", "OK");
} else {
- ExtensionContext::instance().report('N', token, "addsymbol", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "addsymbol", errorMessage.c_str());
}
return S_OK;
}
@@ -554,9 +554,9 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn)
} while (false);
if (success) {
- ExtensionContext::instance().report('R', token, "assign", "Ok");
+ ExtensionContext::instance().report('R', token, 0, "assign", "Ok");
} else {
- ExtensionContext::instance().report('N', token, "assign", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "assign", errorMessage.c_str());
}
return S_OK;
}
@@ -578,9 +578,9 @@ extern "C" HRESULT CALLBACK threads(CIDebugClient *client, PCSTR argsIn)
exc.advanced(),
&errorMessage);
if (gdbmi.empty()) {
- ExtensionContext::instance().report('N', token, "threads", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "threads", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "threads", gdbmi.c_str());
+ ExtensionContext::instance().reportLong('R', token, "threads", gdbmi);
}
return S_OK;
}
@@ -598,9 +598,9 @@ extern "C" HRESULT CALLBACK registers(CIDebugClient *Client, PCSTR argsIn)
const bool humanReadable = !tokens.empty() && tokens.front() == "-h";
const std::string regs = gdbmiRegisters(exc.registers(), exc.control(), humanReadable, IncludePseudoRegisters, &errorMessage);
if (regs.empty()) {
- ExtensionContext::instance().report('N', token, "registers", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "registers", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "registers", regs.c_str());
+ ExtensionContext::instance().reportLong('R', token, "registers", regs);
}
return S_OK;
}
@@ -618,9 +618,9 @@ extern "C" HRESULT CALLBACK modules(CIDebugClient *Client, PCSTR argsIn)
const bool humanReadable = !tokens.empty() && tokens.front() == "-h";
const std::string modules = gdbmiModules(exc.symbols(), humanReadable, &errorMessage);
if (modules.empty()) {
- ExtensionContext::instance().report('N', token, "modules", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "modules", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "modules", modules.c_str());
+ ExtensionContext::instance().reportLong('R', token, "modules", modules);
}
return S_OK;
}
@@ -671,11 +671,11 @@ extern "C" HRESULT CALLBACK memory(CIDebugClient *Client, PCSTR argsIn)
}
if (memory.empty()) {
- ExtensionContext::instance().report('N', token, "memory", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "memory", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "memory", memory.c_str());
+ ExtensionContext::instance().reportLong('R', token, "memory", memory);
if (!errorMessage.empty())
- ExtensionContext::instance().report('W', token, "memory", errorMessage.c_str());
+ ExtensionContext::instance().report('W', token, 0, "memory", errorMessage.c_str());
}
return S_OK;
}
@@ -704,9 +704,9 @@ extern "C" HRESULT CALLBACK stack(CIDebugClient *Client, PCSTR argsIn)
maxFrames, humanReadable, &errorMessage);
if (stack.empty()) {
- ExtensionContext::instance().report('N', token, "stack", errorMessage.c_str());
+ ExtensionContext::instance().report('N', token, 0, "stack", errorMessage.c_str());
} else {
- ExtensionContext::instance().report('R', token, "stack", stack.c_str());
+ ExtensionContext::instance().reportLong('R', token, "stack", stack);
}
return S_OK;
}
diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
index e7470eb6d6..f17d2f7682 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
@@ -950,7 +950,7 @@ bool SymbolGroupNode::expand(std::string *errorMessage)
if (FAILED(hr)) {
*errorMessage = msgExpandFailed(name(), absoluteFullIName(), m_index, msgDebugEngineComFailed("ExpandSymbol", hr));
- ExtensionContext::instance().report('X', 0, "Error", "%s", errorMessage->c_str());
+ ExtensionContext::instance().report('X', 0, 0, "Error", "%s", errorMessage->c_str());
return false;
}
SymbolGroup::SymbolParameterVector parameters;
@@ -1020,12 +1020,12 @@ SymbolGroupNode *SymbolGroupNode::addSymbolByName(const std::string &name,
HRESULT hr = m_symbolGroup->debugSymbolGroup()->AddSymbol(name.c_str(), &index);
if (FAILED(hr)) {
*errorMessage = msgCannotAddSymbol(name, msgDebugEngineComFailed("AddSymbol", hr));
- ExtensionContext::instance().report('X', 0, "Error", "%s", errorMessage->c_str());
+ ExtensionContext::instance().report('X', 0, 0, "Error", "%s", errorMessage->c_str());
return 0;
}
if (index == DEBUG_ANY_ID) { // Occasionally happens for unknown or 'complicated' types
*errorMessage = msgCannotAddSymbol(name, "DEBUG_ANY_ID was returned as symbol index by AddSymbol.");
- ExtensionContext::instance().report('X', 0, "Error", "%s", errorMessage->c_str());
+ ExtensionContext::instance().report('X', 0, 0, "Error", "%s", errorMessage->c_str());
return 0;
}
SymbolParameterVector parameters(1, DEBUG_SYMBOL_PARAMETERS());
diff --git a/src/plugins/debugger/cdb2/cdbengine2.cpp b/src/plugins/debugger/cdb2/cdbengine2.cpp
index 7b3e64baab..7418a2864d 100644
--- a/src/plugins/debugger/cdb2/cdbengine2.cpp
+++ b/src/plugins/debugger/cdb2/cdbengine2.cpp
@@ -1585,23 +1585,31 @@ void CdbEngine::parseOutputLine(QByteArray line)
// can mix things up.
while (isCdbPrompt(line))
line.remove(0, CdbPromptLength);
- // An extension notification
+ // An extension notification (potentially consisting of several chunks)
if (line.startsWith(m_creatorExtPrefix)) {
- // "<qtcreatorcdbext>|type_char|token|serviceName|message"
+ // "<qtcreatorcdbext>|type_char|token|remainingChunks|serviceName|message"
const char type = line.at(m_creatorExtPrefix.size());
// integer token
const int tokenPos = m_creatorExtPrefix.size() + 2;
const int tokenEndPos = line.indexOf('|', tokenPos);
QTC_ASSERT(tokenEndPos != -1, return)
const int token = line.mid(tokenPos, tokenEndPos - tokenPos).toInt();
+ // remainingChunks
+ const int remainingChunksPos = tokenEndPos + 1;
+ const int remainingChunksEndPos = line.indexOf('|', remainingChunksPos);
+ QTC_ASSERT(remainingChunksEndPos != -1, return)
+ const int remainingChunks = line.mid(remainingChunksPos, remainingChunksEndPos - remainingChunksPos).toInt();
// const char 'serviceName'
- const int whatPos = tokenEndPos + 1;
+ const int whatPos = remainingChunksEndPos + 1;
const int whatEndPos = line.indexOf('|', whatPos);
QTC_ASSERT(whatEndPos != -1, return)
const QByteArray what = line.mid(whatPos, whatEndPos - whatPos);
- // Message
- const QByteArray message = line.mid(whatEndPos + 1);
- handleExtensionMessage(type, token, what, message);
+ // Build up buffer, call handler once last chunk was encountered
+ m_extensionMessageBuffer += line.mid(whatEndPos + 1);
+ if (remainingChunks == 0) {
+ handleExtensionMessage(type, token, what, m_extensionMessageBuffer);
+ m_extensionMessageBuffer.clear();
+ }
return;
}
// Check for command start/end tokens within which the builtin command
diff --git a/src/plugins/debugger/cdb2/cdbengine2.h b/src/plugins/debugger/cdb2/cdbengine2.h
index 3f8d3e6157..fa2b7c9f41 100644
--- a/src/plugins/debugger/cdb2/cdbengine2.h
+++ b/src/plugins/debugger/cdb2/cdbengine2.h
@@ -205,6 +205,7 @@ private:
bool m_hasDebuggee;
QTime m_logTime;
mutable int m_elapsedLogTime;
+ QByteArray m_extensionMessageBuffer;
};
} // namespace Cdb