Go使用dlv調試代碼


用 dlv 調試

那有同學問了,有沒有其他可以調試 Go、以及和 Go 程序互動的方法呢?其實是有的!這就是我們要介紹的 dlv 調試工具,目前它對調試 Go 程序的支持是最好的。

之前沒我怎么研究它,只會一些非常簡單的命令,這次學會了幾個進階的指令,威力挺大,也進一步加深了對 Go 的理解。

下面我們帶着一個任務來講解 dlv 如何使用。

我們知道,向一個 nil 的 slice append 元素,不會有任何問題。但是向一個 nil 的 map 插入新元素,馬上就會報 panic。這是為什么呢?又是在哪 panic 呢?

首先寫出讓 map 產生 panic 的示例程序:

package main

func main() {
    var m map[int]int
    m[1] = 1
}

接着用 go build 命令編譯生成可執行文件:

go build a.go

然后,使用 dlv 進入調試狀態:

dlv exec ./a

使用 b 這個命令打斷點,有三種方法:

  1. b + 地址
  2. b + 代碼行數
  3. b + 函數名

我們要在對 map 賦值的地方加個斷點。先找到代碼位置:

cat -n main.go

看到:

賦值的地方在第 5 行,加斷點:

(dlv) b a.go:5
Breakpoint 1 set at 0x45e55d for main.main() ./a.go:5

執行 c 命令,直接運行到斷點處:


運行到斷點處

執行 disass 命令,可以看到匯編指令:


disass

這時使用 si 命令,執行單條指令,多次執行 si,就會執行到 map 賦值函數 mapassign_fast64


mapassign_fast64

這時再用單步命令 s,就會進入判斷 h 的值為 nil 的分支,然后執行 panic 函數:


panic

至此,向 nil 的 map 賦值時,產生 panic 的代碼就被我們找到了。接着,按圖索驥找到對應 runtime 源碼的位置,就可以進一步探索了。

除此之外,我們還可以使用 bt 命令看到調用棧:


調用棧

使用 frame 1 命令可以跳轉到相應位置。這里 1 對應圖中的 a.go:5,也就是我們前面打斷點的地方,是不是非常酷炫。

上面這張圖里我們也能清楚地看到,用戶 goroutine 其實是被 goexit 函數一路調用過來的。當用戶 goroutine 執行完畢后,就會回到 goexit 函數做一些收尾工作。當然,這是題外話了。

另外,用 dlv 也能干第二部分“找到 runtime 源碼”活。

總結

今天系統地講了幾招通過命令和工具查看用戶代碼對應的 runtime 源碼或者匯編代碼的方法,非常實用。最后再匯總一下:

  1. go tool compile
  2. go tool objdump
  3. dlv

使用這些命令和工具,可以讓你在看 Go 源碼的過程中事半功倍。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM