首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >操作`ucontext_t`的正确方法是什么?

操作`ucontext_t`的正确方法是什么?
EN

Stack Overflow用户
提问于 2013-09-20 09:55:38
回答 1查看 2.5K关注 0票数 1

从Redis的源代码中,在文件src/调试器c中,它使用backtrace()记录调用堆栈。在这些操作中,我注意到了getMcontextEip(),看起来在Linux中是这样的:

代码语言:javascript
复制
  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)时,它将被捕获并尝试将调用堆栈记录到文件中:

代码语言:javascript
复制
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看起来是这样的:

代码语言:javascript
复制
(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中,它只是在i386平台上返回uc->uc_mcontext.gregs[14],为什么要这样做?为什么14个而不是其他(有19个元素)?

EN

回答 1

Stack Overflow用户

发布于 2013-10-16 05:10:03

我相信"14“是EIP寄存器,所以当前的指令指针(又名程序计数器)是您需要知道信号被接收时在呼叫堆栈中的位置的起点。

您可能会发现,V8如何将此用于其抽样分析器:edge/src/sampler.cc?spec=svn16109&r=16109是有用的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18913859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档