strace深入分析

发布时间 2023-03-28 20:16:35作者: jinzi
前言:

首先这里要强调的是

1. strace 跟踪打印输出的glibc封装的调用,更准确的说是库调用而非系统调用,很多文章直接写系统调用我觉得不是很严谨,
    这个是shell.c源码  https://github.com/bminor/bash/blob/bc007799f0e1362100375bb95d952d28de4c62fb/shell.c#L357
   调用到了fstat,fstat为glibc库函数,所以它只是对底层的封装,我们可以看到gblic用了很多内嵌汇编来实现相关的底层调用的实现
2. 请参看我的汇编教程,因为没有写完,但是为了区别,所以先参看  https://www.cnblogs.com/aozhejin/p/17205723.html

3.strace官方说法是system call ,但是这里我写的还是调用,比如:open函数调用,我这么写要理解我的意思
strace能做什么:
1、了解你系统上进程中对底层调用时间比较长、花费时间比较多的
2、帮助你了解一些程序运行的机制。
3、了解很多不为人知的内容。

实验环境: 

[root@aozhejin2 /usr/local/src]$uname -r
3.10.0-1160.62.1.el7.x86_64

[root@aozhejin2 /usr/local/src]$cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

[root@aozhejin2 /usr/local/src]$rpm -qa | grep strace
strace-4.24-6.el7.x86_64
查看strace版本
[root@aozhejin2 /proc/self]$strace -V
strace -- version 4.24
Copyright (c) 1991-2018 The strace developers <https://strace.io>.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Optional features enabled: stack-trace=libdw stack-demangle m32-mpers mx32-mpers

查看strace位置

[root@aozhejin2 /proc/self]$which strace
/usr/bin/strace

 

下面是一个利用strace分析的例子:

例如程序
[root@aozhejin2 /usr/local/src]$strace -P /dev/stdout -P /dev/fd/1 ls a.out 
strace: Requested path '/dev/stdout' resolved into '/dev/pts/6'
strace: Requested path '/dev/fd/1' resolved into '/dev/pts/6'
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=34, ws_col=166, ws_xpixel=0, ws_ypixel=0}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
write(1, "a.out\n", 6a.out
)                  = 6
close(1)                                = 0
close(2)                                = 0
+++ exited with 0 +++
分析:
glibc(封装) 
1.fstat  
https://github.com/lattera/glibc/blob/master/io/fstat.c (glibc源码)
https://elixir.bootlin.com/glibc/glibc-2.29/C/ident/fstat
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
2.ioctl操作termios 结构,即跟tty(tty子系统包括termios,ldisc(N_TTY),tty驱动比如pty)相关
linux kernel的头信息
E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\arch\x86\include\asm\ioctl.h ,调用下面的
E:\linux内核\linux-2.6.38.5\linux-2.6.38.5\include\asm-generic\ioctl.h
1.ioctl底层系统调用 https://docs.kernel.org/driver-api/ioctl.html
https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/powerpc/ioctl.c (glibc源码)

 

  统计库函数调用花费的时间情况

[root@aozhejin2 /proc/self]$strace -c ls > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 28.69    0.000317          11        28           mmap
 12.13    0.000134          12        11           open
 11.40    0.000126           9        14           close
  9.95    0.000110           6        18           mprotect
  9.41    0.000104           8        12           fstat
  9.05    0.000100          10        10           read
  4.71    0.000052          26         2           getdents
  4.43    0.000049          12         4         3 access
  2.62    0.000029           9         3           munmap
  2.35    0.000026           8         3         3 ioctl
  1.09    0.000012          12         1           openat
  1.00    0.000011          11         1           execve
  0.81    0.000009           9         1           write
  0.81    0.000009           3         3           brk
  0.81    0.000009           9         1           arch_prctl
  0.72    0.000008           8         1         1 stat
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.001105                   121         9 total

一系列操作

