2017-09-08 3 views
0

J'utilise gdb pour déboguer un code qui démarre un timer. Quand la minuterie sonne dans gdb je me retrouve toujours à l'instruction timer_settime + 16. Est-ce que ce comportement est attendu?Le débogage avec timer/signal se termine toujours dans <timer_settime + 16>

À titre d'exemple, j'ai légèrement modifié le code de la page de manuel timer_settime. L'idée est de passer deux arguments: une chaîne d'entiers et une valeur nsec. Le code lance la minuterie pour sonner après nsec, puis copie la chaîne. Je m'attendais à ce qu'en incrémentant la valeur de nsec, gdb s'arrête à différentes lignes de code, pour finir dans la boucle de copie. Cependant, il s'arrête toujours à.

Est-ce que ce comportement est attendu?

Est-il documenté quelque part?

Existe-t-il un moyen d'atteindre ce que j'attendais (c'est-à-dire: lancer une minuterie qui permet à gdb de s'arrêter lorsque le programme était juste avant (ou après) le signal)? (toujours avec granularité nsec).

code:

#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <signal.h> 
#include <time.h> 

#define CLOCKID CLOCK_REALTIME 
#define SIG SIGUSR1 

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ 
          } while (0) 

unsigned char OUT[32]; 
unsigned char IN[32]; 

unsigned char ascii2hex(char in){ 

unsigned char out; 

    if(('0' <= in) && (in <= '9')) 
     out = in - '0'; 
    if(('A' <= in) && (in <= 'F')) 
     out = in - 'A' + 10; 
    if(('a' <= in) && (in <= 'f')) 
     out = in - 'a' + 10; 

    return out; 
} 

void asciiStr2hex(char * in, unsigned char * out, unsigned int len){ 

int i = 0; 
int j = 0; 
for(i = 0; i < len; i+=2){ 
     out[j++] = (ascii2hex(in[i ]) << 4) + ascii2hex(in[i+1]); 
    } 
} 

void testcode(unsigned char *out, unsigned char *in, unsigned int len){ 
unsigned int i; 
for (i=0;i<len;i++) 
    out[i] = in[i]; 
} 

static void print_siginfo(siginfo_t *si) 
{ 
    timer_t *tidp; 
    int or; 

    tidp = si->si_value.sival_ptr; 

    printf(" sival_ptr = %p; ", si->si_value.sival_ptr); 
    printf(" *sival_ptr = 0x%lx\n", (long) *tidp); 

    or = timer_getoverrun(*tidp); 
    if (or == -1) 
     errExit("timer_getoverrun"); 
    else 
     printf(" overrun count = %d\n", or); 
    } 

static void handler(int sig, siginfo_t *si, void *uc) 
{ 
    /* Note: calling printf() from a signal handler is not 
     strictly correct, since printf() is not async-signal-safe; 
     see signal(7) */ 

    printf("Caught signal %d\n", sig); 
    print_siginfo(si); 
    signal(sig, SIG_IGN); 
} 

int main(int argc, char *argv[]) 
{ 
    timer_t timerid; 
    struct sigevent sev; 
    struct itimerspec its; 
    long long freq_nanosecs; 
    //sigset_t mask; 
    struct sigaction sa; 

    if (argc != 3) { 
     fprintf(stderr, "Usage: %s <16byte> <time-nanosecs>\n", 
       argv[0]); 
     exit(EXIT_FAILURE); 
    } 

    asciiStr2hex(argv[1], IN, 32); 

    /* Establish handler for timer signal */ 

    printf("Establishing handler for signal %d\n", SIG); 
    sa.sa_flags = SA_SIGINFO; 
    sa.sa_sigaction = handler; 
    sigemptyset(&sa.sa_mask); 
    if (sigaction(SIG, &sa, NULL) == -1) 
     errExit("sigaction"); 

    /* Block timer signal temporarily */ 

/*  printf("Blocking signal %d\n", SIG); 
     sigemptyset(&mask); 
     sigaddset(&mask, SIG); 
     if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) 
      errExit("sigprocmask"); 
*/ 
     /* Create the timer */ 

    sev.sigev_notify = SIGEV_SIGNAL; 
    sev.sigev_signo = SIG; 
    sev.sigev_value.sival_ptr = &timerid; 
    if (timer_create(CLOCKID, &sev, &timerid) == -1) 
     errExit("timer_create"); 

    printf("timer ID is 0x%lx\n", (long) timerid); 

    /* Start the timer */ 

    freq_nanosecs = atoll(argv[2]); 
    its.it_value.tv_sec = freq_nanosecs/1000000000; 
    its.it_value.tv_nsec = freq_nanosecs % 1000000000; 
    its.it_interval.tv_sec = its.it_value.tv_sec; 
    its.it_interval.tv_nsec = its.it_value.tv_nsec; 

    if (timer_settime(timerid, 0, &its, NULL) == -1) 
     errExit("timer_settime"); 

    /* Sleep for a while; meanwhile, the timer may expire 
     multiple times */ 

    printf("Sleeping for %d seconds\n", atoi(argv[1])); 

    testcode(OUT, IN, 16); 


    /* Unlock the timer signal, so that timer notification 
     can be delivered */ 

    /* printf("Unblocking signal %d\n", SIG); 
     if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) 
      errExit("sigprocmask"); 
    */ 
    exit(EXIT_SUCCESS); 
} 

