strace调试

转载:http://blog.chinaunix.net/u/2117/showart.php?id=5406

在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因。

这就是调试程序出现的原因。strace是一个必不可少的调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上面)。

首先让我们看一个真实的例子:

启动KDE时出现问题

前一段时间,我在启动KDE的时候出了问题,KDE的错误信息无法给我任何有帮助的线索。

代码:

_KDE_IceTransSocketCreateListener: failed to bind listener

_KDE_IceTransSocketUNIXCreateListener: ...SocketCreateListener() failed

_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

Cannot establish any listening sockets DCOPServer self-test failed.

对我来说这个错误信息没有太多意义,只是一个对KDE来说至关重要的负责进程间通信的程序无法启动。我还可以知道这个错误和ICE协议(Inter Client Exchange)有关,除此之外,我不知道什么是KDE启动出错的原因。

我决定采用strace看一下在启动dcopserver时到底程序做了什么:

代码:

strace -f -F -o ~/dcop-strace.txt dcopserver这里 -f -F选项告诉strace同时跟踪fork和vfork出来的进程,-o选项把所有strace输出写到~/dcop-strace.txt里面,dcopserver是要启动和调试的程序。

再次出现错误之后,我检查了错误输出文件dcop-strace.txt,文件里有很多系统调用的记录。在程序运行出错前的有关记录如下:

代码:

27207 mkdir("/tmp/.ICE-unix", 0777) = -1 EEXIST (File exists)

27207 lstat64("/tmp/.ICE-unix", {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, ...}) = 0

27207 unlink("/tmp/.ICE-unix/dcop27207-1066844596") = -1 ENOENT (No such file or directory)

27207 bind(3, {sin_family=AF_UNIX, path="/tmp/.ICE-unix/dcop27207-1066844596"}, 38) = -1 EACCES (Permission denied)

27207 write(2, "_KDE_IceTrans", 13) = 13

27207 write(2, "SocketCreateListener: failed to "..., 46) = 46

27207 close(3) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13

27207 write(2, "SocketUNIXCreateListener: ...Soc"..., 59) = 59

27207 umask(0) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13

27207 write(2, "MakeAllCOTSServerListeners: fail"..., 64) = 64

27207 write(2, "Cannot establish any listening s"..., 39) = 39

其中第一行显示程序试图创建/tmp/.ICE-unix目录,权限为0777,这个操作因为目录已经存在而失败了。第二个系统调用(lstat64)检查了目录状态,并显示这个目录的权限是0755,这里出现了第一个程序运行错误的线索:程序试图创建属性为0777的目录,但是已经存在了一个属性为 0755的目录。第三个系统调用(unlink)试图删除一个文件,但是这个文件并不存在。这并不奇怪,因为这个操作只是试图删掉可能存在的老文件。

但是,第四行确认了错误所在。他试图绑定到/tmp/.ICE-unix/dcop27207-1066844596,但是出现了拒绝访问错误。. ICE_unix目录的用户和组都是root,并且只有所有者具有写权限。一个非root用户无法在这个目录下面建立文件,如果把目录属性改成0777,则前面的操作有可能可以执行,而这正是第一步错误出现时进行过的操作。

所以我运行了chmod 0777 /tmp/.ICE-unix之后KDE就可以正常启动了,问题解决了,用strace进行跟踪调试只需要花很短的几分钟时间跟踪程序运行,然后检查并分析输出文件。

说明:运行chmod 0777只是一个测试,一般不要把一个目录设置成所有用户可读写,同时不设置粘滞位(sticky bit)。给目录设置粘滞位可以阻止一个用户随意删除可写目录下面其他人的文件。一般你会发现/tmp目录因为这个原因设置了粘滞位。KDE可以正常启动之后,运行chmod + t /tmp/.ICE-unix给.ICE_unix设置粘滞位。

解决库依赖问题

starce 的另一个用处是解决和动态库相关的问题。当对一个可执行文件运行ldd时,它会告诉你程序使用的动态库和找到动态库的位置。但是如果你正在使用一个比较老的glibc版本(2.2或更早),你可能会有一个有bug的ldd程序,它可能会报告在一个目录下发现一个动态库,但是真正运行程序时动态连接程序(/lib/ld-linux.so.2)却可能到另外一个目录去找动态连接库。这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致,或者/etc/ld.so.cache被破坏。在glibc 2.3.2版本上这个错误不会出现,可能ld -linux的这个bug已经被解决了。

