Skip to content

Latest commit

 

History

History
258 lines (188 loc) · 9.8 KB

File metadata and controls

258 lines (188 loc) · 9.8 KB

11.2 Debugging with GDB

Development process during debugging code that developers often need to do one thing, Go language like PHP, Python and other dynamic languages ​​, as long as the modifications do not need to compile can be directly output, and can dynamically at runtime environments print data. Go language course can also Println like the print data to debug, but need to be recompiled each time, which is a very troublesome thing. We know that in Python with pdb / ipdb tools such as debugging, Javascript has similar tools that are able to dynamically display variable information, single-step debugging. But fortunately Go has a similar tool support : GDB. Go inside has built in support for GDB, so we can GDB for debugging, then this section will introduce how GDB to debug Go program.

GDB debugging Profile

GDB is the FSF (Free Software Foundation) published a powerful UNIX-like system under the program debugging tool. Using GDB can do the following things:

  1. Start the program, you can customize according to the developer's requirements to run the program.
  2. Allows the program being debugged by setting the tone in the development of home stopped at a breakpoint. (Breakpoints can be conditional expression)
  3. When the program is stopped, you can check the program at this time what happened.
  4. To dynamically change the current program execution environment.

Go program currently supports the GDB debugger version must be greater than 7.1.

Go program compiled the following points should be noted when

  1. Passing Parameters -ldflags "-s", ignoring the print debug information
  2. pass -gcflags "-N-l" parameter, so you can ignore Go inside to do some optimization, optimization of aggregate variables and functions, etc., so for GDB debugger is very difficult, so at compile time to join these two parameters to avoid these optimizations.

Common commands

GDB of some commonly used commands are as follows

  • list

Abbreviated command l, is used to display the source code, the default display ten lines of code, you can bring back a specific line parameter display, for example : list 15, display ten lines of code, of which the first 15 rows displayed inside ten lines in the middle, as shown below.

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

Abbreviated command b, used to set breakpoints, followed by the number of rows parameter setting breakpoints, such as b 10 set a breakpoint in the tenth row.

  • delete Abbreviated command d, to delete a breakpoint, the breakpoint is set followed by the serial number, the serial number can be obtained through the info breakpoints breakpoint set corresponding serial number is displayed as follows to set a breakpoint number.

    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

Abbreviated command bt, the process used to print the execution of the code, as follows:

#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 command to display information, followed by several parameters, we used the following categories:

  • info locals

Displays the currently executing program variable values

  • info breakpoints

Display a list of currently set breakpoints

  • info goroutines

Goroutine displays the current list of execution, as shown in the code, with* indicates the current execution

* 1 running runtime.gosched
* 2 syscall runtime.entersyscall
3 waiting runtime.gosched
4 runnable runtime.gosched
  • print

Abbreviated command p, or other information used to print variable, followed by the variable name to be printed, of course, there are some very useful function $len() and $cap(), is used to return the current string, slices or maps the length and capacity.

  • whatis

Used to display the current variable type, followed by the variable name, for example, whatis msg, is shown below :

type = struct string

  • next

Abbreviated command n, for single-step debugging, skip the next step, when there is a breakpoint, you can enter n jump to the next step to continue

  • coutinue

Abbreviated command c, to jump out of the current breakpoint can be followed by parameter N, the number of times the breakpoint skipped

  • set variable

This command is used to change the value of a variable during operation, formats such as : set variable <var> = <value>

Debugging process

We use the following code to demonstrate how this GDB to debug Go program, the following is the code that will be demonstrated :

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)
	}
}

Compiled file, an executable file gdbfile:

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

By gdb command to start debugging :

gdb gdbfile

After the first start is not possible to look at this program up and running, just enter the run command carriage return after the program starts to run, the program correctly, then you can see the program output is as follows, and we execute the program directly from the command line output is the same:

(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]	

Well, now we know how to make the program run up, then began to give the code to set a breakpoint :

(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)

The above example shows the b 23 set a breakpoint on line 23, then enter run start the program running. The program now in place to set a breakpoint in front stopped, we need to look at the context of the breakpoint corresponding source code, enter list you can see the display from the current source line before stopping five starts :

(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	}

GDB now running the current program environment has retained some useful debugging information, we just print out the corresponding variables, see the corresponding variable types and values:

(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

Then let the program continue down the execution, please read the following command

(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)

After each entry c code will be executed once, and jump to the next for loop, continue to print out the appropriate information.

Assume that current need to change the context variables, skipping the process and continue to the next step, the modified desired results obtained :

(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)		

Finally a little thought, in front of the entire program is running in the process in the end created a number goroutine, each goroutine are doing :

(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 ?? ()

Commands by viewing goroutines we can clearly understand goruntine performed internally how each function call sequence has plainly shown.

Summary

In this section we introduce the GDB debugger Go program some basic commands, including the run, print, info, set variable, coutinue, list, break and other frequently used debugging commands, by the above examples demonstrate, I believe, through the GDB debugger for the reader has a basic understanding of Go programs, if you want to get more debugging tips, please refer to the official website of the GDB debugger manual, as well as the official website of the GDB manual.

Links