Lorsque débogage dans gdb avec r 00112233445566778899001122334455 2 j'obtenir:

Program received signal SIGUSR1, User defined signal 1. 
0x76fc7c38 in timer_settime() from /lib/arm-linux-gnueabihf/librt.so.1 
(gdb) x/30i $pc 
=> 0x76fc7c38 <timer_settime+16>: cmn r0, #4096 ; 0x1000 
0x76fc7c3c <timer_settime+20>: mov r4, r0 
0x76fc7c40 <timer_settime+24>: bhi 0x76fc7c4c <timer_settime+36> 
0x76fc7c44 <timer_settime+28>: mov r0, r4 
0x76fc7c48 <timer_settime+32>: pop {r3, r4, r7, pc} 
0x76fc7c4c <timer_settime+36>: bl 0x76fc55b4 
0x76fc7c50 <timer_settime+40>: rsb r3, r4, #0 
0x76fc7c54 <timer_settime+44>: mvn r4, #0 
0x76fc7c58 <timer_settime+48>: str r3, [r0] 
0x76fc7c5c <timer_settime+52>: b 0x76fc7c44 <timer_settime+28> 
0x76fc7c60 <timer_settime+56>: andeq r0, r0, r2, lsl #2 
0x76fc7c64: push {r4, r5, r6, r7, r8, r9, r10, lr} 
0x76fc7c68: sub sp, sp, #600 ; 0x258 
0x76fc7c6c: ldr r4, [pc, #340] ; 0x76fc7dc8 
0x76fc7c70: add r1, sp, #512 ; 0x200 
0x76fc7c74: add r4, pc, r4 
0x76fc7c78: mov r0, r4 
0x76fc7c7c: bl 0x76fc56b0 
0x76fc7c80: cmp r0, #0 
0x76fc7c84: bne 0x76fc7c98 
0x76fc7c88: ldr r2, [sp, #512] ; 0x200 
0x76fc7c8c: ldr r3, [pc, #312] ; 0x76fc7dcc 
0x76fc7c90: cmp r2, r3 
0x76fc7c94: beq 0x76fc7d94 
0x76fc7c98: ldr r5, [pc, #304] ; 0x76fc7dd0 
0x76fc7c9c: ldr r0, [pc, #304] ; 0x76fc7dd4 
0x76fc7ca0: add r5, pc, r5 
0x76fc7ca4: add r0, pc, r0 
0x76fc7ca8: mov r1, r5 
0x76fc7cac: bl 0x76fc5524 

Je suis en cours d'exécution tel code sur une pi framboise, mais Je suis assez sûr que j'avais le même comportement sur une autre machine Linux x86_64. J'ai testé avec "poignée stop SIGUSR1".

+0

Probablement le point d'arrêt est défini au point où le débogage est "sûr" pour commencer. Avant cela, le ménage était fait (par exemple enregistrer les registres, mettre en place le cadre de la pile). –

+0

Quelle est l'instruction avant? – Art

+0

Le mécanisme utilisé pour intercepter les signaux de dbg est assez obscur pour moi. Je pensais que gdb peut simplement intercepter tous les signaux avant d'être transmis à l'enfant. Donc je pensais qu'il n'y avait pas de véritable point d'arrêt, juste que l'enfant n'est pas autorisé à continuer tant que gdb retient le signal. Vous suggérez donc qu'un point d'arrêt est défini lorsque le signal sonne et que l'exécution est interrompue? – user5162288

Répondre

0

J'ai finalement trouvé que le problème était que je dois set unwindonsignal off dans gdb pour obtenir le comportement que je m'attendais.