URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 1724
[ Назад ]

Исходное сообщение
"Источник SIGSEGV"

Отправлено Solnuh , 28-Май-03 20:27 
Есть код который выводит имена функций после выполнения которых был вызван сигнал, аля backtrace в gdb, путем прохода вверх по стэку.
Работает прекрасно, только саму функцию в которой произошёл SIGSEGV выявить не получается, получается только с той которая вызвала функцию неблагополучную.
Нету ни одного адреса указывающего на тело функции... как узнать откуда SIGSEGV свалился? gdb прекрасно всё показывает, но как он это делает не знаю. Хелп.

int BP,faddr;
void sighandler(int sig, siginfo_t *info, void *c)
{
        __asm__ ("
                movl ebp,BP
        ");    
        printf("%x\n<br>",info->si_addr);
        while((void*)*((int*)BP)) {    
                faddr=BP;
                BP+=4;
                if(dladdr((void*)*((int*)BP),&a)) {  
                        printf("%s<br>\n",a.dli_sname);
                }
                BP=*((int*)faddr);
        }
}


Содержание

Сообщения в этом обсуждении
"Источник SIGSEGV"
Отправлено qq , 29-Май-03 02:52 
дык gdb использует debug info, засунутое в бинарник компилером, для определения имен ф-ций
а ты используешь ф-цию для получения _экспортированных_ символов
соотв. и видишь ты только те ф-ции, которые экспортированы модулкм...

а почему бы просто не вставить DBGPRINT("entering function X")
где надо?


"Источник SIGSEGV"
Отправлено Solnuh , 29-Май-03 12:16 
>дык gdb использует debug info, засунутое в бинарник компилером, для определения имен
>ф-ций
>а ты используешь ф-цию для получения _экспортированных_ символов
>соотв. и видишь ты только те ф-ции, которые экспортированы модулкм...
>
>а почему бы просто не вставить DBGPRINT("entering function X")
>где надо?

Кажется ты не понял в чём суть и дело воопще :)
Когда вызывается функция то в стэке сохраняются значение esp предыдущей функции и точка куда возвращаться. Дебаг инфа тут в принципе не нужна, нужно только таблицу символов в ELF иметь.
Проблема в том что когда приходит сигнал, я магу найти точку куда функция должна возвратить управление, в стэке неблагополучной функции, и через dladdr() я магу найти имя символа которому пренадлежит этот адрес. А вот адрес тела функции при исполнении которой произошёл сигнал я не знаю и не знаю где его откапать можно.
Расширенный обработчик сигналов:
void sa_sigaction(int, siginfo_t *, void *);
В структуре siginfo_t есть поле:
        void    *si_addr;               /* faulting instruction */
но для SIGSEGV это адрес памяти обращение к которому вызвало ошибку.
В общем ХЕЛП ещё раз :)


"Источник SIGSEGV"
Отправлено qq , 29-Май-03 20:02 
>>дык gdb использует debug info, засунутое в бинарник компилером, для определения имен
>>ф-ций
>>а ты используешь ф-цию для получения _экспортированных_ символов
>>соотв. и видишь ты только те ф-ции, которые экспортированы модулкм...
>>
>>а почему бы просто не вставить DBGPRINT("entering function X")
>>где надо?
>
>Кажется ты не понял в чём суть и дело воопще :)
>Когда вызывается функция то в стэке сохраняются значение esp предыдущей функции и
>точка куда возвращаться. Дебаг инфа тут в принципе не нужна, нужно
>только таблицу символов в ELF иметь.
>Проблема в том что когда приходит сигнал, я магу найти точку куда
>функция должна возвратить управление, в стэке неблагополучной функции, и через dladdr()
>я магу найти имя символа которому пренадлежит этот адрес. А вот
>адрес тела функции при исполнении которой произошёл сигнал я не знаю
>и не знаю где его откапать можно.
>Расширенный обработчик сигналов:
>void sa_sigaction(int, siginfo_t *, void *);
>В структуре siginfo_t есть поле:
>        void    
>*si_addr;          
>    /* faulting instruction */
>но для SIGSEGV это адрес памяти обращение к которому вызвало ошибку.
>В общем ХЕЛП ещё раз :)

хмм.. ну в 90% случаев, прямо перед тем местом куда должно возвратиться управление, будет команда call func,или call [func]
анализируя, можно попытаться что то найти...
хотя это и корявенький метод, но другого что-то не придумывается, похоже состояние процессора на момент сбоя недоступно обычными (известными мне) методами...
ну и ессно что это будет специфично для аппаратной платформы..



