Go源码分析(二)Debug工具

gdb

  • 什么是GDB,GDB官网给出了详细的介绍,下载,以及bug,git地址等
  • 为什么要用它?当你想debug,不知道源代码到底是什么东西的时候,因为只有一个二进制程序;若有太多的goroutine,你根本分不清到底这些里面是什么鬼的时候
  • 如何使用,Golang官网给出了一份教程

命令参数

实战

写一份代码main.go

package main

import "fmt"

func main() {
	for i := 0; i < 10; i++ {
		fmt.Printf("current number is %d", i)
	}
}

编译,依赖GOPATH 设置

go build -gcflags "-N -l"  -o main main.go

开始GDB

[root@bootos src]# gdb main                                                    
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7                           
Copyright (C) 2013 Free Software Foundation, Inc.                              
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.             
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"     
and "show warranty" for details.                                               
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/work/go/src/main...done.
Loading Go Runtime support.
(gdb) 
(gdb) list
1       package main
2
3       import "fmt"
4       func main() {
5               for i := 0; i < 10; i++ {
6                       fmt.Printf("current number is %d\n", i)
7               }
8       }

给第6行添加断点

(gdb) b 6
Breakpoint 1 at 0x488b27: file /home/work/go/src/main.go, line 6.

查看断点;删除断点delete 1

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000488b27 in main.main at /home/work/go/src/main.go:6

开始运行

(gdb) run 
Starting program: /home/work/go/src/main 

Breakpoint 1, main.main () at /home/work/go/src/main.go:6
6                       fmt.Printf("current number is %d\n", i)

查看i的value

(gdb) p i
$1 = 0

i是什么类型的?

(gdb) whatis i
type = int
(gdb) info i
  Num  Description       Executable        
* 1    process 35320     /home/work/go/src/main 

进入函数 fmt.Printf

(gdb) s
fmt.Printf (format="current number is %d\n", a= []interface {} = {...}, n=<optimized out>, err=...) at /root/go/src/fmt/print.go:207
warning: Source file is more recent than executable.
207     func Printf(format string, a ...interface{}) (n int, err error) {

查看代码

(gdb) l
202             return
203     }
204
205     // Printf formats according to a format specifier and writes to standard output.
206     // It returns the number of bytes written and any write error encountered.
207     func Printf(format string, a ...interface{}) (n int, err error) {
208             return Fprintf(os.Stdout, format, a...)
209     }
210
211     // Sprintf formats according to a format specifier and returns the resulting string.

打印参数

(gdb) info args
format = "current number is %d\n"
a =  []interface {} = {{_type = 0x498c60, data = 0x15}}
n = <optimized out>
err = <optimized out>

返回上一层

(gdb) return
Make fmt.Printf return now? (y or n) y
#0  0x0000000000488bb9 in main.main () at /home/work/go/src/main.go:6
6                       fmt.Printf("current number is %d\n", i)

查看当前的goroutines

(gdb) info goroutines 
* 1 running  syscall.Syscall
  2 waiting  runtime.gopark
  3 waiting  runtime.gopark
  17 waiting  runtime.gopark

命令行页面操作的太麻烦了,不够直观,可以使用layout模式

   ┌──/home/work/go/src/main.go──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
   │1       package main                                                                                                                                     │
   │2                                                                                                                                                        │
   │3       import "fmt"   │4       func main() {   │5               for i := 0; i < 10; i++ {   │6                       fmt.Printf("current number is %d\n", i)   │7               }   │8       }                                                                                                                                                
   └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
exec No process In:                                                                                                                         Line: ??   PC: ?? 
warning: Invalid layout specified.
Usage: layout prev | next | <layout_name>

(gdb)  

cgdb

cgdb是gdb的增强版本,若会用gdb和vi,则操作起来更加方便,官方也提供了文件说明。

安装

yum install http://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/c/cgdb-0.6.8-1.el7.x86_64.rpm  -y

Delve

  • Devle 是golang官网提到的一个debug工具,与gdb相比,更好地能够适应golang的runtime机制;