Commit 476dda1b authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debugger[New CDB]: Fix stepping issues, forced shutdown, values.

- Do not report start-up trap as stop reason should one trigger
  while stepping.
- Set current frame to first usable frame, avoiding disassembly
  while stepping
- Kill process in case of forced shutdown with pending (long)
  commands.
- SymbolGroupValue: Do a quick check for accessible values
  and mark failure as 'invalid'.
- Introduce flag indicating existence of simple dumpers to types.
parent b4e42106
......@@ -39,27 +39,28 @@ enum KnownType
KT_Qt_MovableType = 0x40000,
KT_STL_Type = 0x80000,
KT_ContainerType = 0x100000,
KT_HasSimpleDumper = 0x200000,
// Qt Basic
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + 1,
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + 2,
KT_QString = KT_Qt_Type + KT_Qt_MovableType + 3,
KT_QColor = KT_Qt_Type + 4,
KT_QFlags = KT_Qt_Type + 5,
KT_QDate = KT_Qt_Type + KT_Qt_MovableType + 6,
KT_QTime = KT_Qt_Type + KT_Qt_MovableType + 7,
KT_QPoint = KT_Qt_Type + KT_Qt_MovableType + 8,
KT_QPointF = KT_Qt_Type +KT_Qt_MovableType + 9,
KT_QSize = KT_Qt_Type + KT_Qt_MovableType + 11,
KT_QSizeF = KT_Qt_Type + KT_Qt_MovableType + 12,
KT_QLine = KT_Qt_Type + KT_Qt_MovableType + 13,
KT_QLineF = KT_Qt_Type + KT_Qt_MovableType + 14,
KT_QRect = KT_Qt_Type + KT_Qt_MovableType + 15,
KT_QRectF = KT_Qt_Type + KT_Qt_MovableType + 16,
KT_QVariant = KT_Qt_Type + KT_Qt_MovableType + 17,
KT_QBasicAtomicInt = KT_Qt_Type + 18,
KT_QAtomicInt = KT_Qt_Type + 19,
KT_QObject = KT_Qt_Type + 20,
KT_QWidget = KT_Qt_Type + 21,
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2,
KT_QString = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 3,
KT_QColor = KT_Qt_Type + KT_HasSimpleDumper + 4,
KT_QFlags = KT_Qt_Type + KT_HasSimpleDumper + 5,
KT_QDate = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 6,
KT_QTime = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 7,
KT_QPoint = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 8,
KT_QPointF = KT_Qt_Type +KT_Qt_MovableType + KT_HasSimpleDumper + 9,
KT_QSize = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 11,
KT_QSizeF = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 12,
KT_QLine = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 13,
KT_QLineF = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 14,
KT_QRect = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 15,
KT_QRectF = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 16,
KT_QVariant = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 17,
KT_QBasicAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 18,
KT_QAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 19,
KT_QObject = KT_Qt_Type + KT_HasSimpleDumper + 20,
KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + 21,
// Various QT movable types
KT_QPen = KT_Qt_Type + KT_Qt_MovableType + 30,
KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31,
......@@ -130,28 +131,28 @@ enum KnownType
KT_QGlyphJustification = KT_Qt_Type + KT_Qt_PrimitiveType + 97,
KT_QPainterPath_Element = KT_Qt_Type + KT_Qt_PrimitiveType + 98,
// Qt Containers
KT_QStringList = KT_Qt_Type + KT_ContainerType + 1,
KT_QList = KT_Qt_Type + KT_ContainerType + 2,
KT_QLinkedList = KT_Qt_Type + KT_ContainerType + 3,
KT_QVector = KT_Qt_Type + KT_ContainerType + 4,
KT_QStack = KT_Qt_Type + KT_ContainerType + 5,
KT_QQueue = KT_Qt_Type + KT_ContainerType + 6,
KT_QSet = KT_Qt_Type + KT_ContainerType + 7,
KT_QHash = KT_Qt_Type + KT_ContainerType + 8,
KT_QMultiHash = KT_Qt_Type + KT_ContainerType + 9,
KT_QMap = KT_Qt_Type + KT_ContainerType + 10,
KT_QMultiMap = KT_Qt_Type + KT_ContainerType + 11,
KT_QStringList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 1,
KT_QList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 2,
KT_QLinkedList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 3,
KT_QVector = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 4,
KT_QStack = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 5,
KT_QQueue = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 6,
KT_QSet = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 7,
KT_QHash = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 8,
KT_QMultiHash = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 9,
KT_QMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 10,
KT_QMultiMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 11,
// STL
KT_StdString = KT_STL_Type + 1,
KT_StdWString = KT_STL_Type + 2,
KT_StdString = KT_STL_Type + KT_HasSimpleDumper + 1,
KT_StdWString = KT_STL_Type + KT_HasSimpleDumper + 2,
// STL containers
KT_StdVector = KT_STL_Type + KT_ContainerType + 1,
KT_StdList = KT_STL_Type + KT_ContainerType + 2,
KT_StdStack = KT_STL_Type + KT_ContainerType + 3,
KT_StdDeque = KT_STL_Type + KT_ContainerType + 4,
KT_StdSet = KT_STL_Type + KT_ContainerType + 5,
KT_StdMap = KT_STL_Type + KT_ContainerType + 6,
KT_StdMultiMap = KT_STL_Type + KT_ContainerType + 7,
KT_StdVector = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 1,
KT_StdList = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 2,
KT_StdStack = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 3,
KT_StdDeque = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 4,
KT_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5,
KT_StdMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 6,
KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7,
};
#endif // KNOWNTYPE_H
......@@ -736,6 +736,19 @@ std::wstring SymbolGroupNode::symbolGroupFixedValue() const
return value;
}
// A quick check if symbol is valid by checking for inaccessible value
bool SymbolGroupNode::isMemoryAccessible() const
{
static const char notAccessibleValueC[] = "<Memory access error>";
char buffer[sizeof(notAccessibleValueC)];
ULONG obtained = 0;
if (FAILED(symbolGroup()->debugSymbolGroup()->GetSymbolValueText(m_index, buffer, sizeof(notAccessibleValueC), &obtained)))
return false;
if (obtained < sizeof(notAccessibleValueC))
return true;
return strcmp(buffer, notAccessibleValueC) != 0;
}
// Complex dumpers: Get container/fake children
void SymbolGroupNode::runComplexDumpers(const SymbolGroupValueContext &ctx)
{
......
......@@ -224,6 +224,8 @@ public:
std::wstring symbolGroupRawValue() const;
std::wstring symbolGroupFixedValue() const;
// A quick check if symbol is valid by checking for inaccessible value
bool isMemoryAccessible() const;
std::string type() const;
int dumperType() const { return m_dumperType; } // Valid after dumper run
......
......@@ -38,6 +38,8 @@ SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
const SymbolGroupValueContext &ctx) :
m_node(node), m_context(ctx)
{
if (m_node && !m_node->isMemoryAccessible()) // Invalid if no value
m_node = 0;
}
SymbolGroupValue::SymbolGroupValue() :
......@@ -90,6 +92,11 @@ std::string SymbolGroupValue::type() const
return isValid() ? m_node->type() : std::string();
}
std::string SymbolGroupValue::name() const
{
return isValid() ? m_node->name() : std::string();
}
unsigned SymbolGroupValue::size() const
{
return isValid() ? m_node->size() : 0;
......@@ -300,6 +307,17 @@ std::vector<std::string> SymbolGroupValue::innerTypesOf(const std::string &t)
return rc;
}
std::ostream &operator<<(std::ostream &str, const SymbolGroupValue &v)
{
if (v) {
str << '\'' << v.name() << "' 0x" << std::showbase << std::hex << v.address() <<
std::dec << ' ' << v.type() << ": '" << wStringToString(v.value()) << '\'';
} else {
str << "Invalid value '" << v.error() << '\'';
}
return str;
}
// -------------------- Simple dumping helpers
// Courtesy of qdatetime.cpp
......@@ -1099,7 +1117,7 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
if (knownTypeIn)
*knownTypeIn = kt;
if (kt == KT_Unknown) {
if (kt == KT_Unknown || !(kt & KT_HasSimpleDumper)) {
QTC_TRACE_OUT
return SymbolGroupNode::SimpleDumperNotApplicable;
}
......
......@@ -68,6 +68,7 @@ public:
// take pointer value and cast to desired (pointer) type
SymbolGroupValue pointerTypeCast(const char *type) const;
std::string name() const;
std::string type() const;
std::vector<std::string> innerTypes() const { return innerTypesOf(type()); }
std::wstring value() const;
......@@ -107,6 +108,9 @@ private:
mutable std::string m_errorMessage;
};
// For debugging purposes
std::ostream &operator<<(std::ostream &, const SymbolGroupValue &v);
/* Helpers for detecting types reported from IDebugSymbolGroup
* 1) Class prefix==true is applicable to outer types obtained from
* from IDebugSymbolGroup: 'class foo' or 'struct foo'.
......
......@@ -523,6 +523,11 @@ void CdbEngine::runEngine()
postCommand("g", 0);
}
bool CdbEngine::commandsPending() const
{
return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}
void CdbEngine::shutdownInferior()
{
if (debug)
......@@ -535,7 +540,7 @@ void CdbEngine::shutdownInferior()
notifyInferiorShutdownOk();
return;
}
if (!canInterruptInferior()) {
if (!canInterruptInferior() || commandsPending()) {
notifyInferiorShutdownFailed();
return;
}
......@@ -562,8 +567,10 @@ void CdbEngine::shutdownInferior()
void CdbEngine::shutdownEngine()
{
if (debug)
qDebug("CdbEngine::shutdownEngine in state '%s', process running %d",
stateName(state()), isCdbProcessRunning());
qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
"accessible=%d,commands pending=%d",
stateName(state()), isCdbProcessRunning(), m_accessible,
commandsPending());
if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
if (debug)
......@@ -572,8 +579,12 @@ void CdbEngine::shutdownEngine()
return;
}
// detach: Wait for debugger to finish.
if (m_accessible) {
// No longer trigger anything from messages
disconnect(&m_process, SIGNAL(readyReadStandardOutput()), this, 0);
disconnect(&m_process, SIGNAL(readyReadStandardError()), this, 0);
// Go for kill if there are commands pending.
if (m_accessible && !commandsPending()) {
// detach: Wait for debugger to finish.
if (startParameters().startMode == AttachExternal)
detachDebugger();
// Remote requires a bit more force to quit.
......@@ -1351,6 +1362,10 @@ void CdbEngine::handleSessionIdle(const QByteArray &message)
WinException exception;
exception.fromGdbMI(stopReason);
#ifdef Q_OS_WIN
// It is possible to hit on a startup trap while stepping (if something
// pulls DLLs. Avoid showing a 'stopped' Message box.
if (exception.exceptionCode == winExceptionStartupCompleteTrap)
return;
if (Debugger::Internal::isDebuggerWinException(exception.exceptionCode)) {
showStatusMessage(msgInterrupted());
return;
......@@ -1845,7 +1860,7 @@ void CdbEngine::handleStackTrace(const CdbExtensionCommandPtr &command)
for (int i = 0; i < count; i++) {
if (!frames.at(i).file.isEmpty()) {
frames[i].file = QDir::cleanPath(normalizeFileName(frames.at(i).file));
if (current == -1)
if (current == -1 && frames[i].usable)
current = i;
}
}
......
......@@ -145,6 +145,7 @@ private slots:
private:
enum SpecialStopMode { NoSpecialStop, SpecialStopSynchronizeBreakpoints };
bool commandsPending() const;
void handleExtensionMessage(char t, int token, const QByteArray &what, const QByteArray &message);
bool doSetupEngine(QString *errorMessage);
void handleSessionAccessible(unsigned long cdbExState);
......
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