linux环境下服务器程序的查看与gdb调试

https://blog.csdn.net/albertsh/article/details/86298398

https://blog.csdn.net/yitouhan/article/details/41171455?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

这一篇主要是记录下调试服务器程序常用的命令,内容很简单,但是长时间不用很容易记混,因为游戏服务器也不是天天宕机,所以当有一天突然挂掉需要调试的时候,如果记不清调试命令很容易耽误时间,有好几次我就把gdb gameserver core记成了gdb core gameserver,所以干脆把这些内容统计到一起,查询的时候也方便。

查询程序的运行情况
ps aux
命令是常用来查询程序进程运行情况的,基本上不会漏掉,但是显示的无关程序太多,看着不方便所以常配合grep过滤

ps aux | grep gameserver
可以显示指定过滤内容的程序,但是这种显示方式没有标题,对于不熟悉的人来说看不太明白,就像下面这样

$ps aux | grep init
root 1 0.0 0.0 19232 976 ? Ss 2018 0:01 /sbin/init
510 2042 0.0 0.0 105492 932 pts/2 S+ 10:04 0:00 grep init
1
2
3
所以这里给出ps aux默认的输出格式:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
其中STAT: 该行程的状态,linux的进程常见状态:
D 不可中断 uninterruptible sleep (usually IO)
R 运行 runnable (on run queue)
S 中断 sleeping
T 停止 traced or stopped
Z 僵死 a defunct or zombie process
注: 其它状态还包括W(无驻留页), <(高优先级进程), N(低优先级进程), L(内存锁页).

ps -eo pid,lstart,etime,command | grep gameserver
有时需要查询特定进程的指定信息,比如运行时间,那么可以通过-o选项来指定,显示信息很明确
15499 Thu Jan 10 23:22:53 2019 11:24:12 ./gameserver -d
18097 Fri Jan 11 10:47:04 2019 00:01 grep gameserver
1
2
杀死指定进程
killall -10 gameserver: 按照进程名杀死进程,-10为自定义杀死信号

kill -10 gameserver_pid: 按照进程ID杀死进程,-10为自定义杀死信号

kill -9 gameserver_pid: -9为强制杀死进程的信号,无法被捕捉

kill -6 gameserver_pid: -6可以杀死进程并产生core文件

gdb调试
通常要想使用gdb调试需要在编译程序时加上-g选项,之后才能用gdb进行调试:gcc -g main.c -o gameserver,如果想在程序崩溃时产生core文件,还需要设置系统命令ulimit -c unlimited才可以,调试程序又分为直接启动调试、调试core文件和附加到正在运行的进程调试,每种方式的参数略有不同:

直接启动调试,gdb gameserver
这种方式相当于直接通过gdb启动了程序,并开启了调试模式,所以是拉取了新的进程

调试core文件,gdb gameserver core.xxx
这种方式相当于展示程序崩溃前的堆栈情况,并进行调试,所以也算是拉取了新的进程

附加进程调试,gdb attach gameserver_pid/gdb gameserver gameserver_pid
这种方式是将gdb调试工具附加到程序运行的当前进程上,并没有拉取新的进程,操作上也可以先敲gdb回车,然后再attach gameserver_pid,不过这种情况对于其他用户启动的程序,通常会提示“ptrace: 不允许的操作.”,所以需要使用sudo运行gdb

gdb常用命令
以下命令为调试linux程序常用的gdb命令,都是在调试服务器程序core文件过程中不断积累的,还有一些高级命令一般很少用到,掌握下面这些基本上就可以应付很多场景了,其中打印信息的命令print在打印map、vector等显示不友好,可以参考gdb调试脚本中的内容。

run/r:重新开始运行文件
break/b: 设置断点(I. b filename:linenum, II. b functioname, 条件断点: b position if condition)
info/i: 查看信息(I. i b:查看断点信息,i locals: 查看当前帧局部变量值,i threads: 查看线程)
delete/d: 删除断点(delete 3:删除通过info breakpoints查到的第3个断点,其实还可以删除别的)
list/l: 查看原代码(list -n:显示第n行前后的源代码。list 函数名:查看具体函数)
next/n: 逐过程调试(类似于VS的F10)
step/s: 逐语句调试(类似于VS的F11)
frame/f:切换函数的栈帧(可以调试输出指定函数内的情况)f 1 将堆栈从默认的0层,跳到上一层(1层),这样可以打印当层的变量
print/p:打印值及地址(用来显示变量值)
thread/t: 切换线程(调试指定线程,用来处理多线程程序)
continue/c:继续运行(常用调试完断点之后)
backtrace/bt:显示堆栈(可以查看函数的调用的栈帧和层级关系)
where: (可以查看函数的调用的栈帧和层级关系)
source: 加载脚本(可以在调试过程中使用脚本完成复杂逻辑调试)
finish/fin: 跳出函数
return: 返回
ptype:查看变量类型 变量

p (RoomData) 0x7fffd9fdf560