Я пытаюсь написать программу, которая распечатывала бы все системные вызовы, выполняемые программой. У меня возникли проблемы с расширением этого кода для работы со сценариями с несколькими обработками. Я начал с кода из https://github.com/lizrice/strace-from-scratch, а теперь я хотел бы также отслеживать дочерние процессы.
Я попытался добавить параметры PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE
, но это приводит к зависанию процесса по какой-то причине. Я не знаю, почему. Если я не укажу эти параметры, процесс будет завершен, но, конечно, дочерние элементы не будут отслеживаться.
package main
import (
"fmt"
seccomp "github.com/seccomp/libseccomp-golang"
"golang.org/x/sys/unix"
"log"
"os"
"os/exec"
"runtime"
)
func init() {
runtime.LockOSThread()
}
func main() {
var err error
if len(os.Args) < 2 {
log.Fatalf("usage: ./trace-files program [arg]...")
}
cmd := exec.Command(os.Args[1], os.Args[2:]...)
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.SysProcAttr = &unix.SysProcAttr{
Ptrace: true,
}
if err = cmd.Start(); err != nil {
log.Fatalf("error starting command: %s\n", err)
}
if err = cmd.Wait(); err != nil {
// We expect "trace/breakpoint trap" here.
fmt.Printf("Wait returned: %s\n", err)
}
pid := cmd.Process.Pid
exit := true
var regs unix.PtraceRegs
var status unix.WaitStatus
// TODO: Setting these options causes the multiprocessing Python script to hang.
ptraceOptions := unix.PTRACE_O_TRACEVFORK | unix.PTRACE_O_TRACEFORK | unix.PTRACE_O_TRACECLONE
if err = unix.PtraceSetOptions(pid, ptraceOptions); err != nil {
log.Fatalf("error setting ptrace options: %s", err)
}
fmt.Println("pid\tsyscall")
for {
if exit {
err = unix.PtraceGetRegs(pid, ®s)
if err != nil {
break
}
name, err := seccomp.ScmpSyscall(regs.Orig_rax).GetName()
if err != nil {
fmt.Printf("error getting syscall name for orig_rax %d\n", regs.Orig_rax)
}
fmt.Printf("%d\t%s\n", pid, name)
}
if err = unix.PtraceSyscall(pid, 0); err != nil {
log.Fatalf("error calling ptrace syscall: %s\n", err)
}
// TODO: is it OK to overwrite pid here?
pid, err = unix.Wait4(pid, &status, 0, nil)
if err != nil {
log.Fatalf("error calling wait")
}
exit = !exit
}
}
В целях тестирования я написал сценарий Python, который использует многопроцессорность и печатает идентификаторы процессов, которые он породил.
import multiprocessing
import os
def fun(x):
return os.getpid()
if __name__ == "__main__":
print("PYTHON: starting multiprocessing pool")
with multiprocessing.Pool() as pool:
processes = pool.map(fun, range(1000000))
print("PYTHON: ended multiprocessing pool")
processes = map(str, set(processes))
print("PYTHON: process IDs: ", ", ".join(processes))
Когда я запускаю приведенный выше код Go в одной программе процесса, например ls
, все работает нормально.
go run . ls
Но когда я запускаю код Go в сценарии Python, вывод зависает (но только если я предоставлю параметры ptrace, упомянутые выше).
go run . python script.py
Моя конечная цель для этой программы - получить список всех файлов, которые использует программа. Я буду проверять /proc/PID/maps
для каждого системного вызова для этой части, но сначала я хотел бы узнать, как отслеживать многопроцессорные программы. Я попытался просмотреть документацию и код для strace, но это еще больше сбило меня с толку ...