线上有个服务core dump,首先使用gdb打开core文件
gdb bin/xx xx.12769
然后使用backtrace(bt)查看core对应的栈,并使用frame(f)切换到我们业务的层级。
由于core的位置是opencv,调用cv::mean时候core了,我们需要把原始的图片dump出来分析。
业务中有个image_data局部变量保存了入参的图片,下面我们尝试dump出来。
(gdb) p image_data
$3 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
_M_p = 0x7f06d5428c58 "\377\330\377\340"}}
可以看到image_data是std::string,里面有层_M_dataplus._M_p只向了原始的字符串指针。我们需要做的是指定这个字符串长度。 使用网上的一些方法都不太管用,我们来用自己的方法分析。我使用的是gcc8编译,关于std::string可以看看腾讯的这个文章写的比较清楚,gcc的string对象内存布局如下:
所以,我们只需要获取_M_dataplus._M_p的前一个_Rep地址就ok了。
(gdb) p ((std::string::_Rep*)image_data)[-1]
$4 = {<std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base> = {_M_length = 30752, _M_capacity = 32711, _M_refcount = -1},
static _S_max_size = 4611686018427387897, static _S_terminal = 0 '\000', static _S_empty_rep_storage = <optimized out>}
可以看到,字符串长度30752,分配大小32711,没有被引用。
接着,我们知道_M_p的地址是0x7f06d5428c58,因此可以用gdb的dump命令把内存数据保存到文件。但是这个命令需要知道内存的起止,我们现在知道了起始位置和长度,需要计算止地址,这个好办。
打开苹果的编程型计算器,输入起始地址
然后转换成十进制
然后加上长度
然后再转换成十六进制就是我们要的地址了。
然后执行命令
(gdb) dump binary memory /tmp/test.jpg 0x7f06d5428c58 0x7F06D5430478
然后看看/tmp/test.jpg吧~