Macos 如何使lldb忽略EXC\u BAD\u访问异常?
我正在MacOSX上根据sigaction/sa_处理器机制编写一个程序。从用户处运行代码片段,随时准备捕获信号/异常。该程序运行良好,但问题是我无法用lldb调试它。lldb似乎无法忽略任何异常,即使我设置了Macos 如何使lldb忽略EXC\u BAD\u访问异常?,macos,signals,lldb,Macos,Signals,Lldb,我正在MacOSX上根据sigaction/sa_处理器机制编写一个程序。从用户处运行代码片段,随时准备捕获信号/异常。该程序运行良好,但问题是我无法用lldb调试它。lldb似乎无法忽略任何异常,即使我设置了 proc hand -p true -s false SIGSEGV proc hand -p true -s false SIGBUS 控制流在触发异常的指令处停止,即使我尝试了命令c,也不会跳转到我之前安装的sa_处理程序。结果是: Process 764 stopped * t
proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
控制流在触发异常的指令处停止,即使我尝试了命令c
,也不会跳转到我之前安装的sa_处理程序。结果是:
Process 764 stopped
* thread #2: tid = 0xf140, 0x00000001000b8000, stop reason = EXC_BAD_ACCESS (code=2, address=0x1000b8000)
如何使lldb忽略异常/信号,并让程序的sa_处理程序执行其工作
编辑:示例代码
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
static void handler(int signo, siginfo_t *sigaction, void *context)
{
printf("in handler.\n");
signal(signo, SIG_DFL);
}
static void gen_exception()
{
printf("gen_exception in.\n");
*(int *)0 = 0;
printf("gen_exception out.\n");
}
void *gen_exception_thread(void *parg)
{
gen_exception();
return 0;
}
int main()
{
struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
printf("sigaction fails.\n");
return 0;
}
pthread_t id;
pthread_create(&id, NULL, gen_exception_thread, NULL);
pthread_join(id, NULL);
return 0;
}
#包括
#包括
#包括
#包括
#包括
静态void处理程序(int-signo、siginfo\u t*sigaction、void*context)
{
printf(“在处理程序中。\n”);
信号(signo、SIG_DFL);
}
静态无效gen_异常()
{
printf(“gen_异常在。\n”);
*(int*)0=0;
printf(“gen_异常输出。\n”);
}
void*gen\u异常螺纹(void*parg)
{
gen_异常();
返回0;
}
int main()
{
struct-sigaction-sa;
sa.sa_sigaction=handler;
sigemptyset(和sa.sa_面具);
sa.sa_flags=sa_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV,&sa,NULL)=-1){
printf(“sigaction失败。\n”);
返回0;
}
pthread_t id;
pthread_create(&id,NULL,gen_exception_thread,NULL);
pthread_join(id,NULL);
返回0;
}
一点示例代码可以让这样的问题更容易回答。。。我以前从未使用过sigaction
API,但我把它放在了一起-
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void segv_handler (int in)
{
puts ("in segv_handler()");
}
void sigbus_handler (int in)
{
puts ("in sigbus_handler()");
}
int main ()
{
struct sigaction action;
action.sa_mask = 0;
action.sa_flags = 0;
action.sa_handler = segv_handler;
sigaction (SIGSEGV, &action, NULL);
action.sa_handler = sigbus_handler;
sigaction (SIGBUS, &action, NULL);
puts ("about to send SIGSEGV signal from main()");
kill (getpid(), SIGSEGV);
puts ("about to send SIGBUS signal from main()");
kill (getpid(), SIGBUS);
puts ("exiting main()");
}
% lldb a.out
(lldb) br s -n main
(lldb) r
(lldb) pr h -p true -s false SIGSEGV SIGBUS
(lldb) c
Process 54743 resuming
about to send SIGSEGV signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGSEGV
in segv_handler()
about to send SIGBUS signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGBUS
in sigbus_handler()
exiting main()
Process 54743 exited with status = 0 (0x00000000)
(lldb)
#包括
#包括
#包括
无效segv_处理程序(整数英寸)
{
放入(“在segv_handler()中”);
}
无效sigbus_处理程序(int-in)
{
puts(“在sigbus_handler()中”);
}
int main()
{
结构动作;
action.sa_mask=0;
action.sa_标志=0;
action.sa_handler=segv_handler;
sigaction(SIGSEGV,&action,NULL);
action.sa_handler=sigbus_handler;
sigaction(SIGBUS,&action,NULL);
puts(“即将从main()发送SIGSEGV信号”);
kill(getpid(),SIGSEGV);
puts(“即将从main()发送SIGBUS信号”);
kill(getpid(),SIGBUS);
卖出(“退出主();
}
%lldb a.out
(lldb)br s-n干管
(lldb)r
(lldb)pr h-p真-s假SIGSEGV SIGBUS
(lldb)c
进程54743恢复
即将从main()发送SIGSEGV信号
进程54743停止并重新启动:线程1收到信号:SIGSEGV
在segv_handler()中
即将从main()发送SIGBUS信号
进程54743停止并重新启动:线程1收到信号:SIGBUS
在sigbus_handler()中
退出main()
进程54743退出,状态为0(0x00000000)
(lldb)
看起来这里一切正常。如果我在进程句柄
参数中添加了-n false
,lldb就不会打印有关进程的行了。。停止并重新启动
请注意,这些信号设置不会在进程执行期间保持不变。因此,如果您正在启动调试会话(
r
一旦您已经启动了一次进程),则需要重新设置这些会话。您可能需要创建一个命令别名快捷方式,并将其放入~/.lldbinit
文件中,这样您就可以使用一个短cmd来设置处理过程的方式。这是Mac OS X中调试器界面中的一个长期存在的错误(gdb也有同样的问题…),如果您有一个开发人员帐户,请使用它提交一个错误。很少有人真正使用SIGSEGV处理程序,所以这个问题从未引起内核人员的任何注意,所以更多的bug是好的…我在最近的一个项目中需要它,所以我只构建了自己的LLDB。我在tools/debugserver/source/MacOSX/MachTask.mm
中打了一行补丁
err = ::task_set_exception_ports (task, m_exc_port_info.mask, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
到
这会导致debugserver无法捕获EXC\u BAD\u访问
异常。现在,我的自定义LLDB工作得很好:它仍然捕获SIGSEGV
和SIGBUS
,但在面对EXC\u BAD\u访问时不再进入愚蠢的无限循环。在以前的致命信号上设置processhandle
选项也很好,现在我可以调试SEGV处理程序而不受惩罚
苹果真的应该在LLDB中选择这个选项……对他们来说似乎是一个非常简单的解决方案。我们可以很容易地做到。只需添加此代码
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
int ret = task_set_exception_ports(
mach_task_self(),
EXC_MASK_BAD_ACCESS,
MACH_PORT_NULL,//m_exception_port,
EXCEPTION_DEFAULT,
0);
完整代码:
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
static void handler(int signo, siginfo_t *sigaction, void *context)
{
printf("in handler.\n");
signal(signo, SIG_DFL);
}
static void gen_exception()
{
printf("gen_exception in.\n");
*(int *)0 = 0;
printf("gen_exception out.\n");
}
void *gen_exception_thread(void *parg)
{
gen_exception();
return 0;
}
int main()
{
task_set_exception_ports(
mach_task_self(),
EXC_MASK_BAD_ACCESS,
MACH_PORT_NULL,//m_exception_port,
EXCEPTION_DEFAULT,
0);
struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
printf("sigaction fails.\n");
return 0;
}
pthread_t id;
pthread_create(&id, NULL, gen_exception_thread, NULL);
pthread_join(id, NULL);
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态void处理程序(int-signo、siginfo\u t*sigaction、void*context)
{
printf(“在处理程序中。\n”);
信号(signo、SIG_DFL);
}
静态无效gen_异常()
{
printf(“gen_异常在。\n”);
*(int*)0=0;
printf(“gen_异常输出。\n”);
}
void*gen\u异常螺纹(void*parg)
{
gen_异常();
返回0;
}
int main()
{
任务\u设置\u异常\u端口(
mach_task_self(),
EXC\u屏蔽\u不良访问,
MACH\u PORT\u NULL,//m\u exception\u PORT,
默认情况下的例外情况,
0);
struct-sigaction-sa;
sa.sa_sigaction=handler;
sigemptyset(和sa.sa_面具);
sa.sa_flags=sa_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV,&sa,NULL)=-1){
printf(“sigaction失败。\n”);
返回0;
}
pthread_t id;
pthread_create(&id,NULL,gen_exception_thread,NULL);
pthread_join(id,NULL);
返回0;
}
请参阅(中文文章):嗨,吉姆:我注意到你评论说“要做到这一点,最直接的方法是调试器以root用户身份运行”。在OSX上,我可以以root用户身份运行调试器(我知道错误报告是关于iOS的,这是不可能的)。如果调试器以root用户身份运行,我有没有办法修补LLDB以允许它忽略EXC_BAD_访问?*field*@jim ingham您能详细说明一下“实现这一点的直接方法要求调试器以root用户身份运行”吗?假设用户可以以root用户身份运行gdb
proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
static void handler(int signo, siginfo_t *sigaction, void *context)
{
printf("in handler.\n");
signal(signo, SIG_DFL);
}
static void gen_exception()
{
printf("gen_exception in.\n");
*(int *)0 = 0;
printf("gen_exception out.\n");
}
void *gen_exception_thread(void *parg)
{
gen_exception();
return 0;
}
int main()
{
task_set_exception_ports(
mach_task_self(),
EXC_MASK_BAD_ACCESS,
MACH_PORT_NULL,//m_exception_port,
EXCEPTION_DEFAULT,
0);
struct sigaction sa;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
printf("sigaction fails.\n");
return 0;
}
pthread_t id;
pthread_create(&id, NULL, gen_exception_thread, NULL);
pthread_join(id, NULL);
return 0;
}