strace调试工具实战

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chengqiuming/article/details/90137309

一 点睛

strace是一个通过跟踪系统调用来让开发者知道一个程序在后台所做事情的工具。

二 实战

1 代码

#include <iostream>
using namespace std;
int main(){
    int a;
    cin>>a;
    cout<<a<<endl;
    return 0;
}

2 编译并调试

[root@localhost charpter05]# g++ -o test 0501.cpp
[root@localhost charpter05]# ./test
8
8
[root@localhost charpter05]# strace ./test
# 对于命令行下执行程序,execve均为strace输出系统调用中的第1个。strace首先调用fork或clone函数新建一个子
# 进程,然后在子进程中调用exec载入执行的程序(这里为./test)
execve("./test", ["./test"], [/* 25 vars */]) = 0
# 以NULL作为参数调用brk,返回值为内存管理起始地址
brk(NULL)                               = 0x22d2000
# 使用mmap函数进行匿名内存映射,以此来获取4096Byte内存空间,该空间起始地址为0x7fb6b4d5c000
# 匿名内存映射就是为了不涉及具体的文件名,避免了文件的创建以及打开,它只能用于具有亲缘关系的进程间通信。
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d5c000
# 调用access函数校验/etc/ld.so.preload是否存在
# 有错误产生时,一般会返回-1,所以会有错误标志和描述,描述提示没有这个文件
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
# 调用open函数尝试打开/etc/ld.so.cache文件,返回文件描述符3
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
# 使用fstat函数获取/etc/ld.so.cache文件信息。
fstat(3, {st_mode=S_IFREG|0644, st_size=35467, ...}) = 0
# 调用mmap函数将/etc/ld.so.cache文件映射到内存
mmap(NULL, 35467, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb6b4d53000
# close关闭文件描述符3指向的/etc/ld.so.cache文件
close(3)                                = 0
# 调用open和read,从/lib64/libstdc++.so.6中读取832个字节,即读取ELF头信息
# ELF头信息中有进程的进入点,这里就是获得进程的进入点
open("/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\265\5\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=995840, ...}) = 0
mmap(NULL, 3175456, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6b4834000
# 使用mprotect函数对0x7fb6b491d000起始的2097152空间进行保护
# PROT_NONE参数就是不能访问,PROT_READ表示可以访问
mprotect(0x7fb6b491d000, 2097152, PROT_NONE) = 0
mmap(0x7fb6b4b1d000, 40960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xe9000) = 0x7fb6b4b1d000
mmap(0x7fb6b4b27000, 82976, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4b27000
close(3)                                = 0
open("/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0pS\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1139680, ...}) = 0
mmap(NULL, 3150136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6b4532000
mprotect(0x7fb6b4633000, 2093056, PROT_NONE) = 0
mmap(0x7fb6b4832000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x100000) = 0x7fb6b4832000
close(3)                                = 0
open("/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360*\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=88720, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d52000
mmap(NULL, 2184192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6b431c000
mprotect(0x7fb6b4331000, 2093056, PROT_NONE) = 0
mmap(0x7fb6b4530000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7fb6b4530000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
mmap(NULL, 3940800, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6b3f59000
mprotect(0x7fb6b4111000, 2097152, PROT_NONE) = 0
mmap(0x7fb6b4311000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7fb6b4311000
mmap(0x7fb6b4317000, 16832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4317000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d51000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d4f000
arch_prctl(ARCH_SET_FS, 0x7fb6b4d4f740) = 0
mprotect(0x7fb6b4311000, 16384, PROT_READ) = 0
mprotect(0x7fb6b4530000, 4096, PROT_READ) = 0
mprotect(0x7fb6b4832000, 4096, PROT_READ) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d4e000
mprotect(0x7fb6b4b1d000, 32768, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7fb6b4d5d000, 4096, PROT_READ) = 0
# 调用munmap,将/etc/ld.so.cache文件从内存中去映射,与mmap(NULL, 35467, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb6b4d53000对应
munmap(0x7fb6b4d53000, 35467)           = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d5b000
# 对应源码中使用的两个系统调用:read函数和write,读取从终端输入的内容和输出内容到终端
read(0, 8
"8\n", 1024)                    = 2
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6b4d5a000
write(1, "8\n", 28
)                      = 2
# 子进程结束,退出码为0
exit_group(0)                           = ?
+++ exited with 0 +++

3 说明

每一行都是一次系统调用,等号左边的是系统调用的函数名以及参数,右边是该调用的返回值。

从strace结果可以看到,系统首先调用execve,以开始一个新的进程,接着进行一些环节的初始化操作,最后停顿在read(0)上面,这也就是执行到了cin函数后,等待用户输入数字。在输完数字后,再调用write函数将格式化后的数字输出到屏幕,最后调用exit_group退出进程,完成整个程序的执行过程。

从源码分析,真正能与源码对应的只有read和write这两个系统调用,其他系统调用几乎都是进程初始化工作:装载被执行程序,载入libc函数库,设置内存映射等。

猜你喜欢

转载自blog.csdn.net/chengqiuming/article/details/90137309