Как правильно работать с `ucontext_t`?
Из исходного кода Redis, в файле src / debug.c, он использует backtrace()
войти в стек вызовов. в рамках этой операции я заметил getMcontextEip()
В Linux это выглядит так:
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, почему это? а почему 14 а не другие (там было 19 элементов)?
1 ответ
Я полагаю, что "14" является регистром EIP, поэтому указатель текущей инструкции (он же счетчик программ), который является отправной точкой, вам нужно знать, где вы были в стеке вызовов, когда был получен сигнал.
Возможно, вам будет полезно посмотреть, как V8 использует это для своего профилировщика выборки: http://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/sampler.cc?spec=svn16109&r=16109