尽管这样,ldd并不能把所有程序依赖的动态库列出来,系统调用dlopen可以在需要的时候自动调入需要的动态库,而这些库可能不会被ldd列出来。作为glibc的一部分的NSS(Name Server Switch)库就是一个典型的例子, NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库。应用程序不会直接连接到NSS库,glibc则会通过dlopen自动调入NSS库。如果这样的库偶然丢失,你不会被告知存在库依赖问题,但这样的程序就无法通过用户名解析得到用户ID了。让我们看一个例子:

whoami程序会给出你自己的用户名,这个程序在一些需要知道运行程序的真正用户的脚本程序里面非常有用,whoami的一个示例输出如下:

代码:

# whoami

root

假设因为某种原因在升级glibc的过程中负责用户名和用户ID转换的库NSS丢失,我们可以通过把nss库改名来模拟这个环境:

代码:

# mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup

# whoami

whoami: cannot find username for UID 0

这里你可以看到,运行whoami时出现了错误,ldd程序的输出不会提供有用的帮助:

代码:

# ldd /usr/bin/whoami

libc.so.6 => /lib/libc.so.6 (0x4001f000)

/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

你只会看到whoami依赖Libc.so.6和ld-linux.so.2,它没有给出运行whoami所必须的其他库。这里时用strace跟踪whoami时的输出:

代码:

strace -o whoami-strace.txt whoami

open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

open("/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)

open("/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/lib/i686", 0xbffff190) = -1 ENOENT (No such file or directory)

open("/lib/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/lib/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)

open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/lib", {st_mode=S_IFDIR|0755, st_size=2352, ...}) = 0

open("/usr/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

stat64("/usr/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)

open("/usr/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

你可以发现在不同目录下面查找libnss.so.2的尝试,但是都失败了。如果没有strace这样的工具,很难发现这个错误是由于缺少动态库造成的。现在只需要找到libnss.so.2并把它放回到正确的位置就可以了。

限制strace只跟踪特定的系统调用

如果你已经知道你要找什么,你可以让strace只跟踪一些类型的系统调用。例如,你需要看看在configure脚本里面执行的程序,你需要监视的系统调用就是execve。让strace只记录execve的调用用这个命令:

代码:

strace -f -o configure-strace.txt -e execve ./configure

部分输出结果为:

代码:

2720 execve("/usr/bin/expr", ["expr", "a", ":", "(a)"], [/* 31 vars */]) = 0

2725 execve("/bin/basename", ["basename", "./configure"], [/* 31 vars */]) = 0

2726 execve("/bin/chmod", ["chmod", "+x", "conftest.sh"], [/* 31 vars */]) = 0

2729 execve("/bin/rm", ["rm", "-f", "conftest.sh"], [/* 31 vars */]) = 0

2731 execve("/usr/bin/expr", ["expr", "99", "+", "1"], [/* 31 vars */]) = 0

2736 execve("/bin/ln", ["ln", "-s", "conf2693.file", "conf2693"], [/* 31 vars */]) = 0

你已经看到了,strace不仅可以被程序员使用,普通系统管理员和用户也可以使用strace来调试系统错误。必须承认,strace的输出不总是容易理解,但是很多输出对大多数人来说是不重要的。你会慢慢学会从大量输出中找到你可能需要的信息,像权限错误,文件未找到之类的,那时strace就会成为 一个有力的工具了。

阅读(1589) | 评论(0) | 转发(0) |

strace动态调试 php,strace调试相关推荐

  1. php gdb strace抓包,Linux上进程追踪与调试(strace和gdb)

    引言: 我们某些服务出现故障的时候,我们都是根据屏幕的输出以及打印的日志来查找出出现了什么样的错误,但是有时候我们的很多守护进程启动正常却访问不到,比如我们使用Nginx服务,登陆web的时候,却迟迟 ...

  2. Linux 调试之strace

    文章目录 前言 一.strace 例子 1.1 strace 跟踪 free 1.2 strace 跟踪 dd 1.3 strace 其他一些使用选项 二.strace 原理 2.1 ptrace简介 ...

  3. strace 调试 php,Strace 调试 PHP

    strace 命令是一个集诊断.调试.统计与一体的工具,我们可以使用 strace 对应用的系统调用和信号传递的跟踪结果来对应用进行分析,以达到解决问题或者是了解应用工作过程的目的. strace 的 ...

  4. 安卓逆向_12 --- jeb工具的使用 ( 动态调试 smali 代码 【 普通调试 和 debug调试 】)

    From:https://www.52pojie.cn/forum.php?mod=viewthread&tid=742250 jeb 动态调试 smali 代码:https://www.bi ...

  5. Android微信动态调试,Android远程调试的探索与实现

    作为移动开发者,最头疼的莫过于遇到产品上线以后出现了Bug,但是本地开发环境又无法复现的情况.常见的调查线上棘手问题方式大概如下:方法优点缺点联系用户安装已添加测试日志的APK方便定位问题需要用户积极 ...

  6. 安卓逆向_12 --- jeb工具的使用 ( 动态调试 smali 代码 【 普通调试 和 debug调试 】)...

    From:https://www.52pojie.cn/forum.php?mod=viewthread&tid=742250 jeb 动态调试 smali 代码:https://www.bi ...

  7. 调试多线程 查死锁的bug gcore命令 gdb对多线程的调试 gcore pstack 调试常用命令...

    gdb thread apply all bt 如果你发现有那么几个栈停在 pthread_wait 或者类似调用上,大致就可以得出结论:就是它们几个儿女情长,耽误了整个进程. 注意gdb的版本要高于 ...

  8. VC代码的编写和调试---编写易于调试的VC代码

    转自:http://www.vcgood.com/forum_posts.asp?TID=1692&PN=1 一 程序的设计 要避免错误,首先要从好的设计开始.对于程序的设计,需考虑到程序的两 ...

  9. core部署iis的 调试net_远程调试远程 IIS 计算机上的 ASP.NET Core - Visual Studio | Microsoft Docs...

    在 Visual Studio 中远程调试远程 IIS 计算机上的 ASP.NET CoreRemote Debug ASP.NET Core on a Remote IIS Computer in ...

  10. java 调试 工具_Java调试器–权威的工具列表

    java 调试 工具 Java调试是一个复杂的空间. 调试器的类型很多,工具也很多. 在此页面中,我们将介绍7种类型的调试器之间的区别,并查看每个类别中的主要工具,以帮助您为正确的工作选择正确的工具. ...

最新文章

  1. GoogleTest测试框架搭建方法
  2. 全国大学生智能车竞赛申请沁恒RISC-V MCU样品说明
  3. soc 设计soc设计 uml实务手册_采用 USB4 技术升级 SoC 设计
  4. 太棒了!想学英语的好好留着!
  5. 项目中遇到的某些问题及解决办法(一)
  6. docker-compose搭建ELK分布式日志框架
  7. matlab算sma,MA-EMA-SMA-DMA 函数用法、算法、图例、区别
  8. 动态组合sql语句详解
  9. mongodb常用操作——命令行
  10. 服务器配置ssh 登录,取消账号密码登录
  11. 人类微笑表情识别(HOG算法)
  12. iPad 被锁死后如何恢复出厂设置
  13. 第2篇:Python 基础语法
  14. JBoss、Geronimo及Tomcat比较分析
  15. matlab zxing ean13,条形码研究-EAN13 条形码
  16. 数据结构如何申请一个空间的队列_如何用鞋柜来作为隔断,隔出一个玄关空间...
  17. 面经-腾讯前端开发工程师
  18. 最近做的智能垃圾桶程序代码(1)
  19. 漏洞通告 | Atlassian Confluence存在远程代码执行漏洞,悬镜云鲨RASP天然免疫防护...
  20. java 小工 到_测试小工——从0到1搭建最简单的Linux网站

热门文章

  1. 求数的绝对值一定是正数_有理数的绝对值难,那是因为你这些知识点和题型没掌握...
  2. caffe手写数字识别-训练模型
  3. 算法:Maximum Depth of Binary Tree(二叉树的最大深度)
  4. vue 检测ie版本_vue 兼容低版本ie浏览器
  5. 【知识图谱系列】六篇2020年知识图谱预训练论文综述 | 30页汇报ppt免费获取 | GCC,GraphCL,DGI,InfoGraph等模型
  6. 【机器学习系列】MCMC第三讲:理解MCMC前必先弄懂这两点
  7. 机器学习相关博客收藏(KL 散度、信息熵、谱聚类、EM、Isolation Kernel、iForest、元学习、小样本学习、课程学习)
  8. ubuntu facebook/C3D视频特征提取
  9. 实数域上的压缩映射不动点原理
  10. n倍角公式的行列式形式与证明