2013-09-20 5 views
1

От исходного кода Redis, в файле src/debug.c, он использует backtrace() для регистрации стека вызовов. в этих операций, я заметил getMcontextEip(), похоже, что в Linux:Каков правильный способ работы с `ucontext_t`?

static void *getMcontextEip(ucontext_t *uc) { 
    /* Linux */ 
    #if defined(__i386__) 
    return (void*) uc->uc_mcontext.gregs[14]; /* Linux 32 */ 
    #elif defined(__X86_64__) || defined(__x86_64__) 
    return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */ 
    #elif defined(__ia64__)      /* Linux IA64 */ 
    return (void*) uc->uc_mcontext.sc_ip; 
    #endif 
    } 

механизм позади всех из них: в то время был сигнал (т.е. SIGFPE), он будет схвачен и попытаться войти стек вызовов в файл:

void log_stack_trace(ucontext_t *uc) { 
    void *trace[100]; 
    int fd = open(file); 
    int trace_size = backtrace(trace, 100); /* get call stack */ 

    /* overwrite sigaction with caller's address */ 
    if (getMcontextEip(uc) != NULL) 
     trace[1] = getMcontextEip(uc); 

    backtrace_symbols_fd(trace, trace_size, fd); /* log to file */ 
} 

от комментария, мы знаем, он был разработан, чтобы перезапись sigaction с адресом вызывающего, но есть ли намек, чтобы сделать это? Я смоделировал SIGFPE сигнал и отлажен его в GDB, то ucontext_t кажется, что:

(gdb) p *uc 
$6 = { 
    uc_flags = 0, 
    uc_link = 0x0, 
    uc_stack = { 
    ss_sp = 0x0, 
    ss_flags = 2, 
    ss_size = 0 
    }, 
    uc_mcontext = { 
    gregs = {51, 0, 123, 123, 0, 0, -1073745320, -1073745376, -1208258560, 0, -1073745852, 5, 0, 0, 134514547, 115, 2163270, -1073745376, 123}, 
    fpregs = 0xbfffefb0, 
    oldmask = 0, 
    cr2 = 0 
    }, 
    uc_sigmask = { 
    __val = {0, 0, 44472, 8441088, 0, 0, 4294902655, 4294901760, 4294967295, 0 <repeats 23 times>} 
    }, 
    __fpregs_mem = { 
    cw = 0, 
    sw = 0, 
    tag = 895, 
    ipoff = 0, 
    cssel = 0, 
    dataoff = 0, 
    datasel = 0, 
    _st = {{ 
     significand = {0, 0, 8064, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }, { 
     significand = {0, 0, 0, 0}, 
     exponent = 0 
     }}, 
    status = 0 
    } 
} 

В getMcontextEip, он просто возвращает uc->uc_mcontext.gregs[14] на i386 платформы, почему это? и почему а не другие (было 19 элементов)?

ответ

1

Я считаю, что «14» - это регистр EIP, поэтому текущий указатель инструкции (aka program counter), который является отправной точкой, вам нужно знать, где вы были в стеке вызовов, когда сигнал был получен.

Вы могли бы найти полезным, чтобы увидеть, как V8 использует это для своей выборки профилировщика: http://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/sampler.cc?spec=svn16109&r=16109

Смежные вопросы