上下文:我正在为另一个平台编写解释器,这意味着我的程序通常会从任意整数数据加载指针。当谈到分支时,我会尝试取消引用立即读取下一条指令的地址,这样如果地址无效,我会在分支指令的方法中得到分段错误,而不是一段时间之后。这应该使调试更容易。
然而,这并不像我希望的那样有用。当在那里发生段错误时,它应该是完全可恢复的,因为它是由虚拟读取触发的,所以我希望能够将程序的指令指针移回方法的开头并重置段错误。
我可以告诉LLDB忽略已经进入我的程序的SIGSEGV
吗?我知道我可以使用process handle ...
来决定哪些信号进入我的程序,但这不适用于进程当前正在处理的信号(或者说不处理)。
(如果不可能,我想我仍然可以让lldb停止在段错误上而不是将它们传递给程序,但我至少想知道是否可能。)
答案 0 :(得分:4)
我认为您正在努力解决EXC_BAD_ACCESS
以正确使用它。例如,听起来你正在描述这个示例程序中的dataptr
#include <stdio.h>
int main ()
{
void (*funcptr)(void) = 0;
int *dataptr = 0;
puts ("about to deref dataptr");
printf ("%d\n", *dataptr);
puts ("about to call through f ptr");
funcptr();
puts ("done");
return 0;
}
您将在dataptr
来电中的printf
取消引用中点击第一个EXC_BAD_ACCESS。您可以将变量更改为有效值以继续执行。这里的一个技巧是变量dataptr
存在于我的-O0
编译示例中的堆栈中,因此您需要设置此时正在读取的寄存器以获取过去了。这里我只使用main()
的起始地址作为此程序中的有效地址作为一个简单示例。
* thread #1: tid = 0x1f03, 0x0000000100000eb6 a.out`main + 54 at a.c:7, stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
-> 7 printf ("%d\n", *dataptr);
(lldb) disass -c 1 --pc
a.out`main + 54 at a.c:7:
-> 0x100000eb6: movl (%rcx), %esi
(lldb) reg read rcx
rcx = 0x0000000000000000
(lldb) p dataptr
(int *) $0 = 0x0000000000000000
(lldb) p dataptr = (int*) main
(int *) $1 = 0x0000000100000e80
(lldb) reg write rcx `$1`
(lldb) c
Process 77491 resuming
-443987883
about to call through f ptr
* thread #1: tid = 0x1f03, 0x0000000000000000, stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
#0: 0x0000000000000000
现在我停止了因为我通过NULL函数指针调用了。解开这个需要额外的x86_64 ABI知识,但这并不是那么难 - 将pc设置为调用者的返回地址,弹出一个单词然后你就回来了。
(lldb) reg write pc `*(unsigned long long *)$sp`
(lldb) reg write sp `$sp + 8`
(lldb) c
Process 77522 resuming
done
Process 77522 exited with status = 0 (0x00000000)
当然这是在手边调整 - 不太容易自动化。你可以用python函数表达null函数指针deref并添加一个lldb命令来轻松完成它,但是空数据指针deref要求你知道正在访问什么寄存器 - 也许一些巧妙的模式匹配的反汇编指令可以做到对于常见情况,一些python扩展也是一样的。
希望有所帮助。