Skip to content

debug/dwarf: r.Next() returns wrong ent when DWARF5 used. #57046

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

Closed
joeyjiaojg opened this issue Dec 2, 2022 · 16 comments
Closed

debug/dwarf: r.Next() returns wrong ent when DWARF5 used. #57046

joeyjiaojg opened this issue Dec 2, 2022 · 16 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@joeyjiaojg
Copy link

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

go 1.19.3

Does this issue reproduce with the latest release?

yes

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

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="~/.cache/go-build"
GOENV="~/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/x86_64/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/x86_64"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/x86_64/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/x86_64/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.19"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
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 -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build147440491=/tmp/go-build -gno-record-gcc-switches"

What did you do?

0x000142a2:   DW_TAG_subprogram
                DW_AT_low_pc    (0xffffffff81002280)
                DW_AT_high_pc   (0xffffffff810022f0)
                DW_AT_frame_base        (DW_OP_reg7 RSP)
                DW_AT_call_all_calls    (true)
                DW_AT_abstract_origin   (0x000160e6 "rcu_read_unlock")
				
0x000160e6:   DW_TAG_subprogram
                DW_AT_name      ("rcu_read_unlock")
                DW_AT_decl_file ("/x86_64/linux/./include/linux/rcupdate.h")
                DW_AT_decl_line (765)
                DW_AT_prototyped        (true)
                DW_AT_inline    (DW_INL_inlined)

Above is extracted from vmlinux (compiled by clang-15) by llvm-dwarfdump-15, when linux kernel compiled with DWARF5 debug info, go debug/dwarf can't decode entry at 0x000160e6 correctly.

Test program

package main

import (
    "fmt"
    "debug/dwarf"
    "debug/elf"
)

func main() {
    file, err := elf.Open("vmlinux")
    if err != nil {
        return
    }
    debugInfo, err := file.DWARF()
    if err != nil {
        return
    }

        ent, _ := getEntryByOffset(debugInfo, 0x000142a2)
        fmt.Printf("%v\n", ent)
        ent, _ = getEntryByOffset(debugInfo, 0x000160e6)
        fmt.Printf("%v\n", ent)
}

func getEntryByOffset(debugInfo *dwarf.Data, offset dwarf.Offset) (*dwarf.Entry, error) {
        r := debugInfo.Reader()
        r.Seek(offset)
        return r.Next()
}

What did you expect to see?

The 2nd printf should print ent name as rcu_read_unlock.

What did you see instead?

The 2nd printf should print ent name of some other subprogram.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Dec 2, 2022
@ianlancetaylor
Copy link
Member

Can you make the test file available somewhere? Or provide a standalone test? Thanks.

CC @thanm @aclements

@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Dec 3, 2022
@ianlancetaylor ianlancetaylor added this to the Backlog milestone Dec 3, 2022
@joeyjiaojg
Copy link
Author

joeyjiaojg commented Dec 5, 2022

