一、strace
strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用及它所接收的系统信息。
可谓是 linux 下的调试利器,不仅可以用来找程序错误,系统为什么挂死了,命令为什么报错,还可以用来查找哪些程序占用系统资源。
比如想跟踪程序webService调用情况:
第一步,查看webService进程号:
ps aux|grep webService
第二步,查看系统调用:
strace -p 进程号
或者,将记录结果存在output.txt文件中:
strace -o output.txt -T -tt -e trace=all -p 进程号
stace参数:
-bash-4.1# strace
usage: strace [-dDffhiqrtttTvVxx] [-a column] [-e expr] … [-o file]
[-p pid] … [-s strsize] [-u username] [-E var=val] …
[command [arg …]]
or: strace -c [-D] [-e expr] … [-O overhead] [-S sortby] [-E var=val] …
[command [arg …]]
-c – count time, calls, and errors for each syscall and report summary
-f – follow forks, -ff – with output into separate files
-F – attempt to follow vforks, -h – print help message
-i – print instruction pointer at time of syscall
-q – suppress messages about attaching, detaching, etc.
-r – print relative timestamp, -t – absolute timestamp, -tt – with usecs
-T – print time spent in each syscall, -V – print version
-v – verbose mode: print unabbreviated argv, stat, termio[s], etc. args
-x – print non-ascii strings in hex, -xx – print all strings in hex
-a column – alignment COLUMN for printing syscall results (default 40)
-e expr – a qualifying expression: option=[!]all or option=[!]val1[,val2]…
options: trace, abbrev, verbose, raw, signal, read, or write
-o file – send trace output to FILE instead of stderr
-O overhead – set overhead for tracing syscalls to OVERHEAD usecs
-p pid – trace process with process id PID, may be repeated
-D – run tracer process as a detached grandchild, not as parent
-s strsize – limit length of print strings to STRSIZE chars (default 32)
-S sortby – sort syscall counts by: time, calls, name, nothing (default time)
-u username – run command as username handling setuid and/or setgid
-E var=val – put var=val in the environment for command
-E var – remove var from the environment for command
说明:
-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.
-a column
设置返回值的输出位置.默认 为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]…
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\.
-e trace=set
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=set
设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=set
将指 定的系统调用的参数以十六进制显示.
-e signal=set
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=set
输出从指定文件中读出 的数据.例如:
-e read=3,5
-e write=set
输出写入到指定文件中的数据.
-o filename
将strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username 的UID和GID执行被跟踪的命令
二、gdb
基本命令
- 进入GDB:#gdb test
test是要调试的程序,由gcc test.c -g -o test生成。进入后提示符变为(gdb) 。
- 查看源码:(gdb) l
源码会进行行号提示。
如果需要查看在其他文件中定义的函数,在l后加上函数名即可定位到这个函数的定义及查看附近的其他源码。或者:使用断点或单步运行,到某个函数处使用s进入这个函数。
- 设置断点:(gdb) b 6
这样会在运行到源码第6行时停止,可以查看变量的值、堆栈情况等;这个行号是gdb的行号。
- 查看断点处情况:(gdb) info b
可以键入"info b"来查看断点处情况,可以设置多个断点;
- 运行代码:(gdb) r
- 显示变量值:(gdb) p n
在程序暂停时,键入"p 变量名"(print)即可;
GDB在显示变量值时都会在对应值之前加上 N N",而无需写冗长的变量名;
- 观察变量:(gdb) watch n
在某一循环处,往往希望能够观察一个变量的变化情况,这时就可以键入命令"watch"来观察变量的变化情况,GDB在"n"设置了观察点;
- 单步运行:(gdb) n
- 程序继续运行:(gdb) c
使程序继续往下运行,直到再次遇到断点或程序结束;
- 退出GDB:(gdb) q
断点调试
命令格式 | 例子 | 作用 |
---|---|---|
break + 设置断点的行号 | break n | 在n行处设置断点 |
tbreak + 行号或函数名 | tbreak n/func | 设置临时断点,到达后被自动删除 |
break + filename + 行号 | break main.c:10 | 用于在指定文件对应行设置断点 |
break + <0x...> | break 0x3400a | 用于在内存某一位置处暂停 |
break + 行号 + if + 条件 | break 10 if i==3 | 用于设置条件断点,在循环中使用非常方便 |
info breakpoints/watchpoints [n] | info break | n表示断点编号,查看断点/观察点的情况 |
clear + 要清除的断点行号 | clear 10 | 用于清除对应行的断点,要给出断点的行号,清除时GDB会给出提示 |
delete + 要清除的断点编号 | delete 3 | 用于清除断点和自动显示的表达式的命令,要给出断点的编号,清除时GDB不会给出任何提示 |
disable/enable + 断点编号 | disable 3 | 让所设断点暂时失效/使能,如果要让多个编号处的断点失效/使能,可将编号之间用空格隔开 |
awatch/watch + 变量 | awatch/watch i | 设置一个观察点,当变量被读出或写入时程序被暂停 |
rwatch + 变量 | rwatch i | 设置一个观察点,当变量被读出时,程序被暂停 |
catch | 设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常 | |
tcatch | 只设置一次捕捉点,当程序停住以后,应点被自动删除 |
数据命令
命令格式 | 例子 | 作用 |
---|---|---|
display +表达式 | display a | 用于显示表达式的值,每当程序运行到断点处都会显示表达式的值 |
info display | 用于显示当前所有要显示值的表达式的情况 | |
delete + display 编号 | delete 3 | 用于删除一个要显示值的表达式,被删除的表达式将不被显示 |
disable/enable + display 编号 | disable/enable 3 | 使一个要显示值的表达式暂时失效/使能 |
undisplay + display 编号 | undisplay 3 | 用于结束某个表达式值的显示 |
whatis + 变量 | whatis i | 显示某个表达式的数据类型 |
print(p) + 变量/表达式 | p n | 用于打印变量或表达式的值 |
set + 变量 = 变量值 | set i = 3 | 改变程序中某个变量的值 |
调试运行环境相关命令
命令格式 | 例子 | 作用 |
---|---|---|
set args | set args arg1 arg2 | 设置运行参数 |
show args | show args | 参看运行参数 |
set width + 数目 | set width 70 | 设置GDB的行宽 |
cd + 工作目录 | cd ../ | 切换工作目录 |
run | r/run | 程序开始执行 |
step(s) | s | 进入式(会进入到所调用的子函数中)单步执行,进入函数的前提是,此函数被编译有debug信息 |
next(n) | n | 非进入式(不会进入到所调用的子函数中)单步执行 |
finish | finish | 一直运行到函数返回并打印函数返回时的堆栈地址和返回值及参数值等信息 |
until + 行数 | u 3 | 运行到函数某一行 |
continue(c) | c | 执行到下一个断点或程序结束 |
return <返回值> | return 5 | 改变程序流程,直接结束当前函数,并将指定值返回 |
call + 函数 | call func | 在当前位置执行所要运行的函数 |
堆栈相关命令
命令格式 | 例子 | 作用 |
---|---|---|
backtrace/bt | bt | 用来打印栈帧指针 |
frame | frame 1 | 用于打印指定栈帧 |
info reg | info reg | 查看寄存器使用情况 |
info stack | info stack | 查看堆栈使用情况 |
up/down | up/down | 跳到上一层/下一层函数 |
调试core文件
Core Dump:Core的意思是内存,Dump的意思是扔出来,堆出来。开发和使用Unix程序时,有时程序莫名其妙的down了,却没有任何的提示(有时候会提示core dumped),这时候可以查看一下有没有形如core.进程号的文件生成,这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考
生成Core文件
一般默认情况下,core file的大小被设置为了0,这样系统就不dump出core file了。修改后才能生成core文件。
#设置core大小为无限
ulimit -c unlimited
#设置文件大小为无限
ulimit unlimited
这些需要有root权限, 在ubuntu下每次重新打开中断都需要重新输入上面的第一条命令, 来设置core大小为无限
core文件生成路径:输入可执行文件运行命令的同一路径下。若系统生成的core文件不带其他任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。
1)/proc/sys/kernel/core_uses_pid 可以控制 core 文件的文件名中是否添加 pid 作为扩展。文件内容为1,表示添加 pid 作为扩展名,生成的core文件格式为 core.xxxx;为0则表示生成的core文件同一命名为core。
可通过以下命令修改此文件:
echo "1" > /proc/sys/kernel/core_uses_pid
2)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通过以下命令修改此文件:
echo "/corefile/core-%e-%p-%t" > core_pattern,可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳
以下是参数列表:
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
% t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
- 用gdb查看core文件
发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行. gdb [exec file] [core file] 如: gdb ./test core 或gdb ./a.out core-file core.xxxx gdb后, 用bt命令backtrace或where查看程序运行到哪里, 来定位core dump的文件->行. 待调试的可执行文件,在编译的时候需要加-g,core文件才能正常显示出错信息 1)gdb -core=core.xxxx file ./a.out bt 2)gdb -c core.xxxx file ./a.out
- 用gdb实时观察某进程crash信息
启动进程 gdb -p PID c 运行进程至crash gdb会显示crash信息
三、top
四、ps
PS用途
要对进程进行监测和控制,首先必须要了解当前进程的情况,也就是需要查看当前进程,而ps命令就是最基本同时也是非常强大的进程查看命令.使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵尸、哪些进程占用了过多的资源等等.总之大部分信息都是可以通过执行该命令得到的.
PS基本命令
五、Valgrind
Valgrind包括如下工具:
1.Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。
2.Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
3.Cachegrind。它主要用来检查程序中缓存使用出现的问题。
4.Helgrind。它主要用来检查多线程程序中出现的竞争问题。
5.Massif。它主要用来检查程序中堆栈使用中出现的问题。
6.Extension。可以利用core提供的功能,自己编写特定的内存调试工具linux下典型C程序内存空间布局:
linux下堆/栈的区别:
- 申请方式: 栈区内存由系统自动分配,函数结束时释放;堆区内存由程序员自己申请,并指明大小,用户忘释放时,会造成内存泄露,不过进程结束时会由系统回收。
- 申请后系统的响应: 只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出;堆区,空闲链表,分配与回收机制,会产生碎片问题(外部碎片)–>(固定分区存在内部碎片(分配大于实际),可变分区存在外部碎片(太碎无法分配))。
- 申请大小的限制:栈是1或者2M,可以自己改,但是最大不超过8M;堆,看主机是多少位的,如果是32位,就是4G
- 申请效率:栈由系统自动分配,速度较快,程序员无法控制;堆是由new分配的内存,一般速度较慢,而且容易导致内存碎片,但是用起来方便!
- 存储内容:栈,函数调用(返回值,各个参数,局部变量(静态变量不入栈));堆,一般在堆的头部用一个字节存放堆的大小,堆中的具体内容由程序员安排。
- 存取效率的比较:栈比堆快,Eg :char c[] = /”1234567890/”;char *p =/”1234567890/”;读取c[1]和p[1],c[1]读取时直接把字符串中的元素读到寄存器cl中,而p[1]先把指针值读到edx中,再根据edx读取字符,多一次操作。
- 管理方式不同:栈,数据结构中的栈;堆,链表
- 生长方向:栈,高到低;堆,低到高
Valgrind安装 / 使用: