Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jschwinger233 opened this issue Oct 24, 2021 · 5 comments
Closed

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

jschwinger233 opened this issue Oct 24, 2021 · 5 comments
Assignees
Milestone

Comments

@jschwinger233
Copy link

@jschwinger233 jschwinger233 commented Oct 24, 2021

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.

@ALTree
Copy link
Member

@ALTree ALTree commented Oct 24, 2021

Thanks for reporting this. Do you know if it's a go1.17 regression? (i.e., does go1.16 do the right thing?)

Loading

@seankhliao
Copy link
Contributor

@seankhliao seankhliao commented Oct 24, 2021

maybe related? #47354

Loading

@jschwinger233
Copy link
Author

@jschwinger233 jschwinger233 commented Oct 24, 2021

Thanks for reporting this. Do you know if it's a go1.17 regression? (i.e., does go1.16 do the right thing?)

I tried go1.15 and go1.16, the location info in both version seems okay.

Loading

@randall77
Copy link
Contributor

@randall77 randall77 commented Oct 24, 2021

Loading

@thanm thanm self-assigned this Oct 25, 2021
@thanm
Copy link
Contributor

@thanm thanm commented Nov 11, 2021

I retested this morning, and it looks like this is now working properly on tip. In GDB I get:

Thread 1 "issue49133" hit Breakpoint 1, strings.Replace (s="oink oink oink", old="oink", new="moo", n=1, ~r0=...) at /ssd2/xgo/src/strings/strings.go:993
993	func Replace(s, old, new string, n int) string {
(gdb) p n
$4 = 1
(gdb)

There have been several CL's submitted recently to fix DWARF problems: CL 362244, CL 362618, and CL 362244, most likely one of them took care of the problem.

Closing out this issue, please comment if needed.

Loading

@thanm thanm closed this Nov 11, 2021
@thanm thanm added this to the Go1.18 milestone Nov 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants