编写 UNIX® 系统程序充满乐趣,并且具有教育意义。使用 UNIX strace 工具和 GDB(GNU 项目调试工具),您可以真正地深入研究系统的功能,并了解组成这些功能的各种各样的程序。同时使用这两种工具,能够在查看 UNIX 计算机底层信息 的时候,给您带来更好的体验。

UNIX 家族总是为用户提供了丰富的工具。UNIX 是一个工具财宝箱,有了这些工具,您不仅可以完成具有创造性的工作,还可以在深入研究该操作系统的同时得到教育和娱乐。strace(用来跟踪任何程序的系统调用)和 GDB 调试工具(用来在受控的环境中运行程序的功能齐全的调试工具)是实现这个目标的两个有价值的工具。

UNIX 的设计由大量的函数调用(称为系统调用)组成,其中包括一些简单的任务,如在屏幕上显示字符串来设置任务优先级。所有的 UNIX 程序都是通过调用操作系统提供的这些底层服务来完成它们的任务,使用 strace 工具,您可以清楚地看到这些调用过程及其使用的参数。通过这种方式,您可以操作这些程序,以了解它们与操作系统之间的底层交互。

开始游戏

让我们以一个简单的 UNIX 命令 pwd 作为开始,然后更深入地研究该命令在完成其任务的过程中进行了哪些工作。启动 xterm 以创建一个进行实验的受控环境,然后输入下面的命令:

$ pwd

这个 pwd 命令显示了当前的工作目录。在我的计算机上,当时的输出是:

/home/bill/

一个如此简单的函数掩饰了该命令底层的复杂性(顺便说一下,所有的计算机程序都是这样的)。要真正地了解其复杂性,请使用 strace 工具再次运行 pwd 命令:

$ strace pwd

通过该命令,您可以看到,在显示和列举当前工作目录的过程中,UNIX 计算机执行了相当多的操作(请参见清单 1)。