vmlinux is too big to share.
So I'm searching the first "rcu_read_unlock" and its DW_AT_abstract_origin.

  • The 1st one is from compile_unit init/main.c.
  • go doesn't work for init/main.o or vmlinux.
  • vmlinux (compiled from https://github.com/torvalds/linux) w/ compile command LLVM=1 ARCH=x86_64 SRCARCH=x86 make -j$(nproc) with CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y set in .config.
$  ./test vmlinux 0x000142a4 0x000160ed
&{82596 Subprogram true [{Lowpc 18446744071578850531 ClassAddress} {Highpc 112 ClassConstant} {FrameBase [87] ClassExprLoc} {CallAllCalls true ClassFlag} {AbstractOrigin 90349 ClassReference}]}
&{90349 Subprogram false [{Name **event_class_initcall_level** ClassString} {DeclFile 232 ClassConstant} {DeclLine 765 ClassConstant} {Prototyped true ClassFlag} {Inline 1 ClassConstant}]}
$ ./test init/main.o 0x00012b27 0x00014970
&{76583 Subprogram true [{Lowpc 1256 ClassAddress} {Highpc 112 ClassConstant} {FrameBase [87] ClassExprLoc} {CallAllCalls true ClassFlag} {AbstractOrigin 84336 ClassReference}]}
&{84336 Subprogram false [{Name **rcu_read_lock** ClassString} {DeclFile 232 ClassConstant} {DeclLine 765 ClassConstant} {Prototyped true ClassFlag} {Inline 1 ClassConstant}]}

@joeyjiaojg
Copy link
Author

Test program

package main

import (
    "fmt"
    "debug/dwarf"
    "debug/elf"
    "os"
    "strconv"
)

func main() {
    file, err := elf.Open(os.Args[1])
    if err != nil {
        return
    }
    debugInfo, err := file.DWARF()
    if err != nil {
        return
    }

    val, _ := strconv.ParseUint(os.Args[2], 0, 64)
        ent, _ := getEntryByOffset(debugInfo, dwarf.Offset(val))
        fmt.Printf("%v\n", ent)
    val, _ = strconv.ParseUint(os.Args[3], 0, 64)
        ent, _ = getEntryByOffset(debugInfo, dwarf.Offset(val))
        fmt.Printf("%v\n", ent)
}

func getEntryByOffset(debugInfo *dwarf.Data, offset dwarf.Offset) (*dwarf.Entry, error) {
        r := debugInfo.Reader()
        r.Seek(offset)
        return r.Next()
}

@joeyjiaojg
Copy link
Author

Attach the init/main.o instead https://github.com/joeyjiaojg/go/raw/master/test/dwarf/dwarf5.o

@ianlancetaylor
Copy link
Member

It's going to be difficult for us to fix this problem if we can't recreate it ourselves. Anything you can do to make that possible would be appreciated. Thanks.

@joeyjiaojg
Copy link
Author

you can reproduce

bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)

git clone https://github.qualcomm.com/LinuxSecurity/syzkaller
git clone https://github.com/torvalds/linux
cp syzkaller/src/github.com/google/syzkaller/dashboard/config/linux/upstream-apparmor-kasan.config linux/.config
cd linux
LLVM=1 ARCH=x86_64 SRCARCH=x86 make -j$(nproc) olddefconfig
LLVM=1 ARCH=x86_64 SRCARCH=x86 make -j$(nproc)

@joeyjiaojg
Copy link
Author

To avoid confusion, you can use the test steps below only:

wget https://github.com/joeyjiaojg/go/raw/master/test/dwarf/dwarf5.o
copy code in https://github.com/golang/go/issues/57046#issuecomment-1336625504 to test.go
go build test.go

./test init/main.o 0x00012b27 0x00014970
&{76583 Subprogram true [{Lowpc 1256 ClassAddress} {Highpc 112 ClassConstant} {FrameBase [87] ClassExprLoc} {CallAllCalls true ClassFlag} {AbstractOrigin 84336 ClassReference}]}
&{84336 Subprogram false [{Name **rcu_read_lock** ClassString} {DeclFile 232 ClassConstant} {DeclLine 765 ClassConstant} {Prototyped true ClassFlag} {Inline 1 ClassConstant}]}

@mknyszek mknyszek added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Dec 7, 2022
@gopherbot
Copy link
Contributor

Timed out in state WaitingForInfo. Closing.

(I am just a bot, though. Please speak up if this is a mistake or you have the requested information.)

@github-project-automation github-project-automation bot moved this from Todo to Done in Go Compiler / Runtime Jan 7, 2023
@aclements aclements reopened this Jan 9, 2023
@github-project-automation github-project-automation bot moved this from Done to In Progress in Go Compiler / Runtime Jan 9, 2023
@github-project-automation github-project-automation bot moved this from In Progress to Done in Go Compiler / Runtime Jan 9, 2023
@aclements aclements removed the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Jan 9, 2023
@aclements
Copy link
Member

Reopening because @joeyjiaojg provided repro instructions.

@aclements aclements reopened this Jan 9, 2023
@github-project-automation github-project-automation bot moved this from Done to In Progress in Go Compiler / Runtime Jan 9, 2023
@blacktop
Copy link

blacktop commented Mar 2, 2025

any progress on this?

@blacktop
Copy link

blacktop commented Mar 2, 2025

TEST_FILE

#include <stdio.h>

