[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: