gpt4 book ai didi

linux - fork 的 ptraced 进程挂起

转载 作者:IT王子 更新时间:2023-10-29 01:48:26 24 4
gpt4 key购买 nike

我试图在从 Go 调用程序时拦截系统调用,但是我遇到了两个问题。

子进程似乎挂了,父进程也挂了。看起来 wait4(2) 正在阻塞,这看起来很奇怪, child 最终不会调用 exit(2) 退出吗?

我到达 stdout 的系统调用不一致,有时最后一个系统调用是 3,其他时候是 6192 。我的代码中是否存在竞争条件?为什么会这样?

我尝试监听父端的信号,但我没有收到任何信号..

我已经用 /bin/ls 替换了我通常运行的程序。

package main

import (
"syscall"
"fmt"
"os/signal"
"os"
)

func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
go SignalListener(c)

attr := new(syscall.ProcAttr)
attr.Sys = new(syscall.SysProcAttr)
attr.Sys.Ptrace = true

pid, err := syscall.ForkExec("/bin/ls", nil, attr)

if err != nil {
panic(err)
}

var wstat syscall.WaitStatus
var regs syscall.PtraceRegs

for {
fmt.Println("Waiting..")
_, err := syscall.Wait4(pid, &wstat, 0, nil)
fmt.Printf("Exited: %d\n", wstat.Exited())

if err != nil {
fmt.Println(err)
break
}

syscall.PtraceGetRegs(pid, &regs);
fmt.Printf("syscall: %d\n", regs.Orig_eax)

syscall.PtraceSyscall(pid, 0)
}
}

func SignalListener(c <-chan os.Signal) {
s := <-c

fmt.Printf("Got signal %d\n", s)
}

最佳答案

简短的回答是用 Go 拦截系统调用将非常困难,任何 ptrace 都可能不起作用。

Go 有一个运行时,可以将 go-routines 多路复用到 OS 线程上。一个系统调用是一个调度点,所以在系统调用返回后你可以在不同的线程上,而我认为 ptrace 遵循一个线程。

假设您正在 ptrace-ing 的线程正在运行您的主要 go-routine。然后你调用 fmt.Println(它执行 syscall.Write),因此 Go 运行时将你的 go-routine 从那个线程中取出,并在不同的操作系统线程中运行系统调用(系统调用总是在不同的线程中运行)。当系统调用返回时,您的主要 go-routine 被放回可运行例程的调度程序列表中,并且它将在任何可用的 os 线程上继续,这可能不是您正在 ptrace-ing 的线程。

这也是您无法使用 gdb 单步执行 Go 程序的原因。

如果你只是想执行一个外部程序(比如/bin/ls)你可以使用os/exec来自标准库。

接近您尝试执行的程序可能是 delve .我认为这会在每个单步的每个线程上设置一个断点,然后尝试根据 go-routine id 找到你的 go-routine 现在所在的线程。

关于linux - fork 的 ptraced 进程挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18502203/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com