// Define a structure named "example"
struct example {
    int id;
    char name[50];
    float value;
};

// Define a function also named "example"
void example(struct example* item) {
    printf("ID: %d\n", item->id);
    printf("Name: %s\n", item->name);
    printf("Value: %.2f\n", item->value);
}

int main() {
    // Create and initialize an instance of the structure
    struct example my_example = {
        .id = 42,
        .name = "Test Item",
        .value = 3.14159
    };
    
    // Call the function with the same name
    example(&my_example);
    
    return 0;
}

BUILD_CMD

clang -g -gdwarf-5 -glldb -O0 -Xclang -debug-info-kind=constructor example.c -o example

DWARFDUMP

❱ xcrun dwarfdump example.dSYM --name example
example.dSYM/Contents/Resources/DWARF/example:  file format Mach-O arm64

0x0000002d: DW_TAG_subprogram
              DW_AT_low_pc      (0x00000001000004b0)
              DW_AT_high_pc     (0x0000000100000524)
              DW_AT_frame_base  (DW_OP_reg29 W29)
              DW_AT_name        ("example")
              DW_AT_decl_file   ("/private/tmp/dwarf5_test/example.c")
              DW_AT_decl_line   (11)
              DW_AT_prototyped  (true)
              DW_AT_external    (true)

0x00000068: DW_TAG_structure_type
              DW_AT_name        ("example")
              DW_AT_byte_size   (0x3c)
              DW_AT_decl_file   ("/private/tmp/dwarf5_test/example.c")
              DW_AT_decl_line   (4)

TEST_RUNNER

package main

import (
	"debug/dwarf"
	"debug/macho"
	"fmt"
)

func main() {
	file, err := macho.Open("example.dSYM/Contents/Resources/DWARF/example")
	if err != nil {
		panic(err)
	}
	debugInfo, err := file.DWARF()
	if err != nil {
		panic(err)
	}

	ent, err := getEntryByOffset(debugInfo, 0x0000002d)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%v\n", ent)
	ent, _ = getEntryByOffset(debugInfo, 0x00000068)
	fmt.Printf("%v\n", ent)
}

func getEntryByOffset(debugInfo *dwarf.Data, offset dwarf.Offset) (*dwarf.Entry, error) {
	r := debugInfo.Reader()
	r.Seek(offset)
	return r.Next()
}

TEST_RESULTS

go run main.go

&{45 Subprogram true [{Lowpc 2251821288521748 ClassAddress} {Highpc 116 ClassConstant} {FrameBase [109] ClassExprLoc} {Name "char" ClassString} {DeclFile 0 ClassConstant} {DeclLine 11 ClassConstant} {Prototyped true ClassFlag} {External true ClassFlag}]}
&{104 StructType true [{Name "char" ClassString} {ByteSize 60 ClassConstant} {DeclFile 0 ClassConstant} {DeclLine 4 ClassConstant}]}

@blacktop
Copy link

blacktop commented Mar 2, 2025

strangely enough when just iterating over the DIEs via r.Next() I can hit the example, but then when I try and get it by offset set it uses char's string as it's name? I'm thinking either r.Seek has a bug or the DW_FORM_strx's uleb128 reader?

@blacktop
Copy link

blacktop commented Mar 2, 2025

		// We have to adjust by the offset of the
		// compilation unit. This won't work if the
		// program uses Reader.Seek to skip over the
		// unit. Not much we can do about that.

😭

@thanm
Copy link
Contributor

thanm commented Mar 2, 2025

This is being looked at, you can follow along in this tentative CL: https://go-review.googlesource.com/c/go/+/628876 if you want more info.

@blacktop
Copy link

blacktop commented Mar 3, 2025

This is being looked at, you can follow along in this tentative CL: https://go-review.googlesource.com/c/go/+/628876 if you want more info.

nice! I maintain a fork and I solved it for my own purposes in a very similar way, but your's is cleaner ;)

There's also the NEW debug_names that tells you the exact CU index for the entry which might be useful to you, but I don't think looking up types/entries by names is something that pkg needs to do.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/655976 mentions this issue: debug/dwarf: fix problem with DWARF 5 and Seek method

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

7 participants