当集中精力看一个问题的时候,时间久了就会有这样一个状态,天空飘来五个字,那都不算事
ceph源码庞大的体量以及复杂的设计让很多人望而却步,尤其是大量的纯虚函数更是让读者迷失在代码的海洋,这个时候函数调用栈是一个救命的东西,因为它节约了你大量的重复查找的时间

查看最终效果
如下为我想要查看bluestore在处理shareblob的释放逻辑中对put函数的调用者查看

2019-07-11 20:11:30.408525 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::SharedBlob::print_stacktrace()+0x39) [0x7fe3dff055d9]
2019-07-11 20:11:30.408535 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::SharedBlob::put()+0x2c) [0x7fe3dff217bc]
2019-07-11 20:11:30.408536 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(std::_Rb_tree<boost::intrusive_ptr<BlueStore::SharedBlob>, boost::intrusive_ptr<BlueStore::SharedBlob>, std::_Identity<boost::intrusive_ptr<BlueStore::SharedBlob> >, std::less<boost::intrusive_ptr<BlueStore::SharedBlob> >, std::allocator<boost::intrusive_ptr<BlueStore::SharedBlob> > >::_M_erase(std::_Rb_tree_node<boost::intrusive_ptr<BlueStore::SharedBlob> >*)+0x39) [0x7fe3dff8d619]
2019-07-11 20:11:30.408537 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::_txc_finish(BlueStore::TransContext*)+0xbb) [0x7fe3dff2a55b]
2019-07-11 20:11:30.408537 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::_txc_state_proc(BlueStore::TransContext*)+0x216) [0x7fe3dff3c746]
2019-07-11 20:11:30.408538 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::_kv_finalize_thread()+0x630) [0x7fe3dff3e180]
2019-07-11 20:11:30.408538 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/root/ceph-osd(BlueStore::KVFinalizeThread::entry()+0xd) [0x7fe3dff95d2d]
2019-07-11 20:11:30.408539 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/lib64/libpthread.so.0(+0x7df3) [0x7fe3dce62df3]
2019-07-11 20:11:30.408539 7fe3cc5db700  0 bluestore.sharedblob(0x7fe3edad09a0) print_stacktrace/lib64/libc.so.6(clone+0x6d) [0x7fe3dbf573dd]

直接就是一目了然,非常直观。

ps:由于对更高级的systemtap打印调用栈失败,只能退而求其次暂时来手动增加函数调用栈,后期会将该工具的使用详细列举补足该问题

backtrace()和backtrace_symbols()函数实现调用栈

这两个函数linux下使用命令
man backtrace
man backtrace_symbols
能够查看到函数的具体用法
包含函数头文件:#include <execinfo.h>

  • int backtrace(void **buffer, int size); buffer参数用来动态存储调用当前函数的函数指针(地址),size参数则表示当前存储函数指针的数组最大容量。所以这里需要注意将这两个参数容量预估好
  • char **backtrace_symbols(void *const *buffer, int size); 该函数用来将以上获取到的函数地址转为对应容量的字符串数组

代码如下:

void print_stacktrace()
{int size = 16,i=0;void * array[16];int stack_num = backtrace(array, size);char ** stacktrace = backtrace_symbols(array, stack_num);for (; i < stack_num; ++i){printf("%s\n", stacktrace[i]); }free(stacktrace);
}

查看测试代码 print_func_stack.c

#include<stdio.h>
#include <execinfo.h>
void print_stacktrace()
{int size = 16,i=0;void * array[16];int stack_num = backtrace(array, size);char ** stacktrace = backtrace_symbols(array, stack_num);for (; i < stack_num; ++i){printf("%s\n", stacktrace[i]);
//           ldout(coll->store->cct,0) << __func__ << stacktrace[i] << dendl;       }free(stacktrace);
}
int func3(int a)
{print_stacktrace();return a*a;
}
int func2(int b)
{int c=func3(b);return c;
}
int func1(int c)
{return func2(c*c);
}
int main()
{printf("after print stack ,result is %d\n",func1(2));return 0;
}

编译gcc print_func_stack.c -rdynamic -o print_func_stack ,这里需要加上-rdynamic编译参数,它可以连接所有符号,否则打印出来仅仅为16进制函数地址
执行如下,可以看到函数调用栈已经清晰打印

[root@node1 ~]# ./print_func_stack
./print_func_stack(print_stacktrace+0x32) [0x400992]
./print_func_stack(func3+0x15) [0x400a04]
./print_func_stack(func2+0x15) [0x400a22]
./print_func_stack(func1+0x19) [0x400a43]
./print_func_stack(main+0xe) [0x400a53]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f7c766b2af5]
./print_func_stack() [0x400899]
after print stack ,result is 16

ps:
如果代码是C++代码,则如上编译出来的二进制文件是被manle的(即源码标识被c++编译器转为了编译器标识符ABI,会出现我们认为的乱码),这里需要将输出转为demangle(即我们认识的源码标识)。
类似如下:

/root/ceph-osd(_ZN9BlueStore10SharedBlob16print_stacktraceEv+0x2d) [0x7ff22948a5cd]
/root/ceph-osd(_ZN9BlueStore10SharedBlob3putEv+0x2c) [0x7ff2294a61bc]
/root/ceph-osd(_ZN9BlueStore6ExtentD1Ev+0xd1) [0x7ff229511bb1]
/root/ceph-osd(_ZN9BlueStore5Onode3putEv+0x96) [0x7ff2295120f6]
/root/ceph-osd(_ZN9BlueStore9TwoQCache5_trimEmm+0x365) [0x7ff2294b7b75]
/root/ceph-osd(_ZN9BlueStore5Cache8trim_allEv+0x30) [0x7ff229489a80]
/root/ceph-osd(_ZN9BlueStore12_flush_cacheEv+0x9f) [0x7ff2294b9d1f]
/root/ceph-osd(_ZN9BlueStore6umountEv+0x128) [0x7ff2294ba0b8]
/root/ceph-osd(_ZN3OSD8shutdownEv+0x1695) [0x7ff2290a48b5]
/root/ceph-osd(_ZN3OSD13handle_signalEi+0x11f) [0x7ff2290a518f]
/root/ceph-osd(_ZN13SignalHandler5entryEv+0x1d7) [0x7ff2295ebb17]

可以执行如下命令进行过滤
./print_func_stack |c++filt

更具体一点,我们想要查看打印出来的函数具体在哪个程序的哪一行,需要使用如下编译方式
gcc print_func_stack.c -rdynamic -g -o print_func_stack 再增加-g 的gdb调试参数
执行如下命令就可以看到具体函数位置

[root@node1 ~]# ./print_func_stack
./print_func_stack(print_stacktrace+0x32) [0x400992]
./print_func_stack(func3+0x15) [0x400a04]
./print_func_stack(func2+0x15) [0x400a22]
./print_func_stack(func1+0x19) [0x400a43]
./print_func_stack(main+0xe) [0x400a53]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f287597daf5]
./print_func_stack() [0x400899]
after print stack ,result is 16
[root@node1 ~]# addr2line -a 0x400a04 -e print_func_stack -f
0x0000000000400a04
func3
/root/print_func_stack.c:18
[root@node1 ~]# addr2line -a 0x400a04 -e print_func_stack -f -C #该-C参数是将源码转为demangle形式打印,防止看到的是mangle的ABI字符
0x0000000000400a04
func3
/root/print_func_stack.c:18
ceph源码添加函数调用栈

