linux 带源地址trace,使用strace, ltrace寻找故障原因的线索
转自:http://blog.chinaunix.net/uid-20775448-id-3791949.html
在GNU/Linux环境下,当程序出现“疑难杂症”的时候,如何快速定位问题呢?本文介绍strace/ltrace的一些使用方法,内容主要来自个人的读书笔记(可见参考文献)。strace/ltrace 是一类不错的工具,在工作中经常会用到,其主要可以用于:
(1) 了解一个程序的工作原理(可以了解Linux下很多常用的命令实现的原理);
(2) 帮助定位程序中的问题(在开发工作时帮助定位问题);
strace和ltrace的区别:
(1) strace —— Trace system calls and signals (跟踪一个进程的系统调用或信号产生的情况)
(2) ltrace —— A library call tracer (跟踪进程调用库函数的情况)
PS:
n strace最初是为SunOS系统编写的,ltrace最早出现在GUN/Debian
Linux中,这两个工具现在已被移植到了大部分Unix系统中(可以通过which命令查找系统中是否存在此命令),
大多数Linux发行版都自带了strace和ltrace,没有的话也可以尝试手动安装它们。
n 关于系统调用和库函数的区别,APUE第一章有详细的介绍。
n strace和ltrace的使用方法基本相同。其中它们共同最常用的三个命令行参数是:
-f
除了跟踪当前进程外,还跟踪其子进程
-o file
将输出信息写到文件file中,而不是显示到标准错误输出(stderr)
-p PID
绑定到一个由PID对应的正在运行的进程,此参数常用来调试后台进程(守护进程)
n strace和ltrace的输出结果格式基本相似。以strace为例,每一行都是一条系统调用(ltrace为库函数),等号左边是系统调用的函数名及其参数,右边是该调用的返回值。
n 此类工具的原理是也大同小异,都是使用ptrace系统调用跟踪调试运行中的进程。
n 用调试工具实时跟踪程序的运行情况,不仅是诊断软件“疑难杂症”的有效手段,也可以帮助我们理清程序的“脉络”,即快速掌握软件的运行流程和工作原理,不失为一种学习源代码的辅助方法。
目录
0 一段简短的介绍
strace is a common tool upon many GNU/Linuxsystems. Put simply strace
is a "system call tracer" - which is whereit gets its name from.Using
strace, as root, you can monitor the system callsmade by any process
upon your system. This can be enormously beneficial whenyou have a
misbehaving program.
strace(strace - trace system calls and signals)能够跟踪进程使用的系统调用,并显示其内容。因此,当遇到调试不明的故障时,首先使用strace找出系统调用中出错的地方,通常能得到故障发生的线索,特别是与文件有关的错误、参数错误等。
注意:
使用strace能够有效地发现系统调用失败有关的故障,但无法发现用户写出的程序或共享库中发生的错误。
1 strace的基本使用方法
#include
#include
intmain()
{
FILE*fp;
fp = fopen("/etc/shadow","r");
if(fp == NULL)
{
printf("Error!\n");
returnEXIT_FAILURE;
}
returnEXIT_SUCCESS;
}
/*
gcc -Wall -g -o st1 st1.c
$ ./st1
Error!
*/
执行该程序报错是因为程序试图打开一般用户没有读权限的/etc/shadow文件,但是通过错误消息无法得知这一点。真实的程序也会有错误信息内容不明
确、所有地方都显示同样的错误信息的情况,甚至可能什么都不显示。这种情况下,就很难确定错误发生在源代码的什么地方(通过日志信息可以知道最上层调用出
错的地方),因此也无法用GDB设置断点,此时可以使用strace来进一步定位错误。
$ strace ./st1
execve("./st1", ["./st1"], [/* 59 vars */]) = 0
brk(0) = 0x804a000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fc4000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=37293, ...}) = 0
mmap2(NULL, 37293, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fba000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3// (1)
read(3,"\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340Y\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1548470, ...}) = 0
mmap2(NULL, 1312188, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e79000
madvise(0xb7e79000, 1312188, MADV_SEQUENTIAL|0x1) = 0
mmap2(0xb7fb3000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x139) = 0xb7fb3000
mmap2(0xb7fb7000, 9660, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fb7000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e78000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e786b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
