我在下面的代码中找到了用于回溯的代码
struct stack_frame {
struct stack_frame *prev;
void *return_addr;
} __attribute__((packed));
typedef struct stack_frame stack_frame;
__attribute__((noinline, noclone))
void backtrace_from_fp(void **buf, int size)
{
int i;
stack_frame *fp;
__asm__("movl %%ebp, %[fp]" : /* output */ [fp] "=r" (fp));
for(i = 0; i < size && fp != NULL; fp = fp->prev, i++)
buf[i] = fp->return_addr;
}
寻找该代码的原因是我们使用了第三方malloc钩子,因此不想使用backtrace来再次分配内存。以上不适用于x86_64,我将asm语句修改为
__asm__("movl %%rbp, %[fp]" : /* output */ [fp] "=r" (fp));
我崩溃
(gdb) bt
#0 backtrace_from_fp (size=10, buf=<optimized out>) at src/tcmalloc.cc:1910
#1 tc_malloc (size=<optimized out>) at src/tcmalloc.cc:1920
#2 0x00007f5023ade58d in __fopen_internal () from /lib64/libc.so.6
#3 0x00007f501e687956 in selinuxfs_exists () from /lib64/libselinux.so.1
#4 0x00007f501e67fc28 in init_lib () from /lib64/libselinux.so.1
#5 0x00007f5029a32503 in _dl_init_internal () from /lib64/ld-linux-x86-64.so.2
#6 0x00007f5029a241aa in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#7 0x0000000000000001 in ?? ()
#8 0x00007fff22cb8e24 in ?? ()
#9 0x0000000000000000 in ?? ()
(gdb)
(gdb) p $rbp
$2 = (void *) 0x7f501e695f37
(gdb) p (stack_frame *)$rbp
$3 = (stack_frame *) 0x7f501e695f37
(gdb) p *$3
$4 = {prev = 0x69662f636f72702f, return_addr = 0x6d6574737973656c}
(gdb) x /1xw 0x69662f636f72702f
0x69662f636f72702f: Cannot access memory at address 0x69662f636f72702f
(gdb) fr
#0 backtrace_from_fp (size=10, buf=<optimized out>) at src/tcmalloc.cc:1910
1910 in src/tcmalloc.cc
(gdb)
我想念什么吗?关于如何通过代码重建相同内容的任何帮助?。
我想念什么吗?
您引用的代码假定编译后的代码正在使用帧指针寄存器链。
[大约在5-7年前,这是(32位)i*86
的默认值,并且自~~以来一直不是x86_64
的默认值。
代码最有可能在未优化的版本中正常工作,但是使用非古代版本的编译器在32位和64位x86平台上进行优化时,将惨遭失败。
如果您可以用libc
重建all代码(包括-fno-omit-frame-pointer
),则此代码将在大多数时间(而不是all)工作,因为libc
可能有帮助编码的程序集,并且该程序集将没有框架指针链。
一种解决方案是使用libunwind。不幸的是,如果您(或您使用的任何库)也使用malloc
,则从problem内部使用它仍然会遇到dlopen
。