調試Go語言的核心轉儲(Core Dumps)

翻譯原文連接 轉帖/轉載請註明出處linux

英文原文連接【Go, the unwritten parts】 發表於2017/05/22 做者JBD是Go語言開發小組成員git

檢查程序的執行路徑和當前狀態是很是有用的調試手段。核心文件(core file)包含了一個運行進程的內存轉儲和狀態。它主要是用來做爲過後調試程序用的。它也能夠被用來查看一個運行中的程序的狀態。這兩個使用場景使調試文件轉儲成爲一個很是好的診斷手段。咱們能夠用這個方法來作過後診斷和分析線上的服務(production services)。github

在這篇文章中,咱們將用一個簡單的hello world網站服務做爲例子。在現實中,咱們的程序很容易就會變得很複雜。分析核心轉儲給咱們提供了一個機會去重構程序的狀態而且查看只有在某些條件/環境下才能重現的案例。服務器

做者注: 這個調試流程只在Linux上可行。我不是很肯定它是否在其它Unixs系統上工做。macOS對此還不支持。Windows如今也不支持。函數

在咱們開始前,須要確保核心轉儲的ulimit設置在合適的範圍。它的缺省值是0,意味着最大的核心文件大小是0。我一般在個人開發機器上將它設置成unlimited。使用如下命令:post

$ ulimit -c unlimited

接下來,你須要在你的機器上安裝delve網站

下面咱們使用的main.go文件。它註冊了一個簡單的請求處理函數(handler)而後啓動了HTTP服務。ui

$ cat main.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "hello world\n")
    })
    log.Fatal(http.ListenAndServe("localhost:7777", nil))
}

讓咱們編譯並生產二進制文件。翻譯

$ go build .

如今讓咱們假設,這個服務器出了些問題,可是咱們並非很肯定問題的根源。你可能已經在程序里加了不少輔助信息,但仍是沒法從這些調試信息中找出線索。一般在這種狀況下,當前進程的快照會很是有用。咱們能夠用這個快照深刻查看程序的當前狀態。debug

有幾個方式來獲取核心文件。你可能已經熟悉了奔潰轉儲(crash dumps)。它們是在一個程序奔潰的時候寫入磁盤的核心轉儲。Go語言在缺省設置下不會生產奔潰轉儲。可是當你把GOTRACEBACK環境變量設置成「crash」,你就能夠用Ctrl+backslash才觸發奔潰轉儲。以下圖所示:

$ GOTRACEBACK=crash ./hello
(Ctrl+\)

上面的操做會使程序終止,將堆棧跟蹤(stack trace)打印出來,並把核心轉儲文件寫入磁盤。

另外個方法能夠從一個運行的程序得到核心轉儲而不須要終止相應的進程。gcore能夠生產核心文件而無需使運行中的程序退出。

$ ./hello &
$ gcore 546 # 546 is the PID of hello.

根據上面的操做,咱們得到了轉儲而沒有終止對應的進程。下一步就是把核心文件加載進delve並開始分析。

$ dlv core ./hello core.546

差很少就這些。delve的經常使用操做均可以使用。你能夠backtrace,list,查看變量等等。有些功能不可用由於咱們使用的核心轉儲是一個快照而不是正在運行的進程。可是程序執行路徑和狀態所有能夠訪問。

(dlv) bt
 0  0x0000000000457774 in runtime.raise
    at /usr/lib/go/src/runtime/sys_linux_amd64.s:110
 1  0x000000000043f7fb in runtime.dieFromSignal
    at /usr/lib/go/src/runtime/signal_unix.go:323
 2  0x000000000043f9a1 in runtime.crash
    at /usr/lib/go/src/runtime/signal_unix.go:409
 3  0x000000000043e982 in runtime.sighandler
    at /usr/lib/go/src/runtime/signal_sighandler.go:129
 4  0x000000000043f2d1 in runtime.sigtrampgo
    at /usr/lib/go/src/runtime/signal_unix.go:257
 5  0x00000000004579d3 in runtime.sigtramp
    at /usr/lib/go/src/runtime/sys_linux_amd64.s:262
 6  0x00007ff68afec330 in (nil)
    at :0
 7  0x000000000040f2d6 in runtime.notetsleep
    at /usr/lib/go/src/runtime/lock_futex.go:209
 8  0x0000000000435be5 in runtime.sysmon
    at /usr/lib/go/src/runtime/proc.go:3866
 9  0x000000000042ee2e in runtime.mstart1
    at /usr/lib/go/src/runtime/proc.go:1182
10  0x000000000042ed04 in runtime.mstart
    at /usr/lib/go/src/runtime/proc.go:1152

(dlv) ls
> runtime.raise() /usr/lib/go/src/runtime/sys_linux_amd64.s:110 (PC: 0x457774)
   105:     SYSCALL
   106:     MOVL    AX, DI  // arg 1 tid
   107:     MOVL    sig+0(FP), SI   // arg 2
   108:     MOVL    $200, AX    // syscall - tkill
   109:     SYSCALL
=> 110:     RET
   111:
   112: TEXT runtime·raiseproc(SB),NOSPLIT,$0
   113:     MOVL    $39, AX // syscall - getpid
   114:     SYSCALL
   115:     MOVL    AX, DI  // arg 1 pid
相關文章
相關標籤/搜索