How can I make lldb ignore the EXC_BAD_ACCESS exception?
I am writing a program on Mac OSX depending on the sigaction / sa_handler mechanism. Run the code snippet from the user and be ready to catch signals / exceptions at any time. The program works fine, but the problem is that I cannot debug it with lldb. lldb seems unable to ignore any exceptions, even if I set
proc hand -p true -s false SIGSEGV
proc hand -p true -s false SIGBUS
The control flow stops at the statement that throws the exception and doesn't go to the sa_handler I installed earlier, even tried the command c
. Output:
Process 764 stopped
* thread #2: tid = 0xf140, 0x00000001000b8000, stop reason = EXC_BAD_ACCESS (code=2, address=0x1000b8000)
How can I make lldb ignore the exception / signal and let the sa_handler program do its job?
EDIT: example code
#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;
}
source to share
I needed this on a recent project, so I just created my own LLDB. I have paved a line in tools/debugserver/source/MacOSX/MachTask.mm
from
err = ::task_set_exception_ports (task, m_exc_port_info.mask, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
to
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);
which makes debugserver not catch exceptions EXC_BAD_ACCESS
. Now my custom LLDB works really well: it still catches SIGSEGV
and SIGBUS
but no longer goes into a silly endless loop when it encounters EXC_BAD_ACCESS
. Setting parameters process handle
on previously fatal signals is fine too, and now I can debug SEGV handlers with impunity.
Apple really should make this option in LLDB ... seems like a very lightweight solution for them.
source to share
A bit of sample code might make a question like this much easier to answer ... I've never used the API sigaction
before, but I threw this together -
#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)
Everything looks like it is working correctly here. If I added -n false
to the arguments process handle
, lldb would not print the lines about Process .. stopped and restarted
.
Note that these alarm settings are not saved across processes. So, if you start your debug session ( r
after you've already started the process once), you will need to reinstall it. You can create a shortcut with a command alias and place it in your file ~/.lldbinit
so that you can customize the process handling the way you prefer with a short cmd.
source to share
This is a long-standing bug in the debugger interface on Mac OS X (gdb had the same problem ...) If you have a developer account, please post a bug from http://bugreport.apple.com . So few people actually use SIGSEGV handlers that the problem never pays attention to the kernel people, so more bugs are good ...
source to share