usine à gaz des .h
Bonjour à tous
j'ai un curieux problème de programmation.
J'essaie de construire un récupérateur d'erreurs en assembleur et, pour
récupérer les erreurs numériques traitées par le signal SIGFPE, le seul
outil que j'ai trouvé (sur
/technopark02.blogspot.fr/2005/10/handling-sigfpe.fr) est la
construction tournant autour de ucontext.h.
Il est bon de tester les idées en C avant de passer en assembleur, aussi
j'ai pris le programme donné en exemple sur le site ci-dessus et ai
tâché de l'adapter.
Le problème est que l'exemple n'est pas codé pour Linux (c'est pour
Solaris, si je me souviens bien),
et ucontext.h utilise bien sûr des noms liés aux registres comme index
du tableau "gregs", tel un REG_PC dans l'exemple (PC pour Program
Counter, je présume) qui évidemment ne risque pas d'exister sous Linux
i386 (c'est EIP ou RIP).
J'ai trouvé les symboles souhaités dans
/usr/include/i386-linux-gnu/sys/ucontext.h (appelé par
/usr/include/ucontext.h) sous un #ifdef __USE_GNU). Or, alors que les
identifiants "génériques" comme ucontext_t, mcontext_t, uc_mcontext ou
gregs, sont bien visibles, les REG_EAX, etc... ne le sont pas, gcc me
signale un identifiant non déclaré. Ce même si j'essaie d'assurer à la
main que __USE_GNU est bien défini avant le #include <ucontext.h>.
Je fais mes essais de compilation par gcc -c -O2, la fonction trouble(),
écrite en quatre lignes, se contente de renvoyer 0, elle est là pour
masquer son rôle à l'optimiseur et aussi contraindre le générateur de
code d'aller chercher son diviseur sur un registre et non dans la pile
(vérifié par sortie assembleur avec gcc -S -O2).
En remplaçant les REG_E?X par les valeurs (respectivement 8, 9, 10, 11
--- dans l'ordre du texte .c),
le programme fonctionne, en affichant une flopée de "Caught FPE\n" .
Si quelqu'un connaît ce terrain là... ou bien dois-je m'adresser à la
liste devel? Elle me semble a priori destinée aux développeurs de
Linux, non aux développeurs sous Linux.
Cordialement
Philippe Deleval
/* programme fpe trouvé sur internet, avec récupérateur de signal
version brute renvoyant le registre eip sur sa valeur avant signal
conséquence: signal relancé cycliquement */
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ucontext.h>
int trouble ();
void signal_handler (int signo, siginfo_t *si, void *data) {
ucontext_t *uc;
/* uc = ((ucontext_t *) data)->uc_link; */
uc = (ucontext_t *) data;
switch (signo) {
case SIGFPE:
fprintf(stdout, "Caught FPE\n");
/* >uc->uc_mcontext.gregs[REG_PC] = uc->uc_mcontext.gregs[REG_nPC]; */
/* remplacé par changement des registres eax à edx */
uc->uc_mcontext.gregs[REG_EBX] = 1;
uc->uc_mcontext.gregs[REG_EDX] = 1;
uc->uc_mcontext.gregs[REG_ECX] = 1;
uc->uc_mcontext.gregs[REG_EAX] = 1;
break;
default:
fprintf(stdout, "default handler\n");
}
}
int main (void) {
struct sigaction sa, osa;
unsigned int b = ULONG_MAX;
sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = signal_handler;
sigaction(SIGFPE, &sa, &osa);
b /= trouble ();
printf ("Valeur finale: %d\n", b);
return b;
}
int trouble ()
{
return 0;
}
Reply to: