我如何阅读 iOS 中 ptr_refs 给出的引用?

Posted

技术标签:

【中文标题】我如何阅读 iOS 中 ptr_refs 给出的引用?【英文标题】:How do i read references given by ptr_refs in iOS? 【发布时间】:2020-06-10 18:30:13 【问题描述】:

当使用ptr_refs 打印引用列表时,它会给出一些模糊的结果(至少在 ios 中)。例如,我有一个示例应用程序,其中包含这个很小的 ​​ViewController 类和一个对 UILabel 实例的出口引用:

import UIKit

class ViewController: UIViewController 

    @IBOutlet var label: UILabel!

    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        print(label)
    


这是我在打印标签引用时得到的清单:

(lldb) ptr_refs 0x102914810
0x0000000281b04630: malloc(    16) -> 0x281b04630
0x0000000283d09f18: malloc(    96) -> 0x283d09ec0 + 88    
0x0000000280c18d60: malloc(    64) -> 0x280c18d40 + 32     CFXNotificationNameWildcardObjectRegistration0 bytes after CFXNotificationNameWildcardObjectRegistration
0x000000028192b408: malloc(    32) -> 0x28192b400 + 8      _UILabelStringContent._UILabelContent._defaultAttributesProvider
0x0000000283a3d2f0: malloc(    80) -> 0x283a3d2c0 + 48     CFXNotificationObjcObserverRegistration8 bytes after CFXNotificationObjcObserverRegistration
0x0000000283a3d2f8: malloc(    80) -> 0x283a3d2c0 + 56     CFXNotificationObjcObserverRegistration16 bytes after CFXNotificationObjcObserverRegistration
0x000000010290c070: malloc(   864) -> 0x10290bd20 + 848    TtC13ThreadChecker14ViewController216 bytes after TtC13ThreadChecker14ViewController
0x0000000102d058c0: malloc(   304) -> 0x102d05850 + 112

如果这不仅仅是一个示例应用程序,而且它有 10-15 个插座引用,我将很难弄清楚这行代码中的哪个确切引用 - 0x000000010290c070: malloc( 864) -> 0x10290bd20 + 848 TtC13ThreadChecker14ViewController216 bytes after TtC13ThreadChecker14ViewControllerThe

我还尝试了启用MallocStackLogging-s 选项,但是当涉及到插座参考时,此信息不是很有帮助。

如果我只有一个对象的地址ptr_refs给出的列表,有没有办法找出我的代码中的确切变量/字段对应于列表中的引用?

【问题讨论】:

本周早些时候看到你的问题,但是太忙没时间写答案,这个周末终于有时间写了,希望对你有帮助! 【参考方案1】:

首先,右边的名字给了我们一些线索,从中你可以猜到TtC13ThreadChecker14ViewController与你的ViewController类相关联。

_Tt 用于目标; C代表班级; 13是“ThreadChecker”字符串的长度,你的项目名称是ThreadChecker; 14 是“ViewController”字符串的长度,也就是类。你的 ViewController 从 0x10290bd20 开始。

其次,malloc 位于0x000000010290c070。请注意,0x000000010290c070 - 0x10290bd20 = 0x350 是十进制的 848,这就是为什么它将偏移量从“ViewController”的开头设置为 848,即0x10290bd20 + 848。所以这个偏移量 848 是拼图中的一个重要部分。

第三,接下来要做的是找出源代码中的哪一行在偏移量 848 处。为此,我们开始做

(lldb) image list
[  0] 4EB96CD6-42E0-34D8-AB5B-2418F5C55678 0x000000010252c000 /Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB 

即使在这个简单的示例中,应用程序也可能加载了 200-300 个库。对于您自己源代码的当前调查,您可以忽略库,只查看 [0](列表中的第一个元素)。 (在我的示例中,该应用称为 testLLDB;在您的示例中,您可能会看到 ThreadChecker 而不是 testLLDB)。

需要注意的重要一点是图像列表给出了所谓的文件地址,其中您从 Xcode 获得的用于ptr_refs 的地址可能完全不同(模拟器中的实际地址)或在实际运行期间将 iPhone 内存加载到 RAM 的一部分),例如,在您的示例中为 0x102914810文件地址指的是每个目标文件定义的虚拟地址。为了找到偏移量为 848 的源代码行号,您可以使用这些文件地址,您现在只需要一条信息,即 ViewController 代码的开头在哪里,因此您可以获取偏移量848 从那里。

第四,要找到ViewController的代码开头,可以使用

(lldb) image dump sections  /Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB

我们仅将我们获得的 testLLDB 应用的图像指定为 image list 的第一个元素,而不是之后的 100 个库。

lldb 然后会给你类似的东西:

Sections for '/Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0x00000100 container        [0x0000000000000000-0x0000000100000000)* ---  0x00000000 0x00000000 0x00000000 testLLDB.__PAGEZERO
  0x00000200 container        [0x000000010252c000-0x0000000102532000)  r-x  0x00000000 0x00006000 0x00000000 testLLDB.__TEXT
  0x00000001 code             [0x000000010252d260-0x000000010252fa80)  r-x  0x00001260 0x00002820 0x80000400 testLLDB.__TEXT.__text
  0x00000002 code             [0x000000010252fa80-0x000000010252fb5e)  r-x  0x00003a80 0x000000de 0x80000408 testLLDB.__TEXT.__stubs
  0x00000003 code             [0x000000010252fb60-0x000000010252fce2)  r-x  0x00003b60 0x00000182 0x80000400 testLLDB.__TEXT.__stub_helper
  0x00000004 data-cstr        [0x000000010252fce2-0x00000001025309bf)  r-x  0x00003ce2 0x00000cdd 0x00000002 testLLDB.__TEXT.__objc_methname
  0x00000005 data-cstr        [0x00000001025309c0-0x0000000102531817)  r-x  0x000049c0 0x00000e57 0x00000002 testLLDB.__TEXT.__cstring
  0x00000006 regular          [0x0000000102531820-0x0000000102531b50)  r-x  0x00005820 0x00000330 0x00000000 testLLDB.__TEXT.__const
...

还有更多,但对于这个简单的 ViewController,前几节就足以满足我们的目的。查看第一个代码部分,它的范围是[0x000000010252d260-0x000000010252fa80)。所以它从0x000000010252d260开始。这里是我们添加偏移量 848 的地方。但是我们添加的是十六进制,所以我们将 0x350 添加到 0x000000010252d260 以得到 0x000000010252d5b0

最后,我们可以通过以下方式查看源代码的哪一部分引用了标签:

(lldb) image lookup -a 0x000000010252d5b0 --verbose
  Address: testLLDB[0x00000001000015b0] (testLLDB.__TEXT.__text + 848)
  Summary: testLLDB`key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController + 80 at <compiler-generated>
   Module: file = "/Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB", arch = "x86_64"
  CompileUnit: id = 0x00000000, file = "/Users/daniel.wong/OneDrive - V-Key Pte Ltd/ios/testLLDB/testLLDB/testLLDB/ViewController.swift", language = "swift"
 Function: id = 0x10000032e, name = "key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController", mangled = "$s8testLLDB14ViewControllerC5labelSo7UILabelCSgvpACTK", range = [0x000000010252d560-0x000000010252d5bf)
 FuncType: id = 0x10000032e, byte-size = 8, compiler_type = "() -> ()
"
   Blocks: id = 0x10000032e, range = [0x10252d560-0x10252d5bf)
LineEntry: [0x000000010252d560-0x000000010252d5c0): /Users/daniel.wong/OneDrive - V-Key Pte Ltd/ios/testLLDB/testLLDB/<compiler-generated>
   Symbol: id = 0x000000a4, range = [0x000000010252d560-0x000000010252d5c0), name="key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController", mangled="$s8testLLDB14ViewControllerC5labelSo7UILabelCSgvpACTK"
 Variable: id = 0x100000345, name = "label", type = "testLLDB.ViewController", location = DW_OP_fbreg(-16), decl = ViewController.swift:18

所以我们在 ViewController.swift:18 看到它是“testLLDB.ViewController.label 的关键路径获取器:Swift.Optional<__c.uilabel> : testLLDB.ViewController”,这正是您要寻找的。 (好的,对于我的测试视图控制器,标签在第 18 行,因为我还有一个 viewDidLoad 需要几行;对于你的,你应该为你的 ViewController 获得适当的行号)。

这篇文章已经太长了,只是补充一点信息:那些来自CFXNotificationObjcObserverRegistration 的对您标签的引用,这是CoreFoundation 的一部分,所以我们看到not at 引用来自我们自己的源代码.许多引用通常来自CoreFoundation等系统框架;例如,如果您将带有标签的视图放在情节提要中并添加自动布局约束,ptr_refs 命令将另外为您提供许多与自动布局相关的其他参考,例如,

NSContentSizeLayoutConstraint.NSLayoutConstraint._container
0x000060000049ce48: malloc(    96) -> 0x60000049ce40 + 8      NSContentSizeLayoutConstraint.NSLayoutConstraint._container
0x00006000035db208: malloc(    64) -> 0x6000035db200 + 8      NSLayoutDimension.NSLayoutAnchor._referenceItem
0x00006000035db3c8: malloc(    64) -> 0x6000035db3c0 + 8      NSLayoutDimension.NSLayoutAnchor._referenceItem
0x00006000035e9560: malloc(    64) -> 0x6000035e9540 + 32 

【讨论】:

天哪,这比我想象的要复杂得多:)。非常感谢您的努力,它有效!赏金期结束了,所以我可能应该再开始一个来感谢你。另外,您能否解释一下您是如何决定从部分列表中选择哪个部分的?

以上是关于我如何阅读 iOS 中 ptr_refs 给出的引用?的主要内容,如果未能解决你的问题,请参考以下文章

用于 IO 和 SERCOM 的引脚寻址(ARM SAM D 系列)

iOS:地图视图注释未显示针脚

Safari中的引导轮播文本变暗

如何简化地图中的引脚

51单片机中DS1302芯片的引脚配置原理是啥?

如何在 Isabelle/HOL 的引理之外获取见证实例