清单 1:strace pwd 命令的输出
execve("/bin/pwd", ["pwd"], [/* 39 vars */]) = 0
uname({sys="Linux", node="sammy", ...}) = 0
brk(0)                                  = 0x804c000
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4001......fstat64(3, {st_mode=S_IFREG|0644, st_size=115031, ...}) = 0
old_mmap(NULL, 115031, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
close(3)                                = 0
open("/lib/tls/libc.so.6", O_RDONLY)    = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360U\1"..., 1024) = 1024
fstat64(3, {st_mode=S_IFREG|0755, st_size=1547996, ...}) = 0
old_mmap(0x42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x42000000
mprotect(0x4212e000, 20232, PROT_NONE)  = 0
old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000)...
old_mmap(0x42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,...
close(3)                                = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0x40016ac0, limit:1048575, seg_32bit...
munmap(0x40017000, 115031)              = 0
brk(0)                                  = 0x804c000
brk(0x804d000)                          = 0x804d000
brk(0)                                  = 0x804d000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=30301680, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
close(3)                                = 0
brk(0)                                  = 0x804d000
brk(0x804e000)                          = 0x804e000
getcwd("/home/bill", 4096)              = 11
fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 6), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4021700...
write(1, "/home/bill\n", 11/home/bill
)            = 11
munmap(0x40217000, 4096)                = 0
exit_group(0)                           = ?

回页首

UNIX 系统调用的具体细节

关于检索和显示当前工作目录所需的所有系统调用的详细细节,已经超出了本文的讨论范围,但我会介绍如何获取这些信息。清单 1 中的每一行都以类似 C 的格式,清楚地说明了一项系统调用及其参数,这也是 C 程序员希望看到的。Strace 同样以这种方式显示这些调用,不管在实际创建该程序时使用的是何种编程语言。

如果要了解清单 1 中的所有细节信息,对于所有这些系统调用,UNIX 为您提供了大量的文档。清单 1 中“最重要”的函数是 getcwd() 函数,它表示获取当前工作目录。当前的 xterm 显示了 strace pwd 的输出,同时再启动另一个 xterm 并输入下面的命令以查看 UNIX 对该函数的显示:

$ man getcwd

您所看到的应该是 getcwd() 函数完整的清单以及这个重要的 C 函数需要的和返回的参数清单。同样地,您可以输入 man brk 或 man fstat64等等。通常,UNIX 系统通过文档对这些系统函数进行了详细的说明,如果花些时间仔细地研究它们,您将逐渐地了解到 UNIX 的功能是多么的强大,以及学习这些底层系统细节是多么的容易。在所有的操作系统中,UNIX 最善于帮助您理解其底层的处理过程。

回页首

观察 nweb

对于下面几个步骤,您需要使用更庞大且更复杂的程序,而不是像 pwd 这样简单的 UNIX 命令。简单的超文本传输协议 (HTTP) 服务器,如 nweb,是非常适合的。当您在 Internet 上冲浪 的时候,HTTP 服务器侦听浏览器请求,然后通过发送所请求的对象,如 Web 页面和图形文件,以此响应浏览器的请求。

下载并安装 nweb,该软件由 IBM developerWorks 投稿作家 Nigel Griffiths 编写。 (请参阅参考资料部分提供的 Nigel 的文章“nweb: ?"a tiny, safe Web server (static pages only)”(developerWorks,2004 年 6 月)的链接。)

下载 es-nweb.zip 到 $HOME/downloads 目录,然后输入清单 2 中所示的简单命令,以提取、编译并启动该程序:

注意:我假设您需要为 Linux® 工作站编译这个程序。如果实际情况并非如此,那么有关在其他的 UNIX 操作系统上对该程序进行编译的详细信息,请阅读这篇 nweb 文章。

清单 2. 用于提取、编译和启动 nweb 的命令
$ cd src
$ mkdir nweb
$ cd nweb
$ unzip $HOME/downloads/es-nweb.zip
$ gcc -ggdb -O -DLINUX nweb.c -o nweb
$ ./nweb 9090 $HOME/src/nweb &

注意:清单 2 中的 -ggdb 选项和 Nigel 的文章中的内容有些不同,该选项用于告诉 GCC 编译器对该程序进行优化,以便使用 GDB 调试工具对其进行调试,您将在以后用到该调试工具。

接下来,要确认 nweb 服务器已经运行,可以使用清单 3 中所示的 ps 命令来对它进行检查。

清单 3. ps 命令
$ psPID TTY          TIME CMD2913 pts/5    00:00:00 bash4009 pts/5    00:00:00 nweb4011 pts/5    00:00:00 ps

最后,要确认 nweb 确实正在运行并且状态正常,可以在您的计算机上启动一个 Web 浏览器并在地址栏中输入 http://localhost:9090

针对 nweb 使用 strace

现在,让我们来进行一些有趣的工作。启动另一个 xterm,然后使用 strace 来跟踪正在运行的 nweb 服务器。要完成该任务,您必须清楚该程序的进程 ID,并且必须具有适当的权限。您仅仅可以看到一组特定的系统调用,即那些与网络相关的系统调用。输入清单 4 第一行所示的命令作为开始,其中使用了前面显示的 nweb 的进程 ID。您应该看到如下的输出(清单 4 中的第二行)。

清单 4. 开始对 nweb 进行跟踪
$ strace -e trace=network -p 4009
accept(0,

请注意,在调用网络 accept() 函数的过程中停止了跟踪操作。在浏览器中刷新几次 http://localhost:9090 页面,请注意每次刷新该页面时 strace 的显示。这是不是很棒呢?您所看到的是,当 Web 浏览器调用 HTTP 服务器 (nweb) 时,服务器所进行的底层网络调用。简单地说,nweb 正在接受 来自您的浏览器的调用。

您可以在运行 strace 的具有窗口焦点的 xterm 中按下 Ctrl+C 以停止对网络调用的跟踪。

回页首

再来研究 GDB 调试工具

正如您所看到的,strace 可以作为了解用户程序如何通过某些系统调用与操作系统进行交互的一个很好的程序。GDB 调试工具本身也可以附加于一个正在运行的进程,并帮助您进行更深入的研究。

GDB 调试工具非常有用,Internet 上提供了大量的有关该工具的可用信息。通常,调试工具是很有价值的工具,并且任何负责开发和维护计算机系统的人员应该了解如何使用它们。因此,在 nweb 运行于另一个 xterm 会话的同时,按下 Ctrl+C 停止 strace,然后输入清单 5 中所示的命令启动 GDB 调试工具。

清单 5. 启动 GDB 调试工具
$ gdb --quiet
(gdb) attach 4009
Attaching to process 4009
Reading symbols from /home/bill/src/nweb/nweb...done.
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0xffffe410 in ?? ()
(gdb)

-quiet 选项告诉 GDB 调试工具仅显示其提示符,而不要显示所有其他的启动信息。如果需要显示额外的文本信息,可以去掉 -quiet 选项。

attach 4009 命令启动对当前正在运行的 nweb 服务器的调试工作,并且 GDB 调试工具通过读取有关该进程的所有的符号信息来做出同样方式的响应。下一步,使用 info 命令来列举您所研究的程序的相关信息(请参见清单 6)。

清单 6. info 命令列出程序信息
(gdb) info proc
process 4009
cmdline = './nweb'
cwd = '/home/bill/src/nweb'
exe = '/home/bill/src/nweb/nweb'
(gdb)

info 命令(请参见清单 7)的另一个有用的变种是 info functions,然而,函数的列表可能很长。

清单 7. info functions 命令得到的函数列表
(gdb) info functions
All defined functions:File nweb.c:
void log(int, char *, char *, int);
int main(int, char **);
void web(int, int);File __finite:
int __finite();...
(gdb)

因为使用 -ggdb 选项对 nweb 程序进行了编译,所以可执行文件中包含了大量的调试信息,允许该调试工具查看文件中列举的已定义的函数,如清单 7 所示。

回页首

list 和 disassemble 命令

有两个重要的 GDB 调试工具命令,它们分别是 list 和 disassemble。通过使用清单 8 中所示的代码尝试使用这些命令。

清单 8. list 命令
(gdb) list main
121             exit(1);
122     }
123
124
125     main(int argc, char **argv)
126     {
127             int i, port, pid, listenfd, socketfd, hit;
128             size_t length;
129             char *str;
130             static struct sockaddr_in cli_addr; /* static = initialised to zeros */
(gdb)
131             static struct sockaddr_in serv_addr; /* static = initialised to zeros */
132
133             if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) {
134                     (void)printf("hint: nweb Port-Number Top-Directory\n\n"
135             "\tnweb is a small and very safe mini web server\n"
136             "\tnweb only servers out file/web pages with extensions named below\n"
137             "\t and only from the named directory or its sub-directories.\n"
138             "\tThere is no fancy features = safe and secure.\n\n"
139             "\tExample: nweb 8181 /home/nwebdir &\n\n"
140             "\tOnly Supports:");

正如您所看到的,list 命令以源文件的形式列出了正在运行的程序,并标注了相应的行号。按下 Return 键(如第 130 行和第 131 行之间所示)以接着上次的列表继续进行列举。现在,尝试使用 disassemble 命令,可以缩写为 disass(请参见清单 9)。

清单 9. disassemble 命令
(gdb) disass main
Dump of assembler code for function main:
0x08048ba2 <main+0>:    push   ebp
0x08048ba3 <main+1>:    mov    ebp,esp
0x08048ba5 <main+3>:    push   edi
0x08048ba6 <main+4>:    push   esi
0x08048ba7 <main+5>:    push   ebx
0x08048ba8 <main+6>:    sub    esp,0xc
0x08048bab <main+9>:    mov    ebx,DWORD PTR [ebp+12]
0x08048bae <main+12>:   and    esp,0xfffffff0...
0x08048c01 <main+95>:   call   0x8048664 <printf>
0x08048c06 <main+100>:  add    esp,0x10
0x08048c09 <main+103>:  inc    esi
0x08048c0a <main+104>:  cmp    DWORD PTR [ebx+esi],0x0
---Type <return> to continue, or q <return> to quit---

反汇编清单显示了该 main 函数的汇编语言清单。在本示例中,汇编代码指示出运行该代码的计算机使用的是 Intel® Pentium® 处理器。如果该程序运行于不同类型的处理器上,如基于 IBM Power PC® 的计算机,那么您的代码看上去将有很大的区别。

回页首

在其运行的过程中进行监视

因为您所监视的是一个正在运行的程序,所以可以设置相应的断点,然后在它响应浏览器请求并向提出请求的浏览器传输 .html 和 .jpg 文件的同时,对该程序进行监视。清单 10 介绍了如何完成该任务。

清单 10. 设置断点
(gdb) break 188
Breakpoint 1 at 0x8048e70: file nweb.c, line 188.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>continue
>end
(gdb) c
Continuing.

此时,GDB 调试工具已设置为在 nweb 服务器接受 浏览器请求处进行中断,该调试工具将仅仅显示相应的请求并继续处理其他的请求,而不会中断正在运行的程序。刷新几次浏览器中的 http://localhost:9090/ 页面,可以观察到,GDB 调试工具显示了断点并继续运行。

在刷新浏览器页面的同时,您应该看到如清单 11 所示的断点信息,在 GDB 调试工具 xterm 中滚动输出。与 strace 相同,您可以按下 Ctrl+C 来停止对 nweb 服务器的调试。在停止了跟踪操作之后,您可以输入 quit 命令以退出 GDB 调试工具。

清单 11. GDB 调试工具 xterm 中的断点信息
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
Program received signal SIGINT, Interrupt.
0xffffe410 in ?? ()
(gdb) quit
The program is running.  Quit anyway (and detach it)? (y or n) y
Detaching from program: /home/bill/src/nweb/nweb, process 4009
$

请注意,您正告诉 GDB 调试工具停止对一个仍在内存中活动的程序的调试。即使是在退出了调试工具之后,您还可以刷新浏览器页面,并将看到 nweb 仍在运行。可以输入 kill 4009 命令来停止该程序,或者在您退出会话时,该页面将会消失。

和平常一样,您可以通过其 man 和 info 页面来了解各种各样的工具,如 strace 和 GDB 调试工具。请确保使用 UNIX 为您提供的这些工具!

回页首

了解尽可能多的信息

了解关于您所使用的计算机的尽可能多的信息,绝不是件坏事,并且还可以从这个过程中获得乐趣。实际上,UNIX 通过提供各种工具,如 strace 和 GDB 调试工具以及包含在相应的 man 和 info 页面中的大量的信息,鼓励您对系统进行研究和学习。计算机是人类智慧的延伸,并且我们对其了解得越多,它们将变得越有用。

使用 Strace 和 GDB 调试工具的乐趣相关推荐

  1. 用一个例子告诉你gdb调试工具如何使用

                                        用GDB调试程序 GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式 ...

  2. linux卸载gdb命令,Linux_Unix卸载gdb调试工具出现问题的解决方法,  Unix系统通过命令能够卸载 - phpStudy...

    Unix卸载gdb调试工具出现问题的解决方法 Unix系统通过命令能够卸载安装的程序,但有用户在用make uninstall命令卸载gdb调试工具时出现了问题,卸载失败,下面小编就教大家Unix如何 ...

  3. GDB 调试工具使用指南

    GDB 概述 GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具.也许大多数开发人员比较喜欢那种图形界面方式的,像 VC . BCB 等 IDE 的调试,但如果你是在 UNIX ...

  4. 《深入分析GCC 》——2.2 GNU gdb调试工具

    本节书摘来自华章出版社<深入分析GCC >一书中的第2章,第2.2节,作者 王亚刚 ,更多章节内容可以访问云栖社区"华章计算机"公众号查看. 2.2 GNU gdb调试 ...

  5. Linux调试工具strace和gdb常用命令小结-转

    Linux环境下段错误的产生原因及调试方法小结 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是 ...

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

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

  7. Linux下gdb调试工具的使用

    gdb是GNU开源组织发布的一个强大的Linux下的程序调试工具. gdb主要完成四个方面的功能:(1).启动你的程序,可以按照你的自定义的要求随心所欲的运行程序:(2).可让被调试的程序在你所指定的 ...

  8. C 语言编程 — GDB 调试工具

    目录 文章目录 目录 前文列表 代码调试 GDB 启动 GDB 交互命令 运行程序 暂停程序 设置断点 设置观察点 设置捕捉点 打印信息 查询运行信息 分割窗口 前文列表 <程序编译流程与 GC ...

  9. 【C语言基础】gdb调试工具的使用

    gdb调试教程 快速入门 要想快速入门gdb调试,可以直接翻阅基本案例:采内存 介绍 GDB是一个由GNU开源组织发布的.UNIX/LINUX操作系统下的.基于命令行的.功能强大的程序调试工具. 对于 ...

最新文章

  1. lgg6 android 9,【LGG6评测】18:9奇葩比例没采用骁龙835 LG G6解析_LG G6_手机评测-中关村在线...
  2. java实现微信企业付款到银行卡_微信企业付款到银行卡实现方式 - 黎明互联-官方博客 - 黎明互联 - 区块链培训,PHP培训,IT培训,职业技能培训,追求极致!改变您的职业生涯!...
  3. ndarray的数据类型
  4. linux内核打印前有buildroot,buildroot-linux内核
  5. flink中的HybirdmemorySegment
  6. 华为诉争“鸿蒙HongMeng”商标再被驳回;比尔盖茨夫妇正式离婚;iOS 15“查找”新功能,关机也能用|极客头条...
  7. python字符串find_Python字符串find()
  8. 《算法图解》——广度优先探索与队列
  9. python参考手册下载_python参考手册第4版
  10. Excel如何删除表格中的空白列
  11. 华硕服务器 u盘安装系统,华硕电脑u盘安装系统教程
  12. 机器学习分类模型评价指标之混淆矩阵
  13. LeetCode874 模拟行走机器人
  14. 饼图大小调整_PPT制作简约饼图,学会这一个就够了!
  15. HTML5+CSS3小实例:不偷看密码的超萌猫头鹰登录界面
  16. 二叉树寻找节点x的所有祖先
  17. 批量修改txt内容的某个字符串-多快好省
  18. 机器学习中的数学——拟牛顿法(Quasi-Newton Methods)
  19. 计算机休眠唤醒后分辨率变小了,WIN10休眠唤醒后,所有的窗口都跑到了左上角,如何解决?...
  20. 九.配置SMB共享(Samba共享)

热门文章

  1. python多进程管道通信(精)
  2. 设计模式:简单工厂模式(C++)【看不懂算我输】
  3. Ansi与Unicode编码
  4. drf 解析器的配置和使用
  5. Hackerrank manasa-and-combinatorics(数学推导)
  6. 【bzoj2330】 [SCOI2011]糖果
  7. sublime3 常用功能总结
  8. (译)如何使用GameCenter制作一个简单的多人游戏教程:第一部分
  9. VM安装ubuntu18.04完成时不能上网,显示cable unplugged
  10. C++20 要来了!