Skip to content

Commit eb4e55a

Browse files
authored
Disable async mode with LLDB (#184768)
@mraleph proposed a [better fix](#184254 (comment)) for the LLDB Xcode 26.4 breakage and I confirmed that it works. This PR reverts the first fix and adopts the new one, which is to set LLDB to not use async mode. For #184254. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent ab267fe commit eb4e55a

5 files changed

Lines changed: 44 additions & 455 deletions

File tree

packages/flutter_tools/lib/src/ios/core_devices.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,12 @@ class IOSCoreDeviceLauncher {
3838
required XcodeDebug xcodeDebug,
3939
required FileSystem fileSystem,
4040
required ProcessUtils processUtils,
41-
required Xcode xcode,
4241
@visibleForTesting LLDB? lldb,
4342
}) : _coreDeviceControl = coreDeviceControl,
4443
_logger = logger,
4544
_xcodeDebug = xcodeDebug,
4645
_fileSystem = fileSystem,
47-
_lldb = lldb ?? LLDB(logger: logger, processUtils: processUtils, xcode: xcode);
46+
_lldb = lldb ?? LLDB(logger: logger, processUtils: processUtils);
4847

4948
final IOSCoreDeviceControl _coreDeviceControl;
5049
final Logger _logger;

packages/flutter_tools/lib/src/ios/lldb.dart

Lines changed: 28 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,18 @@ import '../base/io.dart';
1111
import '../base/logger.dart';
1212
import '../base/process.dart';
1313
import '../base/utils.dart';
14-
import '../base/version.dart';
15-
import '../macos/xcode.dart';
1614

1715
/// LLDB is the default debugger in Xcode on macOS. Once the application has
1816
/// launched on a physical iOS device, you can attach to it using LLDB.
1917
///
2018
/// See `xcrun devicectl device process launch --help` for more information.
2119
class LLDB {
22-
LLDB({required Logger logger, required ProcessUtils processUtils, required Xcode xcode})
23-
: _xcode = xcode,
24-
_logger = logger,
20+
LLDB({required Logger logger, required ProcessUtils processUtils})
21+
: _logger = logger,
2522
_processUtils = processUtils;
2623

2724
final Logger _logger;
2825
final ProcessUtils _processUtils;
29-
final Xcode _xcode;
3026

3127
_LLDBProcess? _lldbProcess;
3228

@@ -46,10 +42,10 @@ class LLDB {
4642
/// Example: (lldb) Process 6152 stopped
4743
static final _lldbProcessStopped = RegExp(r'Process \d* stopped');
4844

49-
/// Pattern of lldb log when the process is resuming.
45+
/// Pattern of lldb log when the process is resuming and the breakpoint is added.
5046
///
51-
/// Example: (lldb) Process 6152 resuming
52-
static final _lldbProcessResuming = RegExp(r'Process \d+ resuming');
47+
/// Example: (lldb) 1 location added to breakpoint 1
48+
static final _lldbProcessResuming = RegExp(r'location added to breakpoint');
5349

5450
/// Pattern of lldb log when the breakpoint is added.
5551
///
@@ -78,6 +74,9 @@ frame.GetThread().GetProcess().WriteMemory(base, data, error)
7874
if not error.Success():
7975
print(f'Failed to write into {base}[+{page_len}]', error)
8076
return
77+
78+
# If the returned value is False, that tells LLDB not to stop at the breakpoint
79+
return False
8180
''';
8281

8382
/// Starts an LLDB process and inputs commands to start debugging the [appProcessId].
@@ -148,50 +147,19 @@ if not error.Success():
148147
logger: _logger,
149148
);
150149

151-
void printLine(String line) {
152-
if (_isAttached && !_ignoreLog(line)) {
153-
// Only forwards logs after LLDB is attached. All logs before then are part of the
154-
// attach process.
155-
156-
lldbLogForwarder.addLog(line);
157-
} else {
158-
_logger.printTrace('[lldb]: $line');
159-
_logCompleter?.checkForMatch(line);
160-
}
161-
}
150+
final StreamSubscription<String> stdoutSubscription = _lldbProcess!.stdout
151+
.transform(utf8LineDecoder)
152+
.listen((String line) {
153+
if (_isAttached && !_ignoreLog(line)) {
154+
// Only forwards logs after LLDB is attached. All logs before then are part of the
155+
// attach process.
162156

163-
String? processStopLine;
164-
var suppressLogs = false;
165-
166-
final StreamSubscription<String>
167-
stdoutSubscription = _lldbProcess!.stdout.transform(utf8LineDecoder).listen((String line) {
168-
// Skip all logs between process stop and process resume if the stop was caused by a breakpoint
169-
if (line.contains(_lldbProcessStopped)) {
170-
processStopLine = line;
171-
return;
172-
}
173-
// If the last log was a proces stop log, check if it was caused by a breakpoint.
174-
if (processStopLine != null) {
175-
if (line.contains('stop reason = breakpoint')) {
176-
// When we stop due to a breakpoint, supress all logs until we resume.
177-
_lldbProcess?.stdinWriteln('process continue');
178-
suppressLogs = true;
179-
} else {
180-
// Otherwise, print the process stop log.
181-
printLine(processStopLine!);
182-
}
183-
processStopLine = null;
184-
}
185-
if (suppressLogs) {
186-
if (line.contains(_lldbProcessResuming)) {
187-
// After resuming, stop supressing logs.
188-
suppressLogs = false;
189-
}
190-
return;
191-
}
192-
193-
printLine(line);
194-
});
157+
lldbLogForwarder.addLog(line);
158+
} else {
159+
_logger.printTrace('[lldb]: $line');
160+
_logCompleter?.checkForMatch(line);
161+
}
162+
});
195163

196164
final StreamSubscription<String> stderrSubscription = _lldbProcess!.stderr
197165
.transform(utf8LineDecoder)
@@ -257,12 +225,9 @@ if not error.Success():
257225
_breakpointPattern,
258226
).then((value) => value, onError: _handleAsyncError);
259227

260-
final Version? xcodeVersion = _xcode.currentVersion;
261-
final bool useManualContinue = xcodeVersion != null && (xcodeVersion >= Version(26, 4, 0));
262-
final breakpointSetCommand = useManualContinue
263-
? r"breakpoint set --func-regex '^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$'"
264-
: r"breakpoint set --auto-continue true --func-regex '^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$'";
265-
await _lldbProcess?.stdinWriteln(breakpointSetCommand);
228+
await _lldbProcess?.stdinWriteln(
229+
r"breakpoint set --func-regex '^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$'",
230+
);
266231
final String log = await futureLog;
267232
final Match? match = _breakpointPattern.firstMatch(log);
268233
final String? breakpointId = match?.group(1);
@@ -275,6 +240,11 @@ if not error.Success():
275240
await _lldbProcess?.stdinWriteln('breakpoint command add --script-type python $breakpointId');
276241
await _lldbProcess?.stdinWriteln(_pythonScript);
277242
await _lldbProcess?.stdinWriteln('DONE');
243+
244+
// Disable asynchronous mode to workaround issues with rearming of breakpoints.
245+
// See https://github.com/flutter/flutter/issues/184254 and upstream issue
246+
// https://github.com/llvm/llvm-project/issues/190956.
247+
await _lldbProcess?.stdinWriteln('script lldb.debugger.SetAsync(False)');
278248
}
279249

280250
/// Resume the stopped process.

packages/flutter_tools/lib/src/macos/xcdevice.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,6 @@ class XCDevice {
649649
xcodeDebug: _xcodeDebug,
650650
fileSystem: globals.fs,
651651
processUtils: _processUtils,
652-
xcode: _xcode,
653652
),
654653
xcodeDebug: _xcodeDebug,
655654
platform: globals.platform,

packages/flutter_tools/test/general.shard/ios/core_devices_test.dart

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ void main() {
7878
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
7979
final fakeLLDB = FakeLLDB();
8080
final launcher = IOSCoreDeviceLauncher(
81-
xcode: FakeXcode(),
8281
coreDeviceControl: fakeCoreDeviceControl,
8382
logger: logger,
8483
xcodeDebug: FakeXcodeDebug(),
@@ -105,7 +104,6 @@ void main() {
105104
final logger = BufferLogger.test();
106105
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
107106
final launcher = IOSCoreDeviceLauncher(
108-
xcode: FakeXcode(),
109107
coreDeviceControl: fakeCoreDeviceControl,
110108
logger: logger,
111109
xcodeDebug: FakeXcodeDebug(),
@@ -134,7 +132,6 @@ void main() {
134132
final logger = BufferLogger.test();
135133
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
136134
final launcher = IOSCoreDeviceLauncher(
137-
xcode: FakeXcode(),
138135
coreDeviceControl: fakeCoreDeviceControl,
139136
logger: logger,
140137
xcodeDebug: FakeXcodeDebug(),
@@ -159,7 +156,6 @@ void main() {
159156
final logger = BufferLogger.test();
160157
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
161158
final launcher = IOSCoreDeviceLauncher(
162-
xcode: FakeXcode(),
163159
coreDeviceControl: fakeCoreDeviceControl,
164160
logger: logger,
165161
xcodeDebug: FakeXcodeDebug(),
@@ -207,7 +203,6 @@ void main() {
207203
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
208204
final fakeLLDB = FakeLLDB();
209205
final launcher = IOSCoreDeviceLauncher(
210-
xcode: FakeXcode(),
211206
coreDeviceControl: fakeCoreDeviceControl,
212207
logger: logger,
213208
xcodeDebug: FakeXcodeDebug(),
@@ -266,7 +261,6 @@ void main() {
266261
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
267262
final fakeLLDB = FakeLLDB();
268263
final launcher = IOSCoreDeviceLauncher(
269-
xcode: FakeXcode(),
270264
coreDeviceControl: fakeCoreDeviceControl,
271265
logger: logger,
272266
xcodeDebug: FakeXcodeDebug(),
@@ -318,7 +312,6 @@ void main() {
318312
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
319313
final fakeLLDB = FakeLLDB();
320314
final launcher = IOSCoreDeviceLauncher(
321-
xcode: FakeXcode(),
322315
coreDeviceControl: fakeCoreDeviceControl,
323316
logger: logger,
324317
xcodeDebug: FakeXcodeDebug(),
@@ -363,7 +356,6 @@ void main() {
363356
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
364357
final fakeLLDB = FakeLLDB();
365358
final launcher = IOSCoreDeviceLauncher(
366-
xcode: FakeXcode(),
367359
coreDeviceControl: fakeCoreDeviceControl,
368360
logger: logger,
369361
xcodeDebug: FakeXcodeDebug(),
@@ -414,7 +406,6 @@ void main() {
414406
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
415407
final fakeLLDB = FakeLLDB();
416408
final launcher = IOSCoreDeviceLauncher(
417-
xcode: FakeXcode(),
418409
coreDeviceControl: fakeCoreDeviceControl,
419410
logger: logger,
420411
xcodeDebug: FakeXcodeDebug(),
@@ -459,7 +450,6 @@ void main() {
459450
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
460451
final fakeLLDB = FakeLLDB();
461452
final launcher = IOSCoreDeviceLauncher(
462-
xcode: FakeXcode(),
463453
coreDeviceControl: fakeCoreDeviceControl,
464454
logger: logger,
465455
xcodeDebug: FakeXcodeDebug(),
@@ -506,7 +496,6 @@ void main() {
506496
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
507497
final fakeLLDB = FakeLLDB();
508498
final launcher = IOSCoreDeviceLauncher(
509-
xcode: FakeXcode(),
510499
coreDeviceControl: fakeCoreDeviceControl,
511500
logger: logger,
512501
xcodeDebug: FakeXcodeDebug(),
@@ -555,7 +544,6 @@ void main() {
555544
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
556545
final fakeLLDB = FakeLLDB(attachSuccess: false);
557546
final launcher = IOSCoreDeviceLauncher(
558-
xcode: FakeXcode(),
559547
coreDeviceControl: fakeCoreDeviceControl,
560548
logger: logger,
561549
xcodeDebug: FakeXcodeDebug(),
@@ -591,7 +579,6 @@ void main() {
591579
);
592580

593581
final launcher = IOSCoreDeviceLauncher(
594-
xcode: FakeXcode(),
595582
coreDeviceControl: FakeIOSCoreDeviceControl(),
596583
logger: logger,
597584
xcodeDebug: fakeXcodeDebug,
@@ -625,7 +612,6 @@ void main() {
625612
);
626613

627614
final launcher = IOSCoreDeviceLauncher(
628-
xcode: FakeXcode(),
629615
coreDeviceControl: FakeIOSCoreDeviceControl(),
630616
logger: logger,
631617
xcodeDebug: fakeXcodeDebug,
@@ -659,7 +645,6 @@ void main() {
659645
);
660646

661647
final launcher = IOSCoreDeviceLauncher(
662-
xcode: FakeXcode(),
663648
coreDeviceControl: FakeIOSCoreDeviceControl(),
664649
logger: logger,
665650
xcodeDebug: fakeXcodeDebug,
@@ -693,7 +678,6 @@ void main() {
693678
);
694679

695680
final launcher = IOSCoreDeviceLauncher(
696-
xcode: FakeXcode(),
697681
coreDeviceControl: FakeIOSCoreDeviceControl(),
698682
logger: logger,
699683
xcodeDebug: fakeXcodeDebug,
@@ -726,7 +710,6 @@ void main() {
726710
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
727711
final fakeLLDB = FakeLLDB();
728712
final launcher = IOSCoreDeviceLauncher(
729-
xcode: FakeXcode(),
730713
coreDeviceControl: fakeCoreDeviceControl,
731714
logger: logger,
732715
xcodeDebug: xcodeDebug,
@@ -756,7 +739,6 @@ void main() {
756739
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
757740

758741
final launcher = IOSCoreDeviceLauncher(
759-
xcode: FakeXcode(),
760742
coreDeviceControl: fakeCoreDeviceControl,
761743
logger: logger,
762744
xcodeDebug: xcodeDebug,
@@ -785,7 +767,6 @@ void main() {
785767
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
786768

787769
final launcher = IOSCoreDeviceLauncher(
788-
xcode: FakeXcode(),
789770
coreDeviceControl: fakeCoreDeviceControl,
790771
logger: logger,
791772
xcodeDebug: xcodeDebug,
@@ -813,7 +794,6 @@ void main() {
813794
final processUtils = ProcessUtils(processManager: processManager, logger: logger);
814795

815796
final launcher = IOSCoreDeviceLauncher(
816-
xcode: FakeXcode(),
817797
coreDeviceControl: fakeCoreDeviceControl,
818798
logger: logger,
819799
xcodeDebug: xcodeDebug,
@@ -4157,10 +4137,3 @@ class FakeShutdownHooks extends Fake implements ShutdownHooks {
41574137
_isShuttingDown = true;
41584138
}
41594139
}
4160-
4161-
class FakeXcode extends Fake implements Xcode {
4162-
FakeXcode({Version? currentVersion}) : currentVersion = currentVersion ?? Version(15, 0, 0);
4163-
4164-
@override
4165-
final Version currentVersion;
4166-
}

0 commit comments

Comments
 (0)