linux ltrace跟踪lib库调用和strace跟踪进程的系统调用以及进程收到的信号

系统调用是程序向内核请求服务的一种编程方式。要想了解操作系统如何工作,首先要了解系统调用如何工作的。操作系统主要的功能是对应用程序提供抽象。操作系统粗略的分为:操作系统内核使用的内核模式和应用程序运行的用户模式

系统调用和函数调用很类似,输入参数项并返回值。唯一不同之处是系统调用进入内核而函数调用做不到。从用户空间切换到内核空间通过一种特殊的trap机制(陷阱)

备注:trap机制的来历是这样的:内核态的操作系统对所有硬件有完全访问权限,可以运行任何指令;而用户态软件只能使用少数指令,并不具备直接访问硬件的权限。软件要访问硬件或者要调用内核函数该怎么办呢?陷阱指令可以使执行流程从用户态陷入内核态,并把控制权转移给操作系统,用户程序就可以访问硬件和调用内核函数了。

系统调用对于大多数使用者,通过系统调用库(Linux下统称为glibc)来实现的。尽管系统调用的本质是一样的,但发出系统调用的机制很大程度上取决于机器。比如strace sleep 60s在不同机器上系统调用是不同的。

你可能每天都在使用ls命令,但并没有意识到系统调用如何实现的,将其抽象如下:

Command-line utility命令行应用 --->  Invokes functions from system libraries  (glibc)系统lib库 ---> Invokes system calls。

ls命令调用Linux上系统lib库的函数。这些lib又触发系统调用完成整个任务。

ltrace:know the functions were  called from the glibc library

[root@sandbox ~]# yum install ltrace

[root@sandbox ~]#  ltrace ls testdir/

opendir("testdir/")              = { 3 }

readdir({ 3 })              = { 101879119, "." }

readdir({ 3 })              = { 134, ".." }

readdir({ 3 })          = { 101879120, "file1" }

strlen("file1")          = 5

memcpy(0x1665be0, "file1\0", 6)                      = 0x1665be0

readdir({ 3 })      = { 101879122, "file2" }

strlen("file2")      = 5

memcpy(0x166dcb0, "file2\0", 6)                      = 0x166dcb0

readdir({ 3 })          = nil

closedir({ 3 })

一个testdir目录通过opendir lib库函数打开,紧接着是readdir函数,读取目录内容。最后是closedir函数,关掉目录。其他函数先忽略。

strace: trace system calls and signals

strace运行时能截取并记录进程的系统调用和进程接收的信号。每个系统调用的名称,及其参数和返回值打印到标准错误或使用-o指定文件输出。

strace是一个非常有用的诊断,指导和调试工具。 系统管理员,诊断人员和疑难解决人员将发现,对于不容易获取源代码的程序而言,这是无价的,因为它们无需重新编译即可跟踪它们。 由于系统调用和信号是在用户/内核接口上发生的事件(system calls  and signals are events that happen at the user/kernel interface),因此仔细检查此边界对于错误隔离,健全性检查和尝试捕获竞争状(bug isolation, sanity checking and  attempting to capture race conditions)非常有用。

1) system call系统调用举例

"cat /dev/null" is:

open("/dev/null", O_RDONLY) = 3

Errors (通常返回值-1) have the errno  symbol and error string appended.

open("/foo/bar", O_RDONLY) = -1 ENOENT (No such file or directory)

2) Signals信号举例

信号打印为信号符号和已解码的siginfo。 跟踪和中断“ sleep 666”命令的摘录为:

    sigsuspend([]

      --- SIGINT {si_signo=SIGINT, si_code= SI_USER, si_pid=...} ---

      +++ killed by SIGINT +++

假如一个系统调用执行的同时有另外一个正在调用的线程或进程,trace尝试按照先后事件的顺序,将系统调用标记为未完成。调用返回后被标记为恢复。

[pid 28772] select(4, [3], NULL, NULL, NULL

[pid 28779] clock_gettime(CLOCK_REALTIME, {1130322148, 939977000}) = 0

[pid 28772] <... select resumed> )      = 1 (in [3])

trace安装

[root@sandbox ~]# yum install strace

[root@sandbox ~]# rpm -qa | grep -i strace

strace-4.12-9.el7.x86_64

[root@sandbox ~]# strace -V

strace -- version 4.12

系统调用的分类和strace实战

系统调用粗略的分为

1) 进程管理的系统调用

2) 文件管理的系统调用

3) 目录和文件系统管理的系统调用

4) 其他系统调用

[root@sandbox tmp]# strace ls testdir/

execve("/usr/bin/ls", ["ls", "testdir/"], [/* 40 vars */]) = 0

brk(NULL)                  = 0x1f12000

<<< truncated strace output >>>

write(1, "file1  file2\n", 13file1  file2)  = 13

close(1)                          = 0

munmap(0x7fd002c8d000, 4096)      = 0

close(2)                          = 0

exit_group(0)                  = ?

+++ exited with 0 +++

你不用记住每个系统调用函数,通过man来查即可。下面是man相应章节数及其内容:

1. Executable programs or shell commands

2. System calls (functions provided by the  kernel)

3. Library calls (functions within program  libraries)

4. Special files (usually found in /dev)

比如man  2  execve:execve()  executes the program  pointed to by filename'

使用场景:

strace ls testdir/  把调用打印在屏幕上

strace -o trace.log ls testdir 把系统调用输出到文件

strace -v ls testdir  系统调用额外的信息

strace -f ls testdir  进程相关子进程的跟踪

strace -c ls testdir/  统计每次系统调用花费时长和总时长的占比

strace -e open ls testdir 或 strace -e  write, getdents ls testdir指定系统调用函数跟踪

strace -p 22443 指定进程id跟踪

strace -t ls testdir/  显示系统调用的时间戳

参考

Understanding system calls on Linux with strace

https://www.man7.org/linux/man-pages/man1/strace.1.html

你可能感兴趣的:(linux ltrace跟踪lib库调用和strace跟踪进程的系统调用以及进程收到的信号)