forked from qt-creator/qt-creator
Add gdb tracepoint support for Linux
Change-Id: Id2e46bae576a730f8c1b64a247aeed12e6d721af Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
committed by
Gustav Johansson
parent
874029809f
commit
2081038953
@@ -942,7 +942,7 @@ class DumperBase():
|
|||||||
for (k, v) in list(value.items())]) + '}'
|
for (k, v) in list(value.items())]) + '}'
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
return '[' + ','.join([self.resultToMi(k)
|
return '[' + ','.join([self.resultToMi(k)
|
||||||
for k in list(value.items())]) + ']'
|
for k in value]) + ']'
|
||||||
return '"%s"' % value
|
return '"%s"' % value
|
||||||
|
|
||||||
def variablesToMi(self, value, prefix):
|
def variablesToMi(self, value, prefix):
|
||||||
|
@@ -38,6 +38,8 @@ import tempfile
|
|||||||
|
|
||||||
from dumper import DumperBase, Children, toInteger, TopLevelItem
|
from dumper import DumperBase, Children, toInteger, TopLevelItem
|
||||||
from utils import TypeCode
|
from utils import TypeCode
|
||||||
|
from gdbtracepoint import *
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
#
|
#
|
||||||
@@ -1466,7 +1468,55 @@ class Dumper(DumperBase):
|
|||||||
print(timeit.repeat('theDumper.fetchVariables(%s)' % args,
|
print(timeit.repeat('theDumper.fetchVariables(%s)' % args,
|
||||||
'from __main__ import theDumper', number=10))
|
'from __main__ import theDumper', number=10))
|
||||||
|
|
||||||
|
def tracepointModified(self, tp):
|
||||||
|
self.tpExpressions = {}
|
||||||
|
self.tpExpressionWarnings = []
|
||||||
|
s = self.resultToMi(tp.dicts())
|
||||||
|
def handler():
|
||||||
|
print("tracepointmodified=%s" % s)
|
||||||
|
gdb.post_event(handler)
|
||||||
|
|
||||||
|
def tracepointHit(self, tp, result):
|
||||||
|
expressions = '{' + ','.join(["%s=%s" % (k,v) for k,v in self.tpExpressions.items()]) + '}'
|
||||||
|
warnings = []
|
||||||
|
if 'warning' in result.keys():
|
||||||
|
warnings.append(result.pop('warning'))
|
||||||
|
warnings += self.tpExpressionWarnings
|
||||||
|
r = self.resultToMi(result)
|
||||||
|
w = self.resultToMi(warnings)
|
||||||
|
def handler():
|
||||||
|
print("tracepointhit={result=%s,expressions=%s,warnings=%s}" % (r, expressions, w))
|
||||||
|
gdb.post_event(handler)
|
||||||
|
|
||||||
|
def tracepointExpression(self, tp, expression, value, args):
|
||||||
|
key = "x" + str(len(self.tpExpressions))
|
||||||
|
if (isinstance(value, gdb.Value)):
|
||||||
|
try:
|
||||||
|
val = self.fromNativeValue(value)
|
||||||
|
self.prepare(args)
|
||||||
|
with TopLevelItem(self, expression):
|
||||||
|
self.putItem(val)
|
||||||
|
self.tpExpressions[key] = self.output
|
||||||
|
except Exception as e:
|
||||||
|
self.tpExpressions[key] = '"<N/A>"'
|
||||||
|
self.tpExpressionWarnings.append(str(e))
|
||||||
|
elif (isinstance(value, Exception)):
|
||||||
|
self.tpExpressions[key] = '"<N/A>"'
|
||||||
|
self.tpExpressionWarnings.append(str(value))
|
||||||
|
else:
|
||||||
|
self.tpExpressions[key] = '"<N/A>"'
|
||||||
|
self.tpExpressionWarnings.append('Unknown expression value type')
|
||||||
|
return key
|
||||||
|
|
||||||
|
def createTracepoint(self, args):
|
||||||
|
"""
|
||||||
|
Creates a tracepoint
|
||||||
|
"""
|
||||||
|
tp = GDBTracepoint.create(args,
|
||||||
|
onModified=self.tracepointModified,
|
||||||
|
onHit=self.tracepointHit,
|
||||||
|
onExpression=lambda tp, expr, val: self.tracepointExpression(tp, expr, val, args))
|
||||||
|
self.reportResult("tracepoint=%s" % self.resultToMi(tp.dicts()), args)
|
||||||
class CliDumper(Dumper):
|
class CliDumper(Dumper):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Dumper.__init__(self)
|
Dumper.__init__(self)
|
||||||
|
399
share/qtcreator/debugger/gdbtracepoint.py
Normal file
399
share/qtcreator/debugger/gdbtracepoint.py
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
# Contact: https://www.qt.io/licensing/
|
||||||
|
#
|
||||||
|
# This file is part of Qt Creator.
|
||||||
|
#
|
||||||
|
# Commercial License Usage
|
||||||
|
# Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
# accordance with the commercial license agreement provided with the
|
||||||
|
# Software or, alternatively, in accordance with the terms contained in
|
||||||
|
# a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
# and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
# information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
#
|
||||||
|
# GNU General Public License Usage
|
||||||
|
# Alternatively, this file may be used under the terms of the GNU
|
||||||
|
# General Public License version 3 as published by the Free Software
|
||||||
|
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
# included in the packaging of this file. Please review the following
|
||||||
|
# information to ensure the GNU General Public License requirements will
|
||||||
|
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# for ProcessName capture
|
||||||
|
try:
|
||||||
|
import psutil
|
||||||
|
except:
|
||||||
|
psutil = None
|
||||||
|
|
||||||
|
# Caps types
|
||||||
|
Address, \
|
||||||
|
Caller, \
|
||||||
|
Callstack, \
|
||||||
|
FilePos, \
|
||||||
|
Function, \
|
||||||
|
Pid, \
|
||||||
|
ProcessName, \
|
||||||
|
Tick, \
|
||||||
|
Tid, \
|
||||||
|
ThreadName, \
|
||||||
|
Expression, \
|
||||||
|
= range(0, 11)
|
||||||
|
|
||||||
|
class GDBTracepoint(gdb.Breakpoint):
|
||||||
|
"""
|
||||||
|
Python Breakpoint extension for "tracepoints", breakpoints that do not stop the inferior
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create(args, onModified, onHit, onExpression):
|
||||||
|
"""
|
||||||
|
Static creator function
|
||||||
|
"""
|
||||||
|
tp_kwargs = {}
|
||||||
|
if 'temporary' in args.keys():
|
||||||
|
tp_kwargs['temporary'] = args['temporary']
|
||||||
|
spec = args['spec']
|
||||||
|
tp = GDBTracepoint(spec, **tp_kwargs)
|
||||||
|
tp.onModified = onModified
|
||||||
|
tp.onHit = onHit
|
||||||
|
tp.onExpression = onExpression
|
||||||
|
if 'ignore_count' in args.keys():
|
||||||
|
tp.ignore_count = args['ignore_count']
|
||||||
|
if 'enabled' in args.keys():
|
||||||
|
tp.enabled = args['enabled']
|
||||||
|
if 'thread' in args.keys():
|
||||||
|
tp.thread = args['thread']
|
||||||
|
if 'condition' in args.keys():
|
||||||
|
tp.condition = args['condition']
|
||||||
|
if 'caps' in args.keys():
|
||||||
|
for ce in args['caps']:
|
||||||
|
tp.addCaps(ce[0], ce[1])
|
||||||
|
return tp
|
||||||
|
|
||||||
|
def __init__(self, spec, **kwargs):
|
||||||
|
"""
|
||||||
|
Constructor
|
||||||
|
"""
|
||||||
|
kwargs['internal'] = True
|
||||||
|
super(GDBTracepoint, self).__init__(spec, **kwargs)
|
||||||
|
self.caps = []
|
||||||
|
|
||||||
|
_hexSize = 8 if sys.maxsize > 2**32 else 4
|
||||||
|
_hasMonotonicTime = False if sys.version_info[0] <= 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 3) else True
|
||||||
|
|
||||||
|
def dicts(self):
|
||||||
|
"""
|
||||||
|
Returns dictionareis for mi representation
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
result = {}
|
||||||
|
result['number'] = str(self.number)
|
||||||
|
result['enabled'] = 'y' if self.enabled else 'n'
|
||||||
|
result['type'] = 'pseudo_tracepoint'
|
||||||
|
result['disp'] = 'del' if self.temporary else 'keep'
|
||||||
|
result['times'] = str(self.hit_count)
|
||||||
|
result['original-location'] = self.location
|
||||||
|
try:
|
||||||
|
d = gdb.decode_line(self.location)
|
||||||
|
if d[1] is None:
|
||||||
|
result['addr'] = '<PENDING>'
|
||||||
|
result['pending'] = self.location
|
||||||
|
results.append(result)
|
||||||
|
else:
|
||||||
|
if len(d[1]) > 1:
|
||||||
|
result['addr'] = '<MULTIPLE>'
|
||||||
|
results.append(result)
|
||||||
|
for i, sl in enumerate(d[1]):
|
||||||
|
result_ = {}
|
||||||
|
result_['number'] = result['number'] + "." + str(i + 1)
|
||||||
|
result_['enabled'] = 'y' if self.enabled else 'n'
|
||||||
|
if sl.pc is None:
|
||||||
|
result_['addr'] = '<no address>'
|
||||||
|
else:
|
||||||
|
result_['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
|
||||||
|
if sl.symtab and sl.symtab.is_valid():
|
||||||
|
func = self._getFunctionFromAddr(sl.pc)
|
||||||
|
if func:
|
||||||
|
result_['func'] = func.print_name
|
||||||
|
result_['file'] = sl.symtab.filename
|
||||||
|
result_['fullname'] = sl.symtab.fullname()
|
||||||
|
result_['line'] = sl.line
|
||||||
|
results.append(result_)
|
||||||
|
else:
|
||||||
|
sl = d[1][0]
|
||||||
|
if sl.pc is None:
|
||||||
|
result['addr'] = '<no address>'
|
||||||
|
else:
|
||||||
|
result['addr'] = '{0:#0{1}x}'.format(sl.pc, self._hexSize + 2)
|
||||||
|
if sl.symtab and sl.symtab.is_valid():
|
||||||
|
func = self._getFunctionFromAddr(sl.pc)
|
||||||
|
if func:
|
||||||
|
result['func'] = func.print_name
|
||||||
|
result['file'] = sl.symtab.filename
|
||||||
|
result['fullname'] = sl.symtab.fullname()
|
||||||
|
result['line'] = sl.line
|
||||||
|
results.append(result)
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
result['addr'] = '<PENDING>'
|
||||||
|
result['pending'] = self.location
|
||||||
|
results.append(result)
|
||||||
|
return results
|
||||||
|
|
||||||
|
def addCaps(self, capsType, expression=None):
|
||||||
|
"""
|
||||||
|
Adds capture expressions for a tracepoint
|
||||||
|
|
||||||
|
:param caps_type: Type of capture
|
||||||
|
:param expression: Expression for Expression caps type
|
||||||
|
"""
|
||||||
|
if capsType != Expression:
|
||||||
|
expression = None
|
||||||
|
else:
|
||||||
|
if expression is None:
|
||||||
|
expression = ''
|
||||||
|
self.caps.append((self.capsMap[capsType], expression))
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Overridden stop function, this evaluates conditions and captures data from the inferior
|
||||||
|
|
||||||
|
:return: Always False
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.onModified(self)
|
||||||
|
result = {}
|
||||||
|
result['number'] = self.number
|
||||||
|
try:
|
||||||
|
if self.condition:
|
||||||
|
try:
|
||||||
|
result = gdb.parse_and_eval(self.condition)
|
||||||
|
if result.type.code == gdb.TYPE_CODE_BOOL and str(result) == 'false':
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if self.ignore_count > 0:
|
||||||
|
return False
|
||||||
|
if self.thread and gdb.selected_thread().global_num != self.thread:
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
result['warning'] = str(e)
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
if len(self.caps) > 0:
|
||||||
|
caps = []
|
||||||
|
try:
|
||||||
|
for func, expr in self.caps:
|
||||||
|
if expr is None:
|
||||||
|
caps.append(func(self))
|
||||||
|
else:
|
||||||
|
caps.append(func(self, expr))
|
||||||
|
except Exception as e:
|
||||||
|
result['warning'] = str(e)
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
result['caps'] = caps
|
||||||
|
self.onHit(self, result)
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
# Always return false, regardless...
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _getFunctionFromAddr(self, addr):
|
||||||
|
try:
|
||||||
|
block = gdb.block_for_pc(addr)
|
||||||
|
while block and not block.function:
|
||||||
|
block = block.superblock
|
||||||
|
if block is None:
|
||||||
|
return None
|
||||||
|
return block.function
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _getAddress(self):
|
||||||
|
"""
|
||||||
|
Capture function for Address
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
return '{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<null address>'
|
||||||
|
|
||||||
|
def _getCaller(self):
|
||||||
|
"""
|
||||||
|
Capture function for Caller
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
frame = frame.older()
|
||||||
|
if not (frame is None) and (frame.is_valid()):
|
||||||
|
name = frame.name()
|
||||||
|
if name is None:
|
||||||
|
return '<unknown caller>'
|
||||||
|
return name
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown caller>'
|
||||||
|
|
||||||
|
def _getCallstack(self):
|
||||||
|
"""
|
||||||
|
Capture function for Callstack
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frames = []
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if (frame is None) or (not frame.is_valid()):
|
||||||
|
frames.append('<unknown frame>')
|
||||||
|
return str(frames)
|
||||||
|
while not (frame is None):
|
||||||
|
func = frame.function()
|
||||||
|
if func is None:
|
||||||
|
frames.append('{0:#0{1}x}'.format(frame.pc(), self._hexSize + 2))
|
||||||
|
else:
|
||||||
|
sl = frame.find_sal()
|
||||||
|
if sl is None:
|
||||||
|
frames.append(func.symtab.filename)
|
||||||
|
else:
|
||||||
|
frames.append(func.symtab.filename + ':' + str(sl.line))
|
||||||
|
frame = frame.older()
|
||||||
|
return frames
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
def _getFilePos(self):
|
||||||
|
"""
|
||||||
|
Capture function for FilePos
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if (frame is None) or (not frame.is_valid()):
|
||||||
|
return '<unknown file pos>'
|
||||||
|
sl = frame.find_sal()
|
||||||
|
if sl is None:
|
||||||
|
return '<unknown file pos>'
|
||||||
|
return sl.symtab.filename + ':' + str(sl.line)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
def _getFunction(self):
|
||||||
|
"""
|
||||||
|
Capture function for Function
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
if not (frame is None):
|
||||||
|
return str(frame.name())
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown function>'
|
||||||
|
|
||||||
|
def _getPid(self):
|
||||||
|
"""
|
||||||
|
Capture function for Pid
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
(pid, lwpid, tid) = thread.ptid
|
||||||
|
return str(pid)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown pid>'
|
||||||
|
|
||||||
|
def _getProcessName(slef):
|
||||||
|
"""
|
||||||
|
Capture for ProcessName
|
||||||
|
"""
|
||||||
|
# gdb does not expose process name, neither does (standard) python
|
||||||
|
# You can use for example psutil, but it might not be present.
|
||||||
|
# Default to name of thread with ID 1
|
||||||
|
inf = gdb.selected_inferior()
|
||||||
|
if psutil is None:
|
||||||
|
try:
|
||||||
|
if inf is None:
|
||||||
|
return '<unknown process name>'
|
||||||
|
threads = filter(lambda t: t.num == 1, list(inf.threads()))
|
||||||
|
if len(threads) < 1:
|
||||||
|
return '<unknown process name>'
|
||||||
|
thread = threads[0]
|
||||||
|
# use thread name
|
||||||
|
return thread.name
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
else:
|
||||||
|
return psutil.Process(inf.pid).name()
|
||||||
|
|
||||||
|
def _getTick(self):
|
||||||
|
"""
|
||||||
|
Capture function for Tick
|
||||||
|
"""
|
||||||
|
if self._hasMonotonicTime:
|
||||||
|
return str(int(time.monotonic() * 1000))
|
||||||
|
else:
|
||||||
|
return '<monotonic time not available>'
|
||||||
|
|
||||||
|
def _getTid(self):
|
||||||
|
"""
|
||||||
|
Capture function for Tid
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
(pid, lwpid, tid) = thread.ptid
|
||||||
|
if tid == 0:
|
||||||
|
return str(lwpid)
|
||||||
|
else:
|
||||||
|
return str(tid)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown tid>'
|
||||||
|
|
||||||
|
def _getThreadName(self):
|
||||||
|
"""
|
||||||
|
Capture function for ThreadName
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
thread = gdb.selected_thread()
|
||||||
|
if not (thread is None):
|
||||||
|
return str(thread.name)
|
||||||
|
except Exception as e:
|
||||||
|
return str(e)
|
||||||
|
return '<unknown thread name>'
|
||||||
|
|
||||||
|
def _getExpression(self, expression):
|
||||||
|
"""
|
||||||
|
Capture function for Expression
|
||||||
|
|
||||||
|
:param expr: The expression to evaluate
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
value = gdb.parse_and_eval(expression)
|
||||||
|
if value:
|
||||||
|
return self.onExpression(self, expression, value)
|
||||||
|
except Exception as e:
|
||||||
|
return self.onExpression(self, expression, e)
|
||||||
|
|
||||||
|
capsMap = {Address: _getAddress,
|
||||||
|
Caller: _getCaller,
|
||||||
|
Callstack: _getCallstack,
|
||||||
|
FilePos: _getFilePos,
|
||||||
|
Function: _getFunction,
|
||||||
|
Pid: _getPid,
|
||||||
|
ProcessName: _getProcessName,
|
||||||
|
Tid: _getTid,
|
||||||
|
Tick: _getTick,
|
||||||
|
ThreadName: _getThreadName,
|
||||||
|
Expression: _getExpression}
|
@@ -611,17 +611,13 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask)
|
|||||||
m_lineEditModule->setEnabled(partsMask & ModulePart);
|
m_lineEditModule->setEnabled(partsMask & ModulePart);
|
||||||
|
|
||||||
m_labelTracepoint->setEnabled(partsMask & TracePointPart);
|
m_labelTracepoint->setEnabled(partsMask & TracePointPart);
|
||||||
m_labelTracepoint->hide();
|
|
||||||
m_checkBoxTracepoint->setEnabled(partsMask & TracePointPart);
|
m_checkBoxTracepoint->setEnabled(partsMask & TracePointPart);
|
||||||
m_checkBoxTracepoint->hide();
|
|
||||||
|
|
||||||
m_labelCommands->setEnabled(partsMask & CommandPart);
|
m_labelCommands->setEnabled(partsMask & CommandPart);
|
||||||
m_textEditCommands->setEnabled(partsMask & CommandPart);
|
m_textEditCommands->setEnabled(partsMask & CommandPart);
|
||||||
|
|
||||||
m_labelMessage->setEnabled(partsMask & TracePointPart);
|
m_labelMessage->setEnabled(partsMask & TracePointPart);
|
||||||
m_labelMessage->hide();
|
|
||||||
m_lineEditMessage->setEnabled(partsMask & TracePointPart);
|
m_lineEditMessage->setEnabled(partsMask & TracePointPart);
|
||||||
m_lineEditMessage->hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BreakpointDialog::clearOtherParts(unsigned partsMask)
|
void BreakpointDialog::clearOtherParts(unsigned partsMask)
|
||||||
@@ -2106,6 +2102,8 @@ QString BreakpointItem::msgBreakpointTriggered(const QString &threadId) const
|
|||||||
QVariant SubBreakpointItem::data(int column, int role) const
|
QVariant SubBreakpointItem::data(int column, int role) const
|
||||||
{
|
{
|
||||||
if (role == Qt::DecorationRole && column == 0) {
|
if (role == Qt::DecorationRole && column == 0) {
|
||||||
|
if (params.tracepoint)
|
||||||
|
return Icons::TRACEPOINT.icon();
|
||||||
return params.enabled ? Icons::BREAKPOINT.icon()
|
return params.enabled ? Icons::BREAKPOINT.icon()
|
||||||
: Icons::BREAKPOINT_DISABLED.icon();
|
: Icons::BREAKPOINT_DISABLED.icon();
|
||||||
}
|
}
|
||||||
|
@@ -176,6 +176,7 @@ public:
|
|||||||
void setIgnoreCount(int count) { m_parameters.ignoreCount = count; }
|
void setIgnoreCount(int count) { m_parameters.ignoreCount = count; }
|
||||||
void setCommand(const QString &command) { m_parameters.command = command; }
|
void setCommand(const QString &command) { m_parameters.command = command; }
|
||||||
void setCondition(const QString &condition) { m_parameters.condition = condition; }
|
void setCondition(const QString &condition) { m_parameters.condition = condition; }
|
||||||
|
void setMessage(const QString& message) { m_parameters.message = message; }
|
||||||
|
|
||||||
QString msgWatchpointByAddressTriggered(quint64 address) const;
|
QString msgWatchpointByAddressTriggered(quint64 address) const;
|
||||||
QString msgWatchpointByAddressTriggered(quint64 address, const QString &threadId) const;
|
QString msgWatchpointByAddressTriggered(quint64 address, const QString &threadId) const;
|
||||||
|
@@ -506,6 +506,12 @@ DebuggerSettings::DebuggerSettings()
|
|||||||
item->setDefaultValue(true);
|
item->setDefaultValue(true);
|
||||||
insertItem(UseAnnotationsInMainEditor, item);
|
insertItem(UseAnnotationsInMainEditor, item);
|
||||||
|
|
||||||
|
item = new SavedAction;
|
||||||
|
item->setSettingsKey(debugModeGroup, "UsePseudoTracepoints");
|
||||||
|
item->setCheckable(true);
|
||||||
|
item->setDefaultValue(true);
|
||||||
|
insertItem(UsePseudoTracepoints, item);
|
||||||
|
|
||||||
item = new SavedAction;
|
item = new SavedAction;
|
||||||
item->setSettingsKey(debugModeGroup, "UseToolTips");
|
item->setSettingsKey(debugModeGroup, "UseToolTips");
|
||||||
item->setText(tr("Use tooltips in main editor when debugging"));
|
item->setText(tr("Use tooltips in main editor when debugging"));
|
||||||
|
@@ -134,6 +134,7 @@ enum DebuggerActionCode
|
|||||||
WarnOnReleaseBuilds,
|
WarnOnReleaseBuilds,
|
||||||
MultiInferior,
|
MultiInferior,
|
||||||
IntelFlavor,
|
IntelFlavor,
|
||||||
|
UsePseudoTracepoints,
|
||||||
|
|
||||||
// Stack
|
// Stack
|
||||||
MaximalStackDepth,
|
MaximalStackDepth,
|
||||||
|
@@ -115,6 +115,31 @@ static QMessageBox *showMessageBox(QMessageBox::Icon icon,
|
|||||||
return mb;
|
return mb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class TracepointCaptureType
|
||||||
|
{
|
||||||
|
Address,
|
||||||
|
Caller,
|
||||||
|
Callstack,
|
||||||
|
FilePos,
|
||||||
|
Function,
|
||||||
|
Pid,
|
||||||
|
ProcessName,
|
||||||
|
Tick,
|
||||||
|
Tid,
|
||||||
|
ThreadName,
|
||||||
|
Expression
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TracepointCaptureData
|
||||||
|
{
|
||||||
|
TracepointCaptureType type;
|
||||||
|
QVariant expression;
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char tracepointCapturePropertyName[] = "GDB.TracepointCapture";
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// GdbEngine
|
// GdbEngine
|
||||||
@@ -307,6 +332,18 @@ void GdbEngine::handleResponse(const QString &buff)
|
|||||||
handleInterpreterBreakpointModified(allData["interpreterasync"]);
|
handleInterpreterBreakpointModified(allData["interpreterasync"]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (data.startsWith("tracepointhit={")) {
|
||||||
|
GdbMi allData;
|
||||||
|
allData.fromStringMultiple(data);
|
||||||
|
handleTracepointHit(allData["tracepointhit"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data.startsWith("tracepointmodified=")) {
|
||||||
|
GdbMi allData;
|
||||||
|
allData.fromStringMultiple(data);
|
||||||
|
handleTracepointModified(allData["tracepointmodified"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
m_pendingConsoleStreamOutput += data;
|
m_pendingConsoleStreamOutput += data;
|
||||||
|
|
||||||
// Fragile, but it's all we have.
|
// Fragile, but it's all we have.
|
||||||
@@ -2162,6 +2199,7 @@ void GdbEngine::handleCatchInsert(const DebuggerResponse &response, const Breakp
|
|||||||
void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
|
void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(bp, return);
|
QTC_ASSERT(bp, return);
|
||||||
|
bool usePseudoTracepoints = boolSetting(UsePseudoTracepoints);
|
||||||
const QString nr = bkpt["number"].data();
|
const QString nr = bkpt["number"].data();
|
||||||
if (nr.contains('.')) {
|
if (nr.contains('.')) {
|
||||||
// A sub-breakpoint.
|
// A sub-breakpoint.
|
||||||
@@ -2169,6 +2207,10 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
|
|||||||
QTC_ASSERT(sub, return);
|
QTC_ASSERT(sub, return);
|
||||||
sub->params.updateFromGdbOutput(bkpt);
|
sub->params.updateFromGdbOutput(bkpt);
|
||||||
sub->params.type = bp->type();
|
sub->params.type = bp->type();
|
||||||
|
if (usePseudoTracepoints && bp->isTracepoint()) {
|
||||||
|
sub->params.tracepoint = true;
|
||||||
|
sub->params.message = bp->message();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2183,12 +2225,18 @@ void GdbEngine::handleBkpt(const GdbMi &bkpt, const Breakpoint &bp)
|
|||||||
QTC_ASSERT(sub, return);
|
QTC_ASSERT(sub, return);
|
||||||
sub->params.updateFromGdbOutput(location);
|
sub->params.updateFromGdbOutput(location);
|
||||||
sub->params.type = bp->type();
|
sub->params.type = bp->type();
|
||||||
|
if (usePseudoTracepoints && bp->isTracepoint()) {
|
||||||
|
sub->params.tracepoint = true;
|
||||||
|
sub->params.message = bp->message();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A (the?) primary breakpoint.
|
// A (the?) primary breakpoint.
|
||||||
bp->setResponseId(nr);
|
bp->setResponseId(nr);
|
||||||
bp->updateFromGdbOutput(bkpt);
|
bp->updateFromGdbOutput(bkpt);
|
||||||
|
if (usePseudoTracepoints && bp->isTracepoint())
|
||||||
|
bp->setMessage(bp->requestedParameters().message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp)
|
void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, const Breakpoint &bp)
|
||||||
@@ -2334,6 +2382,176 @@ void GdbEngine::handleBreakCondition(const DebuggerResponse &, const Breakpoint
|
|||||||
updateBreakpoint(bp); // Maybe there's more to do.
|
updateBreakpoint(bp); // Maybe there's more to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GdbEngine::updateTracepointCaptures(const Breakpoint &bp)
|
||||||
|
{
|
||||||
|
static QRegularExpression capsRegExp(
|
||||||
|
"(^|[^\\\\])(\\$(ADDRESS|CALLER|CALLSTACK|FILEPOS|FUNCTION|PID|PNAME|TICK|TID|TNAME)"
|
||||||
|
"|{[^}]+})");
|
||||||
|
QString message = bp->globalBreakpoint()->requestedParameters().message;
|
||||||
|
if (message.isEmpty()) {
|
||||||
|
bp->setProperty(tracepointCapturePropertyName, {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVariantList caps;
|
||||||
|
QRegularExpressionMatch match = capsRegExp.match(message, 0);
|
||||||
|
while (match.hasMatch()) {
|
||||||
|
QString t = match.captured(2);
|
||||||
|
if (t[0] == '$') {
|
||||||
|
TracepointCaptureType type;
|
||||||
|
if (t == "$ADDRESS")
|
||||||
|
type = TracepointCaptureType::Address;
|
||||||
|
else if (t == "$CALLER")
|
||||||
|
type = TracepointCaptureType::Caller;
|
||||||
|
else if (t == "$CALLSTACK")
|
||||||
|
type = TracepointCaptureType::Callstack;
|
||||||
|
else if (t == "$FILEPOS")
|
||||||
|
type = TracepointCaptureType::FilePos;
|
||||||
|
else if (t == "$FUNCTION")
|
||||||
|
type = TracepointCaptureType::Function;
|
||||||
|
else if (t == "$PID")
|
||||||
|
type = TracepointCaptureType::Pid;
|
||||||
|
else if (t == "$PNAME")
|
||||||
|
type = TracepointCaptureType::ProcessName;
|
||||||
|
else if (t == "$TICK")
|
||||||
|
type = TracepointCaptureType::Tick;
|
||||||
|
else if (t == "$TID")
|
||||||
|
type = TracepointCaptureType::Tid;
|
||||||
|
else if (t == "$TNAME")
|
||||||
|
type = TracepointCaptureType::ThreadName;
|
||||||
|
else
|
||||||
|
QTC_ASSERT(false, continue);
|
||||||
|
caps << QVariant::fromValue<TracepointCaptureData>(
|
||||||
|
{type, {}, match.capturedStart(2), match.capturedEnd(2)});
|
||||||
|
} else {
|
||||||
|
QString expression = t.mid(1, t.length() - 2);
|
||||||
|
caps << QVariant::fromValue<TracepointCaptureData>(
|
||||||
|
{TracepointCaptureType::Expression, expression, match.capturedStart(2), match.capturedEnd(2)});
|
||||||
|
}
|
||||||
|
match = capsRegExp.match(message, match.capturedEnd());
|
||||||
|
}
|
||||||
|
bp->setProperty(tracepointCapturePropertyName, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleTracepointInsert(const DebuggerResponse &response, const Breakpoint &bp)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(bp, return);
|
||||||
|
if (bp->state() == BreakpointRemoveRequested) {
|
||||||
|
if (response.resultClass == ResultDone) {
|
||||||
|
// This delete was deferred. Act now.
|
||||||
|
const GdbMi mainbkpt = response.data["tracepoint"][0];
|
||||||
|
notifyBreakpointRemoveProceeding(bp);
|
||||||
|
DebuggerCommand cmd("-break-delete " + mainbkpt["number"].data());
|
||||||
|
cmd.flags = NeedsTemporaryStop;
|
||||||
|
runCommand(cmd);
|
||||||
|
notifyBreakpointRemoveOk(bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (response.resultClass == ResultDone) {
|
||||||
|
for (const GdbMi &bkpt : response.data["tracepoint"])
|
||||||
|
handleBkpt(bkpt, bp);
|
||||||
|
if (bp->needsChange()) {
|
||||||
|
bp->gotoState(BreakpointUpdateRequested, BreakpointInsertionProceeding);
|
||||||
|
updateBreakpoint(bp);
|
||||||
|
} else {
|
||||||
|
notifyBreakpointInsertOk(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleTracepointHit(const GdbMi &data)
|
||||||
|
{
|
||||||
|
const GdbMi &result = data["result"];
|
||||||
|
const QString rid = result["number"].data();
|
||||||
|
Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
|
||||||
|
QTC_ASSERT(bp, return);
|
||||||
|
const GdbMi &warnings = data["warnings"];
|
||||||
|
if (warnings.childCount() > 0) {
|
||||||
|
for (const GdbMi &warning: warnings) {
|
||||||
|
emit appendMessageRequested(warning.toString(), ErrorMessageFormat, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString message = bp->message();
|
||||||
|
QVariant caps = bp->property(tracepointCapturePropertyName);
|
||||||
|
if (caps.isValid()) {
|
||||||
|
QList<QVariant> capsList = caps.toList();
|
||||||
|
const GdbMi &miCaps = result["caps"];
|
||||||
|
if (capsList.length() == miCaps.childCount()) {
|
||||||
|
// reverse iterate to make start/end correct
|
||||||
|
for (int i = capsList.length() - 1; i >= 0; --i) {
|
||||||
|
TracepointCaptureData cap = capsList.at(i).value<TracepointCaptureData>();
|
||||||
|
const GdbMi &miCap = miCaps.childAt(i);
|
||||||
|
switch (cap.type) {
|
||||||
|
case TracepointCaptureType::Callstack: {
|
||||||
|
QStringList frames;
|
||||||
|
for (const GdbMi &frame: miCap) {
|
||||||
|
frames.append(frame.data());
|
||||||
|
}
|
||||||
|
message.replace(cap.start, cap.end - cap.start, frames.join(" <- "));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TracepointCaptureType::Expression: {
|
||||||
|
QString key = miCap.data();
|
||||||
|
const GdbMi &expression = data["expressions"][key.toLatin1().data()];
|
||||||
|
if (expression.isValid()) {
|
||||||
|
QString s = expression.toString();
|
||||||
|
// remove '<key>='
|
||||||
|
s = s.right(s.length() - key.length() - 1);
|
||||||
|
message.replace(cap.start, cap.end - cap.start, s);
|
||||||
|
} else {
|
||||||
|
QTC_CHECK(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
message.replace(cap.start, cap.end - cap.start, miCap.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QTC_CHECK(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showMessage(message);
|
||||||
|
emit appendMessageRequested(message, NormalMessageFormat, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleTracepointModified(const GdbMi &data)
|
||||||
|
{
|
||||||
|
QString ba = data.toString();
|
||||||
|
// remove original-location
|
||||||
|
const int pos1 = ba.indexOf("original-location=");
|
||||||
|
const int pos2 = ba.indexOf(":", pos1 + 17);
|
||||||
|
int pos3 = ba.indexOf('"', pos2 + 1);
|
||||||
|
if (ba[pos3 + 1] == ',')
|
||||||
|
++pos3;
|
||||||
|
ba.remove(pos1, pos3 - pos1 + 1);
|
||||||
|
GdbMi res;
|
||||||
|
res.fromString(ba);
|
||||||
|
BreakHandler *handler = breakHandler();
|
||||||
|
Breakpoint bp;
|
||||||
|
for (const GdbMi &bkpt : res) {
|
||||||
|
const QString nr = bkpt["number"].data();
|
||||||
|
if (nr.contains('.')) {
|
||||||
|
// A sub-breakpoint.
|
||||||
|
QTC_ASSERT(bp, continue);
|
||||||
|
SubBreakpoint loc = bp->findOrCreateSubBreakpoint(nr);
|
||||||
|
loc->params.updateFromGdbOutput(bkpt);
|
||||||
|
loc->params.type = bp->type();
|
||||||
|
if (bp->isTracepoint()) {
|
||||||
|
loc->params.tracepoint = true;
|
||||||
|
loc->params.message = bp->message();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// A primary breakpoint.
|
||||||
|
bp = handler->findBreakpointByResponseId(nr);
|
||||||
|
if (bp)
|
||||||
|
bp->updateFromGdbOutput(bkpt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QTC_ASSERT(bp, return);
|
||||||
|
bp->adjustMarker();
|
||||||
|
}
|
||||||
|
|
||||||
bool GdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
|
bool GdbEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
|
||||||
{
|
{
|
||||||
if (runParameters().startMode == AttachToCore)
|
if (runParameters().startMode == AttachToCore)
|
||||||
@@ -2387,31 +2605,100 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp)
|
|||||||
cmd.function = "catch syscall";
|
cmd.function = "catch syscall";
|
||||||
cmd.callback = handleCatch;
|
cmd.callback = handleCatch;
|
||||||
} else {
|
} else {
|
||||||
|
int spec = requested.threadSpec;
|
||||||
if (requested.isTracepoint()) {
|
if (requested.isTracepoint()) {
|
||||||
cmd.function = "-break-insert -a -f ";
|
|
||||||
|
if (boolSetting(UsePseudoTracepoints)) {
|
||||||
|
cmd.function = "createTracepoint";
|
||||||
|
|
||||||
|
if (requested.oneShot)
|
||||||
|
cmd.arg("temporary", true);
|
||||||
|
|
||||||
|
if (int ignoreCount = requested.ignoreCount)
|
||||||
|
cmd.arg("ignore_count", ignoreCount);
|
||||||
|
|
||||||
|
QString condition = requested.condition;
|
||||||
|
if (!condition.isEmpty())
|
||||||
|
cmd.arg("condition", condition.replace('"', "\\\""));
|
||||||
|
|
||||||
|
if (spec >= 0)
|
||||||
|
cmd.arg("thread", spec);
|
||||||
|
|
||||||
|
updateTracepointCaptures(bp);
|
||||||
|
QVariant tpCaps = bp->property(tracepointCapturePropertyName);
|
||||||
|
if (tpCaps.isValid()) {
|
||||||
|
QJsonArray caps;
|
||||||
|
foreach (const auto &tpCap, tpCaps.toList()) {
|
||||||
|
TracepointCaptureData data = tpCap.value<TracepointCaptureData>();
|
||||||
|
QJsonArray cap;
|
||||||
|
cap.append(static_cast<int>(data.type));
|
||||||
|
if (data.expression.isValid())
|
||||||
|
cap.append(data.expression.toString());
|
||||||
|
else
|
||||||
|
cap.append(QJsonValue::Null);
|
||||||
|
caps.append(cap);
|
||||||
|
}
|
||||||
|
cmd.arg("caps", caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for dumping of expressions
|
||||||
|
const static bool alwaysVerbose = qEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
|
||||||
|
cmd.arg("passexceptions", alwaysVerbose);
|
||||||
|
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
|
||||||
|
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
|
||||||
|
cmd.arg("dyntype", boolSetting(UseDynamicType));
|
||||||
|
cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
|
||||||
|
cmd.arg("nativemixed", isNativeMixedActive());
|
||||||
|
cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
|
||||||
|
cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());
|
||||||
|
|
||||||
|
cmd.arg("spec", breakpointLocation2(requested));
|
||||||
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleTracepointInsert(r, bp); };
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cmd.function = "-break-insert -a -f ";
|
||||||
|
|
||||||
|
if (requested.oneShot)
|
||||||
|
cmd.function += "-t ";
|
||||||
|
|
||||||
|
if (!requested.enabled)
|
||||||
|
cmd.function += "-d ";
|
||||||
|
|
||||||
|
if (int ignoreCount = requested.ignoreCount)
|
||||||
|
cmd.function += "-i " + QString::number(ignoreCount) + ' ';
|
||||||
|
|
||||||
|
QString condition = requested.condition;
|
||||||
|
if (!condition.isEmpty())
|
||||||
|
cmd.function += " -c \"" + condition.replace('"', "\\\"") + "\" ";
|
||||||
|
|
||||||
|
cmd.function += breakpointLocation(requested);
|
||||||
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int spec = requested.threadSpec;
|
|
||||||
cmd.function = "-break-insert ";
|
cmd.function = "-break-insert ";
|
||||||
if (spec >= 0)
|
if (spec >= 0)
|
||||||
cmd.function += "-p " + QString::number(spec);
|
cmd.function += "-p " + QString::number(spec);
|
||||||
cmd.function += " -f ";
|
cmd.function += " -f ";
|
||||||
}
|
|
||||||
|
|
||||||
if (requested.oneShot)
|
if (requested.oneShot)
|
||||||
cmd.function += "-t ";
|
cmd.function += "-t ";
|
||||||
|
|
||||||
if (!requested.enabled)
|
if (!requested.enabled)
|
||||||
cmd.function += "-d ";
|
cmd.function += "-d ";
|
||||||
|
|
||||||
if (int ignoreCount = requested.ignoreCount)
|
if (int ignoreCount = requested.ignoreCount)
|
||||||
cmd.function += "-i " + QString::number(ignoreCount) + ' ';
|
cmd.function += "-i " + QString::number(ignoreCount) + ' ';
|
||||||
|
|
||||||
QString condition = requested.condition;
|
QString condition = requested.condition;
|
||||||
if (!condition.isEmpty())
|
if (!condition.isEmpty())
|
||||||
cmd.function += " -c \"" + condition.replace('"', "\\\"") + "\" ";
|
cmd.function += " -c \"" + condition.replace('"', "\\\"") + "\" ";
|
||||||
|
|
||||||
cmd.function += breakpointLocation(requested);
|
cmd.function += breakpointLocation(requested);
|
||||||
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); };
|
cmd.callback = [this, bp](const DebuggerResponse &r) { handleBreakInsert1(r, bp); };
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmd.flags = NeedsTemporaryStop;
|
cmd.flags = NeedsTemporaryStop;
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
@@ -4831,3 +5118,4 @@ DebuggerEngine *createGdbEngine()
|
|||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Debugger::Internal::GdbMi)
|
Q_DECLARE_METATYPE(Debugger::Internal::GdbMi)
|
||||||
|
Q_DECLARE_METATYPE(Debugger::Internal::TracepointCaptureData)
|
||||||
|
@@ -223,6 +223,9 @@ private: ////////// General Interface //////////
|
|||||||
void handleBreakCondition(const DebuggerResponse &response, const Breakpoint &bp);
|
void handleBreakCondition(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp);
|
void handleBreakThreadSpec(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp);
|
void handleBreakLineNumber(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
|
void handleTracepointInsert(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
|
void handleTracepointHit(const GdbMi &data);
|
||||||
|
void handleTracepointModified(const GdbMi &data);
|
||||||
void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, const Breakpoint &bp);
|
void handleInsertInterpreterBreakpoint(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
void handleInterpreterBreakpointModified(const GdbMi &data);
|
void handleInterpreterBreakpointModified(const GdbMi &data);
|
||||||
void handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
|
void handleWatchInsert(const DebuggerResponse &response, const Breakpoint &bp);
|
||||||
@@ -231,6 +234,7 @@ private: ////////// General Interface //////////
|
|||||||
QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
|
QString breakpointLocation(const BreakpointParameters &data); // For gdb/MI.
|
||||||
QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
|
QString breakpointLocation2(const BreakpointParameters &data); // For gdb/CLI fallback.
|
||||||
QString breakLocation(const QString &file) const;
|
QString breakLocation(const QString &file) const;
|
||||||
|
void updateTracepointCaptures(const Breakpoint &bp);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Modules specific stuff
|
// Modules specific stuff
|
||||||
|
@@ -153,6 +153,11 @@ GdbOptionsPageWidget::GdbOptionsPageWidget()
|
|||||||
"<html><head/><body>GDB shows by default AT&&T style disassembly."
|
"<html><head/><body>GDB shows by default AT&&T style disassembly."
|
||||||
"</body></html>"));
|
"</body></html>"));
|
||||||
|
|
||||||
|
auto checkBoxUsePseudoTracepoints = new QCheckBox(groupBoxGeneral);
|
||||||
|
checkBoxUsePseudoTracepoints->setText(GdbOptionsPage::tr("Use pseudo message tracepoints"));
|
||||||
|
checkBoxUsePseudoTracepoints->setToolTip(GdbOptionsPage::tr(
|
||||||
|
"Uses python to extend the ordinary GDB breakpoint class."));
|
||||||
|
|
||||||
QString howToUsePython = GdbOptionsPage::tr(
|
QString howToUsePython = GdbOptionsPage::tr(
|
||||||
"<p>To execute simple Python commands, prefix them with \"python\".</p>"
|
"<p>To execute simple Python commands, prefix them with \"python\".</p>"
|
||||||
"<p>To execute sequences of Python commands spanning multiple lines "
|
"<p>To execute sequences of Python commands spanning multiple lines "
|
||||||
@@ -225,6 +230,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget()
|
|||||||
formLayout->addRow(checkBoxLoadGdbInit);
|
formLayout->addRow(checkBoxLoadGdbInit);
|
||||||
formLayout->addRow(checkBoxLoadGdbDumpers);
|
formLayout->addRow(checkBoxLoadGdbDumpers);
|
||||||
formLayout->addRow(checkBoxIntelFlavor);
|
formLayout->addRow(checkBoxIntelFlavor);
|
||||||
|
formLayout->addRow(checkBoxUsePseudoTracepoints);
|
||||||
|
|
||||||
auto startLayout = new QGridLayout(groupBoxStartupCommands);
|
auto startLayout = new QGridLayout(groupBoxStartupCommands);
|
||||||
startLayout->addWidget(textEditStartupCommands, 0, 0, 1, 1);
|
startLayout->addWidget(textEditStartupCommands, 0, 0, 1, 1);
|
||||||
@@ -248,6 +254,7 @@ GdbOptionsPageWidget::GdbOptionsPageWidget()
|
|||||||
group.insert(action(IntelFlavor), checkBoxIntelFlavor);
|
group.insert(action(IntelFlavor), checkBoxIntelFlavor);
|
||||||
group.insert(action(UseMessageBoxForSignals), checkBoxUseMessageBoxForSignals);
|
group.insert(action(UseMessageBoxForSignals), checkBoxUseMessageBoxForSignals);
|
||||||
group.insert(action(SkipKnownFrames), checkBoxSkipKnownFrames);
|
group.insert(action(SkipKnownFrames), checkBoxSkipKnownFrames);
|
||||||
|
group.insert(action(UsePseudoTracepoints), checkBoxUsePseudoTracepoints);
|
||||||
|
|
||||||
//lineEditSelectedPluginBreakpointsPattern->
|
//lineEditSelectedPluginBreakpointsPattern->
|
||||||
// setEnabled(action(SelectedPluginBreakpoints)->value().toBool());
|
// setEnabled(action(SelectedPluginBreakpoints)->value().toBool());
|
||||||
|
Reference in New Issue
Block a user