Xcode already shows “Attaching,” yet CPU usage on the cloud Mac remains near idle, breakpoints have changed from blue to gray, and the variables pane is empty. Repeatedly clicking Stop, restarting, or deleting DerivedData at this point usually destroys valuable evidence. A more effective approach is to divide the problem into three layers: whether the target process can be debugged, whether a session has been established between LLDB and the target, and whether matching symbols are available for the current build artifact.
Identify which layer is failing first
Start by recording the time of the incident, project commit, Scheme, Configuration, target device, and launch method, then examine Xcode’s status. Do not treat slow attachment, slow application startup, and slow symbol resolution as the same problem.
| Symptom | Check first | Common conclusion |
|---|---|---|
| The application does not launch and LLDB keeps waiting | Target process, launch arguments | The process exited or a different build artifact was launched |
| A process PID is shown, but the interface is unresponsive | Process state, debugging service | The target is paused, blocked, or has not completed the debugging handshake |
| Breakpoints are hollow or gray | Modules and symbols | The module is not loaded, its path changed, or its UUID does not match |
| Execution stops, but local variables are unavailable | Optimization level, debug information | Release optimization merged or eliminated the variables |
Save a process snapshot from another terminal:
mkdir -p "$HOME/lldb-case"
date -u > "$HOME/lldb-case/time.txt"
ps -axo pid,ppid,state,%cpu,etime,command \
> "$HOME/lldb-case/processes.txt"
xcrun simctl list devices \
> "$HOME/lldb-case/simulators.txt"
A persistent U in state may indicate that the process is in uninterruptible sleep, while a persistent T means that it has been stopped. A single snapshot cannot establish a trend, so capturing another one ten seconds later is more useful.
Preserve the evidence before cleaning anything. A successful restart may restore your workflow, but it does not prove that the root cause is gone.
Verify the process and debugging session
Confirm that LLDB attached to the correct artifact
Applications with the same name may exist simultaneously in multiple simulators, test directories, or old build directories. First, use LLDB to confirm the process and loaded images:
(lldb) process status
(lldb) target list
(lldb) image list -o -f
target list should point to the executable from the current build. In image list, the target module’s path should be under the expected Build Products directory. If the path belongs to another DerivedData directory, do not immediately delete everything. Record the old path first and check whether the Scheme reused the wrong build artifact.
If the LLDB command line still responds, run:
(lldb) thread list
(lldb) thread backtrace all
If every thread has a backtrace, the debugging channel has usually been established, and the problem is more likely related to the application waiting internally or to symbol resolution. If the commands continue to produce no output, sample the target process from the system:
sample <PID> 10 1 -file "$HOME/lldb-case/app-sample.txt"
Do not run multiple sample commands in succession. A ten-second sample is enough to determine whether the main thread is waiting on a lock, file I/O, a network call, or a system framework.
Match the dSYM by UUID
Matching file names do not guarantee matching symbols. Each link operation may produce a different UUID, and LLDB will only use a dSYM that corresponds to the Mach-O file.
dwarfdump --uuid "/path/to/MyApp.app/MyApp"
dwarfdump --uuid "/path/to/MyApp.app.dSYM"
The UUIDs for the same architecture must match on both sides. If the application includes arm64, compare at least the arm64 entry. Do not substitute a dSYM from another Archive, another commit, or a later relink.
Check whether the module is loaded
Query the target module in LLDB:
(lldb) image lookup -n AppDelegate
(lldb) image lookup -r -n 'YourModule\..*'
(lldb) breakpoint list
If image lookup cannot find the symbol even though the module appears in image list, check the debug information format first. Development builds should normally generate DWARF or DWARF with dSYM. With highly optimized configurations, functions may be inlined and local variables may be unavailable. In that case, create a dedicated diagnostic Configuration instead of temporarily changing the Release configuration shared by the team.
A breakpoint marked pending is not necessarily an error. If a dynamic framework has not loaded yet, the breakpoint waits for the corresponding image to enter the process. Set a breakpoint at an entry point that is known to be loaded, then observe subsequent modules instead of repeatedly deleting the same breakpoint.
Find handshake failures in system logs
The Xcode interface often reports only that attachment failed, while system logs retain more specific details about process exits, permission denials, or aborted connections. Before reproducing the issue, start a narrowly scoped log capture:
log stream --style compact --info \
--predicate 'process == "debugserver" OR process == "lldb-rpc-server"' \
> "$HOME/lldb-case/debug-session.log"
After reproducing the issue once, stop the capture with Control-C. The log may contain usernames, project paths, and device identifiers, so redact it before submitting a support ticket or sharing it with the team. Avoid collecting system-wide --debug output for an extended period without a specific reason. It creates substantial noise and increases the cost of filtering the results.
If the log shows that the target process exits as soon as LLDB attaches, launch the application independently of LLDB first and confirm that it remains running. If only the test process fails, inspect the test host, test Bundle, and application under test separately instead of focusing only on the main application PID.
Establish a repeatable recovery sequence
Recovery should begin with the least disruptive steps:
- End the current debugging session, but preserve the target application and logs.
- Verify the Scheme, Configuration, run destination, and executable path.
- Compare the Mach-O and dSYM UUIDs.
- Rebuild the current Target without cleaning the entire project.
- Delete the project’s corresponding DerivedData directory only after confirming that an old artifact was reused.
- If the problem remains reproducible, save thread backtraces, a process sample, system logs, and minimal reproduction steps.
Use the following command to list the directories and their modification times before deleting anything, reducing the risk of removing data from other tasks:
find "$HOME/Library/Developer/Xcode/DerivedData" \
-maxdepth 1 -mindepth 1 -type d -print
A cloud Mac may run build, test, and graphical debugging tasks at the same time. Before cleaning, confirm that no other pipeline is using the same directory. A safer approach is to assign a separate -derivedDataPath to each task, keeping debugging evidence separate from automated build caches.
Turn troubleshooting results into acceptance checks
After completing a fix, verify at least four conditions: LLDB can attach after a cold launch, it can attach to an existing process, source breakpoints are hit, and key variables remain visible when execution pauses on an exception. Then exit and reconnect to the remote session and test once more to rule out results that depend on the current graphical session or temporary environment variables.
Teams can add UUID checks, artifact paths, and the Configuration to their build checklists, but scripts should never hard-code personal directories. A truly reliable debugging workflow is not “clean and try again.” It allows any team member to use the same body of evidence to determine whether the failure is in the process, session, or symbol layer, and to repair only the layer that has diverged.
Frequently asked questions
What should I check first when LLDB attaches but never hits a breakpoint?
Use image list to verify that the target module is loaded, then compare the UUID of the executable with its dSYM. An unloaded module leaves the breakpoint pending, while a UUID mismatch prevents correct source mapping.
Should I delete DerivedData as soon as a debugging session hangs?
No. Capture the process list, LLDB output, system logs, and artifact UUIDs first. Delete only the affected project's directory after confirming that stale build data is the cause.
Does remote debugging require exposing a debug port to the internet?
Usually not. Run Xcode and LLDB on the cloud Mac and operate them through a controlled desktop or SSH session. If forwarding is unavoidable, use a restricted tunnel and bind only to the required interface.
Need a physical Mac mini dedicated to a single order?
Compare the M4 and M4 Pro configurations, four rental periods, and five available regions, then choose the device that fits your workflow.