Bug 15432 – Win64: bad code offset in debug line number info
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2015-12-11T07:58:39Z
Last change time
2017-08-16T13:23:37Z
Keywords
pull, symdeb
Assigned to
No Owner
Creator
Rainer Schuetze
Comments
Comment #0 by r.sagitario — 2015-12-11T07:58:39Z
This program:
//////////////
import std.stdio;
enum AnotherColor { Red, }
enum Color { red, }
int main(string[] argv)
{
Color c = Color.red;
writeln(AnotherColor.Red.stringof); // line 10
return 0;
}
//////////////
compiled with "dmd -m64 -g main.d"
generates this disassembly for main (dumpbin):
_Dmain:
0000000000000000: 55 push rbp
0000000000000001: 48 8B EC mov rbp,rsp
0000000000000004: 48 83 EC 28 sub rsp,28h
0000000000000008: 53 push rbx
0000000000000009: 48 89 4D 10 mov qword ptr [rbp+10h],rcx
000000000000000D: 31 C0 xor eax,eax
000000000000000F: 89 45 E0 mov dword ptr [rbp-20h],eax
0000000000000012: 48 8D 0D 00 00 00 lea rcx,[_TMP0]
00
0000000000000019: BB 03 00 00 00 mov ebx,3
000000000000001E: 48 89 5D F0 mov qword ptr [rbp-10h],rbx
0000000000000022: 48 89 4D F8 mov qword ptr [rbp-8],rcx
0000000000000026: 48 8D 4D F0 lea rcx,[rbp-10h]
000000000000002A: 48 83 EC 20 sub rsp,20h
000000000000002E: E8 00 00 00 00 call _D3std5stdio16__T7writelnTAyaZ7writelnFNfAyaZv
0000000000000033: 48 83 C4 20 add rsp,20h
0000000000000037: 31 C0 xor eax,eax
0000000000000039: 5B pop rbx
000000000000003A: 48 8D 65 00 lea rsp,[rbp]
000000000000003E: 5D pop rbp
000000000000003F: C3 ret
and these line number infos ("c:\Program Files (x86)\VisualD\cv2pdb\dumplines"):
Sym: _Dmain
File: main.d
Off 0x0: Line 7
Off 0xd: Line 9
Off 0x12: Line 10
Off 0x36: Line 12
Please note, that the code offset for line 12 is not at the beginning of an address, so setting a breakpoint there corrupts execution (the debugger changes the respective code byte to 0xcc).
Comment #1 by yazan.dabain — 2015-12-11T11:14:25Z
I understand that you are talking about the debug symbols, right? If so, the following is not the cause of this bug.
This bug reminded me of a change I made in the stack trace addresses generation (https://github.com/D-Programming-Language/druntime/commit/8822115bc8d52fa61c15cef38fe77349f18747b9) that I did not test the effect of on Windows.
I made this change so that the addresses coming from the stack trace point before the return address (i.e. to point at the call instruction even though it most probably won't point at the start of it). I don't know if the address to line handler on Windows produces correct mappings for such addresses.
Comment #2 by r.sagitario — 2015-12-12T07:45:01Z
Yes, I'm referring to the debug information generated by dmd, so libraries cannot cause this.
Comment #3 by dlang-bugzilla — 2017-07-03T17:31:50Z
I reproduced this with 2.074.1.
Detailed steps to reproduce (without assuming prior knowledge):
1. You need:
- dumpbin.exe (Visual Studio or Windows SDK)
- dumplines.exe (build from source from https://github.com/rainers/cv2pdb, install Visual D from https://github.com/dlang/visuald/releases, or download stand-alone binary I compiled from https://dump.thecybershadow.net/3d28f947dd7aeeb30325935bc2463d5d/dumplines.exe)
2. Save code to test.d
3. Run: dmd -g -m64 -c test.d
4. Run: dumpbin.exe /DISASM test.obj > test.asm
5. Run: dumplines.exe test.obj > test-lines.txt
6. In test-lines.txt, note the offsets (Off 0x### numbers) for the _Dmain function (should be the first in the file)
7. In test.asm, note the offsets (first column of hex numbers) for the instructions for the _Dmain function (should be the first in the file)
If there are any offsets in test-lines.txt's _Dmain which do not appear in test.asm's _Dmain, then it is an instance of this bug.
A self-contained example would be nice. Would it be possible to reproduce this issue e.g. by throwing an exception and looking at the stack trace for an address not mapped to a line number OSLT?
Comment #4 by r.sagitario — 2017-07-03T18:37:58Z
Here's a further reduction:
///////////////////
void call15432(string col) {}
int test15432() // line 8
{
call15432(null);
return 0;
}
///////////////////
dumpbin:
_D7testpdb9test15432FZi:
0000000000000000: 55 push rbp
0000000000000001: 48 8B EC mov rbp,rsp
0000000000000004: 48 83 EC 10 sub rsp,10h
0000000000000008: 48 C7 45 F0 00 00 mov qword ptr [rbp-10h],0
00 00
0000000000000010: 48 C7 45 F8 00 00 mov qword ptr [rbp-8],0
00 00
0000000000000018: 48 8D 4D F0 lea rcx,[rbp-10h]
000000000000001C: 48 83 EC 20 sub rsp,20h
0000000000000020: E8 00 00 00 00 call _D7testpdb9call15432FAyaZv
0000000000000025: 48 83 C4 20 add rsp,20h
0000000000000029: 31 C0 xor eax,eax
000000000000002B: 48 8B E5 mov rsp,rbp
000000000000002E: 5D pop rbp
000000000000002F: C3 ret
cvdump (https://github.com/Microsoft/microsoft-pdb/blob/master/cvdump/cvdump.exe):
*** LINES
8 00000000 10 00000008 11 00000029 12 0000002A
You could get the offset to the line number before a stack address, but the return adress is still in the preceding line because there is some cleanup code after the call. In this code, the bad adress is even after the line with "return".
Enumerating the line number info is possible in test/runnable/testpdb.d, but a test will have to check specific code to be generated. At least, I don't have an idea what to test for instead.