"Источник SIGSEGV"
Отправлено vnp , 29-Май-03 21:14 
>Есть код который выводит имена функций после выполнения которых был вызван сигнал,
>аля backtrace в gdb, путем прохода вверх по стэку.
>Работает прекрасно, только саму функцию в которой произошёл SIGSEGV выявить не получается,
>получается только с той которая вызвала функцию неблагополучную.
>Нету ни одного адреса указывающего на тело функции... как узнать откуда SIGSEGV
>свалился? gdb прекрасно всё показывает, но как он это делает не
>знаю. Хелп.

gdb делает стойку на ушах. См. i386-linux-tdep.c, например
http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/gdb/i386-li...


"Источник SIGSEGV"
Отправлено Solnuh , 29-Май-03 23:05 
/* When the i386 Linux kernel calls a signal handler and the
   SA_RESTORER flag isn't set, the return address points to a bit of
   code on the stack.  This function returns whether the PC appears to
   be within this bit of code.

   The instruction sequence for normal signals is
       pop    eax
       mov    $0x77,eax
       int    $0x80
   or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.

   Checking for the code sequence should be somewhat reliable, because
   the effect is to call the system call sigreturn.  This is unlikely
   to occur anywhere other than a signal trampoline.

Не понял я канешно как они найдя этот код находят адрес в котором фолт произошёл. Когда делаем return в sighandler после получения SIGSEGV, выполнение взвращается на место фолта и опять происходит SIGSEGV %)
Код который возвращает:
0xbfbfffbd:     mov    $0x158,eax
0xbfbfffc2:     push   eax
0xbfbfffc3:     int    $0x80
Это кажется системный вызов, где поглядеть что за вызов это?:)
PS. Система FreeBSD 4.5


"Источник SIGSEGV"
Отправлено qq , 30-Май-03 01:00 

>0xbfbfffbd:     mov    $0x158,eax
>0xbfbfffc2:     push   eax
>0xbfbfffc3:     int    $0x80
>Это кажется системный вызов, где поглядеть что за вызов это?:)
>PS. Система FreeBSD 4.5  

#define SYS_sigreturn   344


"Источник SIGSEGV"
Отправлено vnp , 30-Май-03 02:46 

>Не понял я канешно как они найдя этот код находят адрес в
>котором фолт произошёл.

Они там дальше описывают, как найти sigcontext; в нем уже есть все
необходимое, в том числе eip (см. /usr/include/asm/sigcontext.h)


"Вдогонку: Источник SIGSEGV"
Отправлено vnp , 30-Май-03 02:53 

>PS. Система FreeBSD 4.5


Тогда вам надо смотреть i386bsd-tdep.c (он рядышком лежит); и bsd
трамплин по-другому устроен.


"Вдогонку: Источник SIGSEGV"
Отправлено Solnuh , 30-Май-03 10:20 
>
>>PS. Система FreeBSD 4.5
>
>Тогда вам надо смотреть i386bsd-tdep.c (он рядышком лежит); и bsd
>трамплин по-другому устроен.

Жалко что по разному :)
Лана, покапаем, но думаю придёца обойтись только предшествующими функциями.


"Источник SIGSEGV"
Отправлено Solnuh , 02-Июн-03 13:00 
Всем спасибо :)
Вот работающий код для FreeBSD 4.5 выуживающий цепочку функций при выполнении которых вызвался сигнал(полезно для отладки без дебагера когда появляется SIGSEGV при работе).

int BP,faddr;

void sighandler(int sig, siginfo_t *info, void *c)
{
        sigcontext *sc;
        Dl_info a;
        int i=1;
        __asm__ (" movl ebp,BP "); //Перед ebp надо вставить знак процента
                                   //каверкается что-то при посте это дело
        sc=(sigcontext*)*((int*)(BP+16));
        BP=*((int*)BP);
        if(dladdr((void*)sc->sc_eip,&a)) {
                printf("%d: %s<br>\n",i,a.dli_sname);
                i++;
        }
        while((void*)*((int*)BP)) {
                faddr=BP;
                BP+=4;
                if(dladdr((void*)*((int*)BP),&a)) {
                        printf("%d: %s<br>\n",i,a.dli_sname);
                        i++;
                }
                BP=*((int*)faddr);
        }
        exit(1);
}

Для линуха сделаю поже если кому нужно.