// linux kernal 3.10.0 [root@localhost go-project]# uname -a Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
// gdb 7.6.1 [root@localhost go-project]# gdb -v GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.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/>.
// go 1.16.2 // 笔者的go源码位置 /root/go/go1.16.2/ [root@localhost go-project]# go version go version go1.16.2 linux/amd64
go测试代码
1 2 3 4 5 6 7
package main
import"fmt"
funcmain(){ fmt.Println("hello word") }
很简单的一段代码,打印输出 “hello word”。
编译go代码
1
[root@localhost demo]# go build -gcflags="-N -l" -o main main.go
[root@localhost demo]# gdb main GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.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 /root/go-project/demo/main...done. warning: File "/root/go/go1.16.2/src/runtime/runtime-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load:/usr/bin/mono-gdb.py". To enable execution of this file add add-auto-load-safe-path /root/go/go1.16.2/src/runtime/runtime-gdb.py line to your configuration file "/root/.gdbinit". To completely disable this security protection add set auto-load safe-path / line to your configuration file "/root/.gdbinit". For more information about this security protection see the "Auto-loading safe path" section in the GDB manual. E.g., run from the shell: info "(gdb)Auto-loading safe path"
(gdb) source /root/go/go1.16.2/src/runtime/runtime-gdb.py Loading Go Runtime support.
(gdb) info files Symbols from "/root/go-project/demo/main". Local exec file: `/root/go-project/demo/main', file type elf64-x86-64. Entry point: 0x465740 0x0000000000401000 - 0x0000000000497773 is .text 0x0000000000498000 - 0x00000000004dbb44 is .rodata 0x00000000004dbce0 - 0x00000000004dc40c is .typelink 0x00000000004dc420 - 0x00000000004dc470 is .itablink 0x00000000004dc470 - 0x00000000004dc470 is .gosymtab 0x00000000004dc480 - 0x0000000000534578 is .gopclntab 0x0000000000535000 - 0x0000000000535020 is .go.buildinfo 0x0000000000535020 - 0x00000000005432e4 is .noptrdata 0x0000000000543300 - 0x000000000054aa90 is .data 0x000000000054aaa0 - 0x00000000005781f0 is .bss 0x0000000000578200 - 0x000000000057d510 is .noptrbss 0x0000000000400f9c - 0x0000000000401000 is .note.go.buildid
使用gdb的子命令info,来查看目标文件的调试信息。
(gdb) help
1
info files -- Names of targets and files being debugged
可以看到可执行文件/root/go-project/demo/main的如下信息:
file type elf64-x86-64 是64位ELF(Linux可执行文件格式)格式的文件
Entry point: 0x465740 程序入口地址是 0x465740
可执行文件的各个段信息以及虚拟内存地址位置信息
通过入口地址追溯go启动过程
通过打断点的方式,来找对应的方法调用过程。
1 2
(gdb) b *0x465740 Breakpoint 1 at 0x465740: file /root/go/go1.16.2/src/runtime/rt0_linux_amd64.s, line 8.
[root@localhost demo]# vim /root/go/go1.16.2/src/runtime/rt0_linux_amd64.s +8
1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "textflag.h" 6 7 TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8 8 JMP _rt0_amd64(SB)
发现跳到了_rt0_amd64方法中,继续追。
1 2
(gdb) b _rt0_amd64 Breakpoint 2 at 0x4621a0: file /root/go/go1.16.2/src/runtime/asm_amd64.s, line 15.
[root@localhost demo]# vim /root/go/go1.16.2/src/runtime/asm_amd64.s +15 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "go_asm.h" 6 #include "go_tls.h" 7 #include "funcdata.h" 8 #include "textflag.h" 9 10 // _rt0_amd64 is common startup code for most amd64 systems when using 11 // internal linking. This is the entry point for the program from the 12 // kernel for an ordinary -buildmode=exe program. The stack holds the 13 // number of arguments and the C-style argv. 14 TEXT _rt0_amd64(SB),NOSPLIT,$-8 15 MOVQ 0(SP), DI // argc 16 LEAQ 8(SP), SI // argv 17 JMP runtime·rt0_go(SB) ......
// !!!调度器初始化 592 // The bootstrap sequence is: 593 // 594 // call osinit 595 // call schedinit 596 // make & queue new G 597 // call runtime·mstart 598 // 599 // The new G calls runtime·main. 600 func schedinit() { 601 lockInit(&sched.lock, lockRankSched) 602 lockInit(&sched.sysmonlock, lockRankSysmon) 603 lockInit(&sched.deferlock, lockRankDefer) 604 lockInit(&sched.sudoglock, lockRankSudog) 605 lockInit(&deadlock, lockRankDeadlock) 606 lockInit(&paniclk, lockRankPanic) 607 lockInit(&allglock, lockRankAllg) 608 lockInit(&allpLock, lockRankAllp) 609 lockInit(&reflectOffs.lock, lockRankReflectOffs) 610 lockInit(&finlock, lockRankFin) 611 lockInit(&trace.bufLock, lockRankTraceBuf) 612 lockInit(&trace.stringsLock, lockRankTraceStrings) 613 lockInit(&trace.lock, lockRankTrace) 614 lockInit(&cpuprof.lock, lockRankCpuprof) 615 lockInit(&trace.stackTab.lock, lockRankTraceStackTab) 616 // Enforce that this lock is always a leaf lock. 617 // All of this lock's critical sections should be 618 // extremely short. 619 lockInit(&memstats.heapStats.noPLock, lockRankLeafRank) 620 621 // raceinit must be the first call to race detector. 622 // In particular, it must be done before mallocinit below calls racemapshadow. 623 _g_ := getg() 624 if raceenabled { 625 _g_.racectx, raceprocctx0 = raceinit() 626 } 627 628 sched.maxmcount = 10000 // 最大系统线程数限制为 1万 629 630 // The world starts stopped. 631 worldStopped() 632 633 moduledataverify() 634 stackinit() // 栈初始化 635 mallocinit() // 内存分配器初始化 636 fastrandinit() // must run before mcommoninit 637 mcommoninit(_g_.m, -1) 638 cpuinit() // must run before alginit 639 alginit() // maps must not be used before this call 640 modulesinit() // provides activeModules 641 typelinksinit() // uses maps, activeModules 642 itabsinit() // uses activeModules 643 644 sigsave(&_g_.m.sigmask) 645 initSigmask = _g_.m.sigmask 646 647 goargs() // 处理命令行参数 648 goenvs() // 处理环境变量参数 649 parsedebugvars() 650 gcinit() // 垃圾回收器初始化 651 652 lock(&sched.lock) 653 sched.lastpoll = uint64(nanotime()) 654 procs := ncpu // !!!通过cpu core 和 GOMAXPROCS 确定P的数量 655 if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { 656 procs = n 657 } 658 if procresize(procs) != nil { // 调整P数量 659 throw("unknown runnable goroutine during bootstrap") 660 } 661 unlock(&sched.lock) 662 663 // World is effectively started now, as P's can run. 664 worldStarted() 665 666 // For cgocheck > 1, we turn on the write barrier at all times 667 // and check all pointer writes. We can't do this until after 668 // procresize because the write barrier needs a P. 669 if debug.cgocheck > 1 { 670 writeBarrier.cgo = true 671 writeBarrier.enabled = true 672 for _, p := range allp { 673 p.wbBuf.reset() 674 } 675 } 676 677 if buildVersion == "" { 678 // Condition should never trigger. This code just serves 679 // to ensure runtime·buildVersion is kept in the resulting binary. 680 buildVersion = "unknown" 681 } 682 if len(modinfo) == 1 { 683 // Condition should never trigger. This code just serves 684 // to ensure runtime·modinfo is kept in the resulting binary. 685 modinfo = "" 686 } 687 }