环境: arm64-ubuntu
相关:strace、ltrace、readelf、patchelf、strings、ldd -v
1). 使用 gdb 启动目标程序(不能直接用gdb启动的,可以先单独启动,再 gdb attach 强制调试)
DIR_APP=/opt/test
gdb --args env LANGUAGE= LD_LIBRARY_PATH=${DIR_APP}:${DIR_APP}/addons/cef:${DIR_APP}/old-libs ${DIR_APP}/main
2). gdb 指令
gdb载入目标程序后会自动暂停程序的运行,要继续运行程序得敲:
r # run
q # quit, 退出 gdb,停止调试但在运行之前,可能需要先静态分析下,好设置断点,设置断点的gdb指令:
b *0x7ff43b8254 # 在指定地址下断, breakpoint
b uv_fs_mkdir # 如果有函数名这种明确的调试符号,可以直接在函数入口处下断,即设置断点
b __libc_start_main
断点被触发后,gdb会暂停程序,此时如要继续运行,得敲入:
c # 或者其它的继续运行指令, 如单步运行 si、ni,运行到函数结束 finish
反汇编指定地址的代码:
x /20i 0x0000007ff43b3a90 # examine,用于解析指定内存地址的数据,可通过选项来决定是解析为汇编指令还是指定格式的数据
display /20i $pc
disp /20i $pc
暂停时自动反汇编的开关打开:
set disassemble-next-line auto
显示当前的函数调用栈:
bt
bt full
显示指定地址的内存:
dump binary memory ./test.so 0x0000007ff4360000 0x0000007ff43e3288
x /20x 0x0000007ff4360000
p (char*)0x7fffffcdb9
显示寄存器值
i registers
p $pc
print $pc
显示各个库都被加载到内存哪个地方(可用于在静态分析工具,如ida中设置段基址: edit -> segment -> rebase):
info proc mappings # 这个才是准确的, info sharelibrary(i sh) 显示的是可执行区的内存起始地址
单步跟踪:
si 会进函数(有调试符号可以不用加i)
ni 不进函数
执行到当前函数结束处
finish
3). gdb 多线程相关的调试
info threads # 显示所有线程
thread n # 切换到指定线程
set scheduler-locking on # 只运行当前线程
4). 断点以外的其它打断方式
catch exception
catch assert
catch catch
catch signal 6 # linux信号拦截也可以打断目标程序的运行
catch signal 11 # SIGSEGV,这个拦截打断类型,对软件在新平台运行报错的排查有用
# 能准确定位到哪个库中的哪个函数中的哪条CPU指令!