同样的方式,将以上函数封装到指定的类中,这里是为了不通类的debug日志方式不通,所以没有定义为全局变量。我这里是直接声明在SharedBlob大类中,所有该类对象都可以调用。定义很简单

 1657 void BlueStore::SharedBlob::print_stacktrace()                  1658 {1659       int size = 16;1660       void * array[16];1661       int stack_num = backtrace(array, size);                   1662       char ** stacktrace = backtrace_symbols(array, stack_num);                                                                                                                                                                                                         1663       for (int i = 0; i < stack_num; ++i)                       1664       {1665 //           printf("%s\n", stacktrace[i]);                     1666            ldout(coll->store->cct,0) << __func__ << stacktrace[i] << dendl;       1667       }1668       free(stacktrace);                                         1669 }

直接将该函数放入bluestore.cc不同函数之中就可以进行调用栈打印。

关于ceph源码 backtrace 打印函数调用栈相关推荐

  1. c/c++ backtrace打印函数调用栈

    效果 解析动态库libtest.so和可执行文件m: 打印原始栈 #include <execinfo.h> void *array[32] = {0};size_t size;char ...

  2. 编译ceph源码:cython module not found问题的解决

    环境:centos7.5 ceph版本:12.2.1 在当前环境对ceph源码rpm包进行重新编译 执行命令rpmbuild --rebuild ceph-12.2.1-0.el7.src.rpm 最 ...

  3. backtrace打印调用栈

    目录 1.backtrace打印调用栈 2.addr2line 1.backtrace打印调用栈 https://blog.csdn.net/hejinjing_tom_com/article/det ...

  4. 《Ceph源码分析》——第1章,第5节RADOS

    本节书摘来自华章出版社<Ceph源码分析>一书中的第1章,第1.5节RADOS,作者常涛,更多章节内容可以访问云栖社区"华章计算机"公众号查看 1.5 RADOS RA ...

  5. 源码阅读之Java栈的实现

    0x00 栈 栈是 Last-In-First-Out (后进先出)的线性表.对栈的操作主要有两个:入栈(push)和出栈(pop).因此它也是一种操作受限的线性表.尽管如此,它在计算机中应用非常广泛 ...

  6. 《Ceph源码分析》——第1章,第一节Ceph的发展历程

    本节书摘来自华章出版社<Ceph源码分析>一书中的第1章,第1.1节Ceph的发展历程,作者常涛,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第1章 Ceph ...

  7. 《Ceph源码分析》——第2章,第2节Buffer

    本节书摘来自华章出版社<Ceph源码分析>一书中的第2章,第2.2节Buffer,作者常涛,更多章节内容可以访问云栖社区"华章计算机"公众号查看 2.2 Buffer ...

  8. 【ceph】CEPH源码解析:读写流程

    相同过程 Ceph的读/写操作采用Primary-Replica模型,客户端只向Object所对应OSD set的Primary OSD发起读/写请求,这保证了数据的强一致性.当Primary OSD ...

  9. 《Ceph源码分析》——导读

    本节书摘来自华章出版社<Ceph源码分析>一书中的导读,作者常涛,更多章节内容可以访问云栖社区"华章计算机"公众号查看 目 录 序言 第1章 Ceph整体架构 1.1 ...

最新文章

  1. jQuery事件处理一瞥
  2. navicat 连接 mogodb 报错 requires authentication
  3. Quartz 在 Spring 中如何动态配置时间--转
  4. python编译原理_编译原理实战课 带你吃透编译技术核心概念与算法
  5. JSF:在正确的阶段进行验证(了解生命周期)
  6. 基于SpringBoot的项目管理后台
  7. kepware mysql_Kepware实现向数据库实时写入数据
  8. PPT资源、技巧与设计网站精选【转自paratop】
  9. VC++6.0常见问题之fatal error C1083解决方案
  10. 中国新中产家庭“清洁观”:能躺着不站着,能靠科技不靠手
  11. 中国自由软件推广先锋的自述,心潮澎湃的一往无前,一定要看!作者:洪峰...
  12. C#数据结构:两栈实现队列,两队列实现栈
  13. 阿里云负载均衡(SLB)简介
  14. 嵌入式系统自动化测试工具
  15. LOGO设计中出现文字背后的意义
  16. css box-shadow 使用
  17. Macbook terminal: No application knows how to open问题
  18. Hangman Judge, UVa 489
  19. Excel被保护了无法复制
  20. 【20210728】【信号处理】Alpha-Beta滤波——一种状态估计的方法

热门文章

  1. DBUtils 笔记
  2. HDU——1106排序(istringstream的使用、STLvector练习)
  3. MVC 中的 ViewModel
  4. 搜索引擎优化培训教程
  5. Elgg网站迁移指南
  6. Microsoft Anti-Cross Site Scripting Library V1.5 发布了
  7. python删除指定位置的字符串_python去除区域 python删除字符串中指定位置字符
  8. 单片机c语言实现表格数据调用,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...
  9. ajax调取json接口,通过 Ajax 调取后台接口将返回的 json 数据绑定在页面上
  10. java opencv 环境_基于java的OpenCV环境搭建