可以使用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测试开关用的,可以忽略
