forked from qt-creator/qt-creator
Debugger: Fix hitting breakpoints repeatedly in multithreading
This change resolves an issue where gdb.parse_and_eval could rerun the multithreading application, causing breakpoints to be hit repeatedly in different threads, leading to an infinite loop. Added checkbox which enables skipping the execution of gdb.parse_and_eval in few places that mitigate the issue. Fixes: QTCREATORBUG-23219 Change-Id: I856d382d033f8a4da394d7422ebb3e131de28e09 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -227,6 +227,7 @@ class DumperBase():
|
|||||||
self.watchers = args.get('watchers', {})
|
self.watchers = args.get('watchers', {})
|
||||||
self.useDynamicType = int(args.get('dyntype', '0'))
|
self.useDynamicType = int(args.get('dyntype', '0'))
|
||||||
self.useFancy = int(args.get('fancy', '0'))
|
self.useFancy = int(args.get('fancy', '0'))
|
||||||
|
self.allowInferiorCalls = int(args.get('allowinferiorcalls', '0'))
|
||||||
self.forceQtNamespace = int(args.get('forcens', '0'))
|
self.forceQtNamespace = int(args.get('forcens', '0'))
|
||||||
self.passExceptions = int(args.get('passexceptions', '0'))
|
self.passExceptions = int(args.get('passexceptions', '0'))
|
||||||
self.isTesting = int(args.get('testing', '0'))
|
self.isTesting = int(args.get('testing', '0'))
|
||||||
|
@@ -739,6 +739,9 @@ class Dumper(DumperBase):
|
|||||||
def nativeParseAndEvaluate(self, exp):
|
def nativeParseAndEvaluate(self, exp):
|
||||||
#self.warn('EVALUATE "%s"' % exp)
|
#self.warn('EVALUATE "%s"' % exp)
|
||||||
try:
|
try:
|
||||||
|
if not self.allowInferiorCalls:
|
||||||
|
return None
|
||||||
|
|
||||||
val = gdb.parse_and_eval(exp)
|
val = gdb.parse_and_eval(exp)
|
||||||
return val
|
return val
|
||||||
except RuntimeError as error:
|
except RuntimeError as error:
|
||||||
@@ -772,6 +775,9 @@ class Dumper(DumperBase):
|
|||||||
#self.warn('PTR: %s -> %s(%s)' % (value, function, addr))
|
#self.warn('PTR: %s -> %s(%s)' % (value, function, addr))
|
||||||
exp = '((%s*)0x%x)->%s(%s)' % (type_name, addr, function, arg)
|
exp = '((%s*)0x%x)->%s(%s)' % (type_name, addr, function, arg)
|
||||||
#self.warn('CALL: %s' % exp)
|
#self.warn('CALL: %s' % exp)
|
||||||
|
if not self.allowInferiorCalls:
|
||||||
|
return None
|
||||||
|
|
||||||
result = gdb.parse_and_eval(exp)
|
result = gdb.parse_and_eval(exp)
|
||||||
#self.warn(' -> %s' % result)
|
#self.warn(' -> %s' % result)
|
||||||
res = self.fromNativeValue(result)
|
res = self.fromNativeValue(result)
|
||||||
@@ -1504,6 +1510,12 @@ class CliDumper(Dumper):
|
|||||||
|
|
||||||
args = {}
|
args = {}
|
||||||
args['fancy'] = 1
|
args['fancy'] = 1
|
||||||
|
# It enables skipping the execution of gdb.parse_and_eval which prevents the application from being rerun,
|
||||||
|
# which could lead to hitting breakpoints repeatedly in different threads, causing an infinite loop.
|
||||||
|
# Currently, gdb.parse_and_eval is bypassed in several places, resolving the bug QTCREATORBUG-23219.
|
||||||
|
# In the future, a full wrapper for gdb.parse_and_eval might be necessary to avoid this issue entirely.
|
||||||
|
# For now, we leave it as-is to retain as much pretty-printing functionality as possible.
|
||||||
|
args['allowinferiorcalls'] = 1
|
||||||
args['passexceptions'] = 1
|
args['passexceptions'] = 1
|
||||||
args['autoderef'] = 1
|
args['autoderef'] = 1
|
||||||
args['qobjectnames'] = 1
|
args['qobjectnames'] = 1
|
||||||
|
@@ -235,6 +235,10 @@ LocalsAndExpressionsSettings::LocalsAndExpressionsSettings()
|
|||||||
useDebuggingHelpers.setDefaultValue(true);
|
useDebuggingHelpers.setDefaultValue(true);
|
||||||
useDebuggingHelpers.setLabelText(Tr::tr("Use Debugging Helpers"));
|
useDebuggingHelpers.setLabelText(Tr::tr("Use Debugging Helpers"));
|
||||||
|
|
||||||
|
allowInferiorCalls.setSettingsKey(debugModeGroup, "AllowInferiorCalls");
|
||||||
|
allowInferiorCalls.setDefaultValue(true);
|
||||||
|
allowInferiorCalls.setLabelText(Tr::tr("Allow inferior calls in debugging helper"));
|
||||||
|
|
||||||
useCodeModel.setSettingsKey(debugModeGroup, "UseCodeModel");
|
useCodeModel.setSettingsKey(debugModeGroup, "UseCodeModel");
|
||||||
useCodeModel.setDefaultValue(true);
|
useCodeModel.setDefaultValue(true);
|
||||||
useCodeModel.setLabelText(Tr::tr("Use code model"));
|
useCodeModel.setLabelText(Tr::tr("Use code model"));
|
||||||
@@ -354,6 +358,7 @@ LocalsAndExpressionsSettings::LocalsAndExpressionsSettings()
|
|||||||
|
|
||||||
return Column {
|
return Column {
|
||||||
useDebuggingHelpers,
|
useDebuggingHelpers,
|
||||||
|
allowInferiorCalls,
|
||||||
useHelper,
|
useHelper,
|
||||||
Space(10),
|
Space(10),
|
||||||
showStdNamespace,
|
showStdNamespace,
|
||||||
|
@@ -76,6 +76,7 @@ public:
|
|||||||
LocalsAndExpressionsSettings();
|
LocalsAndExpressionsSettings();
|
||||||
|
|
||||||
Utils::BoolAspect useDebuggingHelpers{this};
|
Utils::BoolAspect useDebuggingHelpers{this};
|
||||||
|
Utils::BoolAspect allowInferiorCalls{this};
|
||||||
Utils::BoolAspect useCodeModel{this};
|
Utils::BoolAspect useCodeModel{this};
|
||||||
Utils::BoolAspect showThreadNames{this};
|
Utils::BoolAspect showThreadNames{this};
|
||||||
Utils::FilePathAspect extraDumperFile{this}; // For loading a file. Recommended.
|
Utils::FilePathAspect extraDumperFile{this}; // For loading a file. Recommended.
|
||||||
|
@@ -76,6 +76,7 @@ DebuggerSettings::DebuggerSettings() :
|
|||||||
|
|
||||||
// Page 4
|
// Page 4
|
||||||
useDebuggingHelpers{localsAndExpressionSettings().useDebuggingHelpers},
|
useDebuggingHelpers{localsAndExpressionSettings().useDebuggingHelpers},
|
||||||
|
allowInferiorCalls{localsAndExpressionSettings().allowInferiorCalls},
|
||||||
useCodeModel{localsAndExpressionSettings().useCodeModel},
|
useCodeModel{localsAndExpressionSettings().useCodeModel},
|
||||||
showThreadNames{localsAndExpressionSettings().showThreadNames},
|
showThreadNames{localsAndExpressionSettings().showThreadNames},
|
||||||
extraDumperFile{localsAndExpressionSettings().extraDumperFile}, // For loading a file. Recommended.
|
extraDumperFile{localsAndExpressionSettings().extraDumperFile}, // For loading a file. Recommended.
|
||||||
|
@@ -65,6 +65,7 @@ public:
|
|||||||
|
|
||||||
// Page 4: Locals and expressions
|
// Page 4: Locals and expressions
|
||||||
Utils::BoolAspect &useDebuggingHelpers;
|
Utils::BoolAspect &useDebuggingHelpers;
|
||||||
|
Utils::BoolAspect &allowInferiorCalls;
|
||||||
Utils::BoolAspect &useCodeModel;
|
Utils::BoolAspect &useCodeModel;
|
||||||
Utils::BoolAspect &showThreadNames;
|
Utils::BoolAspect &showThreadNames;
|
||||||
Utils::FilePathAspect &extraDumperFile; // For loading a file. Recommended.
|
Utils::FilePathAspect &extraDumperFile; // For loading a file. Recommended.
|
||||||
|
@@ -145,6 +145,8 @@ GdbEngine::GdbEngine()
|
|||||||
this, &GdbEngine::createFullBacktrace);
|
this, &GdbEngine::createFullBacktrace);
|
||||||
connect(&s.useDebuggingHelpers, &BaseAspect::changed,
|
connect(&s.useDebuggingHelpers, &BaseAspect::changed,
|
||||||
this, &GdbEngine::reloadLocals);
|
this, &GdbEngine::reloadLocals);
|
||||||
|
connect(&s.allowInferiorCalls, &BaseAspect::changed,
|
||||||
|
this, &GdbEngine::reloadLocals);
|
||||||
connect(&s.useDynamicType, &BaseAspect::changed,
|
connect(&s.useDynamicType, &BaseAspect::changed,
|
||||||
this, &GdbEngine::reloadLocals);
|
this, &GdbEngine::reloadLocals);
|
||||||
|
|
||||||
@@ -2638,6 +2640,7 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp)
|
|||||||
const DebuggerSettings &s = settings();
|
const DebuggerSettings &s = settings();
|
||||||
cmd.arg("passexceptions", alwaysVerbose);
|
cmd.arg("passexceptions", alwaysVerbose);
|
||||||
cmd.arg("fancy", s.useDebuggingHelpers());
|
cmd.arg("fancy", s.useDebuggingHelpers());
|
||||||
|
cmd.arg("allowinferiorcalls", s.allowInferiorCalls());
|
||||||
cmd.arg("autoderef", s.autoDerefPointers());
|
cmd.arg("autoderef", s.autoDerefPointers());
|
||||||
cmd.arg("dyntype", s.useDynamicType());
|
cmd.arg("dyntype", s.useDynamicType());
|
||||||
cmd.arg("qobjectnames", s.showQObjectNames());
|
cmd.arg("qobjectnames", s.showQObjectNames());
|
||||||
@@ -5164,6 +5167,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms)
|
|||||||
const DebuggerSettings &s = settings();
|
const DebuggerSettings &s = settings();
|
||||||
cmd.arg("passexceptions", alwaysVerbose);
|
cmd.arg("passexceptions", alwaysVerbose);
|
||||||
cmd.arg("fancy", s.useDebuggingHelpers());
|
cmd.arg("fancy", s.useDebuggingHelpers());
|
||||||
|
cmd.arg("allowinferiorcalls", s.allowInferiorCalls());
|
||||||
cmd.arg("autoderef", s.autoDerefPointers());
|
cmd.arg("autoderef", s.autoDerefPointers());
|
||||||
cmd.arg("dyntype", s.useDynamicType());
|
cmd.arg("dyntype", s.useDynamicType());
|
||||||
cmd.arg("qobjectnames", s.showQObjectNames());
|
cmd.arg("qobjectnames", s.showQObjectNames());
|
||||||
|
Reference in New Issue
Block a user