2017-09-08 8 views
0

저는 타이머를 시작하는 코드를 디버깅하기 위해 gdb를 사용하고 있습니다. gdb에서 타이머가 울리면 항상 timer_settime + 16 명령으로 끝납니다. 예상되는 동작입니까?timer/signal을 사용한 디버깅은 항상 <timer_settime + 16>에 끝납니다.

예를 들어 timer_settime 매뉴얼 페이지의 코드를 약간 수정했습니다. 아이디어는 두 개의 인수를 전달하는 것입니다 : 정수 문자열과 nsec 값. 이 코드는 타이머를 실행하여 nsec 후에 링을 울린 다음 문자열을 복사합니다. 나는 gdb가 다른 코드 줄에서 멈추어 nsec 값을 증가시킴으로써 복사 루프 안에서 끝날 것으로 예상했다. 그러나 그것은 항상 멈춘다.

이렇게 예상되는 동작입니까?

어딘가에 문서화되어 있습니까?

예상 한대로 달성 할 수있는 방법이 있습니까 (예 : 링을 사용하면 프로그램이 신호 직전 (또는 그 이후)에 gdb가 멈추는 타이머를 시작합니다)? (항상 nsec 단위로).

코드 :

#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); 
} 

연구와 GDB로 디버그 00112233445566778899001122334455 2 내가 얻을 때 :

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 

내가 라즈베리 파이에 같은 코드를 실행하고,하지만 내가 가진 I'am 확신 다른 리눅스 컴퓨터 x86_64에서 같은 동작. "handle stop SIGUSR1"으로 테스트했습니다.

+0

디버깅이 시작하기에 "안전"한 지점에 중단 점이 설정되었을 것입니다. 그 전에는 하우스 키핑이 완료되었습니다 (예 : 레지스터 저장, 스택 프레임 설정). –

+0

이전의 수업은 무엇입니까? – Art

+0

dbg에서 신호를 가로채는 데 사용되는 메커니즘은 저에게 매우 모호합니다. gdb는 단순히 자식에게 전달되기 전에 모든 신호를 가로 챌 수 있다고 생각했습니다. 따라서 실제 중단 점이 없다고 생각 했으므로 gdb가 신호를 유지하는 한 아동은 계속할 수 없습니다. 신호음이 울리고 실행이 멈출 때 중단 점이 설정되도록 제안 하시겠습니까? – user5162288

답변

0

나는 마침내 문제점이 내가 예상 한 동작을 얻기 위해 gdb에서 set unwindonsignal off을 가져야한다는 것을 알게되었습니다.