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

debug/elf: decoding dwarf section abbrev at offset 0x13: cannot determine class of unknown attribute form #33488

Closed
ghost opened this issue Aug 6, 2019 · 10 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@ghost
Copy link

ghost commented Aug 6, 2019

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

$ go version
go version go1.12.7 windows/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
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\xxx\AppData\Local\go-build
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=c:\xxx\go
set GOPROXY=
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\xxx\AppData\Local\Temp\go-build858273874=/tmp/go-build -gno-record-gcc-switches

What did you do?

I am trying to parse debug info of an embedded binary (ARM / Cortex) generated by Keil uVision.

What did you expect to see?

Be able to call DWARF() on the file without error.

What did you see instead?

Loading the file _elf, err := elf.Open(os.Args[1]) and calling _elf.DWARF() on it results in following error:
decoding dwarf section abbrev at offset 0x13: cannot determine class of unknown attribute form

This error seems to originated from debug/dwarf/entry.go with (in my case) form being formIndirect.

At somewhat similar issue and change is described here: https://go-review.googlesource.com/c/go/+/14541/2/src/debug/dwarf/entry.go and I can returning ClassUnknown for formIndirect does help get some of the parsing done, but I missing crucial pieces of the dwarf section (i.e. the members of a struct I care for seem to get skipped altogether).

As I am new to all of this I'd be thankful any comments on whether I have a funamental misunderstanding of purpose of the elf package (i.e. "was never meant to worked with embedded binariers") or whether there's something else I could besides deep diving into the issue and creating a pull request.

@ianlancetaylor ianlancetaylor added the NeedsFix The path to resolution is known, but the work has not been done. label Aug 6, 2019
@ianlancetaylor ianlancetaylor added this to the Go1.14 milestone Aug 6, 2019
@ianlancetaylor
Copy link
Contributor

At first glance it looks like a bug. I'm not sure parseAbbrev doesn't handle formIndirect.

It would help if you provide a tiny binary that demonstrates the problem, or instructions for how to create one. Thanks.

@ghost
Copy link
Author

ghost commented Aug 7, 2019

Thanks for the reply.

You can trigger the issue using Keil uVision and the "Blinky project Silicon Labs 'EFM32 Giant Gecko microcontroller using Silicon Labs 'EFM32GG-STK3700 Starter Kit' Board", available for installation from Project > Manage > Pack installer. This not to imply the issue is with this particular vendor, I've reproduced it with other projects, too.

Here's the debug file compiled on my machine: Blinky.zip

With the compiled debug version you can run below go code to get error:

elftest.exe efm\Blinky\Debug\Blinky.axf
decoding dwarf section abbrev at offset 0x13: cannot determine class of unknown attribute form

elftest source:

package main

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

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: elftest elf_file")
		os.Exit(1)
	}

	elffile, _ := elf.Open(os.Args[1])

	_, dwarferror := elffile.DWARF()
	if dwarferror != nil {
		fmt.Println(dwarferror.Error())
	}
}

@thanm thanm self-assigned this Aug 14, 2019
@thanm
Copy link
Contributor

thanm commented Aug 14, 2019

I took a look at this as well. As Ian mentioned the problems seem to relate to the handling of DW_FORM_indirect. There is code in that handles it in the main DIE reader but for some reason it is getting rejected in the abbrev code handler. I will send a tentative fix.

FYI, there is some weird DWARF in the binary you posted. Compile units seem to be getting padded with extra null bytes for some reason. Ex:

 <1><2fa>: Abbrev Number: 80 (DW_TAG_typedef)
    <2fb>   DW_AT_name        : uintmax_t
    <305>   DW_AT_type        : DW_FORM_ref2 <0xed>
    <308>   DW_AT_decl_file   : 1
    <309>   DW_AT_decl_line   : 107
    <30a>   DW_AT_decl_column : 33
 <1><30b>: Abbrev Number: 0
 <0><30c>: Abbrev Number: 0
 <-1><30d>: Abbrev Number: 0
 <-2><30e>: Abbrev Number: 0
 <-3><30f>: Abbrev Number: 0
  Compilation Unit @ offset 0x310:

Note the -2, -3 at the end.

@thanm
Copy link
Contributor

thanm commented Aug 14, 2019

Writing a regression test for this is proving to be tricky -- neither clang nor gcc seem to emit abbrevs that use DW_FORM_indirect. About all I can think of for a test is to check in the Blinky.axf file, which is about 380k. Let me know if there are any ideas for a smaller/better test.

@gopherbot
Copy link

Change https://golang.org/cl/190158 mentions this issue: debug/dwarf: better handling for DW_FORM_indirect

@ghost
Copy link
Author

ghost commented Aug 16, 2019

Thanks for the fix! I am out office until beginning of September and won't be able to test until then (best case). For testing in general I cannot make better suggestion either (yet), but I'll add anything else I might come across here later.

gopherbot pushed a commit that referenced this issue Sep 3, 2019
Fix a buglet in abbrev processing related to DW_FORM_indirect. When
reading an abbrev entry if we encounter an attribute with form
DW_FORM_indirect, leave the class as ClassUnknown, then when the
abbrev is walked during the reading of the DIE fill in the class based
on the value read at that point (code for handling DW_FORM_indirect
seems to be already partially in place in the DIE reader).

Updates #33488.

Change-Id: I9dc89abf5cc8d7ea96824c0011bef979de0540bf
Reviewed-on: https://go-review.googlesource.com/c/go/+/190158
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
@thanm
Copy link
Contributor

thanm commented Sep 3, 2019

@g4w Fix submitted. Let me know if I can close this bug out.

t4n6a1ka pushed a commit to t4n6a1ka/go that referenced this issue Sep 5, 2019
Fix a buglet in abbrev processing related to DW_FORM_indirect. When
reading an abbrev entry if we encounter an attribute with form
DW_FORM_indirect, leave the class as ClassUnknown, then when the
abbrev is walked during the reading of the DIE fill in the class based
on the value read at that point (code for handling DW_FORM_indirect
seems to be already partially in place in the DIE reader).

Updates golang#33488.

Change-Id: I9dc89abf5cc8d7ea96824c0011bef979de0540bf
Reviewed-on: https://go-review.googlesource.com/c/go/+/190158
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
@thanm
Copy link
Contributor

thanm commented Sep 10, 2019

I am going to close this bug, please re-open if you see fit. Thanks.

@thanm thanm closed this as completed Sep 10, 2019
@ghost
Copy link
Author

ghost commented Sep 11, 2019

I managed to do a cursory check and it seems to address my issue, thanks. If something else comes up I'll re-open.

@Pymann
Copy link

Pymann commented Jan 25, 2020

I applied changes fro: https://go-review.googlesource.com/c/go/+/190158/
while using newest go-version golang 1.13.6 amd64 windows version.
But in typeunit.go
I had to change line 140 to (deleted first nil pointer param):
e := tur.b.entry(tur.tu.atable, tur.tu.base, tur.tu.vers)

Now I have dwarf info, but i will check for consistency.

@golang golang locked and limited conversation to collaborators Jan 24, 2021
@rsc rsc unassigned thanm Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

4 participants