LINUX.ORG.RU

core dump & gdb - stragne stack


0

0

Доброго дня всем.

Есть httpd сервер (обычный Apache), к нему написан модуль, который выпадает в SigSegV. Мне необходимо узнать где это происходит, и вот какое решение я пытался воплотить:

Я переопределяю обработчик сигнала SigSegV, и в свой функции я делаю vfork(), и далее в новом процессе вызываю gdb, который делает attach к родителю, и делает gcore.

Далее, я этот core файл начинаю использовать:

$ gdb httpd -c 5861.1Hc3Ks-0001WX-gC.5861
....
Loaded symbols for /home/prapor/programs/mca/libs/xalan/lib/libxalanMsg.so.110
#0 0x00002af2e04ffa40 in wait () from /lib/libpthread.so.0
(gdb) bt
#0 0x00002af2e04ffa40 in wait () from /lib/libpthread.so.0
#1 0x00002af2e5edc197 in Signal_SIGSEGV (sig=<value optimized out>) at mod_pm.cpp:51
#2 0x00002af2e073f940 in killpg () from /lib/libc.so.6
#3 0x0000000000000000 in ?? ()
(gdb)

И я не вижу тот стек, который я ожидал увидеть. Ведь, как я понимаю, родитель работал, стек у него должен быть не маленький, а тут ноль.

Я уже проделывал таку штуку на работающем апаче - видел нормальный стек исполнения. Но здесь что-то не то. Ведь смотрите: если обработчик сигнала просто завершит свое выполнение (return;), то процесс будет продолжать выполнять свой код. Так а как же он вернется в этот код, если стек пуст!

Вот снимок стека работающего апача:

(gdb) bt
#0 0x00002af2e07c8363 in select () from /lib/libc.so.6
#1 0x00002af2e00a8115 in apr_sleep (t=<value optimized out>) at time.c:246
#2 0x000000000043b4a5 in ap_wait_or_timeout (status=0x7fffcb10b2bc, exitcode=0x7fffcb10b2b8, ret=0x7fffcb10b290,
p=0x565138) at mpm_common.c:345
#3 0x00000000004448e7 in ap_mpm_run (_pconf=0x16f8, plog=<value optimized out>, s=0x2) at worker.c:1570
#4 0x0000000000420b01 in main (argc=1, argv=0x7fffcb10b488) at main.c:717
(gdb)

Но не то что я видел !

Заранее спасибо за советы.


Странный способ. Запускайте апач с ключом -X и с помощью gdb находите проблемное место в модуле

Chumka ★★★
()

Могу предположить, что обработка сигнала происходит в другом стеке, который и показывается.

Legioner ★★★★★
()
Ответ на: комментарий от Chumka

делал. получал такие стеки работы программ:

(gdb) bt
#0 0x00002b755bd09f60 in __accept_nocancel () from /lib/libpthread.so.0
#1 0x00002b755f876904 in cgid_start (p=<value optimized out>, main_server=0x56a7a0, procnew=<value optimized out>)
at mod_cgid.c:633
#2 0x00002b755f877434 in cgid_init (p=0x565138, plog=<value optimized out>, ptemp=<value optimized out>,
main_server=0x56a7a0) at mod_cgid.c:852
#3 0x000000000043285b in ap_run_post_config (pconf=0x565138, plog=0x5972c8, ptemp=0x56b168, s=0x56a7a0) at config.c:91
#4 0x0000000000420ade in main (argc=2, argv=0x7fff4f900c38) at main.c:706
(gdb) detach

и второго процесса:
Loaded symbols for /home/prapor/programs/mca/libs/xalan/lib/libxalanMsg.so.110
[Switching to Thread 47783066909328 (LWP 14187)]
0x00002b755bd0ac97 in do_sigwait () from /lib/libpthread.so.0
(gdb) bt
#0 0x00002b755bd0ac97 in do_sigwait () from /lib/libpthread.so.0
#1 0x00002b755bd0ad4d in sigwait () from /lib/libpthread.so.0
#2 0x00002b755b8b1fbb in apr_signal_thread (signal_handler=0x442c00 <check_signal>) at signals.c:383
#3 0x0000000000443ff6 in child_main (child_num_arg=<value optimized out>) at worker.c:1227
#4 0x00000000004441f6 in make_child (s=0x56a7a0, slot=0) at worker.c:1306
#5 0x00000000004442b5 in startup_children (number_to_start=1) at worker.c:1375
#6 0x0000000000444fae in ap_mpm_run (_pconf=0x565138, plog=<value optimized out>, s=0x56a7a0) at worker.c:1725
#7 0x0000000000420b01 in main (argc=2, argv=0x7fff4f900c38) at main.c:717
(gdb) detach

и нигде ни намека на мой код.

