debugger: workaround failing 'info locals' on gdb 6.8-symbianelf

This commit is contained in:
hjk
2010-01-14 15:25:53 +01:00
parent 0cadbd85de
commit dd118df7cb
3 changed files with 161 additions and 76 deletions

View File

@@ -32,8 +32,8 @@ def isGoodGdb():
return 'parse_and_eval' in dir(gdb) return 'parse_and_eval' in dir(gdb)
def cleanAddress(addr): def cleanAddress(addr):
# we cannot use str(addr) as it yields rubbish for char pointers # We cannot use str(addr) as it yields rubbish for char pointers
# that might trigger Unicode encoding errors # that might trigger Unicode encoding errors.
return addr.cast(gdb.lookup_type("void").pointer()) return addr.cast(gdb.lookup_type("void").pointer())
def parseAndEvaluate(exp): def parseAndEvaluate(exp):
@@ -50,17 +50,27 @@ def parseAndEvaluate(exp):
gdb.execute("set logging off") gdb.execute("set logging off")
return gdb.history(0) return gdb.history(0)
def listOfLocals(): def listOfLocals(varList):
try: try:
frame = gdb.selected_frame() frame = gdb.selected_frame()
#warn("FRAME %s: " % frame) #warn("FRAME %s: " % frame)
except RuntimeError: except RuntimeError:
warn("FRAME NOT ACCESSIBLE")
return [] return []
# gdb-6.8-symbianelf fails here
hasBlock = 'block' in dir(frame)
items = [] items = []
if isGoodGdb(): if hasBlock and isGoodGdb():
# archer-tromey-python warn("IS GOOD: %s " % varList)
block = frame.block() try:
block = frame.block()
#warn("BLOCK: %s " % block)
except:
warn("BLOCK NOT ACCESSIBLE")
return items
while True: while True:
if block is None: if block is None:
warn("UNEXPECTED 'None' BLOCK") warn("UNEXPECTED 'None' BLOCK")
@@ -94,31 +104,55 @@ def listOfLocals():
# Assuming gdb 7.0 release or 6.8-symbianelf. # Assuming gdb 7.0 release or 6.8-symbianelf.
file = tempfile.mkstemp(prefix="gdbpy_") file = tempfile.mkstemp(prefix="gdbpy_")
filename = file[1] filename = file[1]
#warn("VARLIST: %s " % varList)
#warn("VARLIST: %s " % len(varList))
gdb.execute("set logging off") gdb.execute("set logging off")
gdb.execute("set logging redirect off") gdb.execute("set logging redirect off")
gdb.execute("set logging file %s" % filename) gdb.execute("set logging file %s" % filename)
gdb.execute("set logging redirect on") gdb.execute("set logging redirect on")
gdb.execute("set logging on") gdb.execute("set logging on")
gdb.execute("info locals") try:
gdb.execute("info args") gdb.execute("info args")
# We cannot use "info locals" as at least 6.8-symbianelf
# aborts as soon as we hit unreadable memory.
# gdb.execute("interpreter mi '-stack-list-locals 0'")
# results in &"Recursive internal problem.\n", so we have
# the frontend pass us the list of locals.
# There are two cases, either varList is empty, so we have
# to fetch the list here, or it is not empty with the
# first entry being a dummy.
if len(varList) == 0:
gdb.execute("info locals")
else:
varList = varList[1:]
except:
pass
gdb.execute("set logging off") gdb.execute("set logging off")
gdb.execute("set logging redirect off") gdb.execute("set logging redirect off")
file = open(filename, "r") file = open(filename, "r")
for line in file: for line in file:
if len(line) == 0 or line.startswith(" "): if len(line) == 0 or line.startswith(" "):
continue continue
# The function parameters
pos = line.find(" = ") pos = line.find(" = ")
if pos < 0: if pos < 0:
continue continue
name = line[0:pos] varList.append(line[0:pos])
file.close()
os.remove(filename)
#warn("VARLIST: %s " % varList)
for name in varList:
#warn("NAME %s " % name)
item = Item(0, "local", name, name) item = Item(0, "local", name, name)
try: try:
item.value = frame.read_var(name) # this is a gdb value item.value = frame.read_var(name) # this is a gdb value
except RuntimeError: except RuntimeError:
continue pass
#continue
items.append(item) items.append(item)
file.close()
os.remove(filename)
return items return items
@@ -155,8 +189,8 @@ def isStringType(d, typeobj):
or type == "wstring" or type == "wstring"
def warn(message): def warn(message):
if verbosity > 0: if True or verbosity > 0:
print "XXX: %s " % message.encode("latin1") print "XXX: %s\n" % message.encode("latin1")
pass pass
def check(exp): def check(exp):
@@ -317,13 +351,24 @@ class FrameCommand(gdb.Command):
def invoke(self, arg, from_tty): def invoke(self, arg, from_tty):
args = arg.split(' ') args = arg.split(' ')
#warn("ARG: %s" % arg) #warn("ARG: %s" % arg)
#warn("ARGS: %s" % args) #warn("ARGS: %s" % args)
options = args[0].split(",") options = args[0].split(",")
varList = args[1][1:]
if len(varList) == 0:
varList = []
else:
varList = varList.split(",")
expandedINames = set(args[2].split(","))
watchers = ""
if len(args) > 3:
watchers = base64.b16decode(args[3], True)
#warn("WATCHERS: %s" % watchers)
useFancy = "fancy" in options useFancy = "fancy" in options
expandedINames = set()
if len(args) > 1: #warn("VARIABLES: %s" % varList)
expandedINames = set(args[1].split(","))
#warn("EXPANDED INAMES: %s" % expandedINames) #warn("EXPANDED INAMES: %s" % expandedINames)
module = sys.modules[__name__] module = sys.modules[__name__]
self.dumpers = {} self.dumpers = {}
@@ -337,7 +382,7 @@ class FrameCommand(gdb.Command):
output += '"' + key[7:] + '"' output += '"' + key[7:] + '"'
output += "]," output += "],"
#output += "qtversion=[%d,%d,%d]" #output += "qtversion=[%d,%d,%d]"
output += "qtversion=[4,6,0]," #output += "qtversion=[4,6,0],"
output += "namespace=\"%s\"," % qtNamespace() output += "namespace=\"%s\"," % qtNamespace()
output += "dumperversion=\"2.0\"," output += "dumperversion=\"2.0\","
output += "sizes=[]," output += "sizes=[],"
@@ -349,7 +394,6 @@ class FrameCommand(gdb.Command):
if useFancy: if useFancy:
for key, value in module.__dict__.items(): for key, value in module.__dict__.items():
#if callable(value):
if key.startswith("qdump__"): if key.startswith("qdump__"):
self.dumpers[key[7:]] = value self.dumpers[key[7:]] = value
@@ -365,14 +409,28 @@ class FrameCommand(gdb.Command):
# #
# Locals # Locals
# #
for item in listOfLocals(): for item in listOfLocals(varList):
#warn("ITEM NAME %s: " % item.name) #warn("ITEM NAME %s: " % item.name)
#warn("ITEM VALUE %s: " % item.value) try:
#warn("ITEM VALUE %s: " % item.value)
# Throw on funny stuff, catch below.
dummy = str(item.value)
except:
# Locals with failing memory access.
d.beginHash()
d.put('iname="%s",' % item.iname)
d.put('name="%s",' % item.name)
d.put('addr="<not accessible>",')
d.put('value="<not accessible>",')
d.put('type="%s",' % item.value.type)
d.put('numchild="0"');
d.endHash()
continue
type = item.value.type type = item.value.type
if type.code == gdb.TYPE_CODE_PTR \ if type.code == gdb.TYPE_CODE_PTR \
and item.name == "argv" and str(type) == "char **": and item.name == "argv" and str(type) == "char **":
# Special handling for char** argv: # Special handling for char** argv.
n = 0 n = 0
p = item.value p = item.value
while not isNull(p.dereference()) and n <= 100: while not isNull(p.dereference()) and n <= 100:
@@ -398,7 +456,7 @@ class FrameCommand(gdb.Command):
d.endHash() d.endHash()
else: else:
# A "normal" local variable or parameter # A "normal" local variable or parameter.
try: try:
addr = cleanAddress(item.value.address) addr = cleanAddress(item.value.address)
d.beginHash() d.beginHash()
@@ -407,9 +465,8 @@ class FrameCommand(gdb.Command):
d.safePutItemHelper(item) d.safePutItemHelper(item)
d.endHash() d.endHash()
except AttributeError: except AttributeError:
# thrown by cleanAddreas with message # Thrown by cleanAddress with message "'NoneType' object
# "'NoneType' object has no attribute 'cast'" # has no attribute 'cast'" for optimized-out values.
# for optimized-out values
d.beginHash() d.beginHash()
d.put('iname="%s",' % item.iname) d.put('iname="%s",' % item.iname)
d.put('name="%s",' % item.name) d.put('name="%s",' % item.name)
@@ -426,9 +483,6 @@ class FrameCommand(gdb.Command):
# Watchers # Watchers
# #
d.safeoutput = "" d.safeoutput = ""
watchers = ""
if len(args) > 2:
watchers = base64.b16decode(args[2], True)
if len(watchers) > 0: if len(watchers) > 0:
for watcher in watchers.split("##"): for watcher in watchers.split("##"):
(exp, iname) = watcher.split("#") (exp, iname) = watcher.split("#")
@@ -764,7 +818,8 @@ class Dumper:
#warn("REAL VALUE: %s " % item.value) #warn("REAL VALUE: %s " % item.value)
#try: #try:
# warn("REAL VALUE: %s " % item.value) # warn("REAL VALUE: %s " % item.value)
#except UnicodeEncodeError: #except:
# #UnicodeEncodeError:
# warn("REAL VALUE: <unprintable>") # warn("REAL VALUE: <unprintable>")
value = item.value value = item.value

