利用lldb分析Swift调试问题

swift、lldb

Posted by Karim on January 29, 2025

问题

自从升级了Xcode 16之后,swift环境下使用po就会出现问题,报错如下:

error: type for self cannot be reconstructed: type for typename "$s17swift_lldb_module10ModuleViewCD" was not found
error: Couldn't realize Swift AST type of self. Hint: using `v` to directly inspect variables and fields may still work.

从日志信息可以看出,是因为lldb无法获取到类型信息,导致的问题。

类型信息的作用是什么?

编译器提供的调试信息会告诉给调试器变量在内存中的位置,然后通过Types,lldb可以知道聚合类型源变量中的结构和内存布局,从而知道有哪些字段,并且通过Types使用数据格式化打印出更客观的格式出来。

类型信息从哪里来

在调试器端,用frame variable或v命令的时候,lldb从debug info和swift反射获取类型信息。
而在编译器端,用expr或po命令的时候,lldb通过Modules获取类型信息。

Modules是编译器构建类型声明的方式。

由此可见,应该是因为Modules导入失败,导致了lldb无法获取到类型信息。
通过swift-healthcheck命令,可以用来诊断swift环境的问题,在运行po命令发送错误之后,执行swift-healthcheck命令:

(lldb) swift-healthcheck
Health check written to /var/folders/c5/7j9s6knn0wvfdhfkz1pv67bh0000gn/T/lldb/5648/lldb-healthcheck-cad017.log

然后可以看到输出的日志:

SwiftASTContextForExpressions(module: "swift_lldb_module", cu: "Base64.swift")::LoadOneModule() -- Missing Swift module or Clang module found for "swift_lldb_module", "imported" via SwiftDWARFImporterDelegate. Hint: Register Swift modules with the linker using -add_ast_path.
SwiftASTContextForExpressions(module: "swift_lldb_module", cu: "Base64.swift")::LoadOneModule() -- Missing Swift module or Clang module found for "swift_lldb_module", "imported" via SwiftDWARFImporterDelegate. Hint: Register Swift modules with the linker using -add_ast_path.

因此更加可以确定是Modules导入失败导致的问题。

解决

接下来要怎么解决这个问题已经很明显了,可以通过-add_ast_path来注册Swift模块,让lldb可以找到类型信息。
如果是使用cocoapods,可以通过在Podfile中添加post_integrate脚本来解决这个问题。

post_integrate do |installer|
    #将swift-lldb-debug替换成你的target名字
    xcconfig_path = installer.sandbox.target_support_files_root.to_s + '/Pods-swift-lldb-debug/Pods-swift-lldb-debug.debug.xcconfig'

    xcconfig_content = File.read xcconfig_path
    xcconfig_original_ld_flags = xcconfig_content.match(/OTHER_LDFLAGS = ([^\n]+)\n/)[1]

    swift_module_flags = installer.pods_project.targets.map do |target|
           "-Wl,-add_ast_path,$(TARGET_BUILD_DIR)/#{target.name}/#{target.name}.swiftmodule/$(NATIVE_ARCH_ACTUAL)-apple-$(SHALLOW_BUNDLE_TRIPLE).swiftmodule"
    end.join(' ')

    xcconfig_new_ld_flags = <<~CONTENT

    OTHER_LDFLAGS = #{xcconfig_original_ld_flags} #{swift_module_flags}

    CONTENT

    xcconfig_content.gsub! /OTHER_LDFLAGS = ([^\n]+)\n/, xcconfig_new_ld_flags

    File.open(xcconfig_path, 'w') do |f|
      f.puts xcconfig_content
    end
end

执行pod install之后,就可以在Pods-xxx.debug.xcconfig中看到通过-add_ast_path注册的swift模块。

这样就可以解决lldb无法获取类型信息的问题了,这里还有一个小插曲,如果你的项目是通过rosetta运行到模拟器上,还需要注册到x86_64的swift模块,可以将$(NATIVE_ARCH_ACTUAL)替换成这段手动指定不同架构上:

    swift_module_flags = installer.pods_project.targets.map do |target|      
      "-Wl,-add_ast_path,$(TARGET_BUILD_DIR)/#{target.name}/#{target.name}.swiftmodule/x86_64-apple-$(SHALLOW_BUNDLE_TRIPLE).swiftmodule -Wl,-add_ast_path,$(TARGET_BUILD_DIR)/#{target.name}/#{target.name}.swiftmodule/arm64-apple-$(SHALLOW_BUNDLE_TRIPLE).swiftmodule"
    end.join(' ')

参考

Debug Swift debugging with LLDB
Breakpoint issue: ‘self cannot be reconstructed’


请保持转载后文章内容的完整,以及文章出处。本人保留所有版权相关权利。

分享到: