使用truss、strace或ltrace诊断软件的"疑难杂症"

2023-11-16

作者:李凯斌 2005-01-18 11:03:24 来自:IBM DW中国     进程无法启动,软件运行速度突然变慢,程序的"Segment Fault"等等都是让每个Unix系统用户头痛的问题,本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的"疑难杂症"。

    truss 和strace用来跟踪一个进程的系统调用或信号产生的情况,而 ltrace用来跟踪进程调用库函数的情况。truss是早期为System V R4开发的调试程序,包括Aix、FreeBSD在内的大部分Unix系统都自带了这个工具;而strace最初是为SunOS系统编写的,ltrace 最早出现在GNU/Debian Linux中。这两个工具现在也已被移植到了大部分Unix系统中,大多数Linux发行版都自带了strace和ltrace,而FreeBSD也可通 过Ports安装它们。

    你不仅可以从命令行调试一个新开始的程序,也可以把truss、strace或ltrace绑定到一个已有的PID上来调试一个正在运行的程序。三个调试工具的基本使用方法大体相同,下面仅介绍三者共有,而且是最常用的三个命令行参数:


-f :除了跟踪当前进程外,还跟踪其子进程。

-o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。

-p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。


    使用上述三个参数基本上就可以完成大多数调试任务了,下面举几个命令行例子:


truss -o ls.truss ls -al: 跟踪ls -al的运行,将输出信息写到文件/tmp/ls.truss中。

strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。

ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。


    三个调试工具的输出结果格式也很相似,以strace为例:


brk(0)                                  = 0x8062aa8

brk(0x8063000)                          = 0x8063000

mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0x92f) = 0x40016000


    每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 truss、strace和ltrace的工作原理大同小异,都是使用ptrace系统调用跟踪调试运行中的进程,详细原理不在本文讨论范围内,有兴趣可以参考它们的源代码。

    举两个实例演示如何利用这三个调试工具诊断软件的"疑难杂症":

案例一:运行clint出现Segment Fault错误

    操作系统:FreeBSD-5.2.1-release

    clint是一个C++静态源代码分析工具,通过Ports安装好之后,运行:

# clint foo.cpp

Segmentation fault (core dumped)


    在Unix系统中遇见"Segmentation Fault"就像在MS Windows中弹出"非法操作"对话框一样令人讨厌。OK,我们用truss给clint"把把脉":

# truss -f -o clint.truss clint

Segmentation fault (core dumped)

# tail clint.truss

  739: read(0x6,0x806f000,0x1000)               = 4096 (0x1000)

  739: fstat(6,0xbfbfe4d0)                       = 0 (0x0)

  739: fcntl(0x6,0x3,0x0)                        = 4 (0x4)

  739: fcntl(0x6,0x4,0x0)                        = 0 (0x0)

  739: close(6)                                    = 0 (0x0)

  739: stat("/root/.clint/plugins",0xbfbfe680)   ERR#2 'No such file or directory'

SIGNAL 11

SIGNAL 11

Process stopped because of:  16

process exit, rval = 139


    我们用truss跟踪clint的系 统调用执行情况,并把结果输出到文件clint.truss,然后用tail查看最后几行。注意看clint执行的最后一条系统调用(倒数第五行): stat("/root/.clint/plugins",0xbfbfe680) ERR#2 'No such file or directory',问题就出在这里:clint找不到目录"/root/.clint/plugins",从而引发了段错误。怎样解决?很简单: mkdir -p /root/.clint/plugins,不过这次运行clint还是会"Segmentation Fault"9。继续用truss跟踪,发现clint还需要这个目录"/root/.clint/plugins/python",建好这个目录后 clint终于能够正常运行了。

案例二:vim启动速度明显变慢

    操作系统:FreeBSD-5.2.1-release

    vim 版本为6.2.154,从命令行运行vim后,要等待近半分钟才能进入编辑界面,而且没有任何错误输出。仔细检查了. vimrc和所有的vim脚本都没有错误配置,在网上也找不到类似问题的解决办法,难不成要hacking source code?没有必要,用truss就能找到问题所在:

# truss -f -D -o vim.truss vim


    这里-D参数的作用是:在每行输出前加上相对时间戳,即每执行一条系统调用所耗费的时间。我们只要关注哪些系统调用耗费的时间比较长就可以了,用less仔细查看输出文件vim.truss,很快就找到了疑点:

735: 0.000021511 socket(0x2,0x1,0x0)       = 4 (0x4)

735: 0.000014248 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)

735: 0.000013688 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)

735: 0.000203657 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'

735: 0.000017042 close(4)          = 0 (0x0)

735: 1.009366553 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)

735: 0.000019556 socket(0x2,0x1,0x0)       = 4 (0x4)

735: 0.000013409 setsockopt(0x4,0x6,0x1,0xbfbfe3c8,0x4) = 0 (0x0)

735: 0.000013130 setsockopt(0x4,0xffff,0x8,0xbfbfe2ec,0x4) = 0 (0x0)

735: 0.000272102 connect(0x4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 'Connection refused'

735: 0.000015924 close(4)          = 0 (0x0)

735: 1.009338338 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0x0)

 vim 试图连接10.57.18.27这台主机的6000端口(第四行的 connect()),连接失败后,睡眠一秒钟继续重试(第6行的nanosleep())。以上片断循环出现了十几次,每次都要耗费一秒多钟的时间,这 就是vim明显变慢的原因。可是,你肯定会纳闷:"vim怎么会无缘无故连接其它计算机的6000端口呢?"。问得好,那么请你回想一下6000是什么服 务的端口?没错,就是X Server。看来vim是要把输出定向到一个远程X Server,那么Shell中肯定定义了DISPLAY变量,查看.cshrc,果然有这么一行:setenv DISPLAY ${REMOTEHOST}:0,把它注释掉,再重新登录,问题就解决了。

案例三:用调试工具掌握软件的工作原理

    操作系统:Red Hat Linux 9.0

     用调试工具实时跟踪软件的运行情况不仅是诊断软件"疑难杂症"的有效的手段,也可帮助我们理清软件的"脉络",即快速掌握软件的运行流程和工作原理,不失 为一种学习源代码的辅助方法。下面这个案例展现了如何使用strace通过跟踪别的软件来"触发灵感",从而解决软件开发中的难题的。

     大家都知道,在进程内打开一个文件,都有唯一一个文件描述符(fd:file descriptor)与这个文件对应。而本人在开发一个软件过程中遇到这样一个问题:已知一个fd ,如何获取这个fd所对应文件的完整路径?不管是Linux、FreeBSD或是其它Unix系统都没有提供这样的API,怎么办呢?我们换个角度思考: Unix下有没有什么软件可以获取进程打开了哪些文件?如果你经验足够丰富,很容易想到lsof,使用它既可以知道进程打开了哪些文件,也可以了解一个文 件被哪个进程打开。好,我们用一个小程序来试验一下lsof,看它是如何获取进程打开了哪些文件。


/* testlsof.c */

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

 

int main(void)

{

        open("/tmp/foo", O_CREAT|O_RDONLY);    /* 打开文件/tmp/foo */

        sleep(1200);                                /* 睡眠1200秒,以便进行后续操作 */

        return 0;

}


    将testlsof放入后台运行,其pid为3125。命令lsof -p 3125查看进程3125打开了哪些文件,我们用strace跟踪lsof的运行,输出结果保存在lsof.strace中:


# gcc testlsof.c -o testlsof

# ./testlsof &

[1] 3125

# strace -o lsof.strace lsof -p 3125


    我们以"/tmp/foo"为关键字搜索输出文件lsof.strace,结果只有一条:


# grep '/tmp/foo' lsof.strace

readlink("/proc/3125/fd/3", "/tmp/foo", 4096) = 8

原 来lsof巧妙的利用了/proc/nnnn/fd/目录(nnnn为 pid):Linux内核会为每一个进程在/proc/建立一个以其pid为名的目录用来保存进程的相关信息,而其子目录fd保存的是该进程打开的所有文 件的fd。目标离我们很近了。好,我们到/proc/3125/fd/看个究竟:


# cd /proc/3125/fd/

# ls -l

total 0

lrwx------    1 root     root           64 Nov  5 09:50 0 -> /dev/pts/0

lrwx------    1 root     root           64 Nov  5 09:50 1 -> /dev/pts/0

lrwx------    1 root     root           64 Nov  5 09:50 2 -> /dev/pts/0

lr-x------    1 root     root           64 Nov  5 09:50 3 -> /tmp/foo

# readlink /proc/3125/fd/3

/tmp/foo


    答案已经很明显了:/proc/nnnn/fd/目录下的每一个fd文件都是符号链接,而此链接就指向被该进程打开的一个文件。我们只要用readlink()系统调用就可以获取某个fd对应的文件了,代码如下:


#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/stat.h>

int get_pathname_from_fd(int fd, char pathname[], int n)

{

        char buf[1024];

        pid_t  pid;

        bzero(buf, 1024);

        pid = getpid();

        snprintf(buf, 1024, "/proc/%i/fd/%i", pid, fd);

        return readlink(buf, pathname, n);

}

int main(void)

{

        int fd;

        char pathname[4096];

        bzero(pathname, 4096);

        fd = open("/tmp/foo", O_CREAT|O_RDONLY);

        get_pathname_from_fd(fd, pathname, 4096);

        printf("fd=%d; pathname=%s/n", fd, pathname);

        return 0;

}


     出于安全方面的考虑,在FreeBSD 5 之后系统默认已经不再自动装载proc文件系统,因此,要想使用truss或strace跟踪程序,你必须手工装载proc文件系统:mount -t procfs proc /proc;或者在/etc/fstab中加上一行:


proc                   /proc           procfs  rw              0       0


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用truss、strace或ltrace诊断软件的"疑难杂症" 的相关文章

  • 提领类型双关的指针将破坏重叠规则——strict-aliasing

    转载请保留本行原始出处声明信息 http www zeali net entry 454 MaDe1nZEAL warning dereferencing type punned pointer will break strict alia
  • Linux文件编程常用函数详解——fcntl()函数

    fcntl 函数 include
  • Unix环境编程中的apue.h和err_quit、err_sys问题

    现在开始学习 Unix环境编程 这本书 在学习的时候总会遇到书中的程序编译时会出现问题 所以自己将遇到的问题及解决的方法进行总结 找不到头文件apue h和err qiut err sys 1 apue h是作者自定义的一个头文件 并不是U
  • setlocale()用法笔记

    http www cnblogs com hnrainll archive 2011 05 07 2039700 html C 和 C 的标准库分别有自己的 locale 操作方法 C 标准库的 locale 设定函数是 setlocale
  • Linux 查看进程和线程CPU和内存占用情况

    文章目录 Linux 查看进程有哪些线程 Linux 查看程序内存占用情况 top和free等命令 Linux 查看进程 线程数量 Linux 查看进程有哪些线程 linux 下查看进程内的线程有哪些 首先通过进程名称 假设为SensorD
  • 检验IP地址有效性

    使用inet aton函数
  • Linux中修改MAC地址和IP地址的命令(netset、ip、ifconfig)

    修改MAC地址 ip link set eth0 address aa aa aa aa aa aa 解析 eth0是网卡的名字 可以用ifconfig命令查看 aa aa aa aa aa aa是想要修改后的MAC地址 修改IP地址 1
  • cd命令、pwd命令和环境变量PWD、OLDPWD的关联

    1 cd命令 cd命令这里不多介绍 cd 命令是返回上次所在的目录 2 PWD和OLDPWD环境变量 dai ubuntu env PWD home dai OLDPWD dai ubuntu 3 关联 1 当你输入 cd 命令返回上次的目
  • linux glob函数man页与实例

    Linux Programmer s Manual NAME glob globfree find pathnames matching a pattern free memory from glob SYNOPSIS include
  • 解决/lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found

    原因 编译时用的gcc等系统环境和运行时的环境不同 比如gcc版本不一样 以及其他的运行库版本不同等 方法 官方下载需要的版本库 之后软连接到运行系统上 wget http ftp de debian org debian pool mai
  • CentOS 7升级gcc/CentOS 7 yum 安装gcc

    centos7自带的gcc版本是4 8 手动升级安装很锻炼 毕竟已经0202年了 devtoolset 7 Developer Toolset is designed for developers working on CentOS or
  • 自己实现ls-l命令

    include
  • Linux I/O编程 实验内容

    一 实验目的 练习用UNIX I O进行文件读写的编程方法 用UNIX I O函数管理文本信息 二进制数据 结构体数据 掌握UNIX I O的基本编程方法 练习测时函数使用 通过测量UNIX I O函数运行时间 建立UNIX I O API
  • linux查看、添加、删除环境变量

    阅读目录 一 Linux 环境变量介绍 1 1 Linux 环境变量介绍 1 2 Linux 环境变量分类 1 3 Linux 常用的环境变量 二 Linux 查看环境变量 三 Linux 添加环境变量 3 1 添加系统级环境变量 需roo
  • Richard Stevens的几本书

    版权声明 转载时请以超链接形式标明文章原始出处和作者信息及本声明 http stevens0102 blogbus com logs 37223648 html 博客名取为 纪念Richard Stevens 居然没有写几篇与Stevens
  • 学习GDB

    http blog csdn net blueboy82006 article details 5586109 学习使用 GNU GDB Debugger 作者 王聪 GDB 常用命令参考手册 GDB 命令行参数 GDB 命令 GDB 操作
  • 使用truss、strace或ltrace诊断软件的"疑难杂症"

    作者 李凯斌 2005 01 18 11 03 24 来自 IBM DW中国 进程无法启动 软件运行速度突然变慢 程序的 Segment Fault 等等都是让每个Unix系统用户头痛的问题 本文通过三个实际案例演示如何使用truss st
  • 音视频大牛雷霄骅

    https blog csdn net leixiaohua1020 https www zhihu com question 49211380 https www bilibili com video av9927626 share so
  • popen 使用方法

    popen 可以执行shell命令 并读取此命令的返回值 popen 函数通过创建一个管道 调用fork 产生一个子进程 执行一个shell以运行命令来开启一个进程 可以通过这个管道执行标准输入输出操作 这个管道必须由pclose 函数关闭
  • read和write函数

    read ssize t read int fd void buf size t count fd 文件描述符 通过open获得 buf 需要读取的数据的存放位置 数组的地址 count 指定数组的大小 返回值 成功 gt 0 返回实际读取

随机推荐

  • Java方法求最大值

    package Methoud 用方法求最值 public class M5 public static void main String args int ages 23 58 64 75 64 int max getArryMaxDat
  • 诺基亚如何利用计算机上网,诺基亚E63的WIFI上网功能全教程

    手机端设置 依次点击 功能表 工具 设置 连接 接入点 选中 增加新接入点 1 连接名称 诺基亚e63连接wifi 任意设定 最好设中文或数字 没测试过英文得 2 选择承载方式 为 无线局域网 3 WLAN网络名称 推荐用 搜索图片名称 获
  • node 实现h264视频流buffer转码flv并使用websocket发送

    背景 硬件海康旧监控 编写node服务端以实现网页播放 调用了之前用C封装好的海康接口 视频数据由接口通过回调函数传参过来形成h64裸数据Buffer 本博客记录的就是如何从视频裸流 Buffer转码并回传给websocket 直接上代码
  • 线程的生命周期 笔记

    1 新建 new Thread 进入此状态 2 Thread start 进入就绪状态 或者 在运行状态执行yield 放弃CPU的执行转到就绪状态 或者是阻塞状态转入 3 阻塞状态 sleep 同步锁获取失败进入阻塞状态 执行了wait方
  • 为Jira提供的自动化测试跟踪功能

    在敏捷 DevOps CI CD以及其他任何我们想加入的行业词汇的世界里 开发人员和测试人员面临着快速交付高质量 功能性软件的巨大压力 需求必须由一系列的测试来支持 这样才能看到分配的需求是否得到了满足 许多组织在Jira 或其他平台 中手
  • torch转onnx模型

    torch转onnx模型 一 前言 onnx是开放神经网络交换格式 用于不同框架之间的迁移 推理方面比原生的torch快很多 本文以MobilenetV3做分类任务为例 实现模型转换 二 使用步骤 1 torch转换为onnx 代码如下 t
  • Java开发利器Eclipse和IDEA

    一 文本编辑工具 1 1 EditPlus EditPlus是一款由韩国 Sangil Kim ES Computing 出品的小巧但是功能强大的可处理文本 HTML和程序语言的Windows编辑器 你甚至可以通过设置用户工具将其作为C J
  • Spring boot项目打包war包并将class打包jar包放入war包中

    SpringBootApplication public class SpringBootWarApplication extends SpringBootServletInitializer Override protected Spri
  • Android图表年度最强总结,一篇文章从入门到精通!

    说到Android图表 不得不说一说MPAndroidChart这个强大的开源图表库 至于有多强大 先给你看看实现的效果图 如果效果图成功地引起了你的注意 那么 嘿嘿嘿 当然是把这篇文章看完 最后再点个赞 文章目录 添加依赖 创建视图以及简
  • 迎战 ChatGPT,谷歌聊天机器人 Bard 正式开放测试

    来源 极客邦科技 InfoQ 作者 刘燕 3 月 21 日晚间 谷歌开放了其聊天机器人 Bard 的测试 Bard 最初将可供美国和英国的部分用户使用 用户可以在 bard google com 上注册申请测试 不过谷歌表示推出速度会很慢
  • 【计算机视觉】直接线性变换(DLT)求解P矩阵(3 加入坐标的归一化)(附MATLAB代码)

    引言 本来上一篇帖子就已经达到了精度要求 不过经过同学提醒才发现老师的作业要求中有要求考虑归一化 emmmmm 坐标归一化 进行归一化的必要性和方法参考 计算机视觉中的多视几何 中的描述 上面的是从 2D到2D的结论 不过与从3D到2D的结
  • Python Matplotlib库:统计图补充

    作者简介 人工智能专业本科在读 喜欢计算机与编程 写博客记录自己的学习历程 个人主页 小嗷犬的博客 个人信条 为天地立心 为生民立命 为往圣继绝学 为万世开太平 本文内容 Python Matplotlib库 统计图补充 Python Ma
  • Redux 新教程Redux Toolkit的使用

    关于更新redux 唏嘘 还是跟不上时代的步伐了 哭唧唧 花费了不少的时间学习完redux后 还没用就发现官网的redux更新了新的使用用法 Redux Toolkit 于是乎硬着头皮翻译了一遍官网的Redux Toolkit 整理出最新的
  • 数据类型和运算符

    这里写目录标题 标识符 变量的概念与三要素 variable 变量的声明与使用 练习2 变量 数据类型 基本数据类型 练习3 变量 进制 了解 小数的存储 了解 基本数据类型的转换 数据类型转换的特例 字符串拼接 运算符 算数运算符 练习
  • linux安装spec编译器,RPM包制作之Spec文件参数详解

    看这篇文章的人基本都有一个想法 就是 劳资不想用YUM的安装 不是版本太低就是文件分布太野路子 此时我们需要自己订制软件包的需求 我们会把一些源码包按照我们的需求来做成rpm包 其中的Spec文件是制作RPM包的核心 下面我们以制作NGIN
  • 数据库的三大范式及其重要性,详细易懂

    目录 一 前言 二 三大范式 2 1 第一范式 1NF 列不可再分 2 2 第二范式 2NF 主键关系 2 3 第三范式 3NF 外键关系 三 为什么要遵循三大范式 一 前言 数据库是现代信息系统中的核心组成部分 它的设计和优化对系统的性能
  • 8421码

    8421码是中国大陆的叫法 8421码是BCD代码中最常用的一种 在这种编码方式中每一位二值代码的1都是代表一个固定数值 把每一位的1代表的十进制数加起来 得到的结果就是它所代表的十进制数码 二进制 1 1 1 1 十进制 8 4 2 1
  • 【vue】Failed to resolve component: van-cell If this is a native custom element, make sure to exclude

    问题描述 写vue引入vant组件遇到的问题 Failed to resolve component van cell If this is a native custom element make sure to exclude it f
  • 【华为OD机试真题2023 JS】取出尽量少的球

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 取出尽量少的球 时间限制 1s 空间限制 32MB 限定语言 不限 题目描述 某部门开展Family Day开放日活动 其中有个从桶里取球的游戏 游戏规则如下 有N个容量一样的小
  • 使用truss、strace或ltrace诊断软件的"疑难杂症"

    作者 李凯斌 2005 01 18 11 03 24 来自 IBM DW中国 进程无法启动 软件运行速度突然变慢 程序的 Segment Fault 等等都是让每个Unix系统用户头痛的问题 本文通过三个实际案例演示如何使用truss st