Skip to content

cmd/compile: Go generates wrong .debug_loc in dwarf #49133

@jschwinger233

Description

@jschwinger233

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

$ go version
go version go1.17.2 linux/amd64

Does this issue reproduce with the latest release?

Yes.

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/gray/.cache/go-build"
GOENV="/home/gray/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/gray/Documents/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/gray/Documents/"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.2"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/gray/Documents/src/tmp/go_dwarf/go.mod"
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-build2885186332=/tmp/go-build -gno-record-gcc-switches"
GOROOT/bin/go version: go version go1.17.2 linux/amd64
GOROOT/bin/go tool compile -V: compile version go1.17.2
uname -sr: Linux 5.8.0-50-generic
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.3 LTS
Release:	20.04
Codename:	focal
/lib/x86_64-linux-gnu/libc.so.6: GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.2) stable release version 2.31.
gdb --version: GNU gdb (GDB) 12.0.50.20211024-git

What did you do?

Step 1

I wrote a simple program: https://play.golang.org/p/KQIOD26fmo7

package main

import (
	"fmt"
	"strings"
)

func main() {
	fmt.Println(strings.Replace("oink oink oink", "oink", "moo", 1))
}

Step 2

I built program with default flags and used gdb to run, tried to inspect the arguments when strings.Replace was about to be called:

go_dwarf $ go build .
go_dwarf $ gdb ./go_dwarf
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./go_dwarf...
warning: File "/usr/local/go1.17.2/src/runtime/runtime-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
	add-auto-load-safe-path /usr/local/go1.17.2/src/runtime/runtime-gdb.py
line to your configuration file "/home/gray/.gdbinit".
To completely disable this security protection add
	set auto-load safe-path /
line to your configuration file "/home/gray/.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) b strings.Replace
Breakpoint 1 at 0x47eb40: file /usr/local/go/src/strings/strings.go, line 924.
(gdb) r
Starting program: /home/gray/Dropbox/mac.local/Documents/src/tmp/go_dwarf/go_dwarf 
[New LWP 2610240]
[New LWP 2610241]
[New LWP 2610242]
[New LWP 2610243]

Thread 1 "go_dwarf" hit Breakpoint 1, strings.Replace (s=<error reading variable: access outside bounds of object referenced via synthetic pointer>, 
    old=<error reading variable: access outside bounds of object referenced via synthetic pointer>, new=..., n=4285733) at /usr/local/go/src/strings/strings.go:924
924	func Replace(s, old, new string, n int) string {
(gdb) p n
$1 = 4285733

What did you expect to see?

I expected to see the correct value of variable n: 1.

What did you see instead?

However I got 4285733.

Some other facts that may help

I confirmed that gdb located variable n using dwarf debug info, and details are as followed:

Let's look at .debug_info first, and here's info concerned:

# objdump -Wi

 <1><2aa2>: Abbrev Number: 3 (DW_TAG_subprogram)
    <2aa3>   DW_AT_name        : strings.Replace
    <2ab3>   DW_AT_low_pc      : 0x47eb40
    <2abb>   DW_AT_high_pc     : 0x47f26d
    <2ac3>   DW_AT_frame_base  : 1 byte block: 9c 	(DW_OP_call_frame_cfa)
    <2ac5>   DW_AT_decl_file   : 0x7
    <2ac9>   DW_AT_external    : 1
 <2><2aca>: Abbrev Number: 16 (DW_TAG_formal_parameter)
    <2acb>   DW_AT_name        : s
    <2acd>   DW_AT_variable_parameter: 0
    <2ace>   DW_AT_decl_line   : 924
    <2ad0>   DW_AT_type        : <0x4ba48>
    <2ad4>   DW_AT_location    : 0xd1a (location list)
 <2><2ad8>: Abbrev Number: 16 (DW_TAG_formal_parameter)
    <2ad9>   DW_AT_name        : old
    <2add>   DW_AT_variable_parameter: 0
    <2ade>   DW_AT_decl_line   : 924
    <2ae0>   DW_AT_type        : <0x4ba48>
    <2ae4>   DW_AT_location    : 0xd7a (location list)
 <2><2ae8>: Abbrev Number: 16 (DW_TAG_formal_parameter)
    <2ae9>   DW_AT_name        : new
    <2aed>   DW_AT_variable_parameter: 0
    <2aee>   DW_AT_decl_line   : 924
    <2af0>   DW_AT_type        : <0x4ba48>
    <2af4>   DW_AT_location    : 0xdda (location list)
 <2><2af8>: Abbrev Number: 16 (DW_TAG_formal_parameter)
    <2af9>   DW_AT_name        : n
    <2afb>   DW_AT_variable_parameter: 0
    <2afc>   DW_AT_decl_line   : 924
    <2afe>   DW_AT_type        : <0x4ba38>
    <2b02>   DW_AT_location    : 0xe2c (location list)

We can see the variable n at location 0xe2c, so here's what I got from .debug_loc:

# objdump -Wo

    00000e2c ffffffffffffffff 000000000047eb40 (base address)
    00000e3c 000000000047eb40 000000000047ec80 (DW_OP_fbreg: 48)
    00000e50 000000000047ec80 000000000047ed58 (DW_OP_fbreg: -96)
    00000e65 000000000047ed58 000000000047ed89 (DW_OP_fbreg: 48)
    00000e79 000000000047ed89 000000000047f20c (DW_OP_fbreg: -96)
    00000e8e 000000000047f20c 000000000047f26d (DW_OP_fbreg: 48)
    00000ea2 <End of list>

Because DW_OP_fbreg is calculated based on CFA, so let's turn to .debug_frame:

# objdump -WF

0000ebc4 000000000000003c 00000000 FDE cie=00000000 pc=000000000047eb40..000000000047f26d
   LOC           CFA      ra    
000000000047eb40 rsp+8    c-8   
000000000047eb56 rsp+200  c-8   
000000000047ec06 rsp+8    c-8   
000000000047ec07 rsp+200  c-8   
000000000047ed6c rsp+8    c-8   
000000000047ed6d rsp+200  c-8   
000000000047f190 rsp+8    c-8   
000000000047f191 rsp+200  c-8   
000000000047f219 rsp+8    c-8   
000000000047f26c rsp+8    c-8   

So these information has told us, n is located at $rsp+8+48, and that's exactly where gdb tried to find the variable value:

# gdb ./go_dwarf

(gdb) p int64(&n) - int64($rsp)
$3 = 56

However it doesn't seem working.

I also tried delve debugger instead of gdb, and it turned out dlv generated .debug_loc precisely:

$ dlv debug .
Type 'help' for list of commands.
(dlv) 

# then switch to another terminal, inspect the __debug_bin under the cwd

$ objdump -WioF __debug_bin

I extracted related infomation as followed:

    <b2f>   DW_AT_name        : n
    <b31>   DW_AT_variable_parameter: 0
    <b32>   DW_AT_decl_line   : 924
    <b34>   DW_AT_type        : <0x344b4>
    <b38>   DW_AT_location    : 0xcf8 (location list)

    00000cf8 ffffffffffffffff 00000000004957a0 (base address)
    00000d08 00000000004957a0 00000000004957fe (DW_OP_reg9 (r9))
    00000d1b 00000000004957fe 0000000000495c5b (DW_OP_fbreg: 48)
    00000d2f <End of list>

This time variable n is located at $r9, and that is right.

Then I get back to the normal binary (from go build .), found out the n variable is actually also located at $r9, that's to say go compiler generated the wrong .debug_loc info in dwarf.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions