Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

SIGFPE / signal

333  
evgher постоялец05.06.12 18:58
evgher
05.06.12 18:58 
Существует ли возможность в СИ или даже СИ++ выслеживать "arithmetic exceptions" с помощью
signal.h. Сейчас портирую код с HP-UX. Там присутствовала удобная вишка для отлавливания и корректуры всех "arithmetic exceptions".
Т. е. вызывается Exception_Handler автомотически при "UNDERFLOW, OVERFLOW, DIVEDE BY ZERO" и т. д.
Этот Handler переписывает значение переменной - например ноль.
Спасибо за контруктивные советы
#1 
AlexOtt местный житель05.06.12 20:45
AlexOtt
NEW 05.06.12 20:45 
в ответ evgher 05.06.12 18:58
для юникса, надо поставить обработчик сигнала SIGFPE, как например, вот тут, а дальше уже разруливать по тому что случилось - разделили на 0, переполнение сверху или снизу и т.д. Нужные константы описаны в <sys/signal.h> у них в названиях есть слово FPE
P.S. Stackoverflow - очень полезный ресурс
#2 
evgher постоялец07.06.12 14:42
evgher
NEW 07.06.12 14:42 
в ответ AlexOtt 05.06.12 20:45
Что-то у меня многое не клеется. Например у нас "инструкция": b1 = b1/0.0 - 1e-300*1e-300 (внизу в дисасемблированном виде),
в которой сразу несколько "FPE". При исполнении этой строки "program counter" должен перейти с адреса main+0x004e: на адрес main+0x007b:
после обработки "exception_handler". Разница между адресами соответствует 31, т. е. надо сделать прыжок в коде примерно таким образом:
При инструкции b1 = b1/0.0 разница адресов соответсвует 15-ти, т. е. это число постоянно меняется.
Существует какая либо возможность узнавать при исполнении программы, когда начинается следующая инструкция?
В ответ на:

void sigfpe_handler(int signo, siginfo_t *si, void *MainContext)
{
ucontext_t *pMainContext = @context von main
ucontext_t *pHandlerContext = @context von handler

switch(si->si_code)
{
case FPE_INTDIV: ....
....
case FPE_FLTDIV: puts("floating point divide by zero");
pMainContext->uc_mcontext.gregs[REG_RIP] +=31;
break;
case FPE_FLTOVF: ....
....
}
swapcontextp(pHandlerContext, pMainContext);

}
[цитата/]
....
[цитата]
143 printf("00: b1: %f; b2: %f\n",b1,b2);
0x00000000004009f6: main+0x0026: cvtss2sd 0xfffffffffffffff8(%rbp),%xmm2
0x00000000004009fb: main+0x002b: cvtss2sd 0xfffffffffffffff4(%rbp),%xmm0
0x0000000000400a00: main+0x0030: movsd %xmm0,%xmm1
0x0000000000400a04: main+0x0034: movsd %xmm2,%xmm0
0x0000000000400a08: main+0x0038: movq $_lib_version+0x1fc,%rdi
0x0000000000400a0f: main+0x003f: movl $0x0000000000000002,%eax
0x0000000000400a14: main+0x0044: call 0x00000000004004cc in PLT [ 0x4004cc, .-0x548 ]
0x0000000000400a19: main+0x0049: movl $0x0000000000000000,%eax
144 b1 = b1/0.0 - 1e-300*1e-300;
0x0000000000400a1e: main+0x004e: cvtss2sd 0xfffffffffffffff8(%rbp),%xmm3
0x0000000000400a23: main+0x0053: divsd _lib_version+0x14,%xmm3
0x0000000000400a2c: main+0x005c: movsd _lib_version+0x1c,%xmm2
0x0000000000400a35: main+0x0065: mulsd _lib_version+0x1c,%xmm2
0x0000000000400a3e: main+0x006e: subsd %xmm2,%xmm3
0x0000000000400a42: main+0x0072: cvtsd2ss %xmm3,%xmm2
0x0000000000400a46: main+0x0076: movss %xmm2,0xfffffffffffffff8(%rbp)
145 printf("01: b1: %f; b2: %f\n",b1,b2);
0x0000000000400a4b: main+0x007b: cvtss2sd 0xfffffffffffffff8(%rbp),%xmm3
0x0000000000400a50: main+0x0080: cvtss2sd 0xfffffffffffffff4(%rbp),%xmm2
0x0000000000400a55: main+0x0085: movsd %xmm2,%xmm1
0x0000000000400a59: main+0x0089: movsd %xmm3,%xmm0
0x0000000000400a5d: main+0x008d: movq $_lib_version+0x214,%rdi
0x0000000000400a64: main+0x0094: movl $0x0000000000000002,%eax
0x0000000000400a69: main+0x0099: call 0x00000000004004cc in PLT [ 0x4004cc, .-0x59d ]
0x0000000000400a6e: main+0x009e: movl $0x0000000000000000,%eax

