当前位置: 首页 > 工具软件 > strace > 使用案例 >

Linux之strace命令

秦炜
2023-12-01

strace :监控程序的执行状况

在linux 空间下,运行一个程序时,操作系统会将应用程序封装一个进程的形式,参与操作系统的调度,可以使用strace 跟踪程序运行的情况。

基本功能

  • 监控用户进程与内核进程的交互
  • 追踪进程的系统调用、信号传递、状态变化

一、系统调用

  • 分类
    • 文件和设备访问:open、close、read、write、ioctl等
    • 进程管理:fork、clone、execve、exit 等
    • 信号:signal、kill等
    • 内存管理:brk、mmap、mlock等
    • 进程间通信:semget、信号量、消息队列
    • 网络通信:socket、connect等
  • 常用参数
    -c   统计每一系统调用的所执行的时间,次数和出错的次数等
    -d   输出strace关于标准错误的调试信息
    -f   跟踪由目标进程及调用所产生的子进程
    -F   尝试跟踪目标调用 在-f时,vfork不被跟踪
    -a   设置返回值的输出位置.默认 为40
    -r   打印出相对时间关于每一个系统调用
    -t   在每行输出的后面,显示调用花费时间
    -tt  在每行输出的前面,显示调用花费毫秒级别的时间
    -T   每次系统调用所花费的时间
    -v   对某些相关调用,把完整的环境变量、文件stat结构打印出来
    -p pid  指定要跟踪的进程pid,同时跟踪的多个pid,重复多次-p选项即可
    -o filename: 将跟踪输出写入文件名
    -s 当系统调用的某个参数是字符串时,最多输出制定长度的内容,默认时32个字节 
    
    -e set: 仅跟踪某些系统调用
    -e open,close: 仅跟踪打开/关闭系统调用
    -e file: 仅跟踪文件系统调用/文件操作相关的
    -e process: 跟踪所有涉及流程管理的系统调用
    -e network: 跟踪所有与网络相关的系统调用
    -e signal:跟踪所有与信号相关的系统调用
    -e ipc: 跟踪所有与ipc相关的系统调用
    -e desc: 跟踪所有与文件描述符相关的系统调用
    -e memory: 跟踪所有与内存映射相关的系统调用
    -e set: 仅跟踪指定的信号子集
    
示例《一》
  • 查看一个程序所有的open、close系统调用
  • 查看每个程序调用消耗的时间
  • 统计系统调用次数、错误次数统计
  • 打印系统调用的时间戳
  • 将追踪日志保存到log文件中
注释:

 查看所有程序运行  strace python server.py
 查看所有程序运行  strace ./aa.sh
 
 查看打开系统调用情况     strace -e open ./aa.sh
 查看打开关闭系统调用情况  strace -e open,close ./aa.sh
 查看打开关闭系统调用时间  strace -T -e open,close python3 main.py (T 时间在后面显示)

 查看打开关闭系统调用次数  strace -c -T -e open,close ./aa.sh (如程序一直在运行,停止后才会统计)
 查看打开关闭系统调用时间  strace -t -T -e open,close ./aa.sh  
 查看打开关闭系统调用时间  strace -tt -T -e open,close ./aa.sh  (tt 
 查看打开系统调用输入log  strace -tt -T -e open -o trace.log ./aa.sh  (-o 输入trace.log文件)

strace -tt -T -V -e trace=file -o /data/log/trace.log -s 1024 -p 23489

二、系统调用函数说明

  • 进程管理

    函数名说明
    fork创建一个新进程
    clone按制定条件创建子进程
    execve运行可执行文件
    pause进程将处于阻塞状态
    wait等待子进程终止
    waitpid等待制定子进程终止
  • 文件和设备访问

    函数名说明
    open打开文件
    create创建新文件
    close关闭文件描述符
    read读文件
    write写文件
    pread对文件随机读
    pwrite对文件随机写
    pollI/o多路转换
    truncate截断文件
  • 文件系统操作

    函数名说明
    access确定文件的可存取性
    chmod确定文件的可存取性
    chown改变文件的属主或用户组
    chroot改变文件状态信息
    stat获取文件的状态信息
    lstat获取文件的状态信息
    getdents读取目录项
    mkdir创建目录
    link建立链接
  • 内存管理

    函数名说明
    mmap映射虚拟内存页(分配内存)
    sync将内存缓冲区数据写回硬盘
  • socket 控制

    函数名说明
    socketcallsocket系统调用
    socket建立socket
    bind绑定socket到端口
    connect链接远程主机
    send通过socket发送信息
    sendto发送UDP信息
    sendmsg参见send
    listen监听socket端口
    select对多路同步I/O进行轮询
示例《二》
  • ping baidu系统调用过程

    ping www.baidu.com
    strace ping www.baidu.com
    strace -e poll,select,connect,sendto ping www.baidu.com
    
  • cat /etc/passwd 系统调用过程

    strace cat /etc/passwd
    
    [root@VM-0-14-centos ~]# strace cat /etc/passwd
    
    运行命令
    execve("/usr/bin/cat", ["cat", "/etc/passwd"], 0x7ffeee8bfe78 /* 28 vars */) = 0
    brk(NULL)                               = 0x1d9f000
    
    为运行命名分配内存空间
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6081756000
    
    确定文件的可存取性 -1 表示文件不可读
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (没有那个文件或目录)
    
    打开文件 
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    
    文件状态:作用于已打开的文件的文件描述符而不是文件名
    fstat(3, {st_mode=S_IFREG|0644, st_size=37645, ...}) = 0
    mmap(NULL, 37645, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f608174c000
    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`&\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=2156352, ...}) = 0
    mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f6081168000
    
    参见下文mprotect 命令
    mprotect(0x7f608132c000, 2093056, PROT_NONE) = 0
    mmap(0x7f608152b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f608152b000
    mmap(0x7f6081531000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f6081531000
    close(3)                                = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f608174b000
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6081749000
    arch_prctl(ARCH_SET_FS, 0x7f6081749740) = 0
    mprotect(0x7f608152b000, 16384, PROT_READ) = 0
    mprotect(0x60b000, 4096, PROT_READ)     = 0
    mprotect(0x7f6081757000, 4096, PROT_READ) = 0
    munmap(0x7f608174c000, 37645)           = 0
    brk(NULL)                               = 0x1d9f000
    brk(0x1dc0000)                          = 0x1dc0000
    brk(NULL)                               = 0x1dc0000
    open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=106176928, ...}) = 0
    mmap(NULL, 106176928, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f607ac25000
    close(3)                                = 0
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
    open("/etc/passwd", O_RDONLY)           = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=1419, ...}) = 0
    fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
    read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 65536) = 1419
    write(1, "root:x:0:0:root:/root:/bin/bash\n"..., 1419root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    polkitd:x:999:998:User for polkitd:/:/sbin/nologin
    libstoragemgmt:x:998:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
    rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
    ntp:x:38:38::/etc/ntp:/sbin/nologin
    abrt:x:173:173::/etc/abrt:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    chrony:x:997:995::/var/lib/chrony:/sbin/nologin
    tcpdump:x:72:72::/:/sbin/nologin
    syslog:x:996:994::/home/syslog:/bin/false
    mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false
    tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
    nginx:x:995:991:nginx user:/var/cache/nginx:/sbin/nologin
    redis:x:994:990:Redis Database Server:/var/lib/redis:/sbin/nologin
    ) = 1419
    read(3, "", 65536)                      = 0
    close(3)                                = 0
    close(1)                                = 0
    close(2)                                = 0
    exit_group(0)                           = ?
    +++ exited with 0 +++
    

三、其他

在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。
函数原型如下:

#include <unistd.h>
#include <sys/mmap.h>
int mprotect(const void *start, size_t len, int prot);
mprotect()
函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
1)PROT_READ:表示内存段内的内容可写;
2)PROT_WRITE:表示内存段内的内容可读;
3)PROT_EXEC:表示内存段中的内容可执行;
4)PROT_NONE:表示内存段中的内容根本没法访问。

需要指出的是,指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
 类似资料: