在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ 11.2 使用GDB調(diào)試
7 文本處理
3 Web基礎(chǔ)
14 擴(kuò)展Web框架
10.4 小結(jié)
2.2 Go基礎(chǔ)
2.8 總結(jié)
6.1 session和cookie
5.5 使用beedb庫進(jìn)行ORM開發(fā)
8.3 REST
13.6 小結(jié)
5.4 使用PostgreSQL數(shù)據(jù)庫
14.6 pprof支持
14.1 靜態(tài)文件支持
11.2 使用GDB調(diào)試
7.7 小結(jié)
1 GO環(huán)境配置
14.5 多語言支持
7.1 XML處理
1.5 總結(jié)
13 如何設(shè)計(jì)一個Web框架
14.3 表單及驗(yàn)證支持
12 部署與維護(hù)
10 國際化和本地化
1.1 Go 安裝
6.2 Go如何使用session
5.6 NOSQL數(shù)據(jù)庫操作
6.5 小結(jié)
9.4 避免SQL注入
12.1 應(yīng)用日志
4.2 驗(yàn)證表單的輸入
10.1 設(shè)置默認(rèn)地區(qū)
1.3 Go 命令
9.6 加密和解密數(shù)據(jù)
4.1 處理表單的輸入
4.4 防止多次遞交表單
11.3 Go怎么寫測試用例
8 Web服務(wù)
12.3 應(yīng)用部署
5.7 小結(jié)
12.5 小結(jié)
11 錯誤處理,調(diào)試和測試
9.2 確保輸入過濾
14.2 Session支持
6.4 預(yù)防session劫持
12.4 備份和恢復(fù)
8.1 Socket編程
13.1 項(xiàng)目規(guī)劃
13.4 日志和配置設(shè)計(jì)
7.6 字符串處理
13.2 自定義路由器設(shè)計(jì)
6.3 session存儲
3.4 Go的http包詳解
8.2 WebSocket
10.3 國際化站點(diǎn)
7.5 文件操作
7.4 模板處理
9.1 預(yù)防CSRF攻擊
13.3 controller設(shè)計(jì)
2.6 interface
14.4 用戶認(rèn)證
2.3 流程和函數(shù)
附錄A 參考資料
11.1 錯誤處理
9.5 存儲密碼
9.3 避免XSS攻擊
12.2 網(wǎng)站錯誤處理
6 session和數(shù)據(jù)存儲
2.4 struct類型
3.3 Go如何使得Web工作
2.5 面向?qū)ο?/span>
3.1 Web工作方式
1.2 GOPATH與工作空間
2.1 你好,Go
9.7 小結(jié)
13.5 實(shí)現(xiàn)博客的增刪改
7.2 JSON處理
10.2 本地化資源
7.3 正則處理
2 Go語言基礎(chǔ)
5.1 database/sql接口
4.5 處理文件上傳
8.5 小結(jié)
4.3 預(yù)防跨站腳本
5.3 使用SQLite數(shù)據(jù)庫
14.7 小結(jié)
3.2 Go搭建一個Web服務(wù)器
2.7 并發(fā)
5 訪問數(shù)據(jù)庫
4 表單
3.5 小結(jié)
1.4 Go開發(fā)工具
11.4 小結(jié)
9 安全與加密
5.2 使用MySQL數(shù)據(jù)庫
4.6 小結(jié)
8.4 RPC

11.2 使用GDB調(diào)試

開發(fā)程序過程中調(diào)試代碼是開發(fā)者經(jīng)常要做的一件事情,Go語言不像PHP、Python等動態(tài)語言,只要修改不需要編譯就可以直接輸出,而且可以動態(tài)的在運(yùn)行環(huán)境下打印數(shù)據(jù)。當(dāng)然Go語言也可以通過Println之類的打印數(shù)據(jù)來調(diào)試,但是每次都需要重新編譯,這是一件相當(dāng)麻煩的事情。我們知道在Python中有pdb/ipdb之類的工具調(diào)試,Javascript也有類似工具,這些工具都能夠動態(tài)的顯示變量信息,單步調(diào)試等。不過慶幸的是Go也有類似的工具支持:GDB。Go內(nèi)部已經(jīng)內(nèi)置支持了GDB,所以,我們可以通過GDB來進(jìn)行調(diào)試,那么本小節(jié)就來介紹一下如何通過GDB來調(diào)試Go程序。

GDB調(diào)試簡介

GDB是FSF(自由軟件基金會)發(fā)布的一個強(qiáng)大的類UNIX系統(tǒng)下的程序調(diào)試工具。使用GDB可以做如下事情:

  1. 啟動程序,可以按照開發(fā)者的自定義要求運(yùn)行程序。
  2. 可讓被調(diào)試的程序在開發(fā)者設(shè)定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)
  3. 當(dāng)程序被停住時,可以檢查此時程序中所發(fā)生的事。
  4. 動態(tài)的改變當(dāng)前程序的執(zhí)行環(huán)境。

目前支持調(diào)試Go程序的GDB版本必須大于7.1。

編譯Go程序的時候需要注意以下幾點(diǎn)

  1. 傳遞參數(shù)-ldflags "-s",忽略debug的打印信息
  2. 傳遞-gcflags "-N -l" 參數(shù),這樣可以忽略Go內(nèi)部做的一些優(yōu)化,聚合變量和函數(shù)等優(yōu)化,這樣對于GDB調(diào)試來說非常困難,所以在編譯的時候加入這兩個參數(shù)避免這些優(yōu)化。

常用命令

GDB的一些常用命令如下所示

  • list

    簡寫命令l,用來顯示源代碼,默認(rèn)顯示十行代碼,后面可以帶上參數(shù)顯示的具體行,例如:list 15,顯示十行代碼,其中第15行在顯示的十行里面的中間,如下所示。

      10          time.Sleep(2 * time.Second)
      11          c <- i
      12      }
      13      close(c)
      14  }
      15  
      16  func main() {
      17      msg := "Starting main"
      18      fmt.Println(msg)
      19      bus := make(chan int)
  • break

    簡寫命令 b,用來設(shè)置斷點(diǎn),后面跟上參數(shù)設(shè)置斷點(diǎn)的行數(shù),例如b 10在第十行設(shè)置斷點(diǎn)。

  • delete 簡寫命令 d,用來刪除斷點(diǎn),后面跟上斷點(diǎn)設(shè)置的序號,這個序號可以通過info breakpoints獲取相應(yīng)的設(shè)置的斷點(diǎn)序號,如下是顯示的設(shè)置斷點(diǎn)序號。

      Num     Type           Disp Enb Address            What
      2       breakpoint     keep y   0x0000000000400dc3 in main.main at /home/xiemengjun/gdb.go:23
      breakpoint already hit 1 time
  • backtrace

    簡寫命令 bt,用來打印執(zhí)行的代碼過程,如下所示:

      #0  main.main () at /home/xiemengjun/gdb.go:23
      #1  0x000000000040d61e in runtime.main () at /home/xiemengjun/go/src/pkg/runtime/proc.c:244
      #2  0x000000000040d6c1 in schedunlock () at /home/xiemengjun/go/src/pkg/runtime/proc.c:267
      #3  0x0000000000000000 in ?? ()
  • info

    info命令用來顯示信息,后面有幾種參數(shù),我們常用的有如下幾種:

    • info locals

      顯示當(dāng)前執(zhí)行的程序中的變量值
    • info breakpoints

      顯示當(dāng)前設(shè)置的斷點(diǎn)列表
    • info goroutines

      顯示當(dāng)前執(zhí)行的goroutine列表,如下代碼所示,帶*的表示當(dāng)前執(zhí)行的
      
          * 1  running runtime.gosched
          * 2  syscall runtime.entersyscall
            3  waiting runtime.gosched
            4 runnable runtime.gosched
  • print

    簡寫命令p,用來打印變量或者其他信息,后面跟上需要打印的變量名,當(dāng)然還有一些很有用的函數(shù)$len()和$cap(),用來返回當(dāng)前string、slices或者maps的長度和容量。

  • whatis

    用來顯示當(dāng)前變量的類型,后面跟上變量名,例如whatis msg,顯示如下:

      type = struct string
  • next

    簡寫命令 n,用來單步調(diào)試,跳到下一步,當(dāng)有斷點(diǎn)之后,可以輸入n跳轉(zhuǎn)到下一步繼續(xù)執(zhí)行

  • coutinue

    簡稱命令 c,用來跳出當(dāng)前斷點(diǎn)處,后面可以跟參數(shù)N,跳過多少次斷點(diǎn)

  • set variable

    該命令用來改變運(yùn)行過程中的變量值,格式如:set variable <var>=<value>

調(diào)試過程

我們通過下面這個代碼來演示如何通過GDB來調(diào)試Go程序,下面是將要演示的代碼:

package main

import (
    "fmt"
    "time"
)

func counting(c chan<- int) {
    for i := 0; i < 10; i++ {
        time.Sleep(2 * time.Second)
        c <- i
    }
    close(c)
}

func main() {
    msg := "Starting main"
    fmt.Println(msg)
    bus := make(chan int)
    msg = "starting a gofunc"
    go counting(bus)
    for count := range bus {
        fmt.Println("count:", count)
    }
}

編譯文件,生成可執(zhí)行文件gdbfile:

go build -gcflags "-N -l" gdbfile.go

通過gdb命令啟動調(diào)試:

gdb gdbfile

啟動之后首先看看這個程序是不是可以運(yùn)行起來,只要輸入run命令回車后程序就開始運(yùn)行,程序正常的話可以看到程序輸出如下,和我們在命令行直接執(zhí)行程序輸出是一樣的:

(gdb) run
Starting program: /home/xiemengjun/gdbfile 
Starting main
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
[LWP 2771 exited]
[Inferior 1 (process 2771) exited normally] 

好了,現(xiàn)在我們已經(jīng)知道怎么讓程序跑起來了,接下來開始給代碼設(shè)置斷點(diǎn):

(gdb) b 23
Breakpoint 1 at 0x400d8d: file /home/xiemengjun/gdbfile.go, line 23.
(gdb) run
Starting program: /home/xiemengjun/gdbfile 
Starting main
[New LWP 3284]
[Switching to LWP 3284]

Breakpoint 1, main.main () at /home/xiemengjun/gdbfile.go:23
23          fmt.Println("count:", count)

上面例子b 23表示在第23行設(shè)置了斷點(diǎn),之后輸入run開始運(yùn)行程序?,F(xiàn)在程序在前面設(shè)置斷點(diǎn)的地方停住了,我們需要查看斷點(diǎn)相應(yīng)上下文的源碼,輸入list就可以看到源碼顯示從當(dāng)前停止行的前五行開始:

(gdb) list
18      fmt.Println(msg)
19      bus := make(chan int)
20      msg = "starting a gofunc"
21      go counting(bus)
22      for count := range bus {
23          fmt.Println("count:", count)
24      }
25  }

現(xiàn)在GDB在運(yùn)行當(dāng)前的程序的環(huán)境中已經(jīng)保留了一些有用的調(diào)試信息,我們只需打印出相應(yīng)的變量,查看相應(yīng)變量的類型及值:

(gdb) info locals
count = 0
bus = 0xf840001a50
(gdb) p count
$1 = 0
(gdb) p bus
$2 = (chan int) 0xf840001a50
(gdb) whatis bus
type = chan int

接下來該讓程序繼續(xù)往下執(zhí)行,請繼續(xù)看下面的命令

(gdb) c
Continuing.
count: 0
[New LWP 3303]
[Switching to LWP 3303]

Breakpoint 1, main.main () at /home/xiemengjun/gdbfile.go:23
23 fmt.Println("count:", count)
(gdb) c
Continuing.
count: 1
[Switching to LWP 3302]

Breakpoint 1, main.main () at /home/xiemengjun/gdbfile.go:23
23 fmt.Println("count:", count)

每次輸入c之后都會執(zhí)行一次代碼,又跳到下一次for循環(huán),繼續(xù)打印出來相應(yīng)的信息。

設(shè)想目前需要改變上下文相關(guān)變量的信息,跳過一些過程,并繼續(xù)執(zhí)行下一步,得出修改后想要的結(jié)果:

(gdb) info locals
count = 2
bus = 0xf840001a50
(gdb) set variable count=9
(gdb) info locals
count = 9
bus = 0xf840001a50
(gdb) c
Continuing.
count: 9
[Switching to LWP 3302]

Breakpoint 1, main.main () at /home/xiemengjun/gdbfile.go:23
23 fmt.Println("count:", count)     

最后稍微思考一下,前面整個程序運(yùn)行的過程中到底創(chuàng)建了多少個goroutine,每個goroutine都在做什么:

(gdb) info goroutines
* 1 running runtime.gosched
* 2 syscall runtime.entersyscall 
3 waiting runtime.gosched 
4 runnable runtime.gosched
(gdb) goroutine 1 bt
#0 0x000000000040e33b in runtime.gosched () at /home/xiemengjun/go/src/pkg/runtime/proc.c:927
#1 0x0000000000403091 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
at /home/xiemengjun/go/src/pkg/runtime/chan.c:327
#2 0x000000000040316f in runtime.chanrecv2 (t=void, c=void)
at /home/xiemengjun/go/src/pkg/runtime/chan.c:420
#3 0x0000000000400d6f in main.main () at /home/xiemengjun/gdbfile.go:22
#4 0x000000000040d0c7 in runtime.main () at /home/xiemengjun/go/src/pkg/runtime/proc.c:244
#5 0x000000000040d16a in schedunlock () at /home/xiemengjun/go/src/pkg/runtime/proc.c:267
#6 0x0000000000000000 in ?? ()

通過查看goroutines的命令我們可以清楚地了解goruntine內(nèi)部是怎么執(zhí)行的,每個函數(shù)的調(diào)用順序已經(jīng)明明白白地顯示出來了。

小結(jié)

本小節(jié)我們介紹了GDB調(diào)試Go程序的一些基本命令,包括run、print、info、set variable、coutinue、list、break 等經(jīng)常用到的調(diào)試命令,通過上面的例子演示,我相信讀者已經(jīng)對于通過GDB調(diào)試Go程序有了基本的理解,如果你想獲取更多的調(diào)試技巧請參考官方網(wǎng)站的GDB調(diào)試手冊,還有GDB官方網(wǎng)站的手冊。