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 }