大招!如何把Gdb异常调用栈功能移植到任意平台?

 

Hello,今天又是Q哥来给大家进行分享了~

 

大招!如何把Gdb异常调用栈功能移植到任意平台?_第1张图片

 

当屏幕弹出“Segmentation fault”时,程序员该怎么办?之前文章已经教给大家一个通用的方法就是利用backtrace函数和addr2line命令定位问题,没看过上一篇文章的小伙伴可以戳这里查看如何轻松搞定“Segmentation fault”,看这篇就够了!

 

如果你熟悉gdb,当程序跑飞,我们可以执行backtrace(简写bt)命令,可以dump出异常调用栈。如果你在大厂呆过,你应该知道,商用的定位方法是不允许使用gdb的,只能通过命令行和日志定位问题。

 

所以,今天我们一起分析下gdb源码中backtrace怎么实现的,然后活学活用,把这个功能在任意硬件平台(ARM/MIPS/X64/X32...)上移植出来。

大招!如何把Gdb异常调用栈功能移植到任意平台?_第2张图片

 

首先回顾下,利用gdb在程序异常后执行bt命令的打印。

 

先从gdb官网下载gdb-8.3源码,把backtrace命令当做字符串,可以查到其调用函数,主要功能是获取异常时调用栈地址信息,然后对地址进行解析成文件名、函数名和行号。对代码一层层分析,可以看到最核心的代码段(地址解析),先贴出来,如下:

大招!如何把Gdb异常调用栈功能移植到任意平台?_第3张图片

 

是不是看不懂?没关系,很简单的,一起分析下呗。

 

首先代码最后一行pfilename, pfunctionname, plineno一眼就看出是出参,所以地址解析最核心的函数是bfd_find_nearest_line,该函数参数mypc就是待解析的地址,那么下面的任务就变成给bfd_find_nearest_line函数的参数赋值就行了。

 

bfd_find_nearest_line函数入参主要包括,bfd节点、所属section、符号表和偏移地址,出参则是文件名、函数名和行号。

 

Bfd节点的获取,即current_bfd,直接可以调用bfd模块open函数即可。

 

通过上面代码可以知道Code_section,是通过遍历所有section段,找到text这个section段赋值给Code_section,并把text section段的基地址给code_base。例如用readelf读取section信息,code_base值就是光亮的0X4005C0值。

大招!如何把Gdb异常调用栈功能移植到任意平台?_第4张图片

 

有小伙伴会问,什么是section?

 

这是Linux ELF相关的基础知识,ELF相关的基础知识之前文章已经讲过,可查阅。

 

符号表的获取,方法有很多,例如bfd_canonicalize_symtab、bfd_read_minisymbols函数都可以获取到,可以参考上面的源码。

 

最后需要说的是bfd_find_nearest_line依赖于bfd库,如果你需要把这个异常调用栈功能移植到特定平台(arm/mips),你需要自己编译bfd库。

 

特定平台的bfd库哪里来呢?

 

需要下载binutils源码,可以到官网下载最新的binutils-2.32.tar.gz。

先配置CC=XX ./configure --host==XX,再make生成libbfd.a和libiberty.a。

 

现在开始对之前文章中介绍的backtrace代码进行优化,主要是重构backtrace_symbols函数,利用backtrace和dump_backtrace实现异常调用栈的打印。

 

我们已经知道调用backtrace函数可以获取调用栈地址,考虑到可执行文件包含动态库,下面的分析,是只dump不包含动态库的异常调用栈,这样,如果调用栈地址非本模块本身,则不会做解析。

 

核心代码如下,首先以可执行文件本身作为file,获取fd,然后根据addr,调用dump_current_pc_location函数,传入fd和addr,解析出文件名、函数名和行号。

大招!如何把Gdb异常调用栈功能移植到任意平台?_第5张图片

 

通过gcc example.c  -L./lib -lbfd -liberty -g -ldl -lz  -o example 命令编译,执行example后,可以看到异常调用栈信息。

 

好了,至此,我们已经把gdb的backtrace功能移植出来了。

 

但是如果异常调用栈中还包括动态库中的函数,这个我们目前代码是没有做解析的,这个代码能不能做?

 

答案是肯定的,只要对现有代码做两个地方改动就行了。

 

怎么搞?

 

不急,慢慢来,先消化,后面再深聊。

大招!如何把Gdb异常调用栈功能移植到任意平台?_第6张图片

 

如果想直接获取本文完整代码,可关注公众号,回复”bt”即可下载。

 

欢迎扫码关注,一起学习Linux

 

你可能感兴趣的:(Linux逆向)