Я пишу программу на 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;
}
4 ответа
Мне это было нужно в недавнем проекте, поэтому я только что построил свой собственный 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 ... кажется, для них это действительно простое решение.
Это давняя ошибка в интерфейсе отладчика в Mac OS X (у gdb была такая же проблема ...). Если у вас есть учетная запись разработчика, сообщите об ошибке с помощью http://bugreport.apple.com. Так мало людей на самом деле используют обработчики SIGSEGV, что проблема никогда не привлекает внимания со стороны разработчиков ядра, поэтому больше ошибок - это хорошо ...
Мы легко справимся. Просто добавьте этот код.
#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
Небольшой пример кода может упростить ответ на такой вопрос ... Я никогда раньше не использовал 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.
Похожие вопросы
Связанные вопросы
Новые вопросы
macos
macOS (ранее известная как OS X или Mac OS X) - это операционная система для настольных ПК от Apple, установленная на компьютерах Macintosh. Используйте этот тег только в том случае, если ваш вопрос касается использования API-интерфейсов macOS или поведения, специфичного для macOS, а не потому, что вы запускаете свой код в macOS. Вопросы, связанные с использованием или устранением неполадок macOS, не относятся к теме и принадлежат сообществу «Спроси другое».
tools/debugserver/source/MacOSX/MachTask.mm
?