将函数调用跟踪信息输出到文件而非 stderr,-A以追加的方式写入文件。
strace -o trace.log cat /dev/null
-e 只跟踪 open函数调用
[root@aozhejin2 /usr/local/src]$strace -e open cat /dev/null
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/dev/null", O_RDONLY)             = 3
+++ exited with 0 +++
//strace -e open,mmap,munmap ls  跟踪三个函数调用,等价于  strace -e trace=open,mmap,munmap ls 
[root@aozhejin2 /usr/local/src]$strace -e trace=open -e fault=open cat
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
open("/lib64/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
open("/lib64/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
open("/lib64/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
cat: error while loading shared libraries: libc.so.6: cannot open shared object file: Error 38
+++ exited with 127 +++

[root@aozhejin2 /usr/local/src]$strace -e trace=%file cat /dev/null
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/dev/null", O_RDONLY)             = 3
+++ exited with 0 +++
-e trace=%clock    Trace all system calls that read or modify system clocks 跟踪所有函数调用(读取和修改系统时钟的函数调用).
         %creds    Trace all system calls that read or modify user and group identifiers or capability sets.
         %desc     Trace all file descriptor related system calls.
         %file     跟踪所有以文件名作为参数的函数调用.
         %fstat    Trace fstat and fstatat syscall variants.
         %fstatfs  Trace fstatfs, fstatfs64, fstatvfs, osf_fstatfs, and osf_fstatfs64 system calls.
         %ipc      Trace all IPC related system calls.
         %lstat    Trace lstat syscall variants.
         %memory   跟踪所有内存相关的函数调用.
         %network  跟踪所有网络相关的函数调用
         %process  跟踪进程管理相关的函数调用.
         %pure     Trace syscalls that always succeed and have no arguments.
         %signal   Trace all signal related system calls.
         %stat     Trace stat syscall variants.
         %statfs   Trace statfs, statfs64, statvfs, osf_statfs, and osf_statfs64 system calls.
         %%stat    Trace syscalls used for requesting file status.
         %%statfs  Trace syscalls related to file system statistics.
//跟踪访问指定路径的函数调用
[root@aozhejin2 /usr/local/src]$strace -P /dev/stdout -P /dev/fd/1 ls a.out 
strace: Requested path '/dev/stdout' resolved into '/dev/pts/6'
strace: Requested path '/dev/fd/1' resolved into '/dev/pts/6'
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=34, ws_col=166, ws_xpixel=0, ws_ypixel=0}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
write(1, "a.out\n", 6a.out
)                  = 6
close(1)                                = 0
close(2)                                = 0
+++ exited with 0 +++
//mmap()函数调用返回错误
[root@aozhejin2 /usr/local/src]$strace -e fault=mmap:error=EPERM  cat /dev/null
execve("/usr/bin/cat", ["cat", "/dev/null"], 0x7ffd89842c48 /* 31 vars */) = 0
brk(NULL)                               = 0x2216000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 EPERM (Operation not permitted) (INJECTED)
writev(2, [{iov_base="cat", iov_len=3}, {iov_base=": ", iov_len=2}, {iov_base="error while loading shared libra"..., iov_len=36}, {iov_base=": ", iov_len=2}, {iov_base="", iov_len=0}, {iov_base="", iov_len=0}, {iov_base="cannot create cache for search p"..., iov_len=35}, {iov_base=": ", iov_len=2}, {iov_base="Cannot allocate memory", iov_len=22}, {iov_base="\n", iov_len=1}], 10cat: error while loading shared libraries: cannot create cache for search path: Cannot allocate memory
) = 103
exit_group(127)                         = ?
+++ exited with 127 +++
-i 打印指令指针
[root@aozhejin2 /usr/local/src]$strace -i -e open cat /dev/null
[00007fb148257677] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[00007fb148257677] open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[00007fb147f5f900] open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
[00007fb147f5f900] open("/dev/null", O_RDONLY) = 3
[????????????????] +++ exited with 0 +++
-r打印函数调用时间戳
[root@aozhejin2 /usr/local/src]$strace -r -i -e open cat /dev/null
     0.000000 [00007fdae31ee677] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
     0.000217 [00007fdae31ee677] open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
     0.000847 [00007fdae2ef6900] open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
     0.000204 [00007fdae2ef6900] open("/dev/null", O_RDONLY) = 3
     0.000332 [????????????????] +++ exited with 0 +++
-T 打印函数调用花费的时间
[root@aozhejin2 /usr/local/src]$strace -T -r -i -e open cat /dev/null
     0.000000 [00007f1d7bc90677] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000018>
     0.000191 [00007f1d7bc90677] open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 <0.000018>
     0.000864 [00007f1d7b998900] open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 <0.000018>
     0.000210 [00007f1d7b998900] open("/dev/null", O_RDONLY) = 3 <0.000019>
     0.000337 [????????????????] +++ exited with 0 +++
-c生成摘要信息,针对open
[root@aozhejin2 /usr/local/src]$strace -c -T -r -i -e open cat /dev/null
strace: -i has no effect with -c
strace: -r has no effect with -c
strace: -T has no effect with -c
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000025           6         4           open
------ ----------- ----------- --------- --------- ----------------
100.00    0.000025                     4           total

 

-yy 还是不错的,打印文件描述符相关:

[root@aozhejin2 /proc/self]$strace -yy cat /dev/null
execve("/usr/bin/cat", ["cat", "/dev/null"], 0x7ffeb21b9c90 /* 32 vars */) = 0
brk(NULL)                               = 0x1383000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f111363a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3</etc/ld.so.cache>
fstat(3</etc/ld.so.cache>, {st_mode=S_IFREG|0644, st_size=47788, ...}) = 0
mmap(NULL, 47788, PROT_READ, MAP_PRIVATE, 3</etc/ld.so.cache>, 0) = 0x7f111362e000
close(3</etc/ld.so.cache>)              = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib64/libc-2.17.so>
read(3</usr/lib64/libc-2.17.so>, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
fstat(3</usr/lib64/libc-2.17.so>, {st_mode=S_IFREG|0755, st_size=2156592, ...}) = 0
mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3</usr/lib64/libc-2.17.so>, 0) = 0x7f111304c000
mprotect(0x7f1113210000, 2093056, PROT_NONE) = 0
mmap(0x7f111340f000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3</usr/lib64/libc-2.17.so>, 0x1c3000) = 0x7f111340f000
mmap(0x7f1113415000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1113415000
close(3</usr/lib64/libc-2.17.so>)       = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f111362d000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f111362b000
arch_prctl(ARCH_SET_FS, 0x7f111362b740) = 0
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
access("/etc/sysconfig/strcasecmp-nonascii", F_OK) = -1 ENOENT (No such file or directory)
mprotect(0x7f111340f000, 16384, PROT_READ) = 0
mprotect(0x60b000, 4096, PROT_READ)     = 0
mprotect(0x7f111363b000, 4096, PROT_READ) = 0
munmap(0x7f111362e000, 47788)           = 0
brk(NULL)                               = 0x1383000
brk(0x13a4000)                          = 0x13a4000
brk(NULL)                               = 0x13a4000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3</usr/lib/locale/locale-archive>
fstat(3</usr/lib/locale/locale-archive>, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0
mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3</usr/lib/locale/locale-archive>, 0) = 0x7f110cb09000
close(3</usr/lib/locale/locale-archive>) = 0
fstat(1</dev/pts/7<char 136:7>>, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 7), ...}) = 0
open("/dev/null", O_RDONLY)             = 3</dev/null<char 1:3>>    调用open函数打开字符设备
fstat(3</dev/null<char 1:3>>, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
fadvise64(3</dev/null<char 1:3>>, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3</dev/null<char 1:3>>, "", 65536) = 0    #字符设备/dev/null
close(3</dev/null<char 1:3>>)           = 0    #字符设备
close(1</dev/pts/7<char 136:7>>)        = 0  b #关闭 pts/7
close(2</dev/pts/7<char 136:7>>)        = 0    #关闭 pts/7
exit_group(0)                           = ?
+++ exited with 0 +++

 参看:
   https://linux.die.net/man/2/fstat
   https://man7.org/linux/man-pages/man2/fstat.2.html
   https://man7.org/linux/man-pages/man2/syscalls.2.html    (系统调用的名称列表在这里可以查看)
  
  实验下里面的例子

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
   struct stat sb;
   if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
//glic包装了底层.
if (stat(argv[1], &sb) == -1) { perror("stat"); exit(EXIT_FAILURE); } printf("File type: "); switch (sb.st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; } printf("I-node number: %ld\n", (long) sb.st_ino); printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode); printf("Link count: %ld\n", (long) sb.st_nlink); printf("Ownership: UID=%ld GID=%ld\n",(long) sb.st_uid, (long) sb.st_gid); printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize); printf("File size: %lld bytes\n",(long long) sb.st_size); printf("Blocks allocated: %lld\n",(long long) sb.st_blocks); printf("Last status change: %s", ctime(&sb.st_ctime)); printf("Last file access: %s", ctime(&sb.st_atime)); printf("Last file modification: %s", ctime(&sb.st_mtime)); exit(EXIT_SUCCESS); }

运行:

gcc -g -o teststat teststat.c  && chmod 777 teststat
[root@aozhejin2 /usr/local/src]$./teststat teststat.c File type: regular file I-node number: 974356 Mode: 100644 (octal) Link count: 1 Ownership: UID=0 GID=0 Preferred I/O block size: 4096 bytes File size: 1695 bytes Blocks allocated: 8 Last status change: Tue Mar 28 10:25:57 2023 Last file access: Tue Mar 28 10:26:14 2023 Last file modification: Tue Mar 28 10:25:57 2023
我们使用strace 跟踪一下 bash执行的情况
[root@aozhejin2 /proc/self]$strace -e open bash -l -c 'echo aozhejin'
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/dev/tty", O_RDWR|O_NONBLOCK)     = 3    #打开tty终端
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/proc/meminfo", O_RDONLY|O_CLOEXEC) = 3    #/proc/meminfo 内存使用情况信息
open("/usr/lib64/gconv/gconv-modules.cache", O_RDONLY) = 3
open("/etc/profile", O_RDONLY)          = 3       #打开bash配置
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19929, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19931, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
#SIGCHLD信号是进程状态发生变化时触发
open(
"/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 #打开空设备 open("/etc/profile.d/256term.sh", O_RDONLY) = 3 #该文件是启用了256颜色显示 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 #打开空设备 open("/etc/profile.d/abrt-console-notification.sh", O_RDONLY) = 3 #检测shell是否连接到tty --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19933, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/bash_completion.sh", O_RDONLY) = 3
#会调用 /usr/share/bash-completion/bash_completion open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/colorgrep.sh", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19934, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/colorls.sh", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19936, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19939, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19941, si_uid=0, si_status=1, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/lang.sh", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/less.sh", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/rabbitmqctl-autocomplete.sh", O_RDONLY) = 3 open("/usr/lib/rabbitmq/autocomplete/bash_autocomplete.sh", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/rvm.sh", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19942, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19944, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19946, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/etc/rvmrc", O_RDONLY) = 3 open("/usr/local/rvm/scripts/rvm", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19947, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19949, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19951, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19953, si_uid=0, si_status=1, si_utime=0, si_stime=0} --- open("/etc/rvmrc", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/usr/local/rvm/scripts/base", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19954, si_uid=0, si_status=1, si_utime=0, si_stime=0} --- open("/etc/rvmrc", O_RDONLY) = 3 open("/usr/local/rvm/scripts/initialize", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19955, si_uid=0, si_status=1, si_utime=0, si_stime=0} --- open("/etc/rvmrc", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_gemsets", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_late", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_parse", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_interpreters", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/logging", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/support", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19956, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/usr/local/rvm/scripts/functions/db", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/detect/system", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/detect/system_version/codename", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19957, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19959, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19961, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/usr/local/rvm/scripts/functions/detect/system_name/lsb_release", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/detect/system_name/os_release", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19963, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19968, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19975, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19981, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19983, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19987, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19989, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19991, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19993, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19995, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19997, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19999, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20001, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20003, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20005, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20007, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/usr/local/rvm/scripts/functions/utility", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/utility_logging", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/utility_package", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/utility_rubygems", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/utility_system", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/init", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/cleanup", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/env", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_env", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_project", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_set", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_to", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_trust", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/rvmrc_warning", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/install", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/environment", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/gemset", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/checksum", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/list", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/usr/local/rvm/scripts/functions/version", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_gemsets", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_late", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_parse", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/selector_interpreters", O_RDONLY) = 3 open("/usr/local/rvm/scripts/cd", O_RDONLY) = 3 open("/usr/local/rvm/scripts/extras/bash_zsh_support/chpwd/function.sh", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/cli", O_RDONLY) = 3 open("/usr/local/rvm/scripts/functions/version", O_RDONLY) = 3 open("/usr/local/rvm/scripts/cli", O_RDONLY) = 3 open("/usr/local/rvm/scripts/override_gem", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20008, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20012, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20017, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/vim.sh", O_RDONLY) = 3 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=20018, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/which2.sh", O_RDONLY) = 3 open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 open("/etc/profile.d/sh.local", O_RDONLY) = 3 open("/root/.bash_profile", O_RDONLY) = 3 open("/root/.bashrc", O_RDONLY) = 3 open("/etc/bashrc", O_RDONLY) = 3 aozhejin

 你如果使用 strace -F   bash -l -c 'echo aozhejin'  你也可以得到很多有意思的东西
   

 我们继续做实验:

#include <fcntl.h>   //open包含在这个文件中
#include <stdio.h>   //perror包含在这个文件中
#include <errno.h>
int main(void)
{
 
 //sucess,返回file 
 /*
 if(open("/usr/local/src/stracetest/aozhejin", O_CREAT|O_RDONLY))
 {			
 }else {
	 //出错返回-1
	 perror("文件错误");
 }
 */
 /*
 int fd=open("/usr/local/src/stracetest/aozhejin", O_RDONLY);
 if(fd<0){
	printf("文件不存在或不可读")
	printf("errno is %d\n",errno);
 }
 */
 int fd=open("/usr/local/src/stracetest/aozhejin", O_CREAT|O_RDONLY);
 if(fd<0){
	printf("errno is %d\n",errno);

 }
 /* 打开,如果不存在则创建文件/usr/local/src/stracetest/aozhejin */
 sleep(20000);
 return 0;
 //https://man7.org/linux/man-pages/man2/open.2.html
}
编译gcc teststrace.c
启动 ./a.out

 
 1、open函数文件状态标志(文件访问模式),下表以后补充

O_CLOEXEC 避免一个线程打开一个线程的竞争条件
O_CREAT 如果路径名不存在,则将其创建为常规文件
O_RDONLY  
O_TRUNC  
O_WRONLY  
O_NOCTTY  
O_NOFOLLOW  
O_NONBLOCK  
O_DIRECTORY  
O_DIRECT  
O_DSYNC  
O_EXCL  
O_LARGEFILE  
O_PATH  
O_TMPFILE  

2、错误使用的是内核

   https://man7.org/linux/man-pages/man3/errno.3.html

   实际错误定义在内核的这个文件中

   E:\linux内核\linux-2.6.38.5\include\asm-generic\errno.h

   看看进程fd情况(使用lsof , 列出启动进程的所有打开的文件)

[root@aozhejin2 /proc/39298/fd]$lsof -p 39298
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF      NODE NAME
a.out   39298 root  cwd    DIR  253,0       54 406215066 /usr/local/src/stracetest
a.out   39298 root  rtd    DIR  253,0     4096       128 /
a.out   39298 root  txt    REG  253,0     8416 406215074 /usr/local/src/stracetest/a.out
a.out   39298 root  mem    REG  253,0  2156592 268633378 /usr/lib64/libc-2.17.so
a.out   39298 root  mem    REG  253,0   163312 281915295 /usr/lib64/ld-2.17.so
a.out   39298 root    0u   CHR  136,7      0t0        10 /dev/pts/7
a.out   39298 root    1u   CHR  136,7      0t0        10 /dev/pts/7
a.out   39298 root    2u   CHR  136,7      0t0        10 /dev/pts/7
a.out   39298 root    3r   REG  253,0        0 406215067 /usr/local/src/stracetest/aozhejin
a.out   39298 root    6u   CHR  136,7      0t0        10 /dev/pts/7

解释FD、TYPE、DEVICE列

FD列
u - 文件读写禁止 r - 文件读禁止 w - 文件写禁止 W - 文件写禁止并且写用lock整个文件
上面的u、r、w等叫模式字符对pts(即文件打开模式),
数字代表文件描述符 0u即/dev/pts/7/0 0数字代表标准输入 1代表标准输出 mem - 内存映射文件,一般是共享库
rtd- root目录
txt-文本文件
cwd => 当前工作目录
3r  => 文件描述符3,打开并读
TYPE列
DIR => 目录
REG => 常规文件
CHR=>代表字符设备
FIFO=>代表先进先出
DEVICE列主次设备号
NODE列为inode号

保存结果 $strace -o testresult 

[root@aozhejin2 /usr/local/src/stracetest]$strace -o testresult lsof -p 39298
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF      NODE NAME
a.out   39298 root  cwd    DIR  253,0       54 406215066 /usr/local/src/stracetest
a.out   39298 root  rtd    DIR  253,0     4096       128 /
a.out   39298 root  txt    REG  253,0     8416 406215074 /usr/local/src/stracetest/a.out
a.out   39298 root  mem    REG  253,0  2156592 268633378 /usr/lib64/libc-2.17.so
a.out   39298 root  mem    REG  253,0   163312 281915295 /usr/lib64/ld-2.17.so   //共享库
a.out   39298 root    0u   CHR  136,7      0t0        10 /dev/pts/7    #标准输入  读写禁止
a.out   39298 root    1u   CHR  136,7      0t0        10 /dev/pts/7    #标准输出  读写禁止
a.out   39298 root    2u   CHR  136,7      0t0        10 /dev/pts/7    #标准错误  读写禁止
a.out   39298 root    3r   REG  253,0        0 406215067 /usr/local/src/stracetest/aozhejin #临时文件  读禁止
a.out   39298 root    6u   CHR  136,7      0t0        10 /dev/pts/7    #fd 6 读写禁止

