Go工具和调试详解

栏目: C · 发布时间: 5年前

内容简介:-gcflags: 传递给编译器的参数-ldflags: 传递给链接器的参数-work: 查看编译临时目录

工具集

go build

-gcflags: 传递给编译器的参数

-ldflags: 传递给链接器的参数

-work: 查看编译临时目录

-race: 允许数据竞争检测(仅支持amd64)

-n: 查看但不执行编译指令

-x: 查看并执行编译命令

-a: 强制重新编译所有依赖包

-v: 查看被编译的包名,包括依赖包

-p n:并行编译所使用的CPU数,默认为全部

-o:输出文件名

gcflags:

-B 禁用边界检查

-N 禁用优化

-l 禁用函数内联

-u 禁用unsafe代码

-m 输出优化信息

-S 输出汇编代码

ldflags:

-w 禁用DRAWF调试信息,但不包括符号表

-s 禁用符号表

-X 修改字符串符号值  -X main.VER ‘0.99’  -X main.S ‘abc’

-H 链接文件类型,其中包括windowsgui.   cmd/ld/doc.go

更多参数:

go tool compile -h

go tool link  -h

go install

和go build参数相同,将生成文件拷贝到bin,pkg目录,优先使用GOBIN环境变量指定目录

go clean

-n 查看但不执行清理命令

-x 查看并执行清理命令

-i 删除bin,pkg目录下的二进制文件

-r 清理所有依赖包临时目录

go get

-d 仅下载,不执行安装命令

-t 下载测试所需依赖包

-u 更新包包括其依赖

-v 查看并执行命令

go tool objdump

反汇编可执行文件

go tool objdump -s “main\.\w+” test

条件编译

(一)  GOOS GOARCH

通过runtime.GOOS/GOARCH判断,或使用编译约束标记

// +build darwin linux

ß-----必须有空行,以区别包文档。

package main

在源文件(.go, .h, .c, .s等)头部添加”+build”注释,指示编译器检查相关环境变量。

多个约束标记会合并处理。其中空格表示OR,逗号AND,感叹号NOT。

// +build darwin linux  -------à合并结果(darwin OR linux)AND (amd64 AND (NOT cgo))

// +build amd64,!cgo

如果GOOS,GOARCH不符号,编译器会忽略该文件

(二)   文件名

还可使用文件名来表示编译约束,比如test_darwin_amd64.go.使用文件名拆分多个不同平台源文件,更利于维护。

-rw-r--r--@1 zhangxiaoan admin 11545 11 29 05:38 os_darwin.c

-rw-r--r--@1 zhangxiaoan admin 1382 11 29 05:38 os_darwin.h

-rw-r--r--@1 zhangxiaoan admin 6990 11 29 05:38 os_freebsd.c

-rw-r--r--@1 zhangxiaoan admin 791 11 29 05:38 os_freebsd.h

-rw-r--r--@1 zhangxiaoan admin 644 11 29 05:38 os_freebsd_arm.c

-rw-r--r--@1 zhangxiaoan admin 8624 11 29 05:38 os_linux.c

-rw-r--r--@1 zhangxiaoan admin 1067 11 29 05:38 os_linux.h

-rw-r--r--@1 zhangxiaoan admin 861 11 29 05:38 os_linux_386.c

-rw-r--r--@ 1zhangxiaoan admin 2418 11 29 05:38 os_linux_arm.c

⽀支持:*_GOOS、*_GOARCH、*_GOOS_GOARCH、*_GOARCH_GOOS 格式。

可忽略某个文件,或指定编译器版本号。更多信息参考标准库go/build文档。

// +build ignore

// +build go1.2 ß------最低需要 go 1.2编译

(三)  自定义约束条件

需使用”go build -tags”参数。

跨平台编译

首先得生成与平台相关的 工具 和标准库

$ cd/usr/local/go/src

$GOOS=linux GOARCH=amd64 ./make.bash --no-clean

#Building C bootstrap tool.

cmd/dist

#Building compilers and Go bootstrap tool for host, darwin/amd64.

cmd/6l

cmd/6a

cmd/6c

cmd/6g

...

---

InstalledGo for linux/amd64 in /usr/local/go

Installed commands in/usr/local/go/bin

--no-clean参数避免清除其他平台文件

然后回到项目所在目录,设定GOOS,GOARCH环境变量即可编译目标平台文件

$GOOS=linux GOARCH=amd64 go build -o test

$ filetest

learn:ELF 64-bit LSB executable, x86-64, version 1 (SYSV)

$ uname-a

Darwin Kernel Version12.5.0: RELEASE_X86_64 x86_64

GO GDB语言调试

gdb不能很好的理解GO程序.即使使用gccgo,栈管理,线程和运行时与GDB期望的执行模式也不完全一样。因此GDB对GO程序并不完全可靠,尤其是在调试并发程序时。

GO程序包含DWARF3调试信息,GDB7.1以上版本可以进行调试。.

传递”-w”选项给链接器会去除调试信息。(比如:go build -ldflags “-w” prog.go)

gc编译器生成的代码包含内联函数和寄存器变量优化,可以通过-gcflags “-N -l”去掉优化

常用操作

·         显示代码文件和行号信息,设置断点和查看反汇编 :

·         (gdb) list

·         (gdb) list line

·         (gdb) list file.go : line

·         (gdb) break line

·         (gdb) break file.go : line

(gdb) disas

·         显示 backtraces stack frames:

·         (gdb) bt

(gdb) frame n

·         显示名称,类型和栈上的本地变量,参数和返回值 :

·         (gdb) info locals

·         (gdb) info args

·         (gdb) p variable

(gdb) whatis variable

·         显示名称,类型和全局变量的位置 :

(gdb) info variables regexp

go扩展

GDB最新的扩展机制允许为二进制程序加载扩展脚本。工具链使用这个机制为GDB扩展一些命令来监控运行代码的内部(如goroutines)和内置map,slice,和通道的清晰打印.

如果GDB不能找到扩展脚本,可以手工执行:

(gdb) source/usr/lib/golang/src/runtime/runtime-gdb.py

·         打印 string, slice, map, channel orinterface:

(gdb) p var

·         strings, slices maps $len() $cap() 函数 :

(gdb) p $len( var )

·         转换接口为它们的动态类型 :

·         (gdb) p $dtype( var )

(gdb) iface var

·         查看协程 :

·         (gdb) info goroutines

·         (gdb) goroutine n cmd

(gdb) help goroutine

举例 :

(gdb) goroutine 12 bt

已知问题

字符串的清晰打印只对原始字符串类型有效,从其派生的类型无效

运行库的C代码部分没有类型信息

GDB不理解GO的命名方式, 包中的类型的函数形式为 pkg.(*MyType).Meth

所有的全局变量集中到包”main”

教程

通过regexp包的单元测试程序来演示GDB的使用。

构建程序:cd $GOROOT/src/regexp; go test -c

生成可执行程序regexp.test

$ gdb regexp.test

GNU gdb (GDB) 7.2-gg8

Copyright (C) 2010 Free Software Foundation, Inc.

License GPLv  3+: GNU GPL version 3or later <http://gnu.org/licenses/gpl.html>

Type "show copying" and "show warranty" forlicensing/warranty details.

This GDB was configured as "x86_64-linux".

Reading symbols from /home/user/go/src/regexp/regexp.test...

done.

Loading Go Runtime support.

(gdb)

"Loading Go Runtime support"   意味着 GDB 加载了扩展   $GOROOT/src/runtime/runtime-gdb.py .

如果没有自动加载,可以手工加载 :

(gdb) source/usr/lib/go/src/runtime/runtime-gdb.py

Loading Go Runtime support.

查看代码

使用   "l"     "list" 命令查看源代码 .

(gdb) l

通过函数名显示源代码的特定部分 ( 必须包含其包名 ).

(gdb) l main.main

显示特定文件和行号

(gdb) l regexp.go:1

(gdb) # Hit enter to repeat last command. Here, this lists next 10lines.

关于命名

变量和函数名必须携带其所属的包名。regexp包中的Compile函数被GDB当作’regexp.Compile’

方法必须包含其接收着类型。比如,*Regexp类型的String方法必须写在’regexp.(*Regexp).String’

引用其它变量的类型在调试信息中被加上了一个数字后缀,被闭包引用的变量将会显示为一个添加&前缀的指针

设置断点

TestFind 函数设置断点 :

(gdb) b 'regexp.TestFind'

Breakpoint 1 at 0x424908: file /home/user/go/src/regexp/find_test.go, line148.

运行程序 :

(gdb) run

Starting program: /home/user/go/src/regexp/regexp.test

Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at/home/user/go/src/regexp/find_test.go:148

148  func TestFind(t *testing.T) {

执行在断点处暂停。查看哪个协程正在运行 :

(gdb) info goroutines

1 waiting runtime.gosched

* 13  running runtime.goexit

标记着   *   的为当前正在运行的协程

查看栈.

在程序暂停的地方查看栈回溯 :

(gdb) bt # backtrace

#0  regexp.TestFind (t=0xf8404a89c0)at /home/user/go/src/regexp/find_test.go:148

#1  0x000000000042f60b intesting.tRunner (t=0xf8404a89c0, test=0x573720) at/home/user/go/src/testing/testing.go:156

#2  0x000000000040df64 inruntime.initdone () at /home/user/go/src/runtime/proc.c:242

#3  0x000000f8404a89c0 in ?? ()

#4  0x0000000000573720 in ?? ()

#5  0x0000000000000000 in ?? ()

另外一个协程1,阻塞在通道接收 :

(gdb) goroutine 1 bt

#0  0x000000000040facb inruntime.gosched () at /home/user/go/src/runtime/proc.c:873

#1  0x00000000004031c9 inruntime.chanrecv (c=void, ep=void, selected=void, received=void)

at /home/user/go/src/runtime/chan.c:342

#2  0x0000000000403299 inruntime.chanrecv1 (t=void, c=void) at/home/user/go/src/runtime/chan.c:423

#3  0x000000000043075b intesting.RunTests (matchString={void (struct string, struct string, bool *,error *)}

0x7ffff7f9ef60, tests=  []testing.InternalTest = {...}) at/home/user/go/src/testing/testing.go:201

#4  0x00000000004302b1 in testing.Main(matchString={void (struct string, struct string, bool *, error *)}

0x7ffff7f9ef80, tests=[]testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark ={...})

at /home/user/go/src/testing/testing.go:168

#5  0x0000000000400dc1 in main.main() at /home/user/go/src/regexp/_testmain.go:98

#6  0x00000000004022e7 inruntime.mainstart () at /home/user/go/src/runtime/amd64/asm.s:78

#7  0x000000000040ea6f inruntime.initdone () at /home/user/go/src/runtime/proc.c:243

#8  0x0000000000000000 in ?? ()

栈桢显示我们当前在执行   regexp.TestFind   函数 .

(gdb) info frame

Stack level 0, frame at 0x7ffff7f9ff88:

rip = 0x425530 in regexp.TestFind(/home/user/go/src/regexp/find_test.go:148);

saved rip 0x430233

called by frame at 0x7ffff7f9ffa8

source language minimal.

Arglist at 0x7ffff7f9ff78, args:t=0xf840688b60

Locals at 0x7ffff7f9ff78, Previousframe's sp is 0x7ffff7f9ff88

Saved registers:

rip at 0x7ffff7f9ff80

命令 info locals 显示函数的所有本地变量,   但是这个命令有一定风险,因为它会尝试打印未初始化的变量。可能造成 gdb 打印很大的数组 .

查看函数参数 :

(gdb) info args

t = 0xf840688b60

打印参数时显示的时一个指向   Regexp 值的指针 .

注意 GDB 错误地将 * 放在了类型名的右边 .

(gdb) p re

(gdb) p t

$1 = (struct testing.T *) 0xf840688b60

(gdb) p t

$1 = (struct testing.T *) 0xf840688b60

(gdb) p *t

$2 = {errors = "", failed = false, ch = 0xf8406f5690}

(gdb) p *t->ch

$3 = struct hchan<*testing.T>

struct hchan<*testing.T> 是通道运行时的内部表示 . 它当前为空 , 否则 gdb 会清晰地打印其内容 .

继续执行 :

(gdb) n # execute nextline

149             for _, test := rangefindTests {

(gdb)    # enter is repeat

150                     re :=MustCompile(test.pat)

(gdb) p test.pat

$4 = ""

(gdb) p re

$5 = (struct regexp.Regexp *) 0xf84068d070

(gdb) p *re

$6 = {expr = "", prog = 0xf840688b80, prefix = "",prefixBytes =  []uint8, prefixComplete =true,

prefixRune = 0, cond = 0 '\000',numSubexp = 0, longest = false, mu = {state = 0, sema = 0},

machine =  []*regexp.machine}

(gdb) p *re->prog

$7 = {Inst =  []regexp/syntax.Inst ={{Op = 5 '\005', Out = 0, Arg = 0, Rune = []int}, {Op =

6 '\006', Out = 2, Arg = 0, Rune=  []int}, {Op = 4 '\004', Out = 0, Arg =0, Rune =  []int}},

Start = 1, NumCap = 2}

我们能够跟进 String 函数通过调用 ”s”:

(gdb) s

regexp.(*Regexp).String (re=0xf84068d070, noname=void) at/home/user/go/src/regexp/regexp.go:97

97      func (re *Regexp) String()string {

通过 bt 查看我们执行到哪里 :

(gdb) bt

#0  regexp.(*Regexp).String(re=0xf84068d070, noname=void)

at/home/user/go/src/regexp/regexp.go:97

#1  0x0000000000425615 inregexp.TestFind (t=0xf840688b60)

at/home/user/go/src/regexp/find_test.go:151

#2  0x0000000000430233 intesting.tRunner (t=0xf840688b60, test=0x5747b8)

at/home/user/go/src/testing/testing.go:156

#3  0x000000000040ea6f inruntime.initdone () at /home/user/go/src/runtime/proc.c:243

....

查看源代码 :

(gdb) l

92              mu      sync.Mutex

93              machine []*machine

94      }

95

96      // String returns the sourcetext used to compile the regular expression.

97      func (re *Regexp) String()string {

98              return re.expr

99      }

100

101     // Compile parses a regularexpression and returns, if successful,

清晰打印

GDB's pretty printing mechanism is triggered by regexpmatches on type names. An example for slices:

(gdb) p utf

$22 =  []uint8 = {0 '\000', 0'\000', 0 '\000', 0 '\000'}

因为 slices, arrays strings 不是 C 指针 ,GDB 不能解释带下标的操作,但是你可以通过下面的方式查看其内容 ( 使用 tab 帮助完成 ):

(gdb) p slc

$11 =  []int = {0, 0}

(gdb) p slc-> <TAB>

array  slc    len   

(gdb) p slc->array

$12 = (int *) 0xf84057af00

(gdb) p slc->array[1]

$13 = 0

扩展函数 $len $cap 支持 strings, arrays slices:

(gdb) p $len(utf)

$23 = 4

(gdb) p $cap(utf)

$24 = 4

通道和 maps 是引用类型, gdb 显示为类似 C++ 的指针类型   hash<int,string>* . 解引用操作将会触发清晰打印

接口在运行时表示为一个指向类型描述的指针和一个指向值的指针 .

Go GDB 运行扩展对运行时类型解码并自动触发清晰打印 .

扩展函数 $dtype   为你解码运行时类型 ( 例子在   regexp.go   293 .)

(gdb) p i

$4 = {str = "cbb"}

(gdb) whatis i

type = regexp.input

(gdb) p $dtype(i)

$26 = (struct regexp.inputBytes *) 0xf8400b4930

(gdb) iface i

regexp.input: struct regexp.inputBytes *


以上所述就是小编给大家介绍的《Go工具和调试详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

成功由我

成功由我

刘世英、彭征 / 湖南人民出版社 / 2010-2 / 28.00元

《成功由我:李彦宏快乐成功之道》讲述:他,18岁高分考入北京大学,毕业后到美国名校学习最热门的计算机专业,然后闯荡于华尔街和硅谷这两大金融和技术圣地,31岁回国创立百度……到如今身价数十亿美元,领导的百度发展成为全球第二大搜索引擎,在国内搜索市场占据近八成的市场份额,将有“上帝”之称的Google抛在身后,最近他又掀起了“框计算”风暴,并雄心万丈宣称“未来十年,要让百度在全球一半以上国家成为家喻户......一起来看看 《成功由我》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

html转js在线工具
html转js在线工具

html转js在线工具