五花八门客户问题(BUG) - 用好strace2

本文探讨了strace与gdb在跟踪进程时的冲突,由于两者都基于ptrace函数,因此无法同时作用于同一进程。通过实例展示了当尝试同时使用strace和gdb时,只有一个能够成功控制目标进程。此外,文章还通过strace strace ls的组合,配合bcc工具的execsnoop,详细剖析了strace如何跟踪并控制ls进程的内部活动,揭示了ptrace函数的使用细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

strace与gdb的冲突

细看strace


前言

上文通过strace trace它自个看到了strace的原理:确实是调用了ptrace函数实现的。今天我们再细看一看。

strace与gdb的冲突

既然它两底层都是用ptrace,那么一定不能同时用在同一个进程上。实例验证:

[root]# strace sleep 1000000
...
nanosleep({tv_sec=1000000, tv_nsec=0},
#####阻塞在sleep, 方便我们有机会用gdb尝试attach它#########

启动另外一个session,

[root]# ps -ef|grep sleep
root     1463460 1462937  0 21:12 pts/1    00:00:00 strace sleep 1000000
root     1463463 1463460  0 21:12 pts/1    00:00:00 sleep 1000000
root     1463471    1038  0 21:12 ?        00:00:00 sleep 60

[root]# gdb -p 1463463
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-19.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
  File "/home/mzhai/gdb_support/offsets.py", line 15
    print argv[0], '{'
             ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(argv[0], '{')?
Attaching to process 1463463
warning: process 1463463 is already traced by process 1463460
ptrace: Operation not permitted.
(gdb) quit

它说:已经被1463460跟踪了,而1463460就是strace sleep 1000000。

两者都要控制傀儡进程sleep,只有一个成功。

细看strace

还是上节的思路,strace strace ls, 只是不是统计各个系统函数的调用次数,而是要细看。

为了便于搜索和认清谁是谁,我会同时使用bcc工具中的execsnoop记录各个启动进程的PID和command。

开一个session,运行/usr/share/bcc/tools/execsnoop(我的Alma8.4和redhat9.2都自带):

[root]# execsnoop

再开一个session运行 strace strace ls:

[root]# strace strace ls
execve("/usr/bin/strace", ["strace", "ls"], 0x7ffe1f473048 /* 60 vars */) = 0
brk(NULL)                               = 0x56104a1bb000
...
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f64d4ec1f50) = 1462998
wait4(1462998, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}], WSTOPPED, NULL) = 1462998
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_STOPPED, si_pid=1462998, si_uid=0, si_status=SIGSTOP, si_utime=0, si_stime=0} ---
ptrace(PTRACE_SEIZE, 1462998, NULL, PTRACE_O_TRACESYSGOOD|PTRACE_O_TRACEEXEC|PTRACE_O_TRACEEXIT) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_STOPPED, si_pid=1462998, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
ptrace(PTRACE_INTERRUPT, 1462998)       = 0
kill(1462998, SIGCONT)                  = 0
close(0)                                = 0
...
ptrace(PTRACE_LISTEN, 1462998)          = 0
wait4(-1, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP} | PTRACE_EVENT_STOP << 16], __WALL, NULL) = 1462998
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_CONTINUED, si_pid=1462998, si_uid=0, si_status=SIGCONT, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffc7c00d49c, WNOHANG|__WALL, NULL) = 0
ptrace(PTRACE_SYSCALL, 1462998, NULL, 0) = 0
wait4(-1, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGCONT}], __WALL, NULL) = 1462998
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_TRAPPED, si_pid=1462998, si_uid=0, si_status=SIGCONT, si_utime=0, si_stime=0} ---
ptrace(PTRACE_GETSIGINFO, 1462998, NULL, {si_signo=SIGCONT, si_code=SI_USER, si_pid=1462994, si_uid=0}) = 0
wait4(-1, 0x7ffc7c00d49c, WNOHANG|__WALL, NULL) = 0
ptrace(PTRACE_SYSCALL, 1462998, NULL, SIGCONT) = 0
wait4(-1, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP | 0x80}], __WALL, NULL) = 1462998
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_TRAPPED, si_pid=1462998, si_uid=0, si_status=SIGTRAP, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffc7c00d49c, WNOHANG|__WALL, NULL) = 0
ptrace(PTRACE_GETREGSET, 1462998, NT_PRSTATUS, {iov_base={r15=0xffffffff, r14=0x9, r13=0x7f64d4ec1b00, r12=0x7ffc7c01066e, rbp=0x7ffc7c00d750, rbx=0, r11=0x246, r10=0x7f64d4ec1c80, r9=0x7f64d420b2f0, r8=0, rax=0xffffffffffffffda, rcx=0x7f64d4248e7b, rdx=0x7ffc7c00d750, rsi=0x7ffc7c00d740, rdi=0x7ffc7c00c430, orig_rax=0x3b, rip=0x7f64d4248e7b, cs=0x33, eflags=0x246, rsp=0x7ffc7c00c1d8, ss=0x2b, fs_base=0x7f64d4ec1c80, gs_base=0, ds=0, es=0, fs=0, gs=0}, iov_len=216}) = 0
fstat(2, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}) = 0
process_vm_readv(1462998, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=4096}], 1, [{iov_base=0x7ffc7c00c000, iov_len=4096}], 1, 0) = 4096
process_vm_readv(1462998, [{iov_base="\200\3339\324d\177\0\0\1\0\0\0\0\0\0\0\"\0\0\0\0\0\0\0\0\6b\25Y\7\251\210"..., iov_len=4096}], 1, [{iov_base=0x7ffc7c00d000, iov_len=4096}], 1, 0) = 4096
process_vm_readv(1462998, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=4096}], 1, [{iov_base=0x7ffc7c00f000, iov_len=4096}], 1, 0) = 4096
write(2, "execve(\"/usr/bin/ls\", [\"ls\"], 0x"..., 58execve("/usr/bin/ls", ["ls"], 0x7ffc7c00d750 /* 60 vars */) = 58
ptrace(PTRACE_SYSCALL, 1462998, NULL, 0) = 0
...

此时session1中的输出:

[root]# execsnoop
PCOMM            PID     PPID    RET ARGS
strace           1462991 1462861   0 /usr/bin/strace strace ls
strace           1462994 1462991   0 /usr/bin/strace ls
ls               1462998 1462994   0 /usr/bin/ls

可以清晰的看到第一个strace PID=1462991,第二个=1462994,ls PID=1462998.

而session2中所有的ptrace(...,1462998...)这样的行都是第二个strace的详细活动的一部分(全被第一个strace扒了出来),它干的坏事就是秘密的控制了ls。ptrace第一个参数的含义通过man ptrace能查到。此处简单介绍下上面列出的(还有500多次调用,都省略不提)。




ptrace第一个参数

 
含义
PTRACE_SEIZE  attach到ls
PTRACE_INTERRUPT停止ls
PTRACE_LISTEN继续ls, 但不让其执行指令
PTRACE_SYSCALL继续ls, 但会停止在:1.系统调用退出时 或2.有信号时。目的是第一次得到系统函数的参数,之后得到返回值。
PTRACE_GETSIGINFO得到signal相关的信息
PTRACE_GETREGSET读ls的寄存器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深山老宅

鸡蛋不错的话,要不要激励下母鸡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值