Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Tobias Hunger
qt-creator
Commits
52915776
Commit
52915776
authored
Apr 22, 2009
by
Friedemann Kleint
Browse files
Make CDB load custom dumpers.
Load in a 'well-defined' (temporary) breakpoint at main().
parent
ef8e69d9
Changes
14
Hide whitespace changes
Inline
Side-by-side
share/qtcreator/gdbmacros/gdbmacros.cpp
View file @
52915776
...
...
@@ -2529,7 +2529,11 @@ void *qDumpObjectData440(
int
protocolVersion
,
int
token
,
void
*
data
,
#ifdef Q_CC_MSVC // CDB cannot handle boolean parameters
int
dumpChildren
,
#else
bool
dumpChildren
,
#endif
int
extraInt0
,
int
extraInt1
,
int
extraInt2
,
...
...
src/plugins/debugger/cdb/cdbbreakpoint.cpp
View file @
52915776
...
...
@@ -48,7 +48,8 @@ static const char sourceFileQuoteC = '`';
CDBBreakPoint
::
CDBBreakPoint
()
:
ignoreCount
(
0
),
lineNumber
(
-
1
)
lineNumber
(
-
1
),
oneShot
(
false
)
{
}
...
...
@@ -57,7 +58,8 @@ CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
condition
(
bpd
.
condition
),
ignoreCount
(
0
),
funcName
(
bpd
.
funcName
),
lineNumber
(
-
1
)
lineNumber
(
-
1
),
oneShot
(
false
)
{
if
(
!
bpd
.
ignoreCount
.
isEmpty
())
ignoreCount
=
bpd
.
ignoreCount
.
toInt
();
...
...
@@ -75,6 +77,10 @@ int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
return
1
;
if
(
lineNumber
<
rhs
.
lineNumber
)
return
-
1
;
if
(
oneShot
&&
!
rhs
.
oneShot
)
return
1
;
if
(
!
oneShot
&&
rhs
.
oneShot
)
return
-
1
;
if
(
const
int
fileCmp
=
fileName
.
compare
(
rhs
.
fileName
))
return
fileCmp
;
if
(
const
int
funcCmp
=
funcName
.
compare
(
rhs
.
funcName
))
...
...
@@ -87,7 +93,8 @@ int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
void
CDBBreakPoint
::
clear
()
{
ignoreCount
=
0
;
clearExpressionData
();
oneShot
=
false
;
clearExpressionData
();
}
void
CDBBreakPoint
::
clearExpressionData
()
...
...
@@ -110,6 +117,8 @@ QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp)
nsp
<<
" condition='"
<<
bp
.
condition
<<
'\''
;
if
(
bp
.
ignoreCount
)
nsp
<<
" ignoreCount="
<<
bp
.
ignoreCount
;
if
(
bp
.
oneShot
)
nsp
<<
" oneShot"
;
return
dbg
;
}
...
...
@@ -144,7 +153,10 @@ bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
}
// Pass Count is ignoreCount + 1
ibp
->
SetPassCount
(
ignoreCount
+
1u
);
ibp
->
AddFlags
(
DEBUG_BREAKPOINT_ENABLED
);
ULONG
flags
=
DEBUG_BREAKPOINT_ENABLED
;
if
(
oneShot
)
flags
|=
DEBUG_BREAKPOINT_ONE_SHOT
;
ibp
->
AddFlags
(
flags
);
return
true
;
}
...
...
@@ -190,6 +202,10 @@ bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
ibp
->
GetPassCount
(
&
ignoreCount
);
if
(
ignoreCount
)
ignoreCount
--
;
ULONG
flags
=
0
;
ibp
->
GetFlags
(
&
flags
);
if
(
flags
&
DEBUG_BREAKPOINT_ONE_SHOT
)
oneShot
=
true
;
const
QString
expr
=
QString
::
fromUtf16
(
wszBuf
);
if
(
!
parseExpression
(
expr
))
{
*
errorMessage
=
QString
::
fromLatin1
(
"Parsing of '%1' failed."
).
arg
(
expr
);
...
...
src/plugins/debugger/cdb/cdbbreakpoint.h
View file @
52915776
...
...
@@ -83,6 +83,7 @@ struct CDBBreakPoint
unsigned
long
ignoreCount
;
// ignore count associated with breakpoint
int
lineNumber
;
// line in source file
QString
funcName
;
// name of containing function
bool
oneShot
;
};
QDebug
operator
<<
(
QDebug
,
const
CDBBreakPoint
&
bp
);
...
...
src/plugins/debugger/cdb/cdbdebugengine.cpp
View file @
52915776
...
...
@@ -53,6 +53,7 @@
#include
<utils/consoleprocess.h>
#include
<QtCore/QDebug>
#include
<QtCore/QTimer>
#include
<QtCore/QTimerEvent>
#include
<QtCore/QFileInfo>
#include
<QtCore/QDir>
...
...
@@ -96,13 +97,13 @@ QString msgDebugEngineComResult(HRESULT hr)
case
E_UNEXPECTED
:
return
QLatin1String
(
"E_UNEXPECTED"
);
case
E_NOTIMPL
:
return
QLatin1String
(
"E_NOTIMPL"
);
return
QLatin1String
(
"E_NOTIMPL"
);
}
if
(
hr
==
HRESULT_FROM_WIN32
(
ERROR_ACCESS_DENIED
))
return
QLatin1String
(
"ERROR_ACCESS_DENIED"
);;
if
(
hr
==
HRESULT_FROM_NT
(
STATUS_CONTROL_C_EXIT
))
return
QLatin1String
(
"STATUS_CONTROL_C_EXIT"
);
return
Core
::
Utils
::
winErrorMessage
(
HRESULT_CODE
(
hr
));
return
QLatin1String
(
"E_FAIL "
)
+
Core
::
Utils
::
winErrorMessage
(
HRESULT_CODE
(
hr
));
}
static
QString
msgStackIndexOutOfRange
(
int
idx
,
int
size
)
...
...
@@ -450,14 +451,16 @@ void CdbDebugEnginePrivate::clearDisplay()
bool
CdbDebugEngine
::
startDebugger
()
{
m_d
->
clearDisplay
();
const
DebuggerStartMode
mode
=
m_d
->
m_debuggerManager
->
startMode
();
// Figure out dumper. @TODO: same in gdb...
bool
dumperEnabled
=
false
&&
m_d
->
m_debuggerManager
->
qtDumperLibraryEnabled
();
const
QString
dumperLibName
=
QDir
::
toNativeSeparators
(
m_d
->
m_debuggerManager
->
qtDumperLibraryName
());
const
QString
dumperLibName
=
QDir
::
toNativeSeparators
(
m_d
->
m_debuggerManagerAccess
->
qtDumperLibraryName
());
bool
dumperEnabled
=
mode
!=
AttachCore
&&
!
dumperLibName
.
isEmpty
()
&&
m_d
->
m_debuggerManagerAccess
->
qtDumperLibraryEnabled
();
if
(
dumperEnabled
)
{
const
QFileInfo
fi
(
dumperLibName
);
if
(
!
fi
.
isFile
())
{
const
QString
msg
=
tr
(
"The dumper library '%1' does not exist."
).
arg
(
dumperLibName
);
m_d
->
m_debuggerManager
->
showQtDumperLibraryWarning
(
msg
);
m_d
->
m_debuggerManager
Access
->
showQtDumperLibraryWarning
(
msg
);
dumperEnabled
=
false
;
}
}
...
...
@@ -466,7 +469,6 @@ bool CdbDebugEngine::startDebugger()
QString
errorMessage
;
bool
rc
=
false
;
m_d
->
clearForRun
();
const
DebuggerStartMode
mode
=
m_d
->
m_debuggerManager
->
startMode
();
switch
(
mode
)
{
case
AttachExternal
:
rc
=
startAttachDebugger
(
m_d
->
m_debuggerManager
->
m_attachedPID
,
&
errorMessage
);
...
...
@@ -561,6 +563,52 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *
return
true
;
}
// check for a breakpoint at 'main()'
static
inline
bool
hasBreakPointAtMain
(
const
BreakHandler
*
bp
)
{
if
(
const
int
count
=
bp
->
size
())
{
// check all variations, resolved or not
const
QString
main
=
QLatin1String
(
"main"
);
const
QString
qMain
=
QLatin1String
(
"qMain"
);
const
QString
moduleMainPattern
=
QLatin1String
(
"!main"
);
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
const
QString
&
function
=
bp
->
at
(
i
)
->
funcName
;
if
(
function
==
main
||
function
==
qMain
||
function
.
endsWith
(
moduleMainPattern
))
return
true
;
}
}
return
false
;
}
void
CdbDebugEnginePrivate
::
processCreatedAttached
(
ULONG64
processHandle
,
ULONG64
initialThreadHandle
)
{
setDebuggeeHandles
(
reinterpret_cast
<
HANDLE
>
(
processHandle
),
reinterpret_cast
<
HANDLE
>
(
initialThreadHandle
));
m_debuggerManagerAccess
->
notifyInferiorRunning
();
ULONG
currentThreadId
;
if
(
SUCCEEDED
(
m_cif
.
debugSystemObjects
->
GetThreadIdByHandle
(
initialThreadHandle
,
&
currentThreadId
)))
{
m_currentThreadId
=
currentThreadId
;
}
else
{
m_currentThreadId
=
0
;
}
// Set initial breakpoints
if
(
m_debuggerManagerAccess
->
breakHandler
()
->
hasPendingBreakpoints
())
m_engine
->
attemptBreakpointSynchronization
();
// At any event, we want a temporary breakpoint at main() to load
// the dumpers.
if
(
m_dumper
.
state
()
==
CdbDumperHelper
::
NotLoaded
)
{
if
(
!
hasBreakPointAtMain
(
m_debuggerManagerAccess
->
breakHandler
()))
{
CDBBreakPoint
mainBP
;
// Do not resolve at this point in the rare event someone
// has main in a module
mainBP
.
funcName
=
QLatin1String
(
"main"
);
mainBP
.
oneShot
=
true
;
QString
errorMessage
;
if
(
!
mainBP
.
add
(
m_cif
.
debugControl
,
&
errorMessage
))
m_debuggerManagerAccess
->
showQtDumperLibraryWarning
(
errorMessage
);
}
}
}
void
CdbDebugEngine
::
processTerminated
(
unsigned
long
exitCode
)
{
if
(
debugCDB
)
...
...
@@ -859,13 +907,18 @@ void CdbDebugEngine::continueInferior()
}
// Continue process without notifications
bool
CdbDebugEnginePrivate
::
continueInferiorProcess
(
QString
*
errorMessage
)
bool
CdbDebugEnginePrivate
::
continueInferiorProcess
(
QString
*
errorMessage
Ptr
/* = 0 */
)
{
if
(
debugCDB
)
qDebug
()
<<
Q_FUNC_INFO
;
const
HRESULT
hr
=
m_cif
.
debugControl
->
SetExecutionStatus
(
DEBUG_STATUS_GO
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
msgComFailed
(
"SetExecutionStatus"
,
hr
);
const
QString
errorMessage
=
msgComFailed
(
"SetExecutionStatus"
,
hr
);
if
(
errorMessagePtr
)
{
*
errorMessagePtr
=
errorMessage
;
}
else
{
qWarning
(
"continueInferiorProcess: %s
\n
"
,
qPrintable
(
errorMessage
));
}
return
false
;
}
return
true
;
...
...
@@ -992,10 +1045,10 @@ void CdbDebugEngine::executeDebuggerCommand(const QString &command)
bool
CdbDebugEnginePrivate
::
executeDebuggerCommand
(
CIDebugControl
*
ctrl
,
const
QString
&
command
,
QString
*
errorMessage
)
{
if
(
debugCDB
)
qDebug
()
<<
Q_FUNC_INFO
<<
command
;
// output to all clients, else we do not see anything
const
HRESULT
hr
=
ctrl
->
ExecuteWide
(
DEBUG_OUTCTL_ALL_CLIENTS
,
command
.
utf16
(),
0
);
if
(
debugCDB
)
qDebug
()
<<
"executeDebuggerCommand"
<<
command
<<
SUCCEEDED
(
hr
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
QString
::
fromLatin1
(
"Unable to execute '%1': %2"
).
arg
(
command
,
msgDebugEngineComResult
(
hr
));
...
...
@@ -1300,10 +1353,19 @@ void CdbDebugEnginePrivate::handleDebugEvent()
switch
(
mode
)
{
case
BreakEventHandle
:
case
BreakEventMain
:
if
(
mode
==
BreakEventMain
)
m_dumper
.
load
(
m_debuggerManager
,
m_debuggerManagerAccess
);
m_debuggerManagerAccess
->
notifyInferiorStopped
();
updateThreadList
();
updateStackTrace
();
break
;
case
BreakEventMainLoadDumpers
:
// Temp stop to load dumpers
m_dumper
.
load
(
m_debuggerManager
,
m_debuggerManagerAccess
);
m_engine
->
startWatchTimer
();
continueInferiorProcess
();
break
;
case
BreakEventIgnoreOnce
:
m_engine
->
startWatchTimer
();
break
;
...
...
@@ -1417,17 +1479,6 @@ void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
if
(
debugCDB
>
2
)
qDebug
()
<<
Q_FUNC_INFO
<<
"
\n
"
<<
name
;
updateModules
();
// Call the dumper helper hook and notify about progress.
bool
ignoreNextBreakPoint
;
if
(
m_dumper
.
moduleLoadHook
(
name
,
&
ignoreNextBreakPoint
))
{
if
(
m_dumper
.
state
()
==
CdbDumperHelper
::
Loaded
)
m_debuggerManagerAccess
->
showDebuggerOutput
(
QLatin1String
(
dumperPrefixC
),
QString
::
fromLatin1
(
"Dumpers loaded: %1"
).
arg
(
m_dumper
.
library
()));
}
else
{
m_debuggerManager
->
showQtDumperLibraryWarning
(
m_dumper
.
errorMessage
());
m_debuggerManagerAccess
->
showDebuggerOutput
(
QLatin1String
(
dumperPrefixC
),
QString
::
fromLatin1
(
"Unable to load dumpers: %1"
).
arg
(
m_dumper
.
errorMessage
()));
}
if
(
ignoreNextBreakPoint
)
m_breakEventMode
=
BreakEventIgnoreOnce
;
}
void
CdbDebugEnginePrivate
::
handleBreakpointEvent
(
PDEBUG_BREAKPOINT2
pBP
)
...
...
@@ -1435,6 +1486,17 @@ void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
Q_UNUSED
(
pBP
)
if
(
debugCDB
)
qDebug
()
<<
Q_FUNC_INFO
;
// Did we hit main() and did the user want that or is that just
// our internal BP to load the dumpers?
QString
errorMessage
;
CDBBreakPoint
bp
;
if
(
bp
.
retrieve
(
pBP
,
&
errorMessage
)
&&
!
bp
.
funcName
.
isEmpty
())
{
if
(
bp
.
funcName
==
QLatin1String
(
"main"
)
||
bp
.
funcName
.
endsWith
(
QLatin1String
(
"!main"
)))
{
m_breakEventMode
=
bp
.
oneShot
?
BreakEventMainLoadDumpers
:
BreakEventMain
;
}
if
(
debugCDB
)
qDebug
()
<<
bp
<<
" b-mode="
<<
m_breakEventMode
;
}
}
void
CdbDebugEngine
::
reloadSourceFiles
()
...
...
src/plugins/debugger/cdb/cdbdebugengine_p.h
View file @
52915776
...
...
@@ -98,6 +98,10 @@ struct CdbDebugEnginePrivate
enum
HandleBreakEventMode
{
// Special modes for break event handler.
BreakEventHandle
,
BreakEventIgnoreOnce
,
// We hit main (and the user intended it)
BreakEventMain
,
// We hit main (and the user did not intend it, just load dumpers)
BreakEventMainLoadDumpers
,
BreakEventSyncBreakPoints
,
};
...
...
@@ -107,6 +111,7 @@ struct CdbDebugEnginePrivate
bool
init
(
QString
*
errorMessage
);
~
CdbDebugEnginePrivate
();
void
processCreatedAttached
(
ULONG64
processHandle
,
ULONG64
initialThreadHandle
);
void
setDebuggeeHandles
(
HANDLE
hDebuggeeProcess
,
HANDLE
hDebuggeeThread
);
bool
isDebuggeeRunning
()
const
{
return
m_watchTimer
!=
-
1
;
}
...
...
@@ -125,7 +130,7 @@ struct CdbDebugEnginePrivate
bool
interruptInterferiorProcess
(
QString
*
errorMessage
);
bool
continueInferiorProcess
(
QString
*
errorMessage
);
bool
continueInferiorProcess
(
QString
*
errorMessage
=
0
);
bool
continueInferior
(
QString
*
errorMessage
);
bool
attemptBreakpointSynchronization
(
QString
*
errorMessage
);
...
...
src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
View file @
52915776
...
...
@@ -247,7 +247,8 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
break
;
case
EXCEPTION_ACCESS_VIOLATION
:
{
const
bool
writeOperation
=
e
->
ExceptionInformation
[
0
];
str
<<
(
writeOperation
?
"write access violation"
:
"read access violation"
);
str
<<
(
writeOperation
?
"write"
:
"read"
)
<<
" access violation at: 0x"
<<
e
->
ExceptionInformation
[
1
];
}
break
;
case
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
...
...
@@ -342,8 +343,10 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
QString
msg
;
{
QTextStream
str
(
&
msg
);
formatException
(
Exception
,
m_pEngine
->
m_d
->
m_cif
,
str
);
formatException
(
Exception
,
m_pEngine
->
m_d
->
m_cif
,
str
);
}
if
(
debugCDB
)
qDebug
()
<<
Q_FUNC_INFO
<<
'\n'
<<
msg
;
m_pEngine
->
m_d
->
m_debuggerManagerAccess
->
showApplicationOutput
(
msg
);
return
S_OK
;
}
...
...
@@ -402,18 +405,7 @@ STDMETHODIMP CdbDebugEventCallback::CreateProcess(
Q_UNUSED
(
StartOffset
)
if
(
debugCDB
)
qDebug
()
<<
Q_FUNC_INFO
<<
ModuleName
;
m_pEngine
->
m_d
->
setDebuggeeHandles
(
reinterpret_cast
<
HANDLE
>
(
Handle
),
reinterpret_cast
<
HANDLE
>
(
InitialThreadHandle
));
m_pEngine
->
m_d
->
m_debuggerManagerAccess
->
notifyInferiorRunning
();
ULONG
currentThreadId
;
if
(
SUCCEEDED
(
m_pEngine
->
m_d
->
m_cif
.
debugSystemObjects
->
GetThreadIdByHandle
(
InitialThreadHandle
,
&
currentThreadId
)))
m_pEngine
->
m_d
->
m_currentThreadId
=
currentThreadId
;
else
m_pEngine
->
m_d
->
m_currentThreadId
=
0
;
// Set initial breakpoints
if
(
m_pEngine
->
m_d
->
m_debuggerManagerAccess
->
breakHandler
()
->
hasPendingBreakpoints
())
m_pEngine
->
attemptBreakpointSynchronization
();
m_pEngine
->
m_d
->
processCreatedAttached
(
Handle
,
InitialThreadHandle
);
return
S_OK
;
}
...
...
src/plugins/debugger/cdb/cdbdumperhelper.cpp
View file @
52915776
...
...
@@ -32,11 +32,18 @@
#include
"cdbdebugengine_p.h"
#include
"cdbdebugoutput.h"
#include
"cdbdebugeventcallback.h"
#include
"watchutils.h"
#include
<QtCore/QRegExp>
#include
<QtCore/QCoreApplication>
#include
<QtCore/QTextStream>
enum
{
loadDebug
=
0
};
static
const
char
*
dumperModuleNameC
=
"gdbmacros"
;
static
const
char
*
qtCoreModuleNameC
=
"QtCore"
;
static
const
ULONG
waitTimeOutMS
=
30000
;
namespace
Debugger
{
namespace
Internal
{
...
...
@@ -52,7 +59,7 @@ static bool allocDebuggeeMemory(CIDebugControl *ctl,
OutputRedirector
redir
(
client
,
&
stringHandler
);
if
(
!
CdbDebugEnginePrivate
::
executeDebuggerCommand
(
ctl
,
allocCmd
,
errorMessage
))
return
false
;
// "Allocated 1000 bytes starting at 003a0000" .. hopefully never localized
// "Allocated 1000 bytes starting at 003a0000" .. hopefully never localized
bool
ok
=
false
;
const
QString
output
=
stringHandler
.
result
();
const
int
lastBlank
=
output
.
lastIndexOf
(
QLatin1Char
(
' '
));
...
...
@@ -61,6 +68,8 @@ static bool allocDebuggeeMemory(CIDebugControl *ctl,
if
(
ok
)
*
address
=
addri
;
}
if
(
loadDebug
)
qDebug
()
<<
Q_FUNC_INFO
<<
'\n'
<<
output
<<
*
address
<<
ok
;
if
(
!
ok
)
{
*
errorMessage
=
QString
::
fromLatin1
(
"Failed to parse output '%1'"
).
arg
(
output
);
return
false
;
...
...
@@ -88,25 +97,6 @@ static bool createDebuggeeAscIIString(CIDebugControl *ctl,
return
true
;
}
// Locate 'qstrdup' in the (potentially namespaced) corelib. For some
// reason, the symbol is present in QtGui as well without type information.
static
inline
QString
resolveStrdup
(
CIDebugSymbols
*
syms
,
QString
*
errorMessage
)
{
QStringList
matches
;
const
QString
pattern
=
QLatin1String
(
"*qstrdup"
);
const
QRegExp
corelibPattern
(
QLatin1String
(
"QtCore[d]*4!"
));
Q_ASSERT
(
corelibPattern
.
isValid
());
if
(
!
searchSymbols
(
syms
,
pattern
,
&
matches
,
errorMessage
))
return
QString
();
QStringList
corelibStrdup
=
matches
.
filter
(
corelibPattern
);
if
(
corelibStrdup
.
isEmpty
())
{
*
errorMessage
=
QString
::
fromLatin1
(
"Unable to locate '%1' in '%2' (%3)"
).
arg
(
pattern
,
corelibPattern
.
pattern
(),
matches
.
join
(
QString
(
QLatin1Char
(
','
))));
return
QString
();
}
return
corelibStrdup
.
front
();
}
// Load a library into the debuggee. Currently requires
// the QtCored4.pdb file to be present as we need "qstrdup"
// as dummy symbol. This is ok ATM since dumpers only
...
...
@@ -132,9 +122,10 @@ static bool debuggeeLoadLibrary(CIDebugControl *ctl,
// server, the debugger refuses to recognize it as a function.
// Set up the call stack with a function of same signature (qstrdup)
// and change the call register to LoadLibraryA() before executing "g".
// Prepare call.
const
QString
dummyFunc
=
resolveStrdup
(
syms
,
errorMessage
);
if
(
dummyFunc
.
isEmpty
())
// Prepare call: Locate 'qstrdup' in the (potentially namespaced) corelib. For some
// reason, the symbol is present in QtGui as well without type information.
QString
dummyFunc
=
QLatin1String
(
"*qstrdup"
);
if
(
resolveSymbol
(
syms
,
QLatin1String
(
"QtCore[d]*4!"
),
&
dummyFunc
,
errorMessage
)
!=
ResolveSymbolOk
)
return
false
;
QString
callCmd
=
QLatin1String
(
".call "
);
callCmd
+=
dummyFunc
;
...
...
@@ -145,80 +136,293 @@ static bool debuggeeLoadLibrary(CIDebugControl *ctl,
return
false
;
if
(
!
CdbDebugEnginePrivate
::
executeDebuggerCommand
(
ctl
,
QLatin1String
(
"r eip=Kernel32!LoadLibraryA"
),
errorMessage
))
return
false
;
// This will hit a breakpoint
if
(
loadDebug
)
qDebug
()
<<
" executing 'g'"
;
// This will hit a breakpoint.
if
(
!
CdbDebugEnginePrivate
::
executeDebuggerCommand
(
ctl
,
QString
(
QLatin1Char
(
'g'
)),
errorMessage
))
return
false
;
const
HRESULT
hr
=
ctl
->
WaitForEvent
(
0
,
waitTimeOutMS
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
msgComFailed
(
"WaitForEvent"
,
hr
);
return
false
;
// @Todo: We cannot evaluate output here as it is asynchronous
}
return
true
;
}
CdbDumperHelper
::
CdbDumperHelper
(
CdbComInterfaces
*
cif
)
:
// ------------------- CdbDumperHelper::DumperInputParameters
struct
CdbDumperHelper
::
DumperInputParameters
{
DumperInputParameters
(
int
protocolVersion_
=
1
,
int
token_
=
1
,
quint64
Address_
=
0
,
bool
dumpChildren_
=
false
,
int
extraInt0_
=
0
,
int
extraInt1_
=
0
,
int
extraInt2_
=
0
,
int
extraInt3_
=
0
);
QString
command
(
const
QString
&
dumpFunction
)
const
;
int
protocolVersion
;
int
token
;
quint64
address
;
bool
dumpChildren
;
int
extraInt0
;
int
extraInt1
;
int
extraInt2
;
int
extraInt3
;
};
CdbDumperHelper
::
DumperInputParameters
::
DumperInputParameters
(
int
protocolVersion_
,
int
token_
,
quint64
address_
,
bool
dumpChildren_
,
int
extraInt0_
,
int
extraInt1_
,
int
extraInt2_
,
int
extraInt3_
)
:
protocolVersion
(
protocolVersion_
),
token
(
token_
),
address
(
address_
),
dumpChildren
(
dumpChildren_
),
extraInt0
(
extraInt0_
),
extraInt1
(
extraInt1_
),
extraInt2
(
extraInt2_
),
extraInt3
(
extraInt3_
)
{
}
QString
CdbDumperHelper
::
DumperInputParameters
::
command
(
const
QString
&
dumpFunction
)
const
{
QString
rc
;
QTextStream
str
(
&
rc
);
str
.
setIntegerBase
(
16
);
str
<<
".call "
<<
dumpFunction
<<
'('
<<
protocolVersion
<<
','
<<
token
<<
','
;
str
.
setIntegerBase
(
16
);
str
<<
"0x"
<<
address
;
str
.
setIntegerBase
(
10
);
str
<<
','
<<
(
dumpChildren
?
1
:
0
)
<<
','
<<
extraInt0
<<
','
<<
extraInt1
<<
','
<<
extraInt2
<<
','
<<
extraInt3
<<
')'
;
return
rc
;
}
// ------------------- CdbDumperHelper
CdbDumperHelper
::
CdbDumperHelper
(
CdbComInterfaces
*
cif
)
:
m_state
(
NotLoaded
),
m_cif
(
cif
)
m_cif
(
cif
),
m_inBufferAddress
(
0
),
m_inBufferSize
(
0
),
m_outBufferAddress
(
0
),
m_outBufferSize
(
0
),
m_buffer
(
0
)
{
}
CdbDumperHelper
::~
CdbDumperHelper
()
{
clearBuffer
();
}
void
CdbDumperHelper
::
clearBuffer
()
{
if
(
m_buffer
)
{
delete
[]
m_buffer
;
m_buffer
=
0
;
}
}
void
CdbDumperHelper
::
reset
(
const
QString
&
library
,
bool
enabled
)
{
m_library
=
library
;
m_state
=
enabled
?
NotLoaded
:
Disabled
;
m_dumpObjectSymbol
=
QLatin1String
(
"qDumpObjectData440"
);
m_errorMessage
.
clear
();
m_knownTypes
.
clear
();
m_qtVersion
.
clear
();
m_qtNamespace
.
clear
();
m_inBufferAddress
=
m_outBufferAddress
=
0
;
m_inBufferSize
=
m_outBufferSize
=
0
;
clearBuffer
();
}
bool
CdbDumperHelper
::
moduleLoadHook
(
const
QString
&
name
,
bool
*
ignoreNextBreakPoint
)
// Attempt to load and initialize dumpers, give feedback
// to user.
void
CdbDumperHelper
::
load
(
DebuggerManager
*
manager
,
IDebuggerManagerAccessForEngines
*
access
)
{
*
ignoreNextBreakPoint
=
false
;
bool
ok
=
true
;
// report failure only once
switch
(
m_state
)
{
case
Disabled
:
break
;
case
NotLoaded
:
// Load once QtCore is there.
if
(
name
.
contains
(
QLatin1String
(
"QtCore"
)))
{
if
(
loadDebug
)
qDebug
()
<<
Q_FUNC_INFO
<<
'\n'
<<
name
<<
m_state
<<
executionStatusString
(
m_cif
->
debugControl
);
ok
=
debuggeeLoadLibrary
(
m_cif
->
debugControl
,
m_cif
->
debugClient
,
m_cif
->
debugSymbols
,
m_cif
->
debugDataSpaces
,
m_library
,
&
m_errorMessage
);
if
(
ok
)
{
m_state
=
Loading
;
*
ignoreNextBreakPoint
=
true
;
}
else
{
m_state
=
Failed
;
}
if
(
loadDebug
)
qDebug
()
<<
m_state
<<
executionStatusString
(
m_cif
->
debugControl
);
enum
Result
{
Failed
,
Succeeded
,
NoQtApp
};
if
(
m_state
!=
NotLoaded
)
return
;
manager
->
showStatusMessage
(
QCoreApplication
::
translate
(
"CdbDumperHelper"
,
"Loading dumpers..."
),
10000
);
const
QString
messagePrefix
=
QLatin1String
(
"dumper:"
);
QString
message
;
Result
result
=
Failed
;
do
{
// Do we have Qt and are we already loaded by accident?
QStringList
modules
;
if
(
!
getModuleNameList
(
m_cif
->
debugSymbols
,
&
modules
,
&
message
))
break
;
if
(
modules
.
filter
(
QLatin1String
(
qtCoreModuleNameC
)).
isEmpty
())
{
message
=
QCoreApplication
::
translate
(
"CdbDumperHelper"
,
"The debugger does not appear to be Qt application."
);
result
=
NoQtApp
;
}
break
;
case
Loading
:
// Hurray, loaded. Now resolve the symbols we need
if
(
name
.
contains
(
QLatin1String
(
"gdbmacros"
)))
{
ok
=
resolveSymbols
(
&
m_errorMessage
);
if
(
ok
)
{
m_state
=
Loaded
;
}
else
{
m_state
=
Failed
;
// Make sure the dumper lib is loaded.
if
(
modules
.
filter
(
QLatin1String
(
dumperModuleNameC
),
Qt
::
CaseInsensitive
).
isEmpty
())
{