3

Go からプログラムを呼び出すときにシステムコールをインターセプトしようとしていますが、2 つの問題が発生しています。

子がハングしているように見え、親プロセスもハングします。奇妙に思えるwait4(2)ブロッキングのようです。子供は最終的exit(2)に終了するように呼び出しませんか?

私が取得したシステムコールstdoutは一貫していません。最後のシステムコールが である場合もあれば、3または6である場合もあります192。コードに競合状態がありますか? なぜこれが起こるのですか?

親で信号をリッスンしようとしましたが、何も受信しません..

普段実行しているプログラムを に置き換えました/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)
}
4

1 に答える 1

1

簡単に言えば、Go でシステムコールをインターセプトするのは非常に難しく、ptrace はおそらく何も機能しないということです。

Go には、go ルーチンを OS スレッドに多重化するランタイムがあります。syscall はスケジューリング ポイントであるため、syscall が戻った後は別のスレッドにいる可能性がありますが、ptrace は単一のスレッドに従うと思います。

ptrace しているスレッドがメインの go-routine を実行しているとします。次に、(syscall.Write を実行する) fmt.Println を呼び出すと、Go ランタイムはそのスレッドから go-routine を取得し、別の OS スレッドで syscall を実行します (syscall は常に別のスレッドで実行されます)。syscall が戻ると、メインの go-routine が実行可能なルーチンのスケジューラ リストに戻され、使用可能な OS スレッド (ptrace を実行しているスレッドではない可能性があります) で続行されます。

これは、 を使用して Go プログラムをステップ実行できない理由でもありますgdb

外部プログラム (/bin/ls など) を実行したいだけの場合は、標準ライブラリのos/execを使用できます。

あなたがやろうとしていることに近いプログラムは、おそらくdelveです。各シングルステップですべてのスレッドにブレークポイントを設定し、go-routine id に基づいて go-routine が現在どのスレッドにあるかを見つけようとします。

于 2015-07-30T22:31:17.103 に答える