#3 
AlexOtt местный житель07.06.12 16:22
AlexOtt
NEW 07.06.12 16:22 
в ответ evgher 07.06.12 14:42
ну это сильно зависит от реализации компилятора и уровня оптимизации. В чем заключается задача - пропустить ошибочную конструкцию и просто продолжать работу?
в принципе, надо смотреть мануал на компилятор - мне кажется что у многих были флаги компилятора, которые позволяли отключить генерацию исключений, но я не знаю точно - я лет 10 не работал с расчетными вещами
#4 
evgher постоялец07.06.12 18:43
evgher
NEW 07.06.12 18:43 
в ответ AlexOtt 07.06.12 16:22
Задача заключается в том, чтобы при каждой неправильной "Floating point operation" на "Stack" для ошибочной операции заходило значение 0,0.
И вычесление продолжалось дальше. Т. е.
b = 1.0/0.0 + 10.0 должно равняться 10.0
#5 
Murr патриот07.06.12 19:24
Murr
NEW 07.06.12 19:24 
в ответ evgher 07.06.12 18:43
Напиши выражение с разбивкой, выделив деление с присвоением в отдельный оператор и контролируй его выполнение. Разбираться с нюансами работы со стеком для каждой среды, модели и транслятора - ну его нафиг...
#6 
AlexOtt местный житель07.06.12 20:01
AlexOtt
NEW 07.06.12 20:01 
в ответ evgher 07.06.12 18:43
посмотрите на ключи со словом math со страницы http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html и http://gcc.gnu.org/wiki/FloatingPointMath
#7 
evgher постоялец07.06.12 20:57
evgher
NEW 07.06.12 20:57 
в ответ Murr 07.06.12 19:24
Речь идёт о примерно от 40000 до 100000 строк кода. Причём код этот реализует вычисления для аэробуса по методу "FEM".
Так что разбивать слишком долго придётся)))
#8 
evgher постоялец15.06.12 15:31
evgher
NEW 15.06.12 15:31 
в ответ AlexOtt 07.06.12 20:01
Вообщим с огромным трудом - почти всё перепробывал и наконец-то в силу имеющих библиотечных рессурсов вышел ожидаемый результат
В ответ на:

sunf95 -ftrap=%all -D_GNU_SOURCE -g -c fpetest.f
suncc -ftrap=%all -D_GNU_SOURCE -g -c handling.c
"handling.c", line 66: warning: implicit function declaration: swapcontext
"handling.c", line 85: warning: left operand of "->" must be pointer to struct/union
"handling.c", line 86: warning: left operand of "->" must be pointer to struct/union
sunf95 -ftrap=%all -D_GNU_SOURCE -g -o test fpetest.o handling.o
ContextSize: 23; Adresse: 0
Div-by-zero:-0.1E+31 / 0.0E+00 = 0.0E+00
Underflow: 0.1E-29 * 0.1E-09 = 0.0E+00
Overflow: 0.1E+31 * 0.1E+31 = 0.0E+00
Invalid: 0.0E+00 / 0.0E+00 = 0.0E+00

Длина инструкции в фортране (=4) и Си(=9) разная. Поэтому в зависимости от языка надо правильно определить длину инструкции.
В аналогичном примере тут получается точно выяснить в каком регистре должен быть отложен результат
В ответ на:

* find out registers rd, rs1, rs2, and opf
*/
fop = ((uc->fpu_q->FQu.fpq.fpq_instr)>>fopshift) &0x1ff;
frd = ((uc->fpu_q->FQu.fpq.fpq_instr)>>frdshift) &0x1f;
frs1= ((uc->fpu_q->FQu.fpq.fpq_instr)>>frs1shift)&0x1f;
frs2= ((uc->fpu_q->FQu.fpq.fpq_instr)>>frs2shift )&0x1f;
/*
* check if both rs1 and rs2 are zero (0/0 case)
*/
i = (uc->fpu_fr.fpu_regs[frs2]&0x7fffffff)|uc->fpu_fr.fpu_regs[frs2+1];
j = (uc->fpu_fr.fpu_regs[frs1]&0x7fffffff)|uc->fpu_fr.fpu_regs[frs1+1];
switch (fop) {
case 0x4e: /* fdivd */
if((i|j) == 0) { /* 0/0 , set rd to be zero_over_zero_value */
uc->fpu_fr.fpu_regs[frd] = defaultValue[0];
uc->fpu_fr.fpu_regs[frd+1] = defaultValue[1];
}
break;
}

На нашей ОС структура ucontext выглядит немного по другому: т. е. полей
fpu_fr и fpu_q она не имеет. Чтобы долго не мучатся можно просто переписать
все возможные значения регистров для резултата данных.
В ответ на:

int *defaultValue = (int *) &zero_over_zero_value;
for(int i =0; i < NPREG; i++)
{
(*uc)->_xmm.element[0] = (int)defaultValue[0];
(*uc)->_xmm.element[1] = (int)defaultValue[1];
}

Но тут есть одно НО. Я знаю адрес указателя инструкции, но не его значение. Уже всё перепробывал.
Вопрос публике: Wie kann man anhand des Befehlszeigers auf seinen Inhalt zugreifen?
Т. е.: так было бы правильно, но невозможно из-за отсутствия подструктур fpu*.
В ответ на:

//uc->fpu_q->FQu.fpq.fpq_instr // instruction
frd = ((uc->fpu_q->FQu.fpq.fpq_instr)>>frdshift) &0x1f; // Ergebnisregister
uc->fpu_fr.fpu_regs[frd] = defaultValue[0]; // redifinition of result register
uc->fpu_fr.fpu_regs[frd+1] = defaultValue[1];

В ответ на:

context->uc_mcontext.gregs[REG_RIP] // the current instruction pointer (uint32)
//-----> Wie bekomme ich anhand des Zeigers den Inhalt des Befehls?
#9 
AlexOtt местный житель15.06.12 19:52
AlexOtt
NEW 15.06.12 19:52 
в ответ evgher 15.06.12 15:31
я бы все-таки не парил себе мозги, а поискал бы имеющиеся библиотеки в которых есть такая функциональность. ни за что не поверю, что таких библиотек нет - в том же CERN должны такие вещи быть
#10 
ThorV прохожий01.07.12 16:29
ThorV
NEW 01.07.12 16:29 
в ответ evgher 15.06.12 15:31
IMHO даже не в смысле кодировки, а такой подход к программированию ..как-бы сказать.. нетрадиционной ориентации.
Если уж так хочется приключений, надо читать классику, сиречь Richard W. Stevens "APUE" . Есть такие функции sigsetjmp, siglongjmp, пользуйтесь сколько душе угодно.
А вот это
"Wie kann man anhand des Befehlszeigers auf seinen Inhalt zugreifen?"
уже веселит до колик. Вам надо к не к программистам, а к специалистам по квантовой механике обращаться:)
Я теперь понял, что с таким ПО на аэробусах летать нельзя.
#11 
evgher постоялец04.07.12 16:02
evgher
NEW 04.07.12 16:02 
в ответ ThorV 01.07.12 16:29
Проблема уже почти решена. Нащёт полётов на аэробусе.
Не один самолёт не имеет разрешение выйте в эксплуатацию не пройдя расчётов именно
вот этой программы. Писали её не программисты а очень умные люди. К сожалению не информатики.
#12