View File

@@ -743,7 +743,7 @@ void GdbEngine::postCommand(const QByteArray &command, GdbCommandFlags flags,
void GdbEngine::postCommandHelper(const GdbCommand &cmd) void GdbEngine::postCommandHelper(const GdbCommand &cmd)
{ {
if (!stateAcceptsGdbCommands(state())) { if (!stateAcceptsGdbCommands(state())) {
PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + cmd.command); PENDING_DEBUG(_("NO GDB PROCESS RUNNING, CMD IGNORED: " + cmd.command));
debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2") debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: %1 %2")
.arg(_(cmd.command)).arg(state())); .arg(_(cmd.command)).arg(state()));
return; return;
@@ -1019,6 +1019,7 @@ void GdbEngine::executeDebuggerCommand(const QString &command)
// Called from CoreAdapter and AttachAdapter // Called from CoreAdapter and AttachAdapter
void GdbEngine::updateAll() void GdbEngine::updateAll()
{ {
PENDING_DEBUG("UPDATING ALL\n");
QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/); QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/);
tryLoadDebuggingHelpers(); tryLoadDebuggingHelpers();
reloadModulesInternal(); reloadModulesInternal();
@@ -2469,12 +2470,14 @@ void GdbEngine::handleStackSelectThread(const GdbResponse &)
void GdbEngine::reloadFullStack() void GdbEngine::reloadFullStack()
{ {
PENDING_DEBUG("RELOAD FULL STACK");
postCommand("-stack-list-frames", WatchUpdate, CB(handleStackListFrames), postCommand("-stack-list-frames", WatchUpdate, CB(handleStackListFrames),
QVariant::fromValue<StackCookie>(StackCookie(true, true))); QVariant::fromValue<StackCookie>(StackCookie(true, true)));
} }
void GdbEngine::reloadStack(bool forceGotoLocation) void GdbEngine::reloadStack(bool forceGotoLocation)
{ {
PENDING_DEBUG("RELOAD STACK");
QByteArray cmd = "-stack-list-frames"; QByteArray cmd = "-stack-list-frames";
int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt(); int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt();
if (stackDepth && !m_gdbAdapter->isTrkAdapter()) if (stackDepth && !m_gdbAdapter->isTrkAdapter())
@@ -2485,6 +2488,7 @@ void GdbEngine::reloadStack(bool forceGotoLocation)
// access the memory belonging to the lower frames. But as we know // access the memory belonging to the lower frames. But as we know
// this sometimes happens, ask the second time immediately instead // this sometimes happens, ask the second time immediately instead
// of waiting for the first request to fail. // of waiting for the first request to fail.
// FIXME: Seems to work with 6.8.
if (m_gdbAdapter->isTrkAdapter()) if (m_gdbAdapter->isTrkAdapter())
postCommand(cmd, WatchUpdate); postCommand(cmd, WatchUpdate);
postCommand(cmd, WatchUpdate, CB(handleStackListFrames), postCommand(cmd, WatchUpdate, CB(handleStackListFrames),
@@ -3640,52 +3644,12 @@ void GdbEngine::updateLocals(const QVariant &cookie)
{ {
m_pendingRequests = 0; m_pendingRequests = 0;
if (isSynchroneous()) { if (isSynchroneous()) {
m_processedNames.clear(); if (m_gdbAdapter->isTrkAdapter()) {
manager()->watchHandler()->beginCycle(); postCommand("-stack-list-locals 0",
//m_toolTipExpression.clear(); WatchUpdate, CB(handleStackListLocals0));
WatchHandler *handler = m_manager->watchHandler(); } else {
updateLocalsSync(QByteArray());
QByteArray expanded;
QSet<QByteArray> expandedINames = handler->expandedINames();
QSetIterator<QByteArray> jt(expandedINames);
while (jt.hasNext()) {
expanded.append(jt.next());
expanded.append(',');
} }
if (expanded.isEmpty())
expanded.append("defaults,");
expanded.chop(1);
QByteArray watchers;
if (!m_toolTipExpression.isEmpty())
watchers += m_toolTipExpression.toLatin1()
+ "#" + tooltipINameForExpression(m_toolTipExpression.toLatin1());
QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames);
while (it.hasNext()) {
it.next();
if (!watchers.isEmpty())
watchers += "##";
if (it.key() == WatchHandler::watcherEditPlaceHolder().toLatin1())
watchers += "<Edit>#watch." + QByteArray::number(it.value());
else
watchers += it.key() + "#watch." + QByteArray::number(it.value());
}
QByteArray options;
if (theDebuggerBoolSetting(UseDebuggingHelpers))
options += "fancy,";
if (theDebuggerBoolSetting(AutoDerefPointers))
options += "autoderef,";
if (options.isEmpty())
options += "defaults,";
options.chop(1);
postCommand("-interpreter-exec console \"bb "
+ options + ' ' + expanded + ' ' + watchers.toHex() + '"',
Discardable,
CB(handleStackFrame));
} else { } else {
m_processedNames.clear(); m_processedNames.clear();
@@ -3710,6 +3674,69 @@ void GdbEngine::updateLocals(const QVariant &cookie)
} }
} }
void GdbEngine::handleStackListLocals0(const GdbResponse &response)
{
if (response.resultClass == GdbResultDone) {
// 44^done,data={locals=[name="model",name="backString",...]}
QByteArray varList = "vars"; // Dummy entry, will be stripped by dumper.
foreach (const GdbMi &child, response.data.findChild("locals").children()) {
varList.append(',');
varList.append(child.data());
}
updateLocalsSync(varList);
}
}
void GdbEngine::updateLocalsSync(const QByteArray &varList)
{
m_processedNames.clear();
manager()->watchHandler()->beginCycle();
//m_toolTipExpression.clear();
WatchHandler *handler = m_manager->watchHandler();
QByteArray expanded;
QSet<QByteArray> expandedINames = handler->expandedINames();
QSetIterator<QByteArray> jt(expandedINames);
while (jt.hasNext()) {
expanded.append(jt.next());
expanded.append(',');
}
if (expanded.isEmpty())
expanded.append("defaults,");
expanded.chop(1);
QByteArray watchers;
if (!m_toolTipExpression.isEmpty())
watchers += m_toolTipExpression.toLatin1()
+ "#" + tooltipINameForExpression(m_toolTipExpression.toLatin1());
QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames);
while (it.hasNext()) {
it.next();
if (!watchers.isEmpty())
watchers += "##";
if (it.key() == WatchHandler::watcherEditPlaceHolder().toLatin1())
watchers += "<Edit>#watch." + QByteArray::number(it.value());
else
watchers += it.key() + "#watch." + QByteArray::number(it.value());
}
QByteArray options;
if (theDebuggerBoolSetting(UseDebuggingHelpers))
options += "fancy,";
if (theDebuggerBoolSetting(AutoDerefPointers))
options += "autoderef,";
if (options.isEmpty())
options += "defaults,";
options.chop(1);
postCommand("bb " + options + " @" + varList + ' '
+ expanded + ' ' + watchers.toHex(),
WatchUpdate, CB(handleStackFrame));
}
void GdbEngine::handleStackFrame(const GdbResponse &response) void GdbEngine::handleStackFrame(const GdbResponse &response)
{ {
if (response.resultClass == GdbResultDone) { if (response.resultClass == GdbResultDone) {

View File

@@ -450,6 +450,7 @@ private: ////////// View & Data Stuff //////////
void updateLocals(const QVariant &cookie = QVariant()); void updateLocals(const QVariant &cookie = QVariant());
void handleStackListLocals(const GdbResponse &response); void handleStackListLocals(const GdbResponse &response);
void handleStackListLocals0(const GdbResponse &response);
WatchData localVariable(const GdbMi &item, WatchData localVariable(const GdbMi &item,
const QStringList &uninitializedVariables, const QStringList &uninitializedVariables,
QMap<QByteArray, int> *seen); QMap<QByteArray, int> *seen);
@@ -484,6 +485,8 @@ private: ////////// Convenience Functions //////////
int buttons = 0); int buttons = 0);
void debugMessage(const QString &msg); void debugMessage(const QString &msg);
QMainWindow *mainWindow() const; QMainWindow *mainWindow() const;
void updateLocalsSync(const QByteArray &varList);
}; };
} // namespace Internal } // namespace Internal