1 module ddebug.windows.debuginfo;
2 
3 version(Windows):
4 import dlangui.core.logger;
5 import std.file;
6 import std.algorithm;
7 import std.conv;
8 import std.exception;
9 
10 class FileFormatException : Exception {
11     this(string msg, Exception baseException = null, string file = __FILE__, size_t line = __LINE__) {
12         super(msg, baseException, file, line);
13     }
14     this(Exception baseException = null, string file = __FILE__, size_t line = __LINE__) {
15         super("", baseException, file, line);
16     }
17     //this(string file = __FILE__, size_t line = __LINE__) {
18     //    super("Exception while parsing file format", file, line);
19     //}
20 }
21 
22 
23 struct Buffer {
24     ubyte[] buf;
25     void skip(uint bytes) {
26         enforce(bytes <= buf.length, new FileFormatException("skip: index is outside file range"));
27         buf = buf[bytes .. $];
28     }
29     uint uintAt(uint pos) {
30         enforce(pos + 4 <= buf.length, new FileFormatException("uintAt: index is outside file range"));
31         return cast(uint)buf[pos] | (cast(uint)buf[pos + 1] << 8) | (cast(uint)buf[pos + 2] << 16) | (cast(uint)buf[pos + 3] << 24);
32     }
33     ushort ushortAt(uint pos) {
34         enforce(pos + 2 <= buf.length, new FileFormatException("ushortAt: index is outside file range"));
35         return cast(ushort)buf[pos] | (cast(ushort)buf[pos + 1] << 8);
36     }
37     ubyte ubyteAt(uint pos) {
38         enforce(pos + 1 <= buf.length, new FileFormatException("ubyteAt: index is outside file range"));
39         return buf[pos];
40     }
41     //void check(uint pos, string data) {
42     //    enforce(pos + data.length <= buf.length, new FileFormatException("check: index is outside file range"));
43     //    enforce(equal(buf[pos..pos + data.length], cast(ubyte[])data), new FileFormatException("pattern does not match"));
44     //}
45     void check(uint pos, ubyte[] data) {
46         enforce(pos + data.length <= buf.length, new FileFormatException("check: index is outside file range"));
47         enforce(equal(buf[pos..pos + data.length], data), new FileFormatException("pattern does not match"));
48     }
49 
50     ubyte[] sectionAt(uint pos) {
51         uint rva = uintAt(pos);
52         uint sz = uintAt(pos + 4);
53         Log.d("section rva=", rva, " sz=", sz);
54         if (!sz)
55             return null;
56         enforce(pos + sz <= buf.length, new FileFormatException("sectionAt: index is outside file range"));
57         return buf[rva .. rva + sz];
58     }
59     string stringzAt(uint pos, uint maxSize) {
60         char[] res;
61         for (uint p = pos; maxSize == 0 || p < pos + maxSize; p++) {
62             ubyte ch = ubyteAt(p);
63             if (!ch)
64                 break;
65             res ~= ch;
66         }
67         return cast(string)res;
68     }
69     ubyte[] rangeAt(uint pos, uint size) {
70         Log.d("rangeAt: pos=", pos, " size=", size, " pos+size=", pos+size, " buf.len=", buf.length);
71         uint endp = pos + size;
72         //if (endp > buf.length)
73         //    endp = cast(uint)buf.length;
74         enforce(pos <= endp, new FileFormatException("rangeAt: index is outside file range"));
75         return buf[pos .. endp];
76     }
77 }
78 
79 struct Section {
80     string name;
81     uint vsize;
82     uint rva;
83     uint sz;
84     uint offset;
85     uint flags;
86     this(ref Buffer buf, uint pos) {
87         name = buf.stringzAt(pos, 8);
88         vsize = buf.uintAt(pos + 0x08);
89         rva = buf.uintAt(pos + 0x0C);
90         sz = buf.uintAt(pos + 0x10);
91         offset = buf.uintAt(pos + 0x14);
92         flags = buf.uintAt(pos + 0x28);
93     }
94 }
95 
96 class OMFDebugInfo {
97     Buffer data;
98     uint peoffset;
99     bool load(string filename) {
100         try {
101             data.buf = cast(ubyte[])std.file.read(filename);
102             data.check(0, ['M', 'Z']);
103             peoffset = data.uintAt(0x3c);
104             Buffer pe;
105             pe.buf = data.buf[peoffset .. $];
106             //data.skip(peoffset);
107             pe.check(0, ['P', 'E', 0, 0]);
108             ushort objectCount = pe.ushortAt(0x06);
109             ushort flags = pe.ushortAt(0x16); 
110             ushort subsystem = pe.ushortAt(0x5c); 
111             uint coffRva = pe.uintAt(0x0c);
112             uint coffSize = pe.uintAt(0x10);
113             Log.d("subsystem: ", subsystem, " flags: ", flags, " coffRva:", coffRva, " coffSize:", coffSize);
114             //ubyte[] debugInfo = data.sectionAt(peoffset + 0xA8);
115             //ubyte[] exportInfo = data.sectionAt(peoffset + 0x78);
116             //ubyte[] importInfo = data.sectionAt(peoffset + 0x7c);
117             //ubyte[] resInfo = data.sectionAt(peoffset + 0x88);
118             //Buffer debugHeader;
119             //debugHeader.buf = debugInfo;
120             //uint debugType = debugHeader.uintAt(0x0C);
121             //uint debugSize = debugHeader.uintAt(0x10);
122             //uint debugRva = debugHeader.uintAt(0x14);
123             //uint debugSeek = debugHeader.uintAt(0x18);
124             //Log.d("debugInfo[", debugInfo.length, "] type=", debugType, " debugSize=", debugSize, " rva=", debugRva, " seek=", debugSeek, "  seek-rva=");
125             //ubyte[] debugRaw = data.rangeAt(debugSeek, debugSize);
126             //Log.d("debugRaw: ", debugRaw);
127             ubyte[] debugData;
128             for (int i = 0; i < objectCount; i++) {
129                 Section section = Section(data, peoffset + 0xF8 + i * 0x28);
130                 Log.d("section ", section.name, " rva=", section.rva, " sz=", section.sz, " offset=", section.offset);
131                 if (section.name.equal(".debug"))
132                     debugData = data.rangeAt(section.offset, section.sz);
133             }
134             if (debugData) {
135                 string debugName = cast(string)debugData[1.. debugData[0] + 1];
136                 Log.d("Found debug data: name=", debugName, " sz=", debugData.length);
137             }
138             return true;
139         } catch (Exception e) {
140             throw new FileFormatException(e);
141         }
142     }
143 }
144 
145 debug(DebugInfo) {
146     void debugInfoTest(string filename) {
147         OMFDebugInfo omf = new OMFDebugInfo();
148         Log.d("Loading debug info from file ", filename);
149         try {
150             if (omf.load(filename)) {
151                 Log.d("Loaded ok");
152             } else {
153                 Log.d("Failed");
154             }
155         } catch (FileFormatException e) {
156             Log.e("FileFormatException: ", e);
157         }
158 
159     }
160 
161 }