[root@aozhejin2 /proc/39298/fd]$ls -l total 0 lrwx------ 1 root root 64 Mar 28 15:11 0 -> /dev/pts/7 lrwx------ 1 root root 64 Mar 28 15:11 1 -> /dev/pts/7 lrwx------ 1 root root 64 Mar 28 15:11 2 -> /dev/pts/7 lr-x------ 1 root root 64 Mar 28 15:11 3 -> /usr/local/src/stracetest/aozhejin #文件描述符 lrwx------ 1 root root 64 Mar 28 15:11 6 -> /dev/pts/7
[root@aozhejin2 /proc/47323/fd]$stat 3
  File: ‘3’ -> ‘/usr/local/src/stracetest/aozhejin’
  Size: 64        	Blocks: 0          IO Block: 1024   symbolic link
Device: 3h/3d	Inode: 638075231   Links: 1
Access: (0500/lr-x------)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-03-28 17:16:45.366291259 +0800
Modify: 2023-03-28 17:16:45.365291259 +0800
Change: 2023-03-28 17:16:45.365291259 +0800
 Birth: -
这里注意我直接stat了文件描述符,然后我用readlink找出符号链接所指向的位置 [root@aozhejin2 /proc/39298/fd]$readlink 3 /usr/local/src/stracetest/aozhejin

继续测试文件描述符

//我是在pts/6上启动的程序,会在fork出pid , 文件描述符是这样
[root@aozhejin2 /proc/39298/fd]$ll
total 0
lrwx------ 1 root root 64 Mar 28 15:56 0 -> /dev/pts/6
lrwx------ 1 root root 64 Mar 28 15:56 1 -> /dev/pts/6
lrwx------ 1 root root 64 Mar 28 15:56 2 -> /dev/pts/6
lr-x------ 1 root root 64 Mar 28 15:56 3 -> /usr/local/src/stracetest/aozhejin
lrwx------ 1 root root 64 Mar 28 15:56 6 -> /dev/pts/6//在pts/7终端上进行查看
[root@aozhejin2 /proc/39298/fd]$ps $$
   PID TTY      STAT   TIME COMMAND
 74443 pts/7    Ss     0:00 -bash
在pts/7终端上看到了pts/6创建的进程39298,依然指向的是 pts/6 终端设备
[root@aozhejin2 /proc/39298/fd]$ll
total 0
lrwx------ 1 root root 64 Mar 28 15:56 0 -> /dev/pts/6
lrwx------ 1 root root 64 Mar 28 15:56 1 -> /dev/pts/6
lrwx------ 1 root root 64 Mar 28 15:56 2 -> /dev/pts/6
lr-x------ 1 root root 64 Mar 28 15:56 3 -> /usr/local/src/stracetest/aozhejin
lrwx------ 1 root root 64 Mar 28 15:56 6 -> /dev/pts/6

[root@aozhejin2 /proc/self/fd]$ll
total 0
lrwx------ 1 root root 64 Mar 27 14:12 0 -> /dev/pts/7
lrwx------ 1 root root 64 Mar 27 14:12 1 -> /dev/pts/7
lrwx------ 1 root root 64 Mar 27 14:12 2 -> /dev/pts/7
lrwx------ 1 root root 64 Mar 28 15:56 255 -> /dev/pts/7
lrwx------ 1 root root 64 Mar 27 14:12 6 -> /dev/pts/7

 

参考:
https://strace.io/ 官网
 https://gist.github.com/drj11/930a7288ad623b7714e0c3d92e3586da
https://www.howtoforge.com/linux-strace-command/
https://access.redhat.com/documentation/zh-cn/red_hat_developer_toolset/9/html/user_guide/chap-strace
https://opensource.com/article/19/10/strace
https://www.learnsteps.com/strace-see-what-system-calls-kernal-is-executing/
https://man7.org/linux/man-pages/man2/syscalls.2.html
https://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
https://unix.stackexchange.com/questions/60422/how-to-interpret-this-output-of-lsof-command
https://phoenixnap.com/kb/lsof-command
https://www.thegeekstuff.com/2012/08/lsof-command-examples/
https://man7.org/linux/man-pages/man2/open.2.html  open函数的文件状态标志
https://www.computerhope.com/jargon/f/file-descriptor.htm
termios