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: Debugging optimized code can yield completely bogus values (sometimes) #28486

Closed
dr2chase opened this issue Oct 30, 2018 · 6 comments
Labels
Debugging FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@dr2chase
Copy link
Contributor

Please answer these questions before submitting your issue. Thanks!

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

tip for 1.12 development

Does this issue reproduce with the latest release?

yes

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

linux and osx

What did you do?

This is debugging a program that is currently itself in a CL
( https://go-review.googlesource.com/c/tools/+/143357 )
The program in question is intended to run on OSX, though it is possible to make a copy of the its input (an OSX executable) and run it on Linux.

GOSSAFUNC='main' go build -a  '-gcflags=all=-d=locationlists=4' . >& main.log
cp splitdwarf ./sd 
./sd ./sd
./sd ./sd ./sd.sym 

dlv exec ./sd -- ./splitdwarf
b main.main
c
b 226
c

Line 226 is the header of this loop:

// Map out Dwarf sections (that is, this is section descriptors, not their contents).
offset := uint32(newdwarf.Offset)
for i := dwarf.Firstsect; i < dwarf.Firstsect+dwarf.Nsect; i++ {
o := exeMacho.Sections[i]
s := o.Copy()
s.Offset = offset
us := o.UncompressedSize()
if s.Size < us {
s.Size = uint64(us)
s.Align = 0 // This is apparently true for debugging sections
}
offset += uint32(us)
if strings.HasPrefix(s.Name, "z") {
s.Name = "
" + s.Name[3:] // remove "z"
}
s.Reloff = 0
s.Nreloc = 0
newtoc.AddSection(s)
}


The output from there looks like this:
(dlv) c
> main.main() ./splitdwarf.go:226 (PC: 0x10baedf)
=> 226:		for i := dwarf.Firstsect; i < dwarf.Firstsect+dwarf.Nsect; i++ {
(dlv) p i
(unreadable could not find loclist entry at 0x4d249 for address 0x10baedf)
(dlv) n
> main.main() ./splitdwarf.go:227 (PC: 0x10baf5c)
=> 227:			o := exeMacho.Sections[i]
(dlv) p i
12
(dlv) n
> main.main() ./splitdwarf.go:230 (PC: 0x10bafbe)
=> 230:			us := o.UncompressedSize()
(dlv) n
> main.main() ./splitdwarf.go:232 (PC: 0x10bafe2)
=> 232:				s.Size = uint64(us)
(dlv) n
> main.main() ./splitdwarf.go:233 (PC: 0x10bafe6)
=> 233:				s.Align = 0 // This is apparently true for debugging sections
(dlv) n
> main.main() ./splitdwarf.go:235 (PC: 0x10bafed)
=> 235:			offset += uint32(us)
(dlv) n
> main.main() ./splitdwarf.go:236 (PC: 0x10baff7)
=> 236:			if strings.HasPrefix(s.Name, "__z") {
(dlv) n
> main.main() ./splitdwarf.go:237 (PC: 0x10bb129)
=> 237:				s.Name = "__" + s.Name[3:] // remove "z"
(dlv) n
> main.main() ./splitdwarf.go:240 (PC: 0x10bb00f)
=> 240:			s.Nreloc = 0
(dlv) n
> main.main() ./splitdwarf.go:226 (PC: 0x10baf0e)
=> 226:		for i := dwarf.Firstsect; i < dwarf.Firstsect+dwarf.Nsect; i++ {
(dlv) p i
557440

Notice how ridiculous the value of i is.

The cause appears to be an incorrect location list, but I don't know exactly where it's going wrong (yet). The PC where i is printed wrong is

	splitdwarf.go:226	0x10baef2	eb44				jmp 0x10baf38
	file.go:63		0x10baef4	41833819			cmp dword ptr [r8], 0x19
	file.go:66		0x10baef8	bf44000000			mov edi, 0x44
	file.go:66		0x10baefd	41ba50000000			mov r10d, 0x50
	file.go:66		0x10baf03	410f44fa			cmovz edi, r10d
	file.go:66		0x10baf07	017b14				add dword ptr [rbx+0x14], edi
	file.go:67		0x10baf0a	41017804			add dword ptr [r8+0x4], edi
=>	splitdwarf.go:226	0x10baf0e	8b7c246c			mov edi, dword ptr [rsp+0x6c]
	splitdwarf.go:226	0x10baf12	ffc7				inc edi
	macho.go:121		0x10baf14	4c8b8424f8010000		mov r8, qword ptr [rsp+0x1f8]
	macho.go:121		0x10baf1c	4c8b9c2478010000		mov r11, qword ptr [rsp+0x178]

which is v2338 in block 62

b99: ← b94 b96
v2586 (218) = Phi <mem> v1124 v1130
v2097 (218) = LoadReg <*macho.Segment> v2105 : DX
v1143 (218) = MOVQload <uint64> [48] v2097 v2586 : BX
v1144 (218) = ADDQload <uint64> [40] v1143 v2097 v2586 : BX (macho.x[uint64])
v1146 (1302) = ADDQconst <uint64> [4095] v1144 : BX
v1148 (1302) = ANDQconst <uint64> [-4096] v1146 : BX (~R0[uint64])
v1157 (+218) = MOVQstore <mem> [40] v2226 v1148 v2586
v1162 (219) = MOVQstore <mem> v2 v2129 v1157
v2148 (219) = LoadReg <*macho.File> v739 : BX
v1163 (219) = MOVQstore <mem> [8] v2 v2148 v1162
v1165 (219) = MOVQstoreconst <mem> [val=1,off=16] v2 v1163
v1166 (+219) = CALLstatic <mem> {golang.org/x/tools/cmd/splitdwarf/macho.(*Segment).UncompressedSize} [32] v1165
v1168 (219) = MOVQload <uint64> [24] v2 v1166 : AX
v2071 (219) = LoadReg <*macho.Segment> v2225 : CX
v1172 (219) = MOVQstore <mem> [48] v2071 v1168 v1166
v2028 (220) = LoadReg <*macho.Segment> v2105 : DX
v1181 (+220) = MOVQload <uint64> [32] v2028 v1172 : BX
v1182 (220) = ADDQload <uint64> [24] v1181 v2028 v1172 : BX
v1186 (220) = MOVQstore <mem> [24] v2071 v1182 v1172
v1192 (1302) = ADDQconst <uint64> [4095] v1168 : AX
v1194 (1302) = ANDQconst <uint64> [-4096] v1192 : AX (~R0[uint64])
v1203 (+221) = MOVQstore <mem> [32] v2071 v1194 v1186
v1848 (222) = LoadReg <*macho.FileTOC> v1849 : AX
v1205 (222) = MOVQstore <mem> v2 v1848 v1203
v1206 (222) = MOVQstore <mem> [8] v2 v2071 v1205
v1207 (+222) = CALLstatic <mem> {golang.org/x/tools/cmd/splitdwarf/macho.(*FileTOC).AddSegment} [16] v1206
v2379 (225) = LoadReg <*macho.Segment> v2225 : AX
v1211 (+225) = MOVQload <uint64> [40] v2379 v1207 : CX
v54 (226) = LoadReg <*macho.Segment> v2117 : DX
v1217 (+226) = MOVLload <uint32> [72] v54 v1207 : BX (i[uint32])
v2351 (226) = LoadReg <*macho.File> v739 : SI
Plain → b100 (226)

b62: ← b77 b63
v1479 (61) = Phi <mem> v1437 v1108
v193 (+63) = CMPLconstload <flags> [val=25,off=0] v1145 v1479
v1727 (66) = MOVLconst <uint32> [68] : DI
v2256 (66) = MOVLconst <uint32> [80] : R10
v1496 (66) = CMOVLEQ <uint32> v1727 v2256 v193 : DI (macho.sectionsize·4[uint32])
v1501 (+66) = ADDLmodify <mem> [20] v2017 v1496 v1479
v1511 (+67) = ADDLmodify <mem> [4] v1145 v1496 v1501
v2338 (226) = LoadReg <uint32> v2092 : DI
v1513 (+226) = ADDLconst <uint32> [1] v2338 : DI (i[uint32])
v161 (121) = LoadReg <*macho.File> v739 : R8
v2007 (121) = LoadReg <*macho.Segment> v2117 : R11
v678 (285) = LoadReg <*macho.Segment> v2225 : AX
v669 (226) = Copy <*macho.Segment> v2007 : DX
v1176 (227) = Copy <*macho.File> v161 : SI
v1180 (226) = Copy <uint32> v1513 : BX
v663 (229) = LoadReg <uint32> v1993 : CX
Plain → b100 (+121)

b100: ← b99 b62
v1218 (226) = Phi <uint32> v1217 v1180 : BX (i[uint32])
v1220 (226) = Phi <mem> v1207 v1511
v2542 (229) = Phi <uint32> v1211 v663 : CX (offset[uint32])
v1228 (+226) = MOVLload <uint32> [64] v54 v1220 : DI
v1229 (226) = ADDLload <uint32> [72] v1228 v54 v1220 : DI
v1597 (226) = CMPL <flags> v1218 v1229
ULT v1597 → b101 b103 (likely) (226)

The location list declares that i can be found in BX, which is wrong; it appears to have inferred this because i was in BX at the end of the immediately previous block, b99.

@dr2chase dr2chase self-assigned this Oct 30, 2018
@dr2chase
Copy link
Contributor Author

@heschik If you have any ideas about this, that might be helpful, I am currently slogging through location list construction in ssa/debug.go to figure out how it went wrong here.

@heschi
Copy link
Contributor

heschi commented Oct 30, 2018

Can you attach the ssa.html and -d locationlists output?

@dr2chase
Copy link
Contributor Author

dwarf_and_ssa.zip

Also, my notes here:

   splitdwarf.go:219 0x10bae8d   488b8c24c0010000     mov rcx, qword ptr [rsp+0x1c0]
   splitdwarf.go:219 0x10bae95   48894130       mov qword ptr [rcx+0x30], rax
   splitdwarf.go:220 0x10bae99   488b9424b8010000     mov rdx, qword ptr [rsp+0x1b8]
   splitdwarf.go:220 0x10baea1   488b5a20       mov rbx, qword ptr [rdx+0x20]
   splitdwarf.go:220 0x10baea5   48035a18       add rbx, qword ptr [rdx+0x18]
   splitdwarf.go:220 0x10baea9   48895918       mov qword ptr [rcx+0x18], rbx
   file.go:1302      0x10baead   4805ff0f0000         add rax, 0xfff
   file.go:1302      0x10baeb3   482500f0ffff         and rax, -0x1000
   splitdwarf.go:221 0x10baeb9   48894120       mov qword ptr [rcx+0x20], rax
   splitdwarf.go:222 0x10baebd   488b842448010000     mov rax, qword ptr [rsp+0x148]
   splitdwarf.go:222 0x10baec5   48890424       mov qword ptr [rsp], rax
   splitdwarf.go:222 0x10baec9   48894c2408        mov qword ptr [rsp+0x8], rcx
   splitdwarf.go:222 0x10baece   e89df5feff        call $golang.org/x/tools/cmd/splitdwarf/macho.(*FileTOC).AddSegment
   splitdwarf.go:225 0x10baed3   488b8424c0010000     mov rax, qword ptr [rsp+0x1c0]
   splitdwarf.go:225 0x10baedb   488b4828       mov rcx, qword ptr [rax+0x28]
   splitdwarf.go:226 0x10baedf   488b942478010000     mov rdx, qword ptr [rsp+0x178]
   splitdwarf.go:226 0x10baee7   8b5a48            mov ebx, dword ptr [rdx+0x48]

   splitdwarf.go:226 0x10baeea   488bb424f8010000     mov rsi, qword ptr [rsp+0x1f8]
   splitdwarf.go:226 0x10baef2   eb44           jmp 0x10baf38

   Block 62
   file.go:63     0x10baef4   41833819       cmp dword ptr [r8], 0x19
   file.go:66     0x10baef8   bf44000000        mov edi, 0x44
   file.go:66     0x10baefd   41ba50000000         mov r10d, 0x50
   file.go:66     0x10baf03   410f44fa       cmovz edi, r10d
   file.go:66     0x10baf07   017b14            add dword ptr [rbx+0x14], edi
   file.go:67     0x10baf0a   41017804       add dword ptr [r8+0x4], edi
=> splitdwarf.go:226 0x10baf0e   8b7c246c       mov edi, dword ptr [rsp+0x6c] // v2338
   splitdwarf.go:226 0x10baf12   ffc7           inc edi

   macho.go:121      0x10baf14   4c8b8424f8010000     mov r8, qword ptr [rsp+0x1f8]
   macho.go:121      0x10baf1c   4c8b9c2478010000     mov r11, qword ptr [rsp+0x178]
   splitdwarf.go:285 0x10baf24   488b8424c0010000     mov rax, qword ptr [rsp+0x1c0]
   splitdwarf.go:226 0x10baf2c   4c89da            mov rdx, r11
   splitdwarf.go:227 0x10baf2f   4c89c6            mov rsi, r8
   splitdwarf.go:226 0x10baf32   89fb           mov ebx, edi
   splitdwarf.go:229 0x10baf34   8b4c2454       mov ecx, dword ptr [rsp+0x54]

   splitdwarf.go:226 0x10baf38   8b7a40            mov edi, dword ptr [rdx+0x40] // v1228 -- CL loclist begin
   splitdwarf.go:226 0x10baf3b   037a48            add edi, dword ptr [rdx+0x48] // v1229 -- w/o CL loclist begin

   splitdwarf.go:226 0x10baf3e   39fb           cmp ebx, edi
   splitdwarf.go:226 0x10baf40   0f83bd020000         jnb 0x10bb203
   splitdwarf.go:227 0x10baf46   488b7e48       mov rdi, qword ptr [rsi+0x48]
   splitdwarf.go:227 0x10baf4a   48395e50       cmp qword ptr [rsi+0x50], rbx
   splitdwarf.go:227 0x10baf4e   0f86d3120000         jbe 0x10bc227
   splitdwarf.go:226 0x10baf54   895c246c       mov dword ptr [rsp+0x6c], ebx
   splitdwarf.go:229 0x10baf58   894c2454       mov dword ptr [rsp+0x54], ecx
   splitdwarf.go:227 0x10baf5c   488b04df       mov rax, qword ptr [rdi+rbx*8]
   splitdwarf.go:227 0x10baf60   4889842458010000     mov qword ptr [rsp+0x158], rax
   file.go:596    0x10baf68   488d0dd1ec0200       lea rcx, ptr [rip+0x2ecd1]

@katiehockman katiehockman changed the title Debugging optimized code can yield completely bogus values (sometimes) cmd/splitdwarf: Debugging optimized code can yield completely bogus values (sometimes) Oct 30, 2018
@katiehockman katiehockman added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 30, 2018
@heschi heschi changed the title cmd/splitdwarf: Debugging optimized code can yield completely bogus values (sometimes) cmd/compile: Debugging optimized code can yield completely bogus values (sometimes) Oct 30, 2018
@heschi
Copy link
Contributor

heschi commented Oct 30, 2018

It looks like nothing in buildLocationLists is flushing out pending list entries at the beginning of a block when it was live in the textually previous block but dead in the current one. That will cause list entries to be extended until that list changes for some other reason.

@gopherbot
Copy link

Change https://golang.org/cl/146718 mentions this issue: cmd/compile: for location lists, handle case where prev block is not a pred

@gopherbot
Copy link

Change https://golang.org/cl/150097 mentions this issue: cmd/compile: Avoid and filter out zero-length location-lists.

gopherbot pushed a commit that referenced this issue Dec 12, 2018
This change avoids creating zero length location lists by
repairing an overly aggressive change in CL146718
and by explicitly checking for and filtering out any
zero-length lists that are detected (building
compiler+runtime creates a single one).

Updates #28486.

Change-Id: I01c571fee2376474c7f3038e801bd58fd9e0b820
Reviewed-on: https://go-review.googlesource.com/c/150097
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
@golang golang locked and limited conversation to collaborators Dec 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Debugging FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

4 participants