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: malformed DWARF ranges (child not contained in parent) #33188

Open
thanm opened this issue Jul 19, 2019 · 5 comments
Open

cmd/compile: malformed DWARF ranges (child not contained in parent) #33188

thanm opened this issue Jul 19, 2019 · 5 comments
Assignees
Milestone

Comments

@thanm
Copy link
Member

@thanm thanm commented Jul 19, 2019

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

$ go version
go version devel +79bb1a3653 Thu Jul 18 10:16:59 2019 -0400 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
linux/amd64

What did you do?

Build this program:

package main

import "C"
import "log"

func main() {
	log.Printf("foo")
}

in the usual way, e.g. "go build main.go". Then run

llvm-dwarfdump -verify -verbose main

to check the resulting dwarf.

What did you expect to see?

Clean run

What did you see instead?

A number of errors of the form: "error: DIE address ranges are not contained in its parent's ranges:"

Here is one instance:

0x00006511: DW_TAG_inlined_subroutine
              DW_AT_abstract_origin	(0x00000000000014b8 "runtime.add")
              DW_AT_ranges	(0x00001370
                 [0x0000000000004984, 0x0000000000004988)
                 [0x00000000000049f9, 0x00000000000049fe))
              DW_AT_call_file	("/ssd2/go/src/runtime/chan.go")
              DW_AT_call_line	(121)

which is contained in this DIE:

0x000064e4: DW_TAG_inlined_subroutine
              DW_AT_abstract_origin	(0x0000000000001696 "runtime.chanbuf")
              DW_AT_low_pc	(0x000000000000497c)
              DW_AT_high_pc	(0x0000000000004984)
              DW_AT_call_file	("/ssd2/go/src/runtime/chan.go")
              DW_AT_call_line	(484)

so definitely an inconsistency. Note that the top-level parent is:

0x0000640e: DW_TAG_subprogram
              DW_AT_name	("runtime.chanrecv")
              DW_AT_low_pc	(0x00000000000048a0)
              DW_AT_high_pc	(0x0000000000004f52)
              DW_AT_frame_base	(DW_OP_call_frame_cfa)
              DW_AT_decl_file	("/ssd2/go/src/runtime/chan.go")
              DW_AT_external	(0x01)

There is nothing in the DWARF spec as far as I know that mandates this sort of address range nesting consistency, but I think it would probably be nice if a given inlined subroutines ranges were completely nested inside the parent DIE.

@aarzilli
Copy link
Contributor

@aarzilli aarzilli commented Jan 3, 2020

For the record this did cause delve to misbehave #1795 but it's also very easy to work around inside delve (#1807)

@petrhosek
Copy link

@petrhosek petrhosek commented Aug 14, 2020

We've recently ran into this issue as well when trying to generate GSYM files from Go binaries, see https://llvm.org/PR47157 for additional discussion.

@dr2chase
Copy link
Contributor

@dr2chase dr2chase commented Aug 14, 2020

Do we still believe that this nesting is not actually mandated by the DWARF spec?
It seems like it would be easy for the bug-filers to direct us to the relevant requirements, if they exist.

@thanm thanm self-assigned this Aug 17, 2020
@thanm thanm added NeedsFix and removed NeedsDecision labels Aug 17, 2020
@thanm thanm added this to the Go1.16 milestone Aug 17, 2020
@gopherbot
Copy link

@gopherbot gopherbot commented Aug 17, 2020

Change https://golang.org/cl/248724 mentions this issue: cmd/compile: clean up buggy DWARF inlined info PC ranges

@thanm
Copy link
Member Author

@thanm thanm commented Aug 19, 2020

Here is some more detail on what's happening in the compiler with this bug. There are two problems, one easy to fix and the other more difficult.

The first problem is that the code that computes ranges for inlined routines is not doing the book-keeping properly to insure that child ranges are included in parent ranges when handling nested inlines. This problem triggers the verifier's "DIE address ranges are not contained in its parent's ranges" error. I sent CL 248724 to fix this.

The second problem is trickier. The code that tracks variable scopes in the compiler is more or less independent from the code that handles inlining, meaning that when you have an inlined call whose callsite is positioned within a given lexical scope, the inlined routine DIE doesn't wind up as a child of the scope. This triggers a different error ("DIEs have overlapping address ranges").

Here is a reduced testcase that illustrates the second problem:

File a.go:

package a

func S(f, l, o int, v int) (err error) {
	var n = int32(v)
	return s(f, l, o, &n, 4)
}

func s(f, l, o int, v *int32, sz int) (err error) {
	defer func() { *v = 3 }()
	return nil
}

begin b.go:

package main

import "issue33188/a"

var gf, gl, gof int

func main() {
	for {
		var b [16]int
		e := a.S(gf, gl, gof, 33)
		if e == nil {
			continue
		}
		gf += 9
		b[gf&3] += 1
	}
}

Here's an abstracted version of the DWARF for main.main you get in this situation:

<1><f54>: Abbrev Number: 3 (DW_TAG_subprogram)
   <f55>   DW_AT_name        : main.main
   <f5f>   DW_AT_low_pc      : 0x45cd80
   <f67>   DW_AT_high_pc     : 0x45ce50
   <f6f>   DW_AT_frame_base  : 1 byte block: 9c 	(DW_OP_call_frame_cfa)
   <f71>   DW_AT_decl_file   : 0x2
   <f75>   DW_AT_external    : 1
<2><f76>: Abbrev Number: 20 (DW_TAG_lexical_block)
   <f77>   DW_AT_ranges      : 0x40
<3><f7b>: Abbrev Number: 11 (DW_TAG_variable)
   <f7c>   DW_AT_name        : b
   <f7e>   DW_AT_decl_line   : 9
   <f7f>   DW_AT_type        : <0x3cdc3>
   <f83>   DW_AT_location    : 0x0 (location list)
<3><f87>: Abbrev Number: 0
<2><f88>: Abbrev Number: 6 (DW_TAG_inlined_subroutine)
   <f89>   DW_AT_abstract_origin: <0xf0f>
   <f8d>   DW_AT_low_pc      : 0x45cde8
   <f95>   DW_AT_high_pc     : 0x45ce24
   <f9d>   DW_AT_call_file   : 0x2
   <fa1>   DW_AT_call_line   : 10
<3><fa2>: Abbrev Number: 19 (DW_TAG_formal_parameter)
   <fa3>   DW_AT_abstract_origin: <0xf21>
   <fa7>   DW_AT_location    : 0x35 (location list)
<3><fab>: Abbrev Number: 19 (DW_TAG_formal_parameter)
   <fac>   DW_AT_abstract_origin: <0xf29>
   <fb0>   DW_AT_location    : 0x68 (location list)
<3><fb4>: Abbrev Number: 19 (DW_TAG_formal_parameter)
   <fb5>   DW_AT_abstract_origin: <0xf31>
   <fb9>   DW_AT_location    : 0x9b (location list)
<3><fbd>: Abbrev Number: 14 (DW_TAG_variable)
   <fbe>   DW_AT_abstract_origin: <0xf4b>
   <fc2>   DW_AT_location    : 0xce (location list)
<3><fc6>: Abbrev Number: 0
<2><fc7>: Abbrev Number: 0

where the ranges for the lexical block containing "b" look like

             [0x000000000045cdaf, 0x000000000045cdf0)
             [0x000000000045ce24, 0x000000000045ce46))

which overlaps with the inlined routine but doesn't entirely contain it (and in addition the two DIEs in question are siblings within the main.main DIE, as opposed to having the scope parent the inline.

Fixing this is a good deal more complicated, since the two phases (scope generation and inline handling) operate more or less independently at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.