Commit 285d216b authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debuggeri[CDB]: Add breakpoint command.

Report back breakpoints with modules.
parent acb36acf
......@@ -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);
}
......@@ -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__);
......
......@@ -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;
}
......
......@@ -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());
}
......
......@@ -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;
......
......@@ -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();
}
......@@ -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
{
......
......@@ -21,4 +21,5 @@ test
stack
addwatch
widgetat
breakpoints
KnownStructOutput
......@@ -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 };
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment