濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)

Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)

熱門(mén)標(biāo)簽:揚(yáng)州電銷(xiāo)外呼系統(tǒng)軟件 百度地圖標(biāo)注位置網(wǎng)站 武漢百應(yīng)人工智能電銷(xiāo)機(jī)器人 電腦外呼系統(tǒng)輻射大嗎 上海企業(yè)外呼系統(tǒng)排名 智能語(yǔ)音電銷(xiāo)的機(jī)器人 開(kāi)通400電話申請(qǐng)流程 如何利用高德地圖標(biāo)注家 400手機(jī)電話免費(fèi)辦理

一、什么是系統(tǒng)調(diào)用

In computing, a system call is the programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on. This may include hardware-related services (for example, accessing a hard disk drive), creation and execution of new processes, and communication with integral kernel services such as process scheduling. System calls provide an essential interface between a process and the operating system.

系統(tǒng)調(diào)用是程序向操作系統(tǒng)內(nèi)核請(qǐng)求服務(wù)的過(guò)程,通常包含硬件相關(guān)的服務(wù)(例如訪問(wèn)硬盤(pán)),創(chuàng)建新進(jìn)程等。系統(tǒng)調(diào)用提供了一個(gè)進(jìn)程和操作系統(tǒng)之間的接口。

二、Golang標(biāo)準(zhǔn)庫(kù)-syscall

syscall包包含一個(gè)指向底層操作系統(tǒng)原語(yǔ)的接口。

注意:該軟件包已被鎖定。標(biāo)準(zhǔn)以外的代碼應(yīng)該被遷移到golang.org/x/sys存儲(chǔ)庫(kù)中使用相應(yīng)的軟件包。這也是應(yīng)用新系統(tǒng)或版本所需更新的地方。 Signal , Errno 和 SysProcAttr 在 golang.org/x/sys 中尚不可用,并且仍然必須從 syscall 程序包中引用。有關(guān)更多信息,請(qǐng)參見(jiàn) https://golang.org/s/go1.4-syscall。

https://pkg.go.dev/golang.org/x/sys
該存儲(chǔ)庫(kù)包含用于與操作系統(tǒng)進(jìn)行低級(jí)交互的補(bǔ)充Go軟件包。

1. syscall無(wú)處不在

舉個(gè)最常用的例子, fmt.Println(“hello world”), 這里就用到了系統(tǒng)調(diào)用 write, 我們翻一下源碼。

func Println(a ...interface{}) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
 
func (f *File) write(b []byte) (n int, err error) {
    if len(b) == 0 {
        return 0, nil
    }
    // 實(shí)際的write方法,就是調(diào)用syscall.Write()
    return fixCount(syscall.Write(f.fd, b))
}

2. syscall demo舉例:

 go版本的strace Strace

strace 是用于查看進(jìn)程系統(tǒng)調(diào)用的工具, 一般使用方法如下:

strace -c 用于統(tǒng)計(jì)各個(gè)系統(tǒng)調(diào)用的次數(shù)

[root@localhost ~]# strace -c echo hello
hello
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         1           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0         3           open
  0.00    0.000000           0         5           close
  0.00    0.000000           0         4           fstat
  0.00    0.000000           0         9           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         2           munmap
  0.00    0.000000           0         4           brk
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    36         1 total
[root@localhost ~]#

stace 的實(shí)現(xiàn)原理是系統(tǒng)調(diào)用 ptrace, 我們來(lái)看下 ptrace 是什么。

man page 描述如下:

The ptrace() system call provides a means by which one process (the “tracer”) may observe and control the execution of another process (the “tracee”), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debuggingand system call tracing.

簡(jiǎn)單來(lái)說(shuō)有三大能力:

追蹤系統(tǒng)調(diào)用
讀寫(xiě)內(nèi)存和寄存器
向被追蹤程序傳遞信號(hào)

ptrace接口:

int ptrace(int request, pid_t pid, caddr_t addr, int data);
 
request包含:
PTRACE_ATTACH
PTRACE_SYSCALL
PTRACE_PEEKTEXT, PTRACE_PEEKDATA
等

tracer 使用 PTRACE_ATTACH 命令,指定需要追蹤的PID。緊接著調(diào)用 PTRACE_SYSCALL。
tracee 會(huì)一直運(yùn)行,直到遇到系統(tǒng)調(diào)用,內(nèi)核會(huì)停止執(zhí)行。 此時(shí),tracer 會(huì)收到 SIGTRAP 信號(hào),tracer 就可以打印內(nèi)存和寄存器中的信息了。

接著,tracer 繼續(xù)調(diào)用 PTRACE_SYSCALL, tracee 繼續(xù)執(zhí)行,直到 tracee退出當(dāng)前的系統(tǒng)調(diào)用。
需要注意的是,這里在進(jìn)入syscall和退出syscall時(shí),tracer都會(huì)察覺(jué)。

go版本的strace

了解以上內(nèi)容后,presenter 現(xiàn)場(chǎng)實(shí)現(xiàn)了一個(gè)go版本的strace, 需要在 linux amd64 環(huán)境編譯。
https://github.com/silentred/gosys

// strace.go

package main
 
import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)
 
func main() {
    var err error
    var regs syscall.PtraceRegs
    var ss syscallCounter
    ss = ss.init()
 
    fmt.Println("Run: ", os.Args[1:])
 
    cmd := exec.Command(os.Args[1], os.Args[2:]...)
    cmd.Stderr = os.Stderr
    cmd.Stdout = os.Stdout
    cmd.Stdin = os.Stdin
    cmd.SysProcAttr = syscall.SysProcAttr{
        Ptrace: true,
    }
 
    cmd.Start()
    err = cmd.Wait()
    if err != nil {
        fmt.Printf("Wait err %v \n", err)
    }
 
    pid := cmd.Process.Pid
    exit := true
 
    for {
        // 記得 PTRACE_SYSCALL 會(huì)在進(jìn)入和退出syscall時(shí)使 tracee 暫停,所以這里用一個(gè)變量控制,RAX的內(nèi)容只打印一遍
        if exit {
            err = syscall.PtraceGetRegs(pid, regs)
            if err != nil {
                break
            }
            //fmt.Printf("%#v \n",regs)
            name := ss.getName(regs.Orig_rax)
            fmt.Printf("name: %s, id: %d \n", name, regs.Orig_rax)
            ss.inc(regs.Orig_rax)
        }
        // 上面Ptrace有提到的一個(gè)request命令
        err = syscall.PtraceSyscall(pid, 0)
        if err != nil {
            panic(err)
        }
        // 猜測(cè)是等待進(jìn)程進(jìn)入下一個(gè)stop,這里如果不等待,那么會(huì)打印大量重復(fù)的調(diào)用函數(shù)名
        _, err = syscall.Wait4(pid, nil, 0, nil)
        if err != nil {
            panic(err)
        }
 
        exit = !exit
    }
 
    ss.print()
}

// 用于統(tǒng)計(jì)信息的counter, syscallcounter.go

package main
 
import (
    "fmt"
    "os"
    "text/tabwriter"
 
    "github.com/seccomp/libseccomp-golang"
)
 
type syscallCounter []int
 
const maxSyscalls = 303
 
func (s syscallCounter) init() syscallCounter {
    s = make(syscallCounter, maxSyscalls)
    return s
}
 
func (s syscallCounter) inc(syscallID uint64) error {
    if syscallID > maxSyscalls {
        return fmt.Errorf("invalid syscall ID (%x)", syscallID)
    }
 
    s[syscallID]++
    return nil
}
 
func (s syscallCounter) print() {
    w := tabwriter.NewWriter(os.Stdout, 0, 0, 8, ' ', tabwriter.AlignRight|tabwriter.Debug)
    for k, v := range s {
        if v > 0 {
            name, _ := seccomp.ScmpSyscall(k).GetName()
            fmt.Fprintf(w, "%d\t%s\n", v, name)
        }
    }
    w.Flush()
}
 
func (s syscallCounter) getName(syscallID uint64) string {
    name, _ := seccomp.ScmpSyscall(syscallID).GetName()
    return name
}

最后結(jié)果:

Run:  [echo hello]
Wait err stop signal: trace/breakpoint trap
name: execve, id: 59
name: brk, id: 12
name: access, id: 21
name: mmap, id: 9
name: access, id: 21
name: open, id: 2
name: fstat, id: 5
name: mmap, id: 9
name: close, id: 3
name: access, id: 21
name: open, id: 2
name: read, id: 0
name: fstat, id: 5
name: mmap, id: 9
name: mprotect, id: 10
name: mmap, id: 9
name: mmap, id: 9
name: close, id: 3
name: mmap, id: 9
name: arch_prctl, id: 158
name: mprotect, id: 10
name: mprotect, id: 10
name: mprotect, id: 10
name: munmap, id: 11
name: brk, id: 12
name: brk, id: 12
name: open, id: 2
name: fstat, id: 5
name: mmap, id: 9
name: close, id: 3
name: fstat, id: 5
hello
name: write, id: 1
name: close, id: 3
name: close, id: 3
        1|read
        1|write
        3|open
        5|close
        4|fstat
        7|mmap
        4|mprotect
        1|munmap
        3|brk
        3|access
        1|execve
        1|arch_prctl

三、參考

Golang標(biāo)準(zhǔn)庫(kù)——syscall
參考URL: https://www.jianshu.com/p/44109d5e045b
Golang 與系統(tǒng)調(diào)用
參考URL: https://blog.csdn.net/weixin_33744141/article/details/89033990

以上就是Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)的詳細(xì)內(nèi)容,更多關(guān)于Golang標(biāo)準(zhǔn)庫(kù)syscall的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • 解決Golang 中使用WaitGroup的那點(diǎn)坑
  • 在golang中使用Sync.WaitGroup解決等待的問(wèn)題
  • Golang中的sync包的WaitGroup操作
  • Golang中的sync.WaitGroup用法實(shí)例
  • Golang的os標(biāo)準(zhǔn)庫(kù)中常用函數(shù)的整理介紹
  • Golang 標(biāo)準(zhǔn)庫(kù) tips之waitgroup詳解

標(biāo)簽:宜賓 江西 張掖 黑龍江 延邊 嘉峪關(guān) 武漢 新余

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)》,本文關(guān)鍵詞  Golang,標(biāo)準(zhǔn),庫(kù),syscall,詳解,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于Golang標(biāo)準(zhǔn)庫(kù)syscall詳解(什么是系統(tǒng)調(diào)用)的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    兰溪市| 镇原县| 涞源县| 项城市| 江孜县| 黎平县| 甘泉县| 平果县| 醴陵市| 方山县| 察隅县| 临安市| 错那县| 建阳市| 南华县| 松阳县| 北辰区| 克东县| 正阳县| 晴隆县| 武山县| 青州市| 兖州市| 大足县| 筠连县| 崇左市| 上饶县| 宿州市| 德清县| 缙云县| 屏边| 桑日县| 南溪县| 新宁县| 武城县| 夏河县| 桂林市| 塘沽区| 商都县| 莲花县| 石首市|