By now, you have a solid foundation in debugging. You can find and attach to processes of interest, efficiently create regular expression breakpoints to cover a wide range of culprits, navigate the stack frame and tweak variables using the expression command.

但是,它的时间去探索的最佳工具之一,通过LLDB的权力找到感兴趣的代码。在本章中,你会深吸潜入 image command.

image command is an alias for the target modules subcommand. The image command specializes in querying information about 模块;即,代码加载并在一个处理被执行。模块可以包括很多东西,包括主可执行文件,框架或插件。然而,大多数这些模块通常进来的形式 动态库。动态库的示例包括宏的IOS或AppKit的Uikit。

image command is great for querying information about any private frameworks and its classes or methods not publicly disclosed in these header files.

等......模块?

You’ll continue using the Signals project. Fire up the project, build on the iPhone X Simulator and run.

暂停调试器并在LLDB控制台中键入以下内容:

(lldb) image list 

此命令将列出当前加载的所有模块。你会看到很多!

列表的开始应该看起来像以下内容:

[  0] 1E1B0254-4F55-3985-92E4-B2B6916AD424 0x000000010e7e7000 /Users/derekselander/Library/Developer/Xcode/DerivedData/Signals-atjgadijglwyppbagqpvyvftavcw/Build/Products/Debug-iphonesimulator/Signals.app/Signals 
[  1] 002B0442-3D59-3159-BA10-1C0A77859C6A 0x000000011e7c8000 /usr/lib/dyld 
[  2] E991FA37-F8F9-39BB-B278-3ACF4712A994 0x000000010e817000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/dyld_sim 

这 first module is the app’s main binary, Signals. The second and third modules pertain to the dynamic link editors (dyld). These to modules allow your program to load dynamic libraries into memory as well as the main executable in your process.

但这个名单中有很多更多!您可以仅筛选出对您感兴趣的。键入以下内容:

(lldb) image list Foundation

输出将类似于以下内容:

[  0] D153C8B2-743C-36E2-84CD-C476A5D33C72 0x000000010eb0c000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation 

这是一个有用的方法,可以找到有关您想要的模块或模块的信息。

让我们探索这个输出。那里有一些有趣的位:

  1. 这 module’s UUID is printed out first (D153C8B2-743C-36E2-84CD-C476A5D33C72). The UUID is important for hunting down symbolic information and uniquely identifies the version of the Foundation module.
  2. Following the UUID is the load address (0x000000010eb0c000). This identifies where the Foundation module is loaded into the Signals executable’s process space.
  3. 最后,您可以将模块位于磁盘上的完整路径。

让我们深入潜入另一个普通模块,Uikit。键入以下内容:

(lldb) image dump symtab UIKitCore -s address

This will dump all the symbol table information available for UIKitCore. It’s more output than you can shake a stick at! This command sorts the output by the address in which the functions are implemented in the private UIKitCore module thanks to the -s address argument.

有很多在里面有用的信息,但你不能去读书了这一切,现在可以吗?你需要一种方法来有效地查询UIKitCore模块,具有灵活的方式来搜索感兴趣的代码。

image lookup 命令非常适合过滤掉所有数据。键入以下内容:

(lldb) image lookup -n "-[UIViewController viewDidLoad]"

This will dump out information relating just to UIViewController’s viewDidLoad instance method. You’ll see the name of the symbol relating to this method, and also where the code for that method is implemented inside the UIKitCore framework. This is good and all, but typing this is a little tedious and this can only dump out very specific instances.

This is where regular expressions come into play. The -r option will let you do a regular expression query. Type the following into LLDB:

(lldb) image lookup -rn UIViewController

Not only will this dump out all UIViewController methods, it’ll also spit out results like UIViewControllerBuiltinTransitionViewAnimator since it contains the name UIViewController. You can be smart with the regular expression query to only spit out UIViewController methods. Type the following into LLDB:

(lldb) image lookup -rn '\[UIViewController\ '

Alternatively, you can use the \s meta character to indicate a space so you don’t have to escape an actual space and surround it in quotes. The following expression is equivalent:

(lldb) image lookup -rn \[UIViewController\s

This is good, but what about categories? They come in the form of UIViewController(CategoryName). Search for all UIViewController categories.

(lldb) image lookup -rn '\[UIViewController\(\w+\)\ '

这开始变得复杂。开始时的反斜杠表示您希望“[”,然后是UIViewController的字面字符。

Finally, the literal character of “(” then one or more alphanumeric or underscore characters (denoted by \w+), then “)”, followed by a space.

正常表达式的工作知识将帮助您在加载到二进制文件中的任何模块中创造性地查询任何公共或私有代码。

Not only does this print out both public and private code, this will also give you hints to the methods the UIViewController class overrides from its parent classes.

狩猎代码

Regardless of whether you’re hunting for public or private code, sometimes it’s just interesting trying to figure out how the compiler created the function name for a particular method. You briefly used the image lookup command above to find UIViewController methods. You also used it to hunt for how Swift property setters and getters are named in Chapter 4, “Stopping in Code.”

dispatch_once(&onceToken, ^{
  sharedSignalHandler = [[UnixSignalHandler alloc] initPrivate];
});

(lldb) frame info
frame #0: 0x000000010f9b45a0 Commons`__34+[UnixSignalHandler sharedHandler]_block_invoke(.block_descriptor=0x000000010f9ba200) at UnixSignalHandler.m:72
(lldb) image lookup -rn _block_invoke
(lldb) image lookup -rn _block_invoke Signals
(lldb) image lookup -rn _block_invoke Commons
(lldb) rb appendSignal.*_block_invoke -s Commons
pkill -SIGIO Signals
__38-[UnixSignalHandler appendSignal:sig:]_block_invoke
__38-[UnixSignalHandler appendSignal:sig:]_block_invoke_2
(lldb) frame variable
(__block_literal_5 *)  = 0x0000608000275e80
(int) sig = <read memory from 0x41 failed (0 of 4 bytes read)>

(siginfo_t *) siginfo = <read memory from 0x39 failed (0 of 8 bytes read)>

(UnixSignalHandler *const) self = <read memory from 0x31 failed (0 of 8 bytes read)>
(__block_literal_5 *)  = 0x0000608000275e80
(int) sig = 23
(siginfo_t *) siginfo = 0x00007fff587525e8
(UnixSignalHandler *) self = 0x000061800007d440
(UnixSignal *) unixSignal = 0x000000010bd9eebe
(lldb) image lookup -t  __block_literal_5
Best match found in /Users/derekselander/Library/Developer/Xcode/DerivedData/Signals-efqxsbqzgzcqqvhjgzgeabtwfufy/Build/Products/Debug-iphonesimulator/Signals.app/Frameworks/Commons.framework/Commons:
id = {0x100000cba}, name = "__block_literal_5", byte-size = 52, decl = UnixSignalHandler.m:123, compiler_type = "struct __block_literal_5 {
    void *__isa;
    int __flags;
    int __reserved;
    void (*__FuncPtr)();
    __block_descriptor_withcopydispose *__descriptor;
    UnixSignalHandler *const self;
    siginfo_t *siginfo;
    int sig;
}"
(lldb) frame variable
(lldb) po ((__block_literal_5 *)0x0000618000070200)
<__NSMallocBlock__: 0x0000618000070200>
(lldb) p/x ((__block_literal_5 *)0x0000618000070200)->__FuncPtr
(void (*)()) $1 = 0x000000010756d8a0 (Commons`__38-[UnixSignalHandler appendSignal:sig:]_block_invoke_2 at UnixSignalHandler.m:123)
(lldb) image lookup -a 0x000000010756d8a0
(lldb) po ((__block_literal_5 *)0x0000618000070200)->sig
[(NSMutableArray *)self.signals addObject:unixSignal];
(lldb) p *(__block_literal_5 *)0x0000618000070200

窥探周围

好的,您已发现如何以静态方式检查私人类的实例变量,但该块内存地址太诱色,无法单独留下。尝试将其打印出来并使用动态分析探索它。键入以下内容,用块的地址替换地址:

po 0x0000618000070200
<__NSMallocBlock__: 0x618000070200>
(lldb) image lookup -rn __NSMallocBlock__
(lldb) po [__NSMallocBlock__ superclass]
(lldb) image lookup -rn __NSMallocBlock
(lldb) po [__NSMallocBlock superclass]
(lldb) image lookup -rn 'NSBlock\ '
Address: CoreFoundation[0x000000000018fd80] (CoreFoundation.__TEXT.__text + 1629760)
        Summary: CoreFoundation`-[NSBlock invoke]    
(lldb) po id $block = (id)0x0000618000070200
(lldb) po [$block retain]
(lldb) po [$block invoke]
Appending new signal: SIGIO
 nil

私人调试方法

image lookup command does a beautiful job of searching for private methods as well the public methods you’ve seen throughout your Apple development career.

(lldb) image lookup -rn (?i)\ _\w+description\]
(lldb) image lookup -rn NSObject\(IvarDescription\)
_ivarDescription
_propertyDescription
_methodDescription
_shortMethodDescription
(lldb) po [[UIApplication sharedApplication] _ivarDescription]
(lldb) image lookup -rn '\[UIStatusBar\ set'
(lldb) po (BOOL)[[UIStatusBar class] isSubclassOfClass:[UIView class]]
(lldb) po [[UIApplication sharedApplication] statusBar]
<UIStatusBar_Modern: 0x7fdcf3c0f090; frame = (0 0; 375 44); autoresize = W+BM; layer = <CALayer: 0x60c000036640>>
(lldb) po [0x7fdcf3c0f090 setBackgroundColor:[UIColor purpleColor]]
(lldb) breakpoint delete

然后去哪儿?

As a challenge, try figuring out a pattern using image lookup to find all Swift closures within the Signals module. Once you do that, create a breakpoint on every Swift closure within the Signals module. If that’s too easy, try looking at code that can stop on did/Willset. 物业助手,或做/尝试/捕获块。

有一个技术问题?想报告一个错误吗? 您可以向官方书籍论坛中的书籍作者提出问题和报告错误 这里.

有反馈分享在线阅读体验吗? 如果您对UI,UX,高亮反馈,或者我们的在线读者的其他功能,您可以付款给设计团队与下面的表格:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。