Skip to content

cmd/link: dynamic linking cannot be stepped through using gdb #38378

Closed
@WangLeonard

Description

@WangLeonard

What version of Go are you using (go version)?

$ go version
go version go1.13.3 linux/amd64

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/py3/Project/GOPATH"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/root/py3/Project/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/root/py3/Project/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build442453090=/tmp/go-build -gno-record-gcc-switches"

What did you do?

A simple demo

package main

import (
	"fmt"
	"os"
	"time"
)

var a = 0

//go:noinline
func TestFunc() {
	a++
	time.Sleep(time.Millisecond * 100)
}

func main() {
	fmt.Println(os.Getpid())
	for i := 0; i < 100000; i++ {
		TestFunc()
	}
}

go install -buildmode=shared -linkshared std

go build -linkshared main.go

./main

Then I use gdb to debug, when I use s for single step debugging, it will appear:

which has no line number information.

gdb attach 3839

What did you expect to see?

Can be debugged step by step.

What did you see instead?

Type "apropos word" to search for commands related to "word"...
attach: No such file or directory.
Attaching to process 3839
[New LWP 3840]
[New LWP 3841]
[New LWP 3842]
[New LWP 3843]
[New LWP 3844]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007fb989b424b3 in runtime.futex ()
   from /root/py3/Project/go/pkg/linux_amd64_dynlink/libstd.so
(gdb) b main.TestFunc
Breakpoint 1 at 0x55563d1f77a0
(gdb) c
Continuing.

Thread 1 "main" hit Breakpoint 1, 0x000055563d1f77a0 in main.TestFunc ()
(gdb) s
Single stepping until exit from function main.TestFunc,
which has no line number information.


Thread 1 "main" hit Breakpoint 1, 0x000055563d1f77a0 in main.TestFunc ()
(gdb) s
Single stepping until exit from function main.TestFunc,
which has no line number information.
0x00007fb989b2c680 in time.Sleep ()
   from /root/py3/Project/go/pkg/linux_amd64_dynlink/libstd.so

Even if I use go build -gcflags = '-N -l' -linkshared main.go , still get the same error.

When I use the static link go build main.go, it can be stepped normally.

The process of my analysis:

Add -x option to re-compile, it can be seen that when ld is called, -w is added

root/py3/Project/go/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -installsuffix dynlink -buildmode=exe -buildid=0NYYkm8PmmuyphRyKmYC/4b2T8RfBMeRtkph2OZPF/9y-yYjcMEG_-re1WmH11/0NYYkm8PmmuyphRyKmYC -linkshared -w -extld=gcc /root/.cache/go-build/9d/9d922fc73643e08291edcd472d78431a941d02ea4a67c48a58d6e240635f2934-d
/root/py3/Project/go/pkg/tool/linux_amd64/buildid -w $WORK/b001/exe/a.out # internal

In the source code, if the -w option is added, the .debug_line information will not be generated

func dwarfGenerateDebugSyms(ctxt *Link) {
	if !dwarfEnabled(ctxt) {
		return
	}
	……

	// Write per-package line and range tables and start their CU DIEs.
	debugLine := ctxt.Syms.Lookup(".debug_line", 0)
	debugLine.Type = sym.SDWARFSECT
	debugRanges := ctxt.Syms.Lookup(".debug_ranges", 0)
	debugRanges.Type = sym.SDWARFRANGE
	debugRanges.Attr |= sym.AttrReachable
	syms = append(syms, debugLine)
	……
}

I guess -w was added here, and there is a legacy TODO

func buildModeInit() {
	gccgo := cfg.BuildToolchainName == "gccgo"
	……
	if cfg.BuildLinkshared {
		if gccgo {
			codegenArg = "-fPIC"
		} else {
			switch platform {
			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
				forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1")
			default:
				base.Fatalf("-linkshared not supported on %s\n", platform)
			}
			codegenArg = "-dynlink"
			// TODO(mwhudson): remove -w when that gets fixed in linker.
			forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
		}
	}
}

I want to ask, for dynamically compiled programs, cannot use gdb for single-step debugging, Is there any consideration or any bug?

Is there a supporting plan for this?

This scene is very important to me, I am looking forward to receiving your reply, thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions