GDB调试

一、基础用法

1、查看线程和进程、确定gdb需要挂在哪一个进程上,可以选择设置源文件路径
ps  -ux
gdb hsserver -p 25724 -d ../src/
-p 目标线程号

2、进入进程后,打断点,可以选择打在函数或者具体代码的某一行
break  目标函数(例如:F112201)
break location:在location位置设置断点,位置可以为某一行,某函数名或者其它结构的地址

3、执行程序
c  继续执行
4、需要根据自己的程序确定触发的方法。

可能是直接通过发包触发或者点击某个菜单或者其他方式。
执行方法  用客户端执行目标函数

5、单步调试
enter 逐行调试  
n  单步调试
p 变量名称   输出变量的值

额外命令:
info breakpoints         查看断点的信息
display  跟踪查看某个变量,每次停下来都显示它的值

二、core文件解析
1、放到某文件夹路径下,解压core信息。
    这一步是为了取core时所在的所有库、日志、以及依赖项,可以选择手动拷贝到本机服务器目录下。
    tar -zxvf core.xxx.tar.gz
2、查看core信息:
    gdb
3、打开gdb后执行相应命令:(libs20150303表示解压出来的文件夹,其中20150303表示core产生的当时日期)
    (gdb) set solib-search-path libs20210308/
    (gdb) set solib-absolute-prefix libs20210308/
    (gdb) file libs20210308/bin/hsserver 
    Reading symbols from /home/yufq/core/libs20150303/bin/hsserver...(no debugging symbols found)...done.
    (gdb) core-file core.xxx
4、执行以上日志后就可以看到相应的core信息了。(其中第二个命令"f 2"其中2表示core信息的内容行)
    (gdb) bt
    (gdb) f 2  
    (gdb) p ((CESBMessage *)lpMessage)->m_MsgBodyTagItem
    (gdb) dump binary memory packdata.dat 0x7f59f40035b0 0x7f59f40035b0+3717
    以上命令后会生成packdata.dat,这个即为pack的包内容,可以对异常崩溃留下很多重要线索。
   
非常实用的命令:   
info threads
thread apply all bt

更多基础命令可看下网上的这个:

linux必先利其器篇之--GDB详解_gdb bt 信息-CSDN博客


汇编的一些信息
(gdb) Disassemble
1、显示反汇编的信息,通常会关注“=>”这个符号所在行,一般为指向段错误地址。
2、接下来查看寄存器的值:可以看到段错误的地址,其中的rax(见附件说明)地址为0,说明地址指向了空。
3、Memory Mappings
可以使用i proc m再次检查零是否有效。第一个有效的虚拟地址是0x400000。低于该值的任何内容(如果被引用)将触发分段错误。此时,有几种不同的方法可以进一步挖掘。我将从一些说明步骤开始。
4.后续都需要依赖于程序复现做调试设置断点。。。

GDB调试_第1张图片

GDB调试_第2张图片

GDB调试_第3张图片

GDB调试_第4张图片

三、实例

1、gdb
2、set solib-search-path libs 输入后TAB键libs会取当前目录下的libs****
3、set solib-absolute-prefix libs 输入Tab,同2
4、file libs***/bin/hsserver
5、core-file core.***
6、设置源文件路径:dir /home/secuuft2.0/dinglr_chongyan/core_0907
7、thread apply all bt 查看所有线程执行的堆栈
    Thread后面的地址就是esbmsg的地址
【以下内容需要根据自己的具体业务代码进行分析和调试】

GDB调试_第5张图片
8、执行x/200x CESBMessageFactory::slpESBMessageFactory->m_lpMsgPool[1].m_lppMsgInuse
    显示的地址即每个非0的即队列中的esbmsg


9、p ((CESBMessage*)0x027b24e0)->m_lOwnerTid
    m_lOwnerTid非0的即已经使用的消息,我们需要找到是哪个线程崩溃的以及对应的地址

GDB调试_第6张图片

GDB调试_第7张图片
10、获取5号域值
    调整显示格式:set print pretty on

GDB调试_第8张图片

(gdb) p lpIUFTContext->m_lpIRecordPoolManager //! 获取记录池管理器
$1 = (IRecordPoolManager *) 0x7eff02110010
(gdb) p ((CRecordPoolManagerImpl*) 0x7eff02110010)->lpIRecordPools[1810] //! 获取记录池1810是表ID
$2 = (IRecordPool*) 0xc1adce0
(gdb) p *(CLocklessMemoryRecordPoolImpl*) 0xc1adce0 //! 查看记录池的信息
$3 = 
(gdb) p (IRecord *) (m_lppRecord[0>>m_nShiftCount]+m_nMemUnitSize*(0&m_nIndexMask)) //! 获取0号记录对象
$4 = (IRecord *) 0x7fa877401a20
(gdb) p (RECORD_PREFIX *) (m_lppRecord[1>>m_nShiftCount]+m_nMemUnitSize*(1&m_nIndexMask)+m_nClassSize) //! 获取记录头
$3 = (RECORD_PREFIX *) 0x7fa877401a20
(gdb) p *(hg_cxyhgregister_sync *) (m_lppRecord[1>>m_nShiftCount]+m_nMemUnitSize*(1&m_nIndexMask)+m_nClassSize+8) //! 获取记录内容 hg_cxyhgregister_sync表
$4 = { business_date = 20190520, company_id = 301001, fund_id = 3, asset_id = 11, balance_type = 53 '5', capital_account_id = 3 }
(gdb) p lpIContainers[0] //! 获取索引,通过索引查看记录内容
$1 = (CLocklessSetImpl *) 0xc1adce0
(gdb) pset lpIContainers[0]->m_set IRecord* //! 获取索引中的记录对象
elem[0]: $2 = (IRecord *) 0x7f1ad3553e68
Set size = 1

p ((CUFTContextImpl*)lpIUFTContext)->m_lpIRecordPoolManager

你可能感兴趣的:(linux,服务器,运维)