The LLDB command-line debugger provides underlying debugging services for development on all Apple platforms.

Posts under LLDB tag

32 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

tvOS 26 + Xcode 26 debugger won't launch
I have been using tvOS 18 and Xcode 26 all summer without issue but since updating the tv to the latest tvOS 26 beta I am now unable to attach to debug builds. When using the Run button in Xcode the build completes, the tv screen goes black and then I see a warning in Xcode: Launching "App Name" is taking longer than expected. Do you want to continue to wait? LLDB is likely reading from device memory to resolve symbols. If I continue to wait after around 5 mins, in the Xcode console, I see: warning: libobjc.A.dylib is being read from process memory. This indicates that LLDB could not find the on-disk shared cache for this device. This will likely reduce debugging performance. But the process on the tv hangs indefinately. Hitting stop in Xcode disconnects the debugger but the app then finishes launching successfully on the TV. Trying to use "Debug > Attach to process > [App Name]" once it is running also just hangs the app and waits until stopped. When stopping the hung debugger I see an Xcode error with the following: Could not attach to pid : “1222” Domain: IDEDebugSessionErrorDomain Code: 3 Failure Reason: internal error User Info: { DVTErrorCreationDateKey = "2025-09-01 09:51:54 +0000"; DVTRadarComponentKey = 855031; IDERunOperationFailingWorker = DBGLLDBLauncher; RawUnderlyingErrorMessage = "Xcode has killed the LLDB RPC server to allow the debugger to detach from your process. You may need to manually terminate your process."; } -- Event Metadata: com.apple.dt.IDERunOperationWorkerFinished : { "device_identifier" = "00008110-000240CE1A87801E"; "device_isCoreDevice" = 1; "device_isWireless" = 1; "device_model" = "AppleTV14,1"; "device_osBuild" = "26.0 (23J5348a)"; "device_osBuild_monotonic" = 2309534800; "device_os_variant" = 1; "device_platform" = "com.apple.platform.appletvos"; "device_platform_family" = 4; "device_reality" = 1; "device_thinningType" = "AppleTV14,1"; "device_transport" = 2; "launchSession_schemeCommand" = Run; "launchSession_schemeCommand_enum" = 1; "launchSession_targetArch" = arm64; "launchSession_targetArch_enum" = 6; "operation_duration_ms" = 76122; "operation_errorCode" = 3; "operation_errorDomain" = IDEDebugSessionErrorDomain; "operation_errorWorker" = DBGLLDBLauncher; "operation_error_reportable" = 1; "operation_name" = IDERunOperationWorkerGroup; "param_consoleMode" = 0; "param_debugger_attachToExtensions" = 0; "param_debugger_attachToXPC" = 1; "param_debugger_type" = 3; "param_destination_isProxy" = 0; "param_destination_platform" = "com.apple.platform.appletvos"; "param_diag_MainThreadChecker_stopOnIssue" = 0; "param_diag_MallocStackLogging_enableDuringAttach" = 0; "param_diag_MallocStackLogging_enableForXPC" = 0; "param_diag_allowLocationSimulation" = 0; "param_diag_checker_mtc_enable" = 0; "param_diag_checker_tpc_enable" = 0; "param_diag_gpu_frameCapture_enable" = 0; "param_diag_gpu_shaderValidation_enable" = 0; "param_diag_gpu_validation_enable" = 1; "param_diag_guardMalloc_enable" = 0; "param_diag_memoryGraphOnResourceException" = 0; "param_diag_queueDebugging_enable" = 1; "param_diag_runtimeProfile_generate" = 0; "param_diag_sanitizer_asan_enable" = 0; "param_diag_sanitizer_tsan_enable" = 0; "param_diag_sanitizer_tsan_stopOnIssue" = 0; "param_diag_sanitizer_ubsan_enable" = 0; "param_diag_sanitizer_ubsan_stopOnIssue" = 0; "param_diag_showNonLocalizedStrings" = 0; "param_diag_viewDebugging_enabled" = 1; "param_diag_viewDebugging_insertDylibOnLaunch" = 1; "param_install_style" = 2; "param_launcher_UID" = 2; "param_launcher_allowDeviceSensorReplayData" = 0; "param_launcher_kind" = 0; "param_launcher_style" = 99; "param_launcher_substyle" = 256; "param_lldbVersion_component_idx_1" = 0; "param_lldbVersion_monotonic" = 170300300002; "param_runnable_appExtensionHostRunMode" = 0; "param_testing_launchedForTesting" = 0; "param_testing_suppressSimulatorApp" = 0; "param_testing_usingCLI" = 0; "sdk_canonicalName" = "appletvos26.0"; "sdk_osVersion" = "26.0"; "sdk_platformID" = 3; "sdk_variant" = appletvos; "sdk_version_monotonic" = 2309534400; } -- System Information macOS Version 26.0 (Build 25A5349a) Xcode 26.0 (24208.14) (Build 17A5305k) Timestamp: 2025-09-01T10:51:54+01:00 I have another AppleTV still running on tvOS 18 and builds continue to run and attach fine there. I've tried rebooting the 26 beta AppleTV but I'm at a bit of a loss what else to try?
1
0
201
2d
lldb-dap closes connection
If I build an x64 binary on my M4 Mini, when I try to debug it using Visual Studio remote debugging the connection is closed, which means I cannot debug my code in x64 mode. I need to be able to do this as I have architecture specific code. I have Rosetta installed. FWIW I have the same issue with lldb-mi :( David
3
0
78
Jul ’25
No KDKs available for macOS 26.0 Developer Beta 2 and later
As of now, there is no Kernel Debug Kit (KDK) available for macOS 26.0 Developer Betas after the first build. Kernel Debug Kits are crucial for understanding panics and other bugs within custom Kernel Extensions. Without the KDK for the corresponding macOS version, tools like kmutil fail to recognize a KDK and certain functions are disabled. Additionally, as far as I am aware, a KDK for one build of macOS isn't able to be used on a differing build. Especially since this is a developer beta, where developers are updating their software to function with the latest versions of macOS, I'd expect a KDK to be available for more than one build.
2
0
256
Jul ’25
lldbinit file in Xcode
My ultimate aim is to be able to prevent Xcode from single-stepping into certain C++ functions - just as it does not single-step into std:: functions. It appears to be possible to arrange this by making a more elaborate version of an LLDB setting such as this: target.process.thread.step-avoid-regexp (regex) = ^std:: It also appears to be possible to put this setting into an "lldbinit" file so that LLDB (within Xcode) picks up the setting automatically when a debugging session starts. What I do not know is this: Where do I put the "lldbinit" file inside my project? What Xcode project or target settings need to be made to tell Xcode where to find my "lldbinit" file and use it?
2
0
120
Jun ’25
LLDB is invoking Xcode to display source code all of a sudden. How to switch back?
I've cross posted this at https://stackoverflow.com/q/79647300/6230282 Basically, I use command line and emacs app to develop on daily basis, but all of a sudden, LLDB is invoking Xcode to display source code for me, instead of printing them in command line. How do I switch back? Or alternatively, can I set a custom editor for LLDB? (lldb) version lldb-1700.0.9.502 Apple Swift version 6.1.2 (swiftlang-6.1.2.1.2 clang-1700.0.13.5) About Xcode: Version 16.4 (16F6)
1
0
108
Jun ’25
Xcode JSONDecoder playground fails with 'The LLDB RPC server has crashed.
If I create a playground project that uses a JSONDecoder I get the following error. The LLDB RPC Server has crashed. The crash log is located at ~/Library/Logs/DiagnosticReports and has a prefix 'lldb-rpc-server'. Please file a bug and attach the most recent crash log. I have raised feedback for this, FB17702087, but I hope that there may be a workaround. The code I am using to try and get this to work is from The Apple Developer Documentation - JSON Decoder var greeting = "JSON Test 3" struct GroceryProduct: Codable { var name: String var points: Int var description: String? } let json = """ { "name": "Durian", "points": 600, "description": "A fruit with a distinctive scent." } """.data(using: .utf8)! let decoder = JSONDecoder() let product = try decoder.decode(GroceryProduct.self, from: json) print(product.name) // Prints "Durian" A screenshot of the playground showing the error The crash log (the file type has been changed to txt as ips file types cannot be selected for upload. lldb-rpc-server-2025-05-28-140832.txt
0
0
59
May ’25
[Help] Xcode device debugging of iOS 18.4 / 18.5 is very slow, and it is suspected to be stuck in the stage of loading dynamic libraries in debugserver
Environment Xcode version: Xcode 16.0 iOS device system version: iOS 18.4 / 18.5 Problem description When debugging iOS 18.4/18.5 on a real device, the App starts very slowly after clicking Run, usually taking 2-3 minutes, which is much slower than iOS 18.3. It manifests as Xcode staying in the Launch stage for a long time, and the application stuck in the opening screen interface. Start the APP first, then attach the process, and this problem will not exist Location process Use lldb to enable logs log enable gdb-remote packets After observing the logs, it was found that: The jam mainly occurs when processing two data packets: jGetLoadedDynamicLibrariesInfos and qProcessInfo These two commands involve dynamic library loading information and process meta information, and the response time is much higher than the normal level, far exceeding other gdb-remote instructions Use Instruments / Profiler to analyze: The CPU peak of the real machine debugserver is concentrated in the dynamic library information loading process of _dyld_process_info_create Is there a way to deploy a modified debugserver on the real machine to further locate the problem How to enable and view the debugsever log to further locate the problem
0
1
69
May ’25
Cannot evaluate variables in xCode 16.2 debugger
When I try to look at any variable in the debugger, I get a bunch of errors complaining about inability to find a file in a location that should not exist on my machine... I just upgraded form xCode 15.2, which worked fine, but now I basically cannot debug. Who is this liangchenying? It's almost like the new version was shipped with some developer's paths hard-coded in the configuration. (lldb) po [tableNumberTxt.text integerValue] warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(PortIO.o) 0x00000000000004a7: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(WIFIPort.o) 0x000000000000171c: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(SimpleLogger.o) 0x00000000000009b9: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(POSCommand.o) 0x00000000000035bd: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(WIFIPortToFile.o) 0x00000000000004da: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.warning: (arm64) /Users/stevedavison/lineskip_dev/POS/SNBC/POSSDKForIOSLIB.a(POSSDK.o) 0x0000000000002432: unable to locate module needed for external types: /Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch error: '/Users/liangchenying/Library/Developer/Xcode/DerivedData/POSSDKForIOSLIB-bmkvfovoxsbzudehquaovgmnnooe/Build/Intermediates/PrecompiledHeaders/POSSDKForIOSLIB-Prefix-cfcbmooemqunxmehfbebereyakbw/POSSDKForIOSLIB-Prefix.pch.pch' does not exist Debugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.7
4
0
146
May ’25
Breakpoint on Runtime Issue os_log_fault_default_callback
The app stops on the breakpoint when "All Runtime Issues" is added. If I disable the breakpoint, the app runs normally. Is there a new project setting to avoid this breakpoint from being set. It does not appear to be a valid error. I am running Xcode 16.2. I edited the "Type" field in the breakpoint box. This occurs with the "System Frameworks" option only.
0
2
57
Apr ’25
LLDB RPC server crash in Xcode 16.3
Created a new project in Xcode 16.3. While adding breakpoints app is crashing every time in Xcode and playground both. Tried with swift 5 and swift 6 getting same error. Crash reason : Couldn't find the Objective-C runtime library in loaded images. Message from debugger: The LLDB RPC server has crashed. You may need to manually terminate your process lldb-rpc-server-2025-04-14-092736.txt
4
6
305
May ’25
Xcode Debug Launch Extremely Slow on iOS 18.4 with Large Binary (~1GB)
After upgrading to iOS 18.4, I noticed that launching a debug build from Xcode becomes extremely slow. The same app with the same large debug binary (~1GB) launches normally on devices running iOS 18.3. This issue seems specific to iOS 18.4, possibly related to the way the OS handles large debug binaries or symbols during the launch process. Steps to Reproduce: Connect an iPhone running iOS 18.4 to a Mac with Xcode. Build and run an app using Xcode in Debug mode. Observe the extended launch time. Re-run the same process on another iPhone with iOS 18.3 — launch is fast. Expected Result: Debug launch should be fast and consistent across iOS versions. Actual Result: Debug launch is significantly slower on iOS 18.4 for large binaries (~1GB). Environment: Xcode version: 16.0 macOS version: 15.4 Device: iPhone [model] iOS version: 18.4 (problematic), 18.3 (no issue)
1
2
120
May ’25
Cannot debug app-extension-safe frameworks in main app
The code in my app is split into frameworks that I can use both from my main app and its app extensions. In order to use the frameworks inside the app extension, I need to build them with the Xcode build setting Require Only App-Extension-Safe API set to Yes. When I do that, debugging framework code in my main app no longer works properly. I can set a breakpoint, but any attempt to print a value via p or po will give a set of errors like the following: error: module file /Users/.../Library/Developer/Xcode/DerivedData/...-daqfgouagvlkudfebrmzrurogmld/Build/Intermediates.noindex/SwiftExplicitPrecompiledModules/_errno-B8I5WSZMM09RXHYLYEWSC1BLE.pcm cannot be loaded due to a configuration mismatch with the current compilation error: Objective-C App Extension was enabled in PCH file but is currently disabled How do I fix this?
1
0
121
Jun ’25
A static lib/framework with dwarf info. Will leaking your private info?
When you build a static library that includes DWARF information, you may encounter error messages in the binary package generated by Xcodebuild. Upon examining the DWARF information with dwarfdump, you will find that any entries containing keywords like dir are all absolute paths specific to the publisher's computer. This is quite alarming, as it poses a risk of leaking private information. Additionally, when debugging an app, you can encounter consistent warning notes indicating that the referenced path addresses cannot be found. This is because the absolute path addresses generated during the 'xcodebuild' process reflect the paths from the computer used to build it. When distributing this to others, how can anyone access these paths? Has the design of the secondary linking process for DWARF considered the issues related to binary distribution? Are there existing solutions to address and handle privacy concerns? Is there a solution to allow the distributed DWARF files to be correctly recognized during compilation and debugging of the app? BTW: Incorrect paths can indeed affect LLDB's ability to load and debug the application effectively?
1
0
209
Mar ’25
Understanding Mach-O Symbols
This posts collects together a bunch of information about the symbols found in a Mach-O file. It assumes the terminology defined in An Apple Library Primer. If you’re unfamiliar with a term used here, look there for the definition. If you have any questions or comments about this, start a new thread in the Developer Tools & Services > General topic area and tag it with Linker. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Understanding Mach-O Symbols Every Mach-O file has a symbol table. This symbol table has many different uses: During development, it’s written by the compiler. And both read and written by the linker. And various other tools. During execution, it’s read by the dynamic linker. And also by various APIs, most notably dlsym. The symbol table is an array of entries. The format of each entry is very simple, but they have been used and combined in various creative ways to achieve a wide range of goals. For example: In a Mach-O object file, there’s an entry for each symbol exported to the linker. In a Mach-O image, there’s an entry for each symbol exported to the dynamic linker. And an entry for each symbol imported from dynamic libraries. Some entries hold information used by the debugger. See Debug Symbols, below. Examining the Symbol Table There are numerous tools to view and manipulate the symbol table, including nm, dyld_info, symbols, strip, and nmedit. Each of these has its own man page. A good place to start is nm: % nm Products/Debug/TestSymTab U ___stdoutp 0000000100000000 T __mh_execute_header U _fprintf U _getpid 0000000100003f44 T _main 0000000100008000 d _tDefault 0000000100003ecc T _test 0000000100003f04 t _testHelper Note In the examples in this post, TestSymTab is a Mach-O executable that’s formed by linking two Mach-O object files, main.o and TestCore.o. There are three columns here, and the second is the most important. It’s a single letter indicating the type of the entry. For example, T is a code symbol (in Unix parlance, code is in the text segment), D is a data symbol, and so on. An uppercase letter indicates that the symbol is visible to the linker; a lowercase letter indicates that it’s internal. An undefined (U) symbol has two potential meanings: In a Mach-O image, the symbol is typically imported from a specific dynamic library. The dynamic linker connects this import to the corresponding exported symbol of the dynamic library at load time. In a Mach-O object file, the symbol is undefined. In most cases the linker will try to resolve this symbol at link time. Note The above is a bit vague because there are numerous edge cases in how the system handles undefined symbols. For more on this, see Undefined Symbols, below. The first column in the nm output is the address associated with the entry, or blank if an address is not relevant for this type of entry. For a Mach-O image, this address is based on the load address, so the actual address at runtime is offset by the slide. See An Apple Library Primer for more about those concepts. The third column is the name for this entry. These names have a leading underscore because that’s the standard name mangling for C. See An Apple Library Primer for more about name mangling. The nm tool has a lot of formatting options. The ones I use the most are: -m — This prints more information about each symbol table entry. For example, if a symbol is imported from a dynamic library, this prints the library name. For a concrete example, see A Deeper Examination below. -a — This prints all the entries, including debug symbols. We’ll come back to that in the Debug Symbols section, below. -p — By default nm sorts entries by their address. This disables that sort, causing nm to print the entries in the order in which they occur in the symbol table. -x — This outputs entries in a raw format, which is great when you’re trying to understand what’s really going on. See Raw Symbol Information, below, for an example of this. A Deeper Examination To get more information about each symbol table, run nm with the -m option: % nm -m Products/Debug/TestSymTab (undefined) external ___stdoutp (from libSystem) 0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header (undefined) external _fprintf (from libSystem) (undefined) external _getpid (from libSystem) 0000000100003f44 (__TEXT,__text) external _main 0000000100008000 (__DATA,__data) non-external _tDefault 0000000100003ecc (__TEXT,__text) external _test 0000000100003f04 (__TEXT,__text) non-external _testHelper This contains a world of extra information about each entry. For example: You no longer have to remember cryptic single letter codes. Instead of U, you get undefined. If the symbol is imported from a dynamic library, it gives the name of that dynamic library. Here we see that _fprintf is imported from the libSystem library. It surfaces additional, more obscure information. For example, the referenced dynamically flag is a flag used by the linker to indicate that a symbol is… well… referenced dynamically, and thus shouldn’t be dead stripped. Undefined Symbols Mach-O’s handling of undefined symbols is quite complex. To start, you need to draw a distinction between the linker (aka the static linker) and the dynamic linker. Undefined Symbols at Link Time The linker takes a set of files as its input and produces a single file as its output. The input files can be Mach-O images or dynamic libraries [1]. The output file is typically a Mach-O image [2]. The goal of the linker is to merge the object files, resolving any undefined symbols used by those object files, and create the Mach-O image. There are two standard ways to resolve an undefined symbol: To a symbol exported by another Mach-O object file To a symbol exported by a dynamic library In the first case, the undefined symbol disappears in a puff of linker magic. In the second case, it records that the generated Mach-O image depends on that dynamic library [3] and adds a symbol table entry for that specific symbol. That entry is also shown as undefined, but it now indicates the library that the symbol is being imported from. This is the core of the two-level namespace. A Mach-O image that imports a symbol records both the symbol name and the library that exports the symbol. The above describes the standard ways used by the linker to resolve symbols. However, there are many subtleties here. The most radical is the flat namespace. That’s out of scope for this post, because it’s a really bad option for the vast majority of products. However, if you’re curious, the ld man page has some info about how symbol resolution works in that case. A more interesting case is the -undefined dynamic_lookup option. This represents a halfway house between the two-level namespace and the flat namespace. When you link a Mach-O image with this option, the linker resolves any undefined symbols by adding a dynamic lookup undefined entry to the symbol table. At load time, the dynamic linker attempts to resolve that symbol by searching all loaded images. This is useful if your software works on other Unix-y platforms, where a flat namespace is the norm. It can simplify your build system without going all the way to the flat namespace. Of course, if you use this facility and there are multiple libraries that export that symbol, you might be in for a surprise! [1] These days it’s more common for the build system to pass a stub library (.tbd) to the linker. The effect is much the same as passing in a dynamic library. In this discussion I’m sticking with the old mechanism, so just assume that I mean dynamic library or stub library. If you’re unfamiliar with the concept of a stub library, see An Apple Library Primer. [2] The linker can also merge the object files together into a single object file, but that’s relatively uncommon operation. For more on that, see the discussion of the -r option in the ld man page. [3] It adds an LC_LOAD_DYLIB load command with the install name from the dynamic library. See Dynamic Library Identification for more on that. Undefined Symbols at Load Time When you load a Mach-O image the dynamic linker is responsible for finding all the libraries it depends on, loading them, and connecting your imports to their exports. In the typical case the undefined entry in your symbol table records the symbol name and the library that exports the symbol. This allows the dynamic linker to quickly and unambiguously find the correct symbol. However, if the entry is marked as dynamic lookup [1], the dynamic linker will search all loaded images for the symbol and connect your library to the first one it finds. If the dynamic linker is unable to find a symbol, its default behaviour is to fail the load of the Mach-O image. This changes if the symbol is a weak reference. In that case, the dynamic linking continues to load the image but sets the address of the symbol to NULL. See Weak vs Weak vs Weak, below, for more about this. [1] In this case nm shows the library name as dynamically looked up. Weak vs Weak vs Weak Mach-O supports two different types of weak symbols: Weak references (aka weak imports) Weak definitions IMPORTANT If you use the term weak without qualification, the meaning depends on your audience. App developers tend to assume that you mean a weak reference whereas folks with a C++ background tend to assume that you mean a weak definition. It’s best to be specific. Weak References Weak references support the availability mechanism on Apple platforms. Most developers build their apps with the latest SDK and specify a deployment target, that is, the oldest OS version on which their app runs. Within the SDK, each declaration is annotated with the OS version that introduced that symbol [1]. If the app uses a symbol introduced later than its deployment target, the compiler flags that import as a weak reference. The app is then responsible for not using the symbol if it’s run on an OS release where it’s not available. For example, consider this snippet: #include <xpc/xpc.h> void testWeakReference(void) { printf("%p\n", xpc_listener_set_peer_code_signing_requirement); } The xpc_listener_set_peer_code_signing_requirement function is declared like so: API_AVAILABLE(macos(14.4)) … int xpc_listener_set_peer_code_signing_requirement(…); The API_AVAILABLE macro indicates that the symbol was introduced in macOS 14.4. If you build this code with the deployment target set to macOS 13, the symbol is marked as a weak reference: % nm -m Products/Debug/TestWeakRefC … (undefined) weak external _xpc_listener_set_peer_code_signing_requirement (from libSystem) If you run the above program on macOS 13, it’ll print NULL (actually 0x0). Without support for weak references, the dynamic linker on macOS 13 would fail to load the program because the _xpc_listener_set_peer_code_signing_requirement symbol is unavailable. [1] In practice most of the SDK’s declarations don’t have availability annotations because they were introduced before the minimum deployment target supported by that SDK. Weak definitions Weak references are about imports. Weak definitions are about exports. A weak definition allows you to export a symbol from multiple images. The dynamic linker coalesces these symbol definitions. Specifically: The first time it loads a library with a given weak definition, the dynamic linker makes it the primary. It registers that definition such that all references to the symbol resolve to it. This registration occurs in a namespace dedicated to weak definitions. That namespace is flat. Any subsequent definitions of that symbol are ignored. Weak definitions are weird, but they’re necessary to support C++’s One Definition Rule in a dynamically linked environment. IMPORTANT Weak definitions are not just weird, but also inefficient. Avoid them where you can. To flush out any unexpected weak definitions, pass the -warn_weak_exports option to the static linker. The easiest way to create a weak definition is with the weak attribute: __attribute__((weak)) void testWeakDefinition(void) { } IMPORTANT The C++ compiler can generate weak definitions without weak ever appearing in your code. This shows up in nm like so: % nm -m Products/Debug/TestWeakDefC … 0000000100003f40 (__TEXT,__text) weak external _testWeakDefinition … The output is quite subtle. A symbol flagged as weak external is either a weak reference or a weak definition depending on whether it’s undefined or not. For clarity, use dyld_info instead: % dyld_info -imports -exports Products/Debug/TestWeakRefC Products/Debug/TestWeakDefC [arm64]: … -imports: … 0x0001 _xpc_listener_set_peer_code_signing_requirement [weak-import] (from libSystem) % dyld_info -imports -exports Products/Debug/TestWeakDefC Products/Debug/TestWeakDefC [arm64]: -exports: offset symbol … 0x00003F40 _testWeakDefinition [weak-def] … … Here, weak-import indicates a weak reference and weak-def a weak definition. Weak Library There’s one final confusing use of the term weak, that is, weak libraries. A Mach-O image includes a list of imported libraries and a list of symbols along with the libraries they’re imported from. If an image references a library that’s not present, the dynamic linker will fail to load the library even if all the symbols it references in that library are weak references. To get around this you need to mark the library itself as weak. If you’re using Xcode it will often do this for your automatically. If it doesn’t, mark the library as optional in the Link Binary with Libraries build phase. Use otool to see whether a library is required or optional. For example, this shows an optional library: % otool -L Products/Debug/TestWeakRefC Products/Debug/TestWeakRefC: /usr/lib/libEndpointSecurity.dylib (… 511.60.5, weak) … In the non-optional case, there’s no weak indicator: % otool -L Products/Debug/TestWeakRefC Products/Debug/TestWeakRefC: /usr/lib/libEndpointSecurity.dylib (… 511.60.5) … Debug Symbols or Why the DWARF still stabs. (-: Historically, all debug information was stored in symbol table entries, using a format knows as stabs. This format is now obsolete, having been largely replaced by DWARF. However, stabs symbols are still used for some specific roles. Note See <mach-o/stab.h> and the stab man page for more about stabs on Apple platforms. See stabs and DWARF for general information about these formats. In DWARF, debug symbols aren’t stored in the symbol table. Rather, debug information is stored in various __DWARF sections. For example: % otool -l Intermediates.noindex/TestSymTab.build/Debug/TestSymTab.build/Objects-normal/arm64/TestCore.o | grep __DWARF -B 1 sectname __debug_abbrev segname __DWARF … The compiler inserts this debug information into the Mach-O object file that it creates. Eventually this Mach-O object file is linked into a Mach-O image. At that point one of two things happens, depending on the Debug Information Format build setting. During day-to-day development, set Debug Information Format to DWARF. When the linker creates a Mach-O image from a bunch of Mach-O object files, it doesn’t do anything with the DWARF information in those objects. Rather, it records references to the source objects files into the final image. This is super quick. When you debug that Mach-O image, the debugger finds those references and uses them to locate the DWARF information in the original Mach-O object files. Each reference is stored in a stabs OSO symbol table entry. To see them, run nm with the -a option: % nm -a Products/Debug/TestSymTab … 0000000000000000 - 00 0001 OSO …/Intermediates.noindex/TestSymTab.build/Debug/TestSymTab.build/Objects-normal/arm64/TestCore.o 0000000000000000 - 00 0001 OSO …/Intermediates.noindex/TestSymTab.build/Debug/TestSymTab.build/Objects-normal/arm64/main.o … Given the above, the debugger knows to look for DWARF information in TestCore.o and main.o. And notably, the executable does not contain any DWARF sections: % otool -l Products/Debug/TestSymTab | grep __DWARF -B 1 % When you build your app for distribution, set Debug Information Format to DWARF with dSYM File. The executable now contains no DWARF information: % otool -l Products/Release/TestSymTab | grep __DWARF -B 1 % Xcode runs dsymutil tool to collect the DWARF information, organise it, and export a .dSYM file. This is actually a document package, within which is a Mach-O dSYM companion file: % find Products/Release/TestSymTab.dSYM Products/Release/TestSymTab.dSYM Products/Release/TestSymTab.dSYM/Contents … Products/Release/TestSymTab.dSYM/Contents/Resources/DWARF Products/Release/TestSymTab.dSYM/Contents/Resources/DWARF/TestSymTab … % file Products/Release/TestSymTab.dSYM/Contents/Resources/DWARF/TestSymTab Products/Release/TestSymTab.dSYM/Contents/Resources/DWARF/TestSymTab: Mach-O 64-bit dSYM companion file arm64 That file contains a copy of the the DWARF information from all the original Mach-O object files, optimised for use by the debugger: % otool -l Products/Release/TestSymTab.dSYM/Contents/Resources/DWARF/TestSymTab | grep __DWARF -B 1 … sectname __debug_line segname __DWARF … Raw Symbol Information As described above, each Mach-O file has a symbol table that’s an array of symbol table entries. The structure of each entry is defined by the declarations in <mach-o/nlist.h> [1]. While there is an nlist man page, the best documentation for this format is the the comments in the header itself. Note The terms nlist stands for name list and dates back to truly ancient versions of Unix. Each entry is represented by an nlist_64 structure (nlist for 32-bit Mach-O files) with five fields: n_strx ‘points’ to the string for this entry. n_type encodes the entry type. This is actually split up into four subfields, as discussed below. n_sect is the section number for this entry. n_desc is additional information. n_value is the address of the symbol. The four fields within n_type are N_STAB (3 bits), N_PEXT (1 bit), N_TYPE (3 bits), and N_EXT (1 bit). To see these raw values, run nm with the -x option: % nm -a -x Products/Debug/TestSymTab … 0000000000000000 01 00 0300 00000036 _getpid 0000000100003f44 24 01 0000 00000016 _main 0000000100003f44 0f 01 0000 00000016 _main … This prints a column for n_value, n_type, n_sect, n_desc, and n_strx. The last column is the string you get when you follow the ‘pointer’ in n_strx. The mechanism used to encode all the necessary info into these fields is both complex and arcane. For the details, see the comments in <mach-o/nlist.h> and <mach-o/stab.h>. However, just to give you a taste: The entry for getpid has an n_type field with just the N_EXT flag set, indicating that this is an external symbol. The n_sect field is 0, indicating a text symbol. And n_desc is 0x0300, with the top byte indicating that the symbol is imported from the third dynamic library. The first entry for _main has an n_type field set to N_FUN, indicating a stabs function symbol. The n_desc field is the line number, that is, line 22. The second entry for _main has an n_type field with N_TYPE set to N_SECT and the N_EXT flag set, indicating a symbol exported from a section. In this case the section number is 1, that is, the text section. [1] There is also an <nlist.h> header that defines an API that returns the symbol table. The difference between <nlist.h> and <mach-o/nlist.h> is that the former defines an API whereas the latter defines the Mach-O on-disk format. Don’t include both; that won’t end well!
0
0
832
Mar ’25
Xcode Playground - The LLDB RPC server has crashed.
I am trying to learn Metal development on my MacBook Pro M1 Pro (Sequoia 15.3.1) on Xcode Playground, but when I write these two lines of code: import Metal let device = MTLCreateSystemDefaultDevice()! I get the error The LLDB RPC server has crashed. Any ideas as to what I can do to solve this? I have rebooted the machine and reinstalled Xcode...
3
0
454
Mar ’25
Metal: Non-uniform thread groups unsupported in Simulator? Is it?
My app is running Compute Shaders that use non-uniform thread groups. When I run the app in the debugger with a simulator target the app crashes on encoder.dispatchThreads and the error message is: Dispatch Threads with Non-Uniform Threadgroup Size is not supported on this device. Previously the log output states that: Metal Shader Validation is unsupported for Simulator. However: When I stop the debugger and just run the app in the simulator without the debugger attached, the app just runs fine and does not crash. The SwiftUI Preview that also triggers the Compute Shader when preparing data also just runs fine without a crash. I can run and debug on a real device no problem - I just don't have all sizes available. Is there anything I need to check in my lldb/simulator configuration? It obviously does work, just the debugger cannot really deal with it? Any input would be nice as this really slows my down as I have to be extremely careful when debugging on the simulator.
2
0
537
Mar ’25
Wireless debugging
The charging port of my iPhone may be damaged due to water, and it cannot be charged and transmitted data. It can only be charged wirelessly that does not support data transmission. However, since Xcode supports wireless debugging, I can continue to test my App. However, I recently changed to a new Mac, but there is no connection record with the iPhone in the new Mac, which makes it impossible to debug wirelessly. So I want to know how to realize wireless debugging on such a device without debugging records?
2
0
402
Feb ’25
lldb: argument starting with hash disappears.
Here's a simple C++ program that echoes its arguments... #include <stdio.h> int main(int argc, char* argv[]) { for (int i=0; i<argc; ++i) printf("%d %s\n", i, argv[i]); } This works as expected... > ./test arg1 #arg2 arg3 0 ./test 1 arg1 2 #arg2 3 arg3 Running under lldb gives this... > lldb ./test arg1 #arg2 arg3 (lldb) target create "./test" Current executable set to '/Users/richard/Work/test' (arm64). (lldb) settings set -- target.run-args "arg1" "#arg2" "arg3" (lldb) run Process 6138 launched: '/Users/richard/Work/test' (arm64) 0 /Users/richard/Work/test 1 arg1 Process 6138 exited with status = 0 (0x00000000) I get the same if I quote the arguments, or if I add them to the run line. Stepping into main() we see the argv and args values are as though we only had the first argument. If I quote the second argument and add an initial space " #arg1" then it works. I first saw this on an M1 running Sequoia 13.1. It am now on OS 13.3. lldb --version lldb-1600.0.39.109 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
2
1
356
Feb ’25