我正在Mac OSX上编写一个程序,具体取决于sigaction / sa_handler机制。从用户运行代码片段,随时准备捕获信号/异常。该程序工作正常,但问题是我无法用lldb调试它。即使我设置了
,lldb似乎也无法忽略任何异常proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
控制流在触发异常的指令处停止,并且不会跳转到我之前安装的sa_handler,即使我尝试了命令c
。输出是:
Process 764 stopped
* thread #2: tid = 0xf140, 0x00000001000b8000, stop reason = EXC_BAD_ACCESS (code=2, address=0x1000b8000)
如何让lldb忽略异常/信号并让程序的sa_handler工作呢?
编辑:示例代码
#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;
}
答案 0 :(得分:3)
这是Mac OS X中调试器界面中的一个长期存在的错误(gdb也有同样的问题...)如果您有开发人员帐户,请提交http://bugreport.apple.com的错误。因此很少有人真正使用SIGSEGV处理程序,这个问题永远不会引起内核人员的注意,所以更多的错误是好的......
答案 1 :(得分:2)
我在最近的一个项目中需要这个,所以我只是建立了自己的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);
到
err = ::task_set_exception_ports (task, m_exc_port_info.mask & ~EXC_MASK_BAD_ACCESS, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
导致调试服务器无法捕获EXC_BAD_ACCESS
个异常。现在,我的自定义LLDB工作得很好:它仍然会捕获SIGSEGV
和SIGBUS
,但在面对EXC_BAD_ACCESS
时不再进入愚蠢的无限循环。在先前致命的信号上设置process handle
选项也可以正常工作,我现在可以调试SEGV处理程序而不受惩罚。
Apple真的应该在LLDB中做出这个选项......对他们来说似乎是一个非常简单的解决方案。
答案 2 :(得分: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)
一切看起来都像是在这里正常工作。如果我将-n false
添加到process handle
参数中,则lldb不会打印关于Process .. stopped and restarted
的行。
请注意,这些信号设置不会在流程执行过程中持续存在。因此,如果您已经开始调试会话(r
一旦您已启动该流程一次),那么您需要重新设置这些会话。您可能需要创建命令别名快捷方式并将其放在~/.lldbinit
文件中,以便您可以使用短cmd设置进程处理方式。
答案 3 :(得分:0)
我们可以轻松做到。只需添加此代码即可。
#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);
别忘了这样做
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;
}
请参阅(中文文章):https://zhuanlan.zhihu.com/p/33542591