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
2cd7e615
Commit
2cd7e615
authored
May 10, 2010
by
Friedemann Kleint
Browse files
Debugger[CDB]: Add WatchPoints and breakpoint thread restriction.
parent
f678fce3
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/plugins/debugger/cdb/breakpoint.cpp
View file @
2cd7e615
...
...
@@ -50,48 +50,21 @@ namespace CdbCore {
static
const
char
sourceFileQuoteC
=
'`'
;
BreakPoint
::
BreakPoint
()
:
type
(
Code
),
lineNumber
(
-
1
),
address
(
0
),
threadId
(
-
1
),
ignoreCount
(
0
),
oneShot
(
false
),
enabled
(
true
)
{
}
int
BreakPoint
::
compare
(
const
BreakPoint
&
rhs
)
const
{
if
(
lineNumber
>
rhs
.
lineNumber
)
return
1
;
if
(
lineNumber
<
rhs
.
lineNumber
)
return
-
1
;
if
(
address
>
rhs
.
address
)
return
1
;
if
(
address
<
rhs
.
address
)
return
-
1
;
if
(
ignoreCount
>
rhs
.
ignoreCount
)
return
1
;
if
(
ignoreCount
<
rhs
.
ignoreCount
)
return
-
1
;
if
(
oneShot
&&
!
rhs
.
oneShot
)
return
1
;
if
(
!
oneShot
&&
rhs
.
oneShot
)
return
-
1
;
if
(
enabled
&&
!
rhs
.
enabled
)
return
1
;
if
(
!
enabled
&&
rhs
.
enabled
)
return
-
1
;
if
(
const
int
fileCmp
=
fileName
.
compare
(
rhs
.
fileName
))
return
fileCmp
;
if
(
const
int
funcCmp
=
funcName
.
compare
(
rhs
.
funcName
))
return
funcCmp
;
if
(
const
int
condCmp
=
condition
.
compare
(
rhs
.
condition
))
return
condCmp
;
return
0
;
}
void
BreakPoint
::
clear
()
{
type
=
Code
;
ignoreCount
=
0
;
threadId
=
-
1
;
oneShot
=
false
;
enabled
=
true
;
clearExpressionData
();
...
...
@@ -108,23 +81,35 @@ void BreakPoint::clearExpressionData()
QDebug
operator
<<
(
QDebug
dbg
,
const
BreakPoint
&
bp
)
{
QDebug
nsp
=
dbg
.
nospace
();
if
(
bp
.
address
)
nsp
<<
"0x"
<<
QString
::
number
(
bp
.
address
,
16
)
<<
' '
;
if
(
!
bp
.
fileName
.
isEmpty
())
{
nsp
<<
"fileName='"
<<
bp
.
fileName
<<
':'
<<
bp
.
lineNumber
<<
'\''
;
dbg
.
nospace
()
<<
bp
.
toString
();
return
dbg
;
}
QString
BreakPoint
::
toString
()
const
{
QString
rc
;
QTextStream
str
(
&
rc
);
str
<<
(
type
==
BreakPoint
::
Code
?
"Code "
:
"Data "
);
if
(
address
)
{
str
.
setIntegerBase
(
16
);
str
<<
"0x"
<<
address
<<
' '
;
str
.
setIntegerBase
(
10
);
}
if
(
!
fileName
.
isEmpty
())
{
str
<<
"fileName='"
<<
fileName
<<
':'
<<
lineNumber
<<
'\''
;
}
else
{
nsp
<<
"funcName='"
<<
bp
.
funcName
<<
'\''
;
str
<<
"funcName='"
<<
funcName
<<
'\''
;
}
if
(
!
bp
.
condition
.
isEmpty
())
nsp
<<
" condition='"
<<
bp
.
condition
<<
'\''
;
if
(
bp
.
ignoreCount
)
nsp
<<
" ignoreCount="
<<
bp
.
ignoreCount
;
if
(
bp
.
enabled
)
nsp
<<
" enabled"
;
if
(
bp
.
oneShot
)
nsp
<<
" oneShot"
;
return
dbg
;
if
(
threadId
>=
0
)
str
<<
" thread="
<<
threadId
;
if
(
!
condition
.
isEmpty
())
str
<<
" condition='"
<<
condition
<<
'\''
;
if
(
ignoreCount
)
str
<<
" ignoreCount="
<<
ignoreCount
;
str
<<
(
enabled
?
" enabled"
:
" disabled"
);
if
(
oneShot
)
str
<<
" oneShot"
;
return
rc
;
}
QString
BreakPoint
::
expression
()
const
...
...
@@ -155,25 +140,59 @@ QString BreakPoint::expression() const
return
rc
;
}
static
inline
QString
msgCannotSetBreakpoint
(
const
QString
&
exp
,
const
QString
&
why
)
{
return
QString
::
fromLatin1
(
"Unable to set breakpoint '%1' : %2"
).
arg
(
exp
,
why
);
}
bool
BreakPoint
::
apply
(
CIDebugBreakpoint
*
ibp
,
QString
*
errorMessage
)
const
{
const
QString
expr
=
expression
();
if
(
debugBP
)
qDebug
()
<<
Q_FUNC_INFO
<<
*
this
<<
expr
;
const
HRESULT
hr
=
ibp
->
SetOffsetExpressionWide
(
reinterpret_cast
<
PCWSTR
>
(
expr
.
utf16
()));
HRESULT
hr
=
ibp
->
SetOffsetExpressionWide
(
reinterpret_cast
<
PCWSTR
>
(
expr
.
utf16
()));
if
(
FAILED
(
hr
))
{
*
errorMessage
=
QString
::
fromLatin1
(
"Unable to set breakpoint '%1' : %2"
).
arg
(
expr
,
CdbCore
::
msgComFailed
(
"SetOffsetExpressionWide"
,
hr
));
*
errorMessage
=
msgCannotSetBreakpoint
(
expr
,
CdbCore
::
msgComFailed
(
"SetOffsetExpressionWide"
,
hr
));
return
false
;
}
// Pass Count is ignoreCount + 1
ibp
->
SetPassCount
(
ignoreCount
+
1u
);
hr
=
ibp
->
SetPassCount
(
ignoreCount
+
1u
);
if
(
FAILED
(
hr
))
qWarning
(
"Error setting passcount %d %s "
,
ignoreCount
,
qPrintable
(
expr
));
// Set up size for data breakpoints
if
(
type
==
Data
)
{
const
ULONG
size
=
1u
;
hr
=
ibp
->
SetDataParameters
(
size
,
DEBUG_BREAK_READ
|
DEBUG_BREAK_WRITE
);
if
(
FAILED
(
hr
))
{
const
QString
msg
=
QString
::
fromLatin1
(
"Cannot set watch size to %1: %2"
).
arg
(
size
).
arg
(
CdbCore
::
msgComFailed
(
"SetDataParameters"
,
hr
));
*
errorMessage
=
msgCannotSetBreakpoint
(
expr
,
msg
);
return
false
;
}
}
// Thread
if
(
threadId
>=
0
)
{
hr
=
ibp
->
SetMatchThreadId
(
threadId
);
if
(
FAILED
(
hr
))
{
const
QString
msg
=
QString
::
fromLatin1
(
"Cannot set thread id to %1: %2"
).
arg
(
threadId
).
arg
(
CdbCore
::
msgComFailed
(
"SetMatchThreadId"
,
hr
));
*
errorMessage
=
msgCannotSetBreakpoint
(
expr
,
msg
);
return
false
;
}
}
// Flags
ULONG
flags
=
0
;
if
(
enabled
)
flags
|=
DEBUG_BREAKPOINT_ENABLED
;
if
(
oneShot
)
flags
|=
DEBUG_BREAKPOINT_ONE_SHOT
;
ibp
->
AddFlags
(
flags
);
hr
=
ibp
->
AddFlags
(
flags
);
if
(
FAILED
(
hr
))
{
const
QString
msg
=
QString
::
fromLatin1
(
"Cannot set flags to 0x%1: %2"
).
arg
(
flags
,
0
,
16
).
arg
(
CdbCore
::
msgComFailed
(
"AddFlags"
,
hr
));
*
errorMessage
=
msgCannotSetBreakpoint
(
expr
,
msg
);
return
false
;
}
return
true
;
}
...
...
@@ -192,7 +211,8 @@ bool BreakPoint::add(CIDebugControl* debugControl,
*
address
=
0
;
if
(
id
)
*
id
=
0
;
HRESULT
hr
=
debugControl
->
AddBreakpoint2
(
DEBUG_BREAKPOINT_CODE
,
DEBUG_ANY_ID
,
&
ibp
);
const
ULONG
iType
=
type
==
Code
?
DEBUG_BREAKPOINT_CODE
:
DEBUG_BREAKPOINT_DATA
;
HRESULT
hr
=
debugControl
->
AddBreakpoint2
(
iType
,
DEBUG_ANY_ID
,
&
ibp
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
msgCannotAddBreakPoint
(
CdbCore
::
msgComFailed
(
"AddBreakpoint2"
,
hr
));
return
false
;
...
...
@@ -321,16 +341,41 @@ void BreakPoint::clearNormalizeFileNameCache()
normalizedFileNameCache
()
->
clear
();
}
static
inline
QString
msgCannotRetrieveBreakpoint
(
const
QString
&
why
)
{
return
QString
::
fromLatin1
(
"Cannot retrieve breakpoint: %1"
).
arg
(
why
);
}
static
inline
int
threadIdOfBreakpoint
(
CIDebugBreakpoint
*
ibp
)
{
// Thread: E_NOINTERFACE indicates no thread has been set.
int
threadId
=
-
1
;
ULONG
iThreadId
;
if
(
S_OK
==
ibp
->
GetMatchThreadId
(
&
iThreadId
))
threadId
=
iThreadId
;
return
threadId
;
}
bool
BreakPoint
::
retrieve
(
CIDebugBreakpoint
*
ibp
,
QString
*
errorMessage
)
{
clear
();
// Get type
ULONG
iType
;
ULONG
processorType
;
HRESULT
hr
=
ibp
->
GetType
(
&
iType
,
&
processorType
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
msgCannotRetrieveBreakpoint
(
CdbCore
::
msgComFailed
(
"GetType"
,
hr
));
return
false
;
}
type
=
iType
==
DEBUG_BREAKPOINT_CODE
?
Code
:
Data
;
// Get & parse expression
WCHAR
wszBuf
[
MAX_PATH
];
const
HRESULT
hr
=
ibp
->
GetOffsetExpressionWide
(
wszBuf
,
MAX_PATH
,
0
);
hr
=
ibp
->
GetOffsetExpressionWide
(
wszBuf
,
MAX_PATH
,
0
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
QString
::
fromLatin1
(
"Cannot retrieve breakpoint: %1"
).
arg
(
CdbCore
::
msgComFailed
(
"GetOffsetExpressionWide"
,
hr
));
*
errorMessage
=
msgCannotRetrieveBreakpoint
(
CdbCore
::
msgComFailed
(
"GetOffsetExpressionWide"
,
hr
));
return
false
;
}
threadId
=
threadIdOfBreakpoint
(
ibp
);
// Pass Count is ignoreCount + 1
ibp
->
GetPassCount
(
&
ignoreCount
);
if
(
ignoreCount
)
...
...
@@ -523,4 +568,34 @@ bool BreakPoint::setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id,
return
true
;
}
// Change thread-id of a breakpoint
static
inline
QString
msgCannotSetBreakPointThread
(
unsigned
long
id
,
int
tid
,
const
QString
&
why
)
{
return
QString
::
fromLatin1
(
"Cannot set breakpoint %1 thread to %2: %3"
).
arg
(
id
).
arg
(
tid
).
arg
(
why
);
}
bool
BreakPoint
::
setBreakPointThreadById
(
CIDebugControl
*
ctl
,
unsigned
long
id
,
int
threadId
,
QString
*
errorMessage
)
{
if
(
debugBP
)
qDebug
()
<<
Q_FUNC_INFO
<<
id
<<
threadId
;
CIDebugBreakpoint
*
ibp
=
breakPointById
(
ctl
,
id
,
errorMessage
);
if
(
!
ibp
)
{
*
errorMessage
=
msgCannotSetBreakPointThread
(
id
,
threadId
,
*
errorMessage
);
return
false
;
}
// Compare thread ids
const
int
oldThreadId
=
threadIdOfBreakpoint
(
ibp
);
if
(
oldThreadId
==
threadId
)
return
true
;
const
ULONG
newIThreadId
=
threadId
==
-
1
?
DEBUG_ANY_ID
:
static_cast
<
ULONG
>
(
threadId
);
if
(
debugBP
)
qDebug
()
<<
"Changing thread id of "
<<
id
<<
" from "
<<
oldThreadId
<<
" to "
<<
threadId
<<
'('
<<
newIThreadId
<<
')'
;
const
HRESULT
hr
=
ibp
->
SetMatchThreadId
(
newIThreadId
);
if
(
FAILED
(
hr
))
{
*
errorMessage
=
msgCannotSetBreakPointThread
(
id
,
threadId
,
*
errorMessage
);
return
false
;
}
return
true
;
}
}
// namespace CdbCore
src/plugins/debugger/cdb/breakpoint.h
View file @
2cd7e615
...
...
@@ -49,18 +49,21 @@ namespace CdbCore {
struct
BreakPoint
{
BreakPoint
();
enum
Type
{
Code
,
// Stop in code.
Data
// Stop when accessing address.
};
int
compare
(
const
BreakPoint
&
rhs
)
const
;
BreakPoint
()
;
void
clear
();
void
clearExpressionData
();
QString
expression
()
const
;
// Apply parameters
// Apply parameters (with the exception of type, which is
// passed as a parameter to IDebugControl within add().
bool
apply
(
IDebugBreakpoint2
*
ibp
,
QString
*
errorMessage
)
const
;
// Convenience to add to a IDebugControl4
// Convenience to add to a IDebugControl4
.
bool
add
(
CIDebugControl
*
debugControl
,
QString
*
errorMessage
,
unsigned
long
*
id
=
0
,
...
...
@@ -76,16 +79,20 @@ struct BreakPoint
static
IDebugBreakpoint2
*
breakPointById
(
CIDebugControl
*
ctl
,
unsigned
long
id
,
QString
*
errorMessage
);
static
bool
removeBreakPointById
(
CIDebugControl
*
ctl
,
unsigned
long
id
,
QString
*
errorMessage
);
static
bool
setBreakPointEnabledById
(
CIDebugControl
*
ctl
,
unsigned
long
id
,
bool
enabled
,
QString
*
errorMessage
);
static
bool
setBreakPointThreadById
(
CIDebugControl
*
ctl
,
unsigned
long
id
,
int
threadId
,
QString
*
errorMessage
);
// Return a 'canonical' file (using '/' and capitalized drive letter)
static
QString
normalizeFileName
(
const
QString
&
f
);
static
void
clearNormalizeFileNameCache
();
QString
toString
()
const
;
Type
type
;
QString
fileName
;
// short name of source file
int
lineNumber
;
// line in source file
QString
funcName
;
// name of containing function
quint64
address
;
int
threadId
;
QString
condition
;
// condition associated with breakpoint
unsigned
long
ignoreCount
;
// ignore count associated with breakpoint
bool
oneShot
;
...
...
@@ -94,10 +101,6 @@ struct BreakPoint
QDebug
operator
<<
(
QDebug
,
const
BreakPoint
&
bp
);
inline
bool
operator
==
(
const
BreakPoint
&
b1
,
const
BreakPoint
&
b2
)
{
return
b1
.
compare
(
b2
)
==
0
;
}
inline
bool
operator
!=
(
const
BreakPoint
&
b1
,
const
BreakPoint
&
b2
)
{
return
b1
.
compare
(
b2
)
!=
0
;
}
}
}
// namespace CdbCore
#endif // CDBCOREBREAKPOINTS_H
src/plugins/debugger/cdb/cdbbreakpoint.cpp
View file @
2cd7e615
...
...
@@ -37,6 +37,37 @@ namespace Internal {
enum
{
debugBP
=
0
};
// Convert breakpoint structs
CdbCore
::
BreakPoint
breakPointFromBreakPointData
(
const
Debugger
::
Internal
::
BreakpointData
&
bpd
)
{
CdbCore
::
BreakPoint
rc
;
rc
.
type
=
bpd
.
type
==
Debugger
::
Internal
::
BreakpointData
::
BreakpointType
?
CdbCore
::
BreakPoint
::
Code
:
CdbCore
::
BreakPoint
::
Data
;
if
(
rc
.
type
==
CdbCore
::
BreakPoint
::
Data
)
{
QByteArray
addressBA
=
bpd
.
address
;
if
(
addressBA
.
startsWith
(
"0x"
))
addressBA
.
remove
(
0
,
2
);
bool
ok
;
rc
.
address
=
addressBA
.
toULongLong
(
&
ok
,
16
);
if
(
!
ok
)
qWarning
(
"Cdb: Cannot convert watchpoint address '%s'"
,
bpd
.
address
.
constData
());
}
if
(
!
bpd
.
threadSpec
.
isEmpty
())
{
bool
ok
;
rc
.
threadId
=
bpd
.
threadSpec
.
toInt
(
&
ok
);
if
(
!
ok
)
qWarning
(
"Cdb: Cannot convert breakpoint thread specification '%s'"
,
bpd
.
address
.
constData
());
}
rc
.
fileName
=
QDir
::
toNativeSeparators
(
bpd
.
fileName
);
rc
.
condition
=
bpd
.
condition
;
rc
.
funcName
=
bpd
.
funcName
;
rc
.
ignoreCount
=
bpd
.
ignoreCount
.
isEmpty
()
?
0
:
bpd
.
ignoreCount
.
toInt
();
rc
.
lineNumber
=
bpd
.
lineNumber
.
isEmpty
()
?
-
1
:
bpd
.
lineNumber
.
toInt
();
rc
.
oneShot
=
false
;
rc
.
enabled
=
bpd
.
enabled
;
return
rc
;
}
static
inline
QString
msgCannotSetBreakAtFunction
(
const
QString
&
func
,
const
QString
&
why
)
{
...
...
@@ -93,7 +124,7 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
breakPointOk
=
ncdbbp
.
add
(
debugControl
,
&
warning
,
&
id
,
&
address
);
if
(
breakPointOk
)
{
if
(
debugBP
)
qDebug
(
)
<<
"Added
"
<<
id
<<
" at "
<<
address
<<
ncdbbp
;
qDebug
(
"Added
%lu at 0x%lx %s"
,
id
,
address
,
qPrintable
(
ncdbbp
.
toString
()))
;
handler
->
takeInsertedBreakPoint
(
nbd
);
updateMarkers
=
true
;
nbd
->
pending
=
false
;
...
...
@@ -123,6 +154,18 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
foreach
(
BreakpointData
*
dbd
,
handler
->
takeDisabledBreakpoints
())
if
(
!
CdbCore
::
BreakPoint
::
setBreakPointEnabledById
(
debugControl
,
dbd
->
bpNumber
.
toUInt
(),
false
,
&
warning
))
warnings
->
push_back
(
warning
);
// Check for modified thread ids.
for
(
int
i
=
handler
->
size
()
-
1
;
i
>=
0
;
i
--
)
{
BreakpointData
*
bpd
=
handler
->
at
(
i
);
if
(
bpd
->
threadSpec
!=
bpd
->
bpThreadSpec
)
{
const
int
newThreadSpec
=
bpd
->
threadSpec
.
isEmpty
()
?
-
1
:
bpd
->
threadSpec
.
toInt
();
if
(
CdbCore
::
BreakPoint
::
setBreakPointThreadById
(
debugControl
,
bpd
->
bpNumber
.
toUInt
(),
newThreadSpec
,
errorMessage
))
{
bpd
->
bpThreadSpec
=
bpd
->
threadSpec
;
}
else
{
qWarning
(
"%s"
,
qPrintable
(
*
errorMessage
));
}
}
}
if
(
updateMarkers
)
handler
->
updateMarkers
();
...
...
@@ -130,7 +173,11 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
if
(
debugBP
>
1
)
{
QList
<
CdbCore
::
BreakPoint
>
bps
;
CdbCore
::
BreakPoint
::
getBreakPoints
(
debugControl
,
&
bps
,
errorMessage
);
qDebug
().
nospace
()
<<
"### Breakpoints in engine: "
<<
bps
;
QDebug
nsp
=
qDebug
().
nospace
();
const
int
count
=
bps
.
size
();
nsp
<<
"### Breakpoints in engine: "
<<
count
<<
'\n'
;
for
(
int
i
=
0
;
i
<
count
;
i
++
)
nsp
<<
" #"
<<
i
<<
' '
<<
bps
.
at
(
i
)
<<
'\n'
;
}
return
true
;
}
...
...
src/plugins/debugger/cdb/cdbbreakpoint.h
View file @
2cd7e615
...
...
@@ -42,23 +42,12 @@ QT_BEGIN_NAMESPACE
class
QDebug
;
QT_END_NAMESPACE
// Convert breakpoint structs
inline
CdbCore
::
BreakPoint
breakPointFromBreakPointData
(
const
Debugger
::
Internal
::
BreakpointData
&
bpd
)
{
CdbCore
::
BreakPoint
rc
;
rc
.
fileName
=
QDir
::
toNativeSeparators
(
bpd
.
fileName
);
rc
.
condition
=
bpd
.
condition
;
rc
.
funcName
=
bpd
.
funcName
;
rc
.
ignoreCount
=
bpd
.
ignoreCount
.
isEmpty
()
?
0
:
bpd
.
ignoreCount
.
toInt
();
rc
.
lineNumber
=
bpd
.
lineNumber
.
isEmpty
()
?
-
1
:
bpd
.
lineNumber
.
toInt
();
rc
.
oneShot
=
false
;
rc
.
enabled
=
bpd
.
enabled
;
return
rc
;
}
namespace
Debugger
{
namespace
Internal
{
// Convert breakpoint structs
CdbCore
::
BreakPoint
breakPointFromBreakPointData
(
const
Debugger
::
Internal
::
BreakpointData
&
bpd
);
// Synchronize (halted) engine with BreakHandler.
bool
synchronizeBreakPoints
(
CIDebugControl
*
ctl
,
CIDebugSymbols
*
syms
,
BreakHandler
*
bh
,
...
...
src/plugins/debugger/cdb/cdbdebugengine.cpp
View file @
2cd7e615
...
...
@@ -1539,7 +1539,9 @@ void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
expression
.
clear
();
}
if
(
!
expression
.
isEmpty
())
m_stoppedMessage
=
CdbDebugEngine
::
tr
(
"Breakpoint: %1"
).
arg
(
expression
);
m_stoppedMessage
=
breakpoint
.
type
==
CdbCore
::
BreakPoint
::
Code
?
CdbDebugEngine
::
tr
(
"Breakpoint: %1"
).
arg
(
expression
)
:
CdbDebugEngine
::
tr
(
"Watchpoint: %1"
).
arg
(
expression
);
}
void
CdbDebugEngine
::
reloadSourceFiles
()
...
...
@@ -1560,7 +1562,8 @@ void CdbDebugEngine::syncDebuggerPaths()
unsigned
CdbDebugEngine
::
debuggerCapabilities
()
const
{
return
DisassemblerCapability
|
RegisterCapability
|
ShowMemoryCapability
;
return
DisassemblerCapability
|
RegisterCapability
|
ShowMemoryCapability
|
WatchpointCapability
;
}
// Accessed by DebuggerManager
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment