可以使用docker构造自己的环境:
Dockerfile
FROM centos RUN yum install golang -y && yum install dlv -y && yum install binutils -y && yum install vim -y && yum install gdb -y
//构造image, Dockerfile所在目录 sudo docker build -t test . //一定要带上权限参数privileged , 因为docker限制了dlv的权限 sudo docker run -it --privileged test
下面是本地本机安装,不用docker
先安装dlv
git clone https://github.com/derekparker/delve.git cd delve/cmd/dlv/ go build go install
由于我安装的go version相对dlv版本比较新,所以需要添加参数忽略版本比较
[jet@192 study]$ ./dlv exec ./main Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false) [jet@192 study]$ ./dlv exec ./main --check-go-version Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false) [jet@192 study]$ ./dlv exec ./main --check-go-version=false Type 'help' for list of commands. (dlv) b *0x464540 Breakpoint 1 set at 0x464540 for _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8 (dlv) b runqput Breakpoint 2 set at 0x440e93 for runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126 (dlv) brunqget Command failed: command not available (dlv) b runqget Breakpoint 3 set at 0x4412c0 for runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238 (dlv) b globrunqput Breakpoint 4 set at 0x43a966,0x43b52e,0x43c9d0,0x43e51c,0x45a906,0x45b554 for runtime.injectglist() /usr/lib/golang/src/runtime/proc.go:5017 (dlv) b globrunqget
[jet@192 study]$ readelf -h main ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x464540 Start of program headers: 64 (bytes into file) Start of section headers: 456 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 7 Size of section headers: 64 (bytes) Number of section headers: 25 Section header string table index: 3 [jet@192 study]$ dlv exec ./main bash: dlv: command not found... [jet@192 study]$ ./dlv exec ./main Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false) [jet@192 study]$ ./dlv exec ./main --check-go-version Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false) [jet@192 study]$ ./dlv exec ./main --check-go-version=false Type 'help' for list of commands. (dlv) b *0x464540 Breakpoint 1 set at 0x464540 for _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8 (dlv) b runqput Breakpoint 2 set at 0x440e93 for runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126 (dlv) brunqget Command failed: command not available (dlv) b runqget Breakpoint 3 set at 0x4412c0 for runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238 (dlv) b globrunqput Breakpoint 4 set at 0x43a966,0x43b52e,0x43c9d0,0x43e51c,0x45a906,0x45b554 for runtime.injectglist() /usr/lib/golang/src/runtime/proc.go:5017 (dlv) b globrunqget Breakpoint 10 set at 0x440c53 for runtime.globrunqget() /usr/lib/golang/src/runtime/proc.go:5040 (dlv) c > _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8 (hits total:1) (PC: 0x464540) Warning: debugging optimized function 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) 9: 10: TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0 11: JMP _rt0_amd64_lib(SB) (dlv) bt 0 0x0000000000464540 in _rt0_amd64_linux at /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8 1 0x0000000000000000 in ??? at :0 error: NULL address (truncated) (dlv) c > runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126 (hits total:1) (PC: 0x440e93) Warning: debugging optimized function 5121: // runqput tries to put g on the local runnable queue. 5122: // If next is false, runqput adds g to the tail of the runnable queue. 5123: // If next is true, runqput puts g in the _p_.runnext slot. 5124: // If the run queue is full, runnext puts g on the global queue. 5125: // Executed only by the owner P. =>5126: func runqput(_p_ *p, gp *g, next bool) { 5127: if randomizeScheduler && next && fastrand()%2 == 0 { 5128: next = false 5129: } 5130: 5131: if next { (dlv) bt 0 0x0000000000440e93 in runtime.runqput at /usr/lib/golang/src/runtime/proc.go:5126 1 0x000000000045d95f in runtime.newproc.func1 at /usr/lib/golang/src/runtime/proc.go:3531 2 0x000000000043cbae in runtime.newproc at /usr/lib/golang/src/runtime/proc.go:3527 3 0x00000000004611b4 in runtime.rt0_go at /usr/lib/golang/src/runtime/asm_amd64.s:220 (dlv) c > runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238 (hits total:1) (PC: 0x4412c0) Warning: debugging optimized function 5233: 5234: // Get g from local runnable queue. 5235: // If inheritTime is true, gp should inherit the remaining time in the 5236: // current time slice. Otherwise, it should start a new time slice. 5237: // Executed only by the owner P. =>5238: func runqget(_p_ *p) (gp *g, inheritTime bool) { 5239: // If there's a runnext, it's the next G to run. 5240: for { 5241: next := _p_.runnext 5242: if next == 0 { 5243: break (dlv) bt 0 0x00000000004412c0 in runtime.runqget at /usr/lib/golang/src/runtime/proc.go:5238 1 0x000000000043ae05 in runtime.schedule at /usr/lib/golang/src/runtime/proc.go:2664 2 0x0000000000437373 in runtime.mstart1 at /usr/lib/golang/src/runtime/proc.go:1179 3 0x00000000004372ae in runtime.mstart at /usr/lib/golang/src/runtime/proc.go:1119 4 0x00000000004611bb in runtime.rt0_go at /usr/lib/golang/src/runtime/asm_amd64.s:225 (dlv) c > runtime.goschedImpl() /usr/lib/golang/src/runtime/proc.go:5016 (hits total:1) (PC: 0x43b52e) Warning: debugging optimized function 5011: // Put gp on the global runnable queue. 5012: // Sched must be locked. 5013: // May run during STW, so write barriers are not allowed. 5014: //go:nowritebarrierrec 5015: func globrunqput(gp *g) { =>5016: sched.runq.pushBack(gp) 5017: sched.runqsize++ 5018: } 5019: 5020: // Put gp at the head of the global runnable queue. 5021: // Sched must be locked. (dlv) bt 0 0x000000000043b52e in runtime.globrunqput at /usr/lib/golang/src/runtime/proc.go:5016 1 0x000000000043b52e in runtime.goschedImpl at /usr/lib/golang/src/runtime/proc.go:2849 2 0x000000000043b7f4 in runtime.gopreempt_m at /usr/lib/golang/src/runtime/proc.go:2880 3 0x00000000004495fc in runtime.newstack at /usr/lib/golang/src/runtime/stack.go:1040 4 0x000000000046144f in runtime.morestack at /usr/lib/golang/src/runtime/asm_amd64.s:449 5 0x00000000004611b4 in runtime.rt0_go at /usr/lib/golang/src/runtime/asm_amd64.s:220 (dlv)
可以看到
func runqput 函数里面对于goroutine他们的顺序是 runnext ---> runq ---> global queue
randomizeSchuduler 是race测试开关用的,可以忽略