首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用libunwind实现异常

使用libunwind实现异常
EN

Stack Overflow用户
提问于 2020-02-01 06:48:01
回答 1查看 832关注 0票数 3

在编译器上工作,需要一些帮助,了解并使用libunwind。到目前为止,我的情况如下:

代码语言:javascript
复制
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

typedef void *data_t;
typedef struct exception_stack_st *exception_stack_t;

struct exception_stack_st {
  unw_cursor_t catch_block;
  exception_stack_t prev;
};

/* PROTOTYPES */
void foo(void);
void bar(void);
void set_try(void);
void clear_try(void);
bool check_exception(void);
void throw_exception(data_t);
void print_backtrace();

/* GLOBALS */
exception_stack_t exception_stack = NULL;
data_t curr_exception = NULL;

int main(void) {
  foo();
}

void foo(void) {
  printf("In foo\n");
  set_try();
  if(check_exception()) {
    printf("EXCEPTION: %s\n", (char*)curr_exception);
    goto CATCH;
  }
  bar();
  printf("This should never run\n");
 CATCH:
  clear_try();
  printf("Leaving foo\n");
}

void bar(void) {
  printf("In bar\n");
  throw_exception("Throwing an exception in bar");
  printf("Leaving bar\n");
}

void set_try(void) {
  unw_cursor_t cursor;
  unw_context_t context;
  unw_word_t ip, offp;
  char buf[1024];
  unw_getcontext(&context);
  unw_init_local(&cursor, &context);
  unw_step(&cursor);
  unw_get_reg(&cursor, UNW_REG_IP, &ip);
  unw_get_proc_name(&cursor, buf, 1024, &offp);
  printf("%s+0x%lx  IP %lx\n", buf, offp, ip);

  exception_stack_t cb = malloc(sizeof(struct exception_stack_st));
  cb->catch_block = cursor;
  cb->prev = exception_stack;
  exception_stack = cb;
}

void clear_try(void) {
  if (exception_stack != NULL)
    exception_stack = exception_stack->prev;
  curr_exception = NULL;
}

void throw_exception(data_t exception) {
  unw_word_t ip, offp;
  char buf[1024];
  curr_exception = exception;
  unw_get_reg(&(exception_stack->catch_block), UNW_REG_IP, &ip);
  unw_get_proc_name(&(exception_stack->catch_block), buf, 1024, &offp);
  printf("%s+0x%lx  IP %lx\n", buf, offp, ip);
  unw_resume(&(exception_stack->catch_block));
  printf("PANIC: unw_resume returned.\n");
  exit(1);
}

bool check_exception(void) {
  return curr_exception != NULL;
}

void print_backtrace() {
  unw_cursor_t cursor;
  unw_context_t context;
  char buf[1024];
  unw_getcontext(&context);
  unw_init_local(&cursor, &context);
  printf("BACKTRACE:\n");
  while(unw_step(&cursor) > 0) {
    unw_get_proc_name(&cursor, buf, 1024, NULL);
    printf("%s\n", buf);
  }
}

好吧,这已经很混乱了,但是一些上下文可能有助于证明这些奇怪的选择是合理的。我想要做的是在调用throw_exception时,在调用foo中的set_try之后,在调用堆栈的任何一点上调用foo,以便将堆栈展开,并将CPU状态恢复到调用set_try之后,但在条件调用之前。虽然这目前只是一个小型C程序,但我打算在编译器中使用这些函数的一般结构,它将生成必要的函数调用(类似于在C++中使用g++执行异常的方式),这就是为什么我使用labels+goto作为一种快速模拟将要生成的程序集的方式。我尝试过使用libunwind的setjmp实现,但它不太适合我的用例。

我正在处理的问题与unw_resume在解除调用堆栈后恢复的位置有关。无论发生什么,printf("This should never run\n")似乎每次都运行。我的理解是,它应该将堆栈和CPU状态恢复到调用unw_getcontext时存储的任何内容,而且我认为存储的状态是正确的,因为当我调用set_trythrow_exception时,IP寄存器(或PC寄存器,因为这是x86_64)的值在光标中完全相同。我甚至多次跳入gdb,在调用set_try之后和条件之前查看PC寄存器,每次都与打印输出相匹配。

我的问题是:

  • 我是不是误解了unw_resume
  • 我需要修改PC (UNW_REG_IP)寄存器吗?
  • 除了nongnu.org文档之外,还有其他地方可以帮助我处理libunwind吗?

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-03 01:22:17

首先是好消息:修复后,您的程序生成(我假设的)输出:

代码语言:javascript
复制
./a.out
In foo
foo+0x31  IP 557615f273a1
In bar
foo+0x31  IP 557615f273a1
foo+0x31  IP 557615f273a1
EXCEPTION: Throwing an exception in bar
Leaving foo

现在坏消息是:你的原始程序有几个单独的问题:

  1. 用于初始化游标的上下文(机器状态)在使用游标的持续时间内必须保持有效。这在本地手册页中得到了明确的说明。 违反此规则导致您的程序在unw_resume调用期间在我的机器上使用SIGSEGV。
  2. unw_step更新游标,但不更新上下文,而后者实际上用于恢复unw_resume中的机器状态。 这一点可以在简历文件中更清楚地说明。

要修复问题1,只需将unw_context_t移动到exception_stack_st中,如下所示:

代码语言:javascript
复制
struct exception_stack_st {
  unw_context_t context;
  unw_cursor_t cursor;
  exception_stack_t prev;
};

并一起初始化它们:

代码语言:javascript
复制
  exception_stack_t cb = malloc(sizeof(*cb));
  unw_getcontext(&cb->context);
  unw_init_local(&cb->cursor, &cb->context);

要修复问题2,需要在要返回的框架中建立机器上下文。

这需要将set_try转换为宏或始终内联的函数,并摆脱unw_step

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

https://stackoverflow.com/questions/60014693

复制
相关文章

相似问题

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