GoLang dlv调试启动过程

实验环境

  • Ubuntu 20.04 x86_64 5.4.0 2CPU 4GB
  • go1.17.12 linux/amd64
  • Delve Debugger 1.9.0
  • 待调试代码示例
package main
//go:noinline
func sum(a, b int) int {
	sum := 0
	sum = a + b
	return sum
}
//go:noinline
func main() {
	a := 3
	b := 5
	c := sum(a, b)
	a = c + b
}

dlv 调试指令简介

指令含义
n一行一行执行
s单步 多指令, 调试汇编代码
si单步 单指令 ,调试汇编代码
ls显示源代码
p打印变量
b设置断点
bp打印断点
regs打印寄存器值

调试入口点

二进制可执行文件在Linux系统是一种ELF文件格式,与进城虚拟地址空间分布一一对应。ELF文件可以显示入口点;

go build -o cmd cmd.go 
readelf -h cmd | less
程序入口符号:_rt0_amd64_linux

开始调试探索

先看图片有个印象
~/go/bin/dlv debug cmd.go
(dlv) b _rt0_amd64_linux
(dlv) bp
...
Breakpoint 1 (enabled) at 0x458180 for _rt0_amd64_linux() /usr/local/go/src/runtime/rt0_linux_amd64.s:8 (0)
(dlv)
(dlv) c
 	 6:	
     7:	TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
=>   8:		JMP	_rt0_amd64(SB)
(dlv) si
    15:	TEXT _rt0_amd64(SB),NOSPLIT,$-8
=>  16:		MOVQ	0(SP), DI	// argc
    17:		LEAQ	8(SP), SI	// argv
    18:		JMP	runtime·rt0_go(SB)
(dlv) n
(dlv) n
    15:	TEXT _rt0_amd64(SB),NOSPLIT,$-8
    16:		MOVQ	0(SP), DI	// argc
    17:		LEAQ	8(SP), SI	// argv
=>  18:		JMP	runtime·rt0_go(SB)
(dlv) si
    81:	TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
    82:		// copy arguments forward on an even stack
=>  83:		MOVQ	DI, AX		// argc
    84:		MOVQ	SI, BX		// argv
    85:		SUBQ	$(4*8+7), SP		// 2args 2auto
    86:		ANDQ	$~15, SP
    87:		MOVQ	AX, 16(SP)
    88:		MOVQ	BX, 24(SP)
(dlv) s 多次
(dlv) s
   206:		MOVL	16(SP), AX		// copy argc
   207:		MOVL	AX, 0(SP)
   208:		MOVQ	24(SP), AX		// copy argv
   209:		MOVQ	AX, 8(SP)
=> 210:		CALL	runtime·args(SB)
   211:		CALL	runtime·osinit(SB)
   212:		CALL	runtime·schedinit(SB)
(dlv) si  多次
    61:	func args(c int32, v **byte) {
=>  62:		argc = c
    63:		argv = v
    64:		sysargs(c, v)
    65:	}
(dlv) n  多次
   210:		CALL	runtime·args(SB)
=> 211:		CALL	runtime·osinit(SB)
   212:		CALL	runtime·schedinit(SB)
(dlv) si  多次 
=> 301:	func osinit() {
   302:		ncpu = getproccount()  
(dlv) n  多次
   210:		CALL	runtime·args(SB)
   211:		CALL	runtime·osinit(SB)
=> 212:		CALL	runtime·schedinit(SB)
(dlv) si 多次
=> 654:	func schedinit() {
   655:		lockInit(&sched.lock, lockRankSched)
   656:		lockInit(&sched.sysmonlock, lockRankSysmon)
   657:		lockInit(&sched.deferlock, lockRankDefer)
   658:		lockInit(&sched.sudoglock, lockRankSudog)
   659:		lockInit(&deadlock, lockRankDeadlock)
(dlv) n 多次  
   681:	
   682:		sched.maxmcount = 10000             //设置调度g最大值
   683:	
   684:		// The world starts stopped.
=> 685:		worldStopped()
   686:	
   687:		moduledataverify()
   688:		stackinit()						   //栈初始化
   689:		mallocinit()					   //内存分配初始化
   690:		fastrandinit() 
   691:		mcommoninit(_g_.m, -1)
   692:		cpuinit()       // must run before alginit
   693:		alginit()       // maps must not be used before this call
=> 694:		modulesinit()   // provides activeModules
   695:		typelinksinit() // uses maps, activeModules
   696:		itabsinit()     // uses activeModules
(dlv) n 多次 
   706:		goargs()							//go 请求参数
   707:		goenvs()							//go 环境变量
   708:		parsedebugvars()				
   709:		gcinit()							//垃圾回收初始化
   710:	
=> 711:		lock(&sched.lock)
   712:		sched.lastpoll = uint64(nanotime())
   713:		procs := ncpu						//系统核数
(dlv) p procs
2
(dlv) n 多次 
=> 717:		if procresize(procs) != nil {		//创建P
   718:			throw("unknown runnable goroutine during bootstrap")
   719:		}
(dlv) si
=>4994:	func procresize(nprocs int32) *p {
  4995:		assertLockHeld(&sched.lock)
  4996:		assertWorldStopped()
(dlv) n 多次 
  5020:			if nprocs <= int32(cap(allp)) {
  5021:				allp = allp[:nprocs]
  5022:			} else {
=>5023:				nallp := make([]*p, nprocs)   //创建多处理器P
  5024:				// Copy everything up to allp's cap so we
  5025:				// never lose old allocated Ps.
  5026:				copy(nallp, allp[:cap(allp)])
  5027:				allp = nallp
  5028:			}
(dlv) n 多次 
  5046:		// initialize new P's
  5047:		for i := old; i < nprocs; i++ {
  5048:			pp := allp[i]
=>5049:			if pp == nil {
  5050:				pp = new(p)
  5051:			}
  5052:			pp.init(i)
  5053:			atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
  5054:		}  
(dlv) n 多次 
   212:		CALL	runtime·schedinit(SB)
   213:	
   214:		// create a new goroutine to start program
   215:		MOVQ	$runtime·mainPC(SB), AX		// entry
   216:		PUSHQ	AX
   217:		PUSHQ	$0			// arg size
=> 218:		CALL	runtime·newproc(SB)
(dlv) si 多次
=>4250:	func newproc(siz int32, fn *funcval) {
  4251:		argp := add(unsafe.Pointer(&fn), sys.PtrSize)
  4252:		gp := getg()
  4253:		pc := getcallerpc()
(dlv) n 多次  
   218:		CALL	runtime·newproc(SB)
   219:		POPQ	AX
   220:		POPQ	AX
   221:	
   222:		// start this M
=> 223:		CALL	runtime·mstart(SB)
   224:	
   225:		CALL	runtime·abort(SB)	// mstart should never return
(dlv) si 多次
   247:	TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
=> 248:		CALL	runtime·mstart0(SB)
   249:		RET // not reached
(dlv) si 多次
=>1339:	func mstart0() {
  1340:		_g_ := getg()
(dlv) n 多次 
  1361:		_g_.stackguard0 = _g_.stack.lo + _StackGuard
  1362:		// This is the g0, so we can also call go:systemstack
  1363:		// functions, which check stackguard1.
  1364:		_g_.stackguard1 = _g_.stackguard0
=>1365:		mstart1()
(dlv) p _StackGuard
928
(dlv) si 多次
=>1380:	func mstart1() {
  1381:		_g_ := getg()
(dlv) n 多次 
  1393:		_g_.sched.g = guintptr(unsafe.Pointer(_g_))
  1394:		_g_.sched.pc = getcallerpc()
=>1395:		_g_.sched.sp = getcallersp()
  1396:	
  1397:		asminit()
  1398:		minit()
(dlv) n 多次 
  1410:		if _g_.m != &m0 {
  1411:			acquirep(_g_.m.nextp.ptr())
  1412:			_g_.m.nextp = 0
  1413:		}
=>1414:		schedule()
(dlv) si 多次
=>3291:	func schedule() {
  3292:		_g_ := getg()
  3310:		pp := _g_.m.p.ptr()
  3311:		pp.preempt = false
  3312:	    .....
=>3313:		if sched.gcwaiting != 0 {
  3314:			gcstopm()
  3315:			goto top
  3316:		}
  3327:	    .....
=>3328:		checkTimers(pp, 0)
(dlv) n 多次 
  3351:		if gp == nil {  //防止全局g饥饿,每61次取全局
=>3355:			if _g_.m.p.ptr().schedtick%61 == 0 && sched.runqsize > 0 {
  3356:				lock(&sched.lock)
  3357:				gp = globrunqget(_g_.m.p.ptr(), 1)
  3358:				unlock(&sched.lock)
  3359:			}
  3360:		}
(dlv) n 多次  
=>3361:		if gp == nil {
  3362:			gp, inheritTime = runqget(_g_.m.p.ptr())  //从P本地队列取g
  3363:			// We can see gp != nil here even if the M is spinning,
  3364:			// if checkTimers added a local goroutine via goready.
  3365:		}
(dlv) n 多次  
=>3366:		if gp == nil {
  3367:			gp, inheritTime = findrunnable()  //本地队列空时,寻找可用g,复杂
  3368:		}
(dlv) n 多次
=>3406:		execute(gp, inheritTime)
(dlv) p inheritTime
true
(dlv) si 多次
  2670:	func execute(gp *g, inheritTime bool) {
=>2671:		_g_ := getg()
  2672:	
  2673:		// Assign gp.m before entering _Grunning so running Gs have an
  2674:		// M.
  2675:		_g_.m.curg = gp
  2676:		gp.m = _g_.m
(dlv) n 多次
  2677:		casgstatus(gp, _Grunnable, _Grunning)
  2678:		gp.waitsince = 0
  2679:		gp.preempt = false
=>2680:		gp.stackguard0 = gp.stack.lo + _StackGuard  //栈边界,用于伸缩栈
  2681:		if !inheritTime {
  2682:			_g_.m.p.ptr().schedtick++
  2683:		}
(dlv) n 多次
=>2700:		gogo(&gp.sched)

(dlv) p gp.sched
runtime.gobuf {sp: 824633911256, pc: 4393312, g: 824633721664, ctxt: unsafe.Pointer(0x46d288), ret: 0, lr: 0, bp: 0}

(dlv) si 多次
   257:	TEXT runtime·gogo(SB), NOSPLIT, $0-8
=> 258:		MOVQ	buf+0(FP), BX		// gobuf
   259:		MOVQ	gobuf_g(BX), DX
   260:		MOVQ	0(DX), CX		// make sure g != nil
   261:		JMP	gogo<>(SB)
(dlv) si 多次
   257:	TEXT runtime·gogo(SB), NOSPLIT, $0-8
   258:		MOVQ	buf+0(FP), BX		// gobuf
   259:		MOVQ	gobuf_g(BX), DX
   260:		MOVQ	0(DX), CX		// make sure g != nil
=> 261:		JMP	gogo<>(SB)
(dlv) regs
    Rip = 0x00000000004566ac
    Rsp = 0x00007ffe3e239650
    Rax = 0x000000c000000378
    Rbx = 0x000000c000000378
    Rcx = 0x000000c00002e000
    Rdx = 0x000000c000000340
    Rsi = 0x0000000000000001
    Rdi = 0x0000000000000000
    Rbp = 0x00007ffe3e239670
     R8 = 0x0000000000430901
     R9 = 0x0000000000430c80
    R10 = 0x0000000000000008
    R11 = 0x0000000000000206
    R12 = 0x00007ffe3e2392e8
    R13 = 0x0000000000000000
    R14 = 0x00000000004b6800
    R15 = 0x0000000000002030
 Rflags = 0x0000000000000246	[PF ZF IF IOPL=0]
     Es = 0x0000000000000000
     Cs = 0x0000000000000033
     Ss = 0x000000000000002b
     Ds = 0x0000000000000000
     Fs = 0x0000000000000000
     Gs = 0x0000000000000000
Fs_base = 0x00000000004b6a30
Gs_base = 0x0000000000000000

(dlv) si 多次
   263:	TEXT gogo<>(SB), NOSPLIT, $0
   264:		get_tls(CX)
=> 265:		MOVQ	DX, g(CX)
   266:		MOVQ	DX, R14		// set the g register
   267:		MOVQ	gobuf_sp(BX), SP	// restore SP
   268:		MOVQ	gobuf_ret(BX), AX
   269:		MOVQ	gobuf_ctxt(BX), DX
   270:		MOVQ	gobuf_bp(BX), BP
(dlv) si 多次
   271:		MOVQ	$0, gobuf_sp(BX)	// clear to help garbage collector
   272:		MOVQ	$0, gobuf_ret(BX)
   273:		MOVQ	$0, gobuf_ctxt(BX)
   274:		MOVQ	$0, gobuf_bp(BX)
   275:		MOVQ	gobuf_pc(BX), BX
=> 276:		JMP	BX

(dlv) regs
    Rip = 0x000000000045595e
    Rsp = 0x000000c00002e7d8
    Rax = 0x0000000000000000
    Rbx = 0x0000000000430960
    Rcx = 0x000000c00002e000
    Rdx = 0x000000000046d288
    Rsi = 0x0000000000000001
    Rdi = 0x0000000000000000
    Rbp = 0x0000000000000000
     R8 = 0x0000000000430901
     R9 = 0x0000000000430c80
    R10 = 0x0000000000000008
    R11 = 0x0000000000000206
    R12 = 0x00007ffe3e2392e8
    R13 = 0x0000000000000000
    R14 = 0x000000c000000340
    R15 = 0x0000000000002030
 Rflags = 0x0000000000000246	[PF ZF IF IOPL=0]
     Es = 0x0000000000000000
     Cs = 0x0000000000000033
     Ss = 0x000000000000002b
     Ds = 0x0000000000000000
     Fs = 0x0000000000000000
     Gs = 0x0000000000000000
Fs_base = 0x00000000004b6a30
Gs_base = 0x0000000000000000

(dlv) ls
   271:		MOVQ	$0, gobuf_sp(BX)	// clear to help garbage collector
   272:		MOVQ	$0, gobuf_ret(BX)
   273:		MOVQ	$0, gobuf_ctxt(BX)
   274:		MOVQ	$0, gobuf_bp(BX)
   275:		MOVQ	gobuf_pc(BX), BX
=> 276:		JMP	BX

(dlv) si 多次
=> 145:	func main() {
   146:		g := getg()

(dlv) si 多次
   155:		if sys.PtrSize == 8 {             //最大栈
=> 156:			maxstacksize = 1000000000
   157:		} else {
   158:			maxstacksize = 250000000
   159:		}
(dlv) p sys.PtrSize
8

(dlv) si 多次
   169:		if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon
   170:			// For runtime_syscall_doAllThreadsSyscall, we
   171:			// register sysmon is not ready for the world to be
   172:			// stopped.
   173:			atomic.Store(&sched.sysmonStarting, 1)
=> 174:			systemstack(func() {        //创建sysmon
   175:				newm(sysmon, nil, -1)
   176:			})
   177:		}
   
(dlv) si 多次
=> 204:		doInit(&runtime_inittask) // 先执行 init 函数
(dlv) si 多次
=> 214:		gcenable()				 // 开启gc回收逻辑

(dlv) si 多次
   254:		fn := main_main    //编写代码的main函数
=> 255:		fn()

(dlv) si 多次
    10:	//go:noinline
=>  11:	func main() {
    12:		a := 3
    13:		b := 5
    14:		c := sum(a, b)
    15:		a = c + b
    16:	}

(dlv) n 多次
=> 264:	if atomic.Load(&runningPanicDefers) != 0{//执行main函数执行defer 函数
   265:	 // Running deferred functions should not take long. 
   266:		for c := 0; c < 1000; c++ {
   267:			if atomic.Load(&runningPanicDefers) == 0 {
   268:				break
   269:			}
   
(dlv) p runningPanicDefers
0

(dlv) n 多次
=> 273:		if atomic.Load(&panicking) != 0 {  //执行panic
   274:			gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
   275:		}

(dlv) p panicking
0

(dlv) n 多次
=> 277:		exit(0)   //程序结束
   278:		for {
   279:			var x *int32
   280:			*x = 0
   281:		}

启动流程放大图

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cugriver

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值