Я вот что думаю: я думаю, тот код, который вызывает SigSegV работает в другом потоке, и gdb отлаживает не тот что мне надо.


Насчет стека: как я понимаю, ядро подменяет стек при вызове обработчика сигнала, и возвращает себе старый стек, когда поток выходит из обработчика. Поэтому, видимо надо делать дамп после того, как поток вернулся к исполнению. Сейчас проверю..

nial
() автор топика
Ответ на: комментарий от nial

> Я вот что думаю: я думаю, тот код, который вызывает SigSegV работает в другом потоке, и gdb отлаживает не тот что мне надо.

А что мешает раскрутить стек в обработчике sigsegv?

mv ★★★★★
()
Ответ на: комментарий от nial

>Насчет стека: как я понимаю, ядро подменяет стек при вызове обработчика сигнала, и возвращает себе старый стек, когда поток выходит из обработчика. Поэтому, видимо надо делать дамп после того, как поток вернулся к исполнению. Сейчас проверю..

Именно.

для x86 http://www.linuxjournal.com/article/6391

>...

>As a consequence of this mechanism, the first two entries in the stack frame chain when you get into the signal handler contain, respectively, a return address inside your signal handler and one inside sigaction() in libc. The stack frame of the last function called before the signal (which, in case of fault signals, also is the one that supposedly caused the problem) is lost.

anonymous
()
Ответ на: комментарий от mv

>А что мешает раскрутить стек в обработчике sigsegv?

См. ссылку в моем предыдущем сообщении. Напрямую это сделать невозможно, нужен хак (работает только для x86 судя по комментам).

anonymous
()
Ответ на: комментарий от anonymous

> См. ссылку в моем предыдущем сообщении. Напрямую это сделать невозможно, нужен хак (работает только для x86 судя по комментам).

Странно, а как это получается у меня?

void segv_handler(int sig, siginfo_t* info, void* secret)
{
log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(_T("SEGV"));

void *trace[16];
char **messages = (char **)NULL;
int i, trace_size = 0;
ucontext_t *uc = (ucontext_t *)secret;

LOG4CXX_FATAL(logger, _T(format("segmentation fault in process %d at address %p") % info->si_addr % uc->uc_mcontext.gregs[REG_EIP]));

trace_size = backtrace(trace, 16);
trace[1] = (void *)uc->uc_mcontext.gregs[REG_EIP];

messages = backtrace_symbols(trace, trace_size);
LOG4CXX_FATAL(logger, _T("backtrace"));

for (i = 1; i < trace_size; ++i) {
LOG4CXX_FATAL(logger, _T(format("[%d] %s") % i % messages[i]));
}
abort();
}

mv ★★★★★
()
Ответ на: комментарий от mv

>Странно, а как это получается у меня?

По традиции по ссылкам не ходим?

Ключевая строчка

/* overwrite sigaction with caller's address */
trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];

Весь фокус в том, что третий параметр обработчика ни где не документирован.. void *secret

void segv_handler(int sig, siginfo_t* info, void* secret)

В твоем коде как раз так и сделано.. хз, может оно и боян уже...

anonymous
()
Ответ на: комментарий от anonymous

> Весь фокус в том, что третий параметр обработчика ни где не документирован.. void *secret

> void segv_handler(int sig, siginfo_t* info, void* secret)

> В твоем коде как раз так и сделано.. хз, может оно и боян уже..

Вам шашечки или ехать? Бэктрейс подобным образом делается замечательно, понять, в каком месте падает, соответственно, можно.

mv ★★★★★
()
Ответ на: комментарий от mv

>Бэктрейс подобным образом делается замечательно,

Особенно на архитектурах отличных от x86 ;)

Я смотрю ты не читатель, до свидания, мне больше сказать нечего.

anonymous
()
Ответ на: комментарий от anonymous

Верно, стек я таким образом прочитал, но это только стек (я имею в виду названия функций). Когда я смотрю на программу из-под gdb, то я вижу не только символы, но и параметры функций:

#0 0x00002af578721c10 in strlen () from /lib/libc.so.6
(gdb) bt
#0 0x00002af578721c10 in strlen () from /lib/libc.so.6
#1 0x00002af5786f3b70 in vfprintf () from /lib/libc.so.6
#2 0x00002af5786f970a in printf () from /lib/libc.so.6
#3 0x00002af57de6dbd6 in TApacheAgent::getRequest (tid=1090525504) at ApacheAgent.cpp:126
...

Да, я понимаю, что используя стек можно узнать о переменных, но я плохо разбираюсь в этих вещах, и думаю решить задачу другим способом: что если попытаться подменить то-ли eip, то-ли еще какие регистры, и заставить gdb сделать gcore ?

Быть может уже кто-то практиковал такое ?

nial
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.