我包含了iOS标签,但是我在Core i7 MacBook Pro(x86-64上)的模拟器中运行,对吧?,所以我认为这并不重要。
我正在调试Flurry的视频广告中的崩溃。我有一个关于Objective-C异常的断点。当断点被击中时,我在objc_msgSend
。 callstack包含私有Flurry和iOS方法的混合,没有任何公开,也没有我写过的东西。从register read
堆栈帧调用objc_msgSend
会输出以下内容:
(lldb) register read
General Purpose Registers:
eax = 0x1ac082d0
ebx = 0x009600b5 "spaceWillDismiss:interstitial:"
ecx = 0x03e2cddb "makeKeyAndVisible"
edx = 0x0000003f
edi = 0x0097c6f3 "removeWindow"
esi = 0x00781e65 App`-[FlurryAdViewController removeWindow] + 12
ebp = 0xbfffd608
esp = 0xbfffd5e8
ss = 0x00000023
eflags = 0x00010202 App`-[FeedTableCell setupVisibleCommentAndLike] + 1778 at FeedTableCell.m:424
eip = 0x049bd09b libobjc.A.dylib`objc_msgSend + 15
cs = 0x0000001b
ds = 0x00000023
es = 0x00000023
fs = 0x00000000
gs = 0x0000000f
我对这个输出有几个问题。
答案 0 :(得分:1)
我无法专门与iOS / Objective-C框架布局进行对话,因此我无法回答有关EBX和EDI的问题。但我可以帮助你了解EIP和EFLAGS,并给你一些关于ESP / EBP和选择器寄存器的一般提示。 (顺便说一下,模拟器正在模拟32位x86环境;你可以说,因为你的寄存器是32位长。)
EIP是instruction pointer寄存器,也称为程序计数器,它包含当前正在执行的机器指令的地址。因此,它将指向程序崩溃的位置,或更一般地说,程序在遇到断点,转储核心等时的位置。
EIP被保存并恢复以实现函数调用(在机器代码级别 - 内联可能导致高级语言调用不执行实际调用)。在内存不安全的语言中,堆栈缓冲区溢出可能会覆盖指令指针的保存值,导致返回指令返回错误的位置。如果你很幸运,被覆盖的值将在下一次内存提取时触发段错误,但EIP的值将是任意的,并且在调试问题时无益。如果您不走运,攻击者会将新EIP指向有用的代码,因此许多环境都会使用"堆栈Cookie"或者"金丝雀"在恢复保存/覆盖的EIP之前检测这些覆盖,在这种情况下,EIP值可能有用。
EFLAGS不是内存地址,可以说不是通用寄存器。 EFLAGS的每个位都是可以通过各种指令设置或测试的标志。最重要的标志是进位,零和符号标志,它们由算术指令设置并用于条件分支。您的调试器将其误解为内存地址并将其显示为最接近的函数,但这实际上与您的崩溃无关。 (+ 1778
是赠品:这意味着EFLAGS将1778个字节指向函数,但该函数实际上不太可能长达1778个字节。)
ESP是堆栈指针,EBP(通常)是帧指针(也称为基指针)。这些寄存器绑定了调用堆栈上的当前帧。您的调试器通常可以根据这些指针向您显示堆栈变量和当前调用堆栈的值。如果出现损坏,有时您可以手动检查堆栈以恢复EBP并手动展开调用堆栈。注意,可以在没有帧指针(帧指针省略)的情况下编译代码,释放EBP用于其他用途;这在x86上很常见,因为通用寄存器很少。
SS,CS,DS,ES,FS和GS保留段选择器,在分页之前用于实现segmentation的旧时代。今天,FS和GS通常被操作系统用于进程和线程状态块;它们是唯一进入x86-64的选择器寄存器。选择器寄存器通常对调试没有帮助。