08.19 跟踪系统调用
本节将介绍一种非常先进的技术,它使用syscall包,并允许你监视在Go程序中执行的系统调用。
本节不包含在我的《
Go系统编程》书籍中,Packt出版社,2017年
Go程序名为traceSyscall.go,并分为五部分。traceSyscall.go第一部分代码如下:
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
)
var maxSyscalls = 0
const SYSCALLFILE = "SYSCALLS"你将很快学习SYSCALLFILE变量的作用。
traceSyscall.go第二部分代码如下:
func main() {
var SYSTEMCALLS []string
f, err := os.Open(SYSCALLFILE)
defer f.Close()
if err != nil {
fmt.Println(err)
return
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
line = strings.Replace(line, " ", "", -1)
line = strings.Replace(line, "SYS_", "", -1)
temp := strings.ToLower(strings.Split(line, "=")[0])
SYSTEMCALLS = append(SYSTEMCALLS, temp)
maxSyscalls++
}请注意,SYSCALLS文件的信息取自syscall包的文档,它将每个系统调用与一个数字相关联,该数字是系统调用的内部Go表示形式。该文件主要用于打印被跟踪程序所使用的系统调用的名称。
SYSCALLS文件的格式如下:
在读取文本文件后,程序创建名为SYSTEMCALLS的切片来存储信息。
traceSyscall.go第三部分代码如下:
COUNTER切片存储在被跟踪的程序中每个系统调用的次数。
traceSyscall.go的第四部分代码如下:
syscall.PtraceSyscall()函数的作用是:告诉Go继续执行正在被跟踪的程序,但是当程序进入或退出系统调用时停止执行,这正是我们想要的!由于每个系统调用在被调用之前和完成其工作之后都会被跟踪,因此我们使用before变量来计算每个系统调用仅一次。
traceSyscall.go的最后一部分代码如下:
在这一部分中,我们打印切片COUNTER的内容。切片SYSTEMCALLS用于在知道系统调用的Go数字表示时,来查找系统调用的名称。
在macOS High Sierra机器上执行traceSyscall.go会创建如下的输出:
同样,traceSyscall.go程序不能在macOS和Mac OS X上运行。
在Debian Linux机器上执行程序会创建如下的输出:
在程序结束时,traceSyscall.go打印程序中调用每个系统调用的次数!traceSyscall.go的正确性通过strace -c程序的输出进行验证。
Last updated
Was this helpful?