0
|
1 /**
|
|
2 This module is used to extract CodeView symbolic debugging information and to
|
|
3 perform queries upon that information.
|
|
4
|
|
5 TODO:
|
|
6 * Add support for CodeView 5.0 and PDB formats.
|
|
7 * Add support to extract type information.
|
|
8
|
|
9 Authors:
|
|
10 Jeremie Pelletier
|
|
11
|
|
12 References:
|
|
13 $(LINK http://www.x86.org/ftp/manuals/tools/sym.pdf)
|
|
14 $(LINK http://undocumented.rawol.com/sbs-w2k-1-windows-2000-debugging-support.pdf)
|
|
15 $(LINK http://www.microsoft.com/msj/0399/hood/hood0399.aspx)
|
|
16 $(LINK http://source.winehq.org/source/include/wine/mscvpdb.h)
|
|
17 $(LINK http://www.digitalmars.com/d/2.0/abi.html)
|
|
18
|
|
19 License:
|
|
20 Public Domain
|
|
21 */
|
|
22 module dbg.symbol.CodeView;
|
|
23
|
|
24 import dbg.Debug;
|
|
25
|
|
26 class CodeViewDebugInfo : ISymbolicDebugInfo {
|
|
27 /**
|
|
28 Load CodeView data from the given memory view.
|
|
29 */
|
|
30 this(in void[] view)
|
|
31 in {
|
|
32 assert(view.length && view.ptr);
|
|
33 }
|
|
34 body {
|
|
35 _view = view;
|
|
36
|
|
37 auto header = cast(CV_HEADER*)_view.ptr;
|
|
38 CheckOffset(header.offset);
|
|
39
|
|
40 // TODO: Only supporting NB09 (CodeView 4.10) right now
|
|
41 if(!header.signature == CV_SIGNATURE_NB09)
|
|
42 throw new CodeViewUnsupportedException(this);
|
|
43
|
|
44 auto dir = cast(CV_DIRECTORY*)(view.ptr + header.offset);
|
|
45 if(dir.dirSize != CV_DIRECTORY.sizeof || dir.entrySize != CV_ENTRY.sizeof)
|
|
46 throw new CodeViewCorruptedException(this);
|
|
47
|
|
48 CvModule globalModule;
|
|
49 _modules ~= globalModule;
|
|
50
|
|
51 foreach(ref e; dir.entries) {
|
|
52 CheckOffset(e.offset);
|
|
53
|
|
54 switch(e.sst) {
|
|
55 case sstModule: ParseModule(&e); break;
|
|
56 case sstLibraries: ParseLibraries(&e); break;
|
|
57 case sstAlignSym: ParseAlignSymbols(&e); break;
|
|
58 case sstSrcModule: ParseSrcModule(&e); break;
|
|
59 case sstGlobalPub:
|
|
60 case sstStaticSym:
|
|
61 case sstGlobalSym: ParseHashSymbols(&e); break;
|
|
62 case sstGlobalTypes: ParseGlobalTypes(&e); break;
|
|
63
|
|
64 // TODO:
|
|
65 /*case sstFileIndex:
|
|
66 case sstSegMap:
|
|
67 case sstSegName:*/
|
|
68
|
|
69 default:
|
|
70 }
|
|
71 }
|
|
72 }
|
|
73
|
|
74 /**
|
|
75 Get the procedure symbol matching the given address.
|
|
76 */
|
|
77 SymbolInfo ResolveSymbol(size_t rva) const
|
|
78 in {
|
|
79 assert(rva);
|
|
80 }
|
|
81 body {
|
|
82 SymbolInfo symbol;
|
|
83
|
|
84 foreach(ref m; _modules[0 .. _maxSymModule + 1])
|
|
85 if(m.symbols.QueryProc(rva, &symbol))
|
|
86 goto Found;
|
|
87
|
|
88 foreach(ref m; _modules[0 .. _maxSymModule + 1])
|
|
89 if(m.symbols.QueryCodeData(rva, &symbol))
|
|
90 goto Found;
|
|
91
|
|
92 Found:
|
|
93 return symbol;
|
|
94 }
|
|
95
|
|
96 /**
|
|
97 Get the file/line mapping corresponding to the given relative address.
|
|
98 */
|
|
99 FileLineInfo ResolveFileLine(size_t rva) const
|
|
100 in {
|
|
101 assert(rva);
|
|
102 }
|
|
103 body {
|
|
104 FileLineInfo fileLine;
|
|
105
|
|
106 if(_maxSrcModule)
|
|
107 foreach(m; _modules[1 .. _maxSrcModule + 1])
|
|
108 if(m.src.Query(rva, &fileLine))
|
|
109 break;
|
|
110
|
|
111 return fileLine;
|
|
112 }
|
|
113
|
|
114 private:
|
|
115
|
|
116 void ParseModule(in CV_ENTRY* e) {
|
|
117 auto mod = cast(CV_MODULE*)(_view.ptr + e.offset);
|
|
118
|
|
119 if(e.modIndex != _modules.length || mod.style != CV_MOD_STYLE)
|
|
120 throw new CodeViewCorruptedException(this);
|
|
121
|
|
122 with(*mod)
|
|
123 _modules ~= CvModule(overlay, lib, segments, name.name);
|
|
124 }
|
|
125
|
|
126 void ParseLibraries(in CV_ENTRY* e) {
|
|
127 if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this);
|
|
128
|
|
129 auto name = cast(OMF_NAME*)(_view.ptr + e.offset);
|
|
130 auto end = cast(const(void)*)name + e.size;
|
|
131
|
|
132 while(name < end) {
|
|
133 if(name.len) _libraries ~= name.name;
|
|
134
|
|
135 name = cast(OMF_NAME*)(cast(void*)name + 1 + name.len);
|
|
136 }
|
|
137 }
|
|
138
|
|
139 void ParseAlignSymbols(in CV_ENTRY* e) {
|
|
140 if(e.modIndex == ushort.max || e.modIndex <= 0 || e.modIndex >= _modules.length)
|
|
141 throw new CodeViewCorruptedException(this);
|
|
142
|
|
143 if(e.modIndex > _maxSymModule) _maxSymModule = e.modIndex;
|
|
144
|
|
145 auto sym = cast(CV_SYMBOL*)(_view.ptr + e.offset);
|
|
146
|
|
147 if(sym.header.type == 0) sym = cast(CV_SYMBOL*)(cast(void*)sym + 4);
|
|
148
|
|
149 _modules[e.modIndex].symbols.Init(sym, cast(void*)sym + e.size);
|
|
150 }
|
|
151
|
|
152 void ParseHashSymbols(in CV_ENTRY* e) {
|
|
153 if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this);
|
|
154
|
|
155 auto hash = cast(CV_SYMHASH*)(_view.ptr + e.offset);
|
|
156 auto p = cast(void*)hash + CV_SYMHASH.sizeof;
|
|
157
|
|
158 _modules[0].symbols.Init(cast(CV_SYMBOL*)p, p + hash.symInfoSize);
|
|
159 }
|
|
160
|
|
161 void ParseSrcModule(in CV_ENTRY* e) {
|
|
162 if(e.modIndex == ushort.max || e.modIndex <= 0 || e.modIndex >= _modules.length)
|
|
163 throw new CodeViewCorruptedException(this);
|
|
164
|
|
165 if(e.modIndex > _maxSrcModule) _maxSrcModule = e.modIndex;
|
|
166
|
|
167 auto src = cast(CV_SRCMODULE*)(_view.ptr + e.offset);
|
|
168
|
|
169 with(_modules[e.modIndex].src) {
|
|
170 data = src;
|
|
171 fileOffsets = src.fileOffsets;
|
|
172 codeOffsets = src.codeOffsets;
|
|
173 segmentIds = src.segmentIds;
|
|
174 }
|
|
175 }
|
|
176
|
|
177 void ParseGlobalTypes(in CV_ENTRY* e) {
|
|
178 if(e.modIndex != ushort.max) throw new CodeViewCorruptedException(this);
|
|
179
|
|
180 // TODO: this currently crash stuff randomly
|
|
181 /*auto header = cast(CV_GLOBALTYPES*)(_view.ptr + e.offset);
|
|
182 _types.Init(header, cast(void*)header + e.size);*/
|
|
183 }
|
|
184
|
|
185 void CheckOffset(int offset) {
|
|
186 if(offset > _view.length) throw new CodeViewCorruptedException(this);
|
|
187 }
|
|
188
|
|
189 const(void)[] _view;
|
|
190
|
|
191 CvModule[] _modules;
|
|
192 uint _maxSymModule;
|
|
193 uint _maxSrcModule;
|
|
194 string[] _libraries;
|
|
195 CvTypes _types;
|
|
196 }
|
|
197
|
|
198 abstract class CodeViewException : Exception {
|
|
199 this(string msg) {
|
|
200 super(msg);
|
|
201 }
|
|
202 }
|
|
203
|
|
204 class CodeViewUnsupportedException : CodeViewException {
|
|
205 this(in CodeViewDebugInfo cv) {
|
|
206 super("CodeView version unsupported.");
|
|
207 }
|
|
208 }
|
|
209
|
|
210 class CodeViewCorruptedException : CodeViewException {
|
|
211 this(in CodeViewDebugInfo cv) {
|
|
212 super("Corrupted CodeView data.");
|
|
213 }
|
|
214 }
|
|
215
|
|
216 private:
|
|
217 alias int cmp_t;
|
|
218 uint BinarySearch(scope cmp_t delegate(uint i) dg, uint low, uint high) {
|
|
219 if(high < low) return uint.max;
|
|
220
|
|
221 uint mid = low + ((high - low) / 2);
|
|
222 cmp_t cmp = dg(mid);
|
|
223
|
|
224 if(cmp > 0) return BinarySearch(dg, low, mid - 1);
|
|
225 if(cmp < 0) return BinarySearch(dg, mid + 1, high);
|
|
226 return mid;
|
|
227 }
|
|
228
|
|
229 uint BinarySearch(in uint[] a, uint value, uint low, uint high) {
|
|
230 if(high < low) return uint.max;
|
|
231
|
|
232 uint mid = low + ((high - low) / 2);
|
|
233
|
|
234 if(a[mid] > value) return BinarySearch(a, value, low, mid - 1);
|
|
235 if(a[mid] < value) return BinarySearch(a, value, mid + 1, high);
|
|
236 return mid;
|
|
237 }
|
|
238
|
|
239 struct CvModule {
|
|
240 ushort overlay;
|
|
241 ushort lib;
|
|
242 CV_SEGMENT[] segments;
|
|
243 string name;
|
|
244
|
|
245 CvSymbols symbols;
|
|
246 CvSrcModule src;
|
|
247 }
|
|
248
|
|
249 struct CvSymbols {
|
|
250 ubyte compileMachine;
|
|
251 ubyte compileLanguage;
|
|
252 ushort compileFlags;
|
|
253 string compileName;
|
|
254 ushort segment;
|
|
255
|
|
256 CvProc[] procSymbols;
|
|
257 CvData[] codeSymbols;
|
|
258
|
|
259 void Init(const(CV_SYMBOL)* sym, in void* end) {
|
|
260 int i = 0;
|
|
261 while(sym < end && i < 100) {
|
|
262 ++i;
|
|
263 switch(sym.header.type) {
|
|
264 case S_COMPILE_V1:
|
|
265 with(sym.compile_v1) {
|
|
266 compileMachine = machine;
|
|
267 compileLanguage = language;
|
|
268 compileFlags = flags;
|
|
269 compileName = name.name;
|
|
270 }
|
|
271 break;
|
|
272
|
|
273 case S_SSEARCH_V1:
|
|
274 if(!segment) segment = sym.ssearch.segment;
|
|
275 break;
|
|
276
|
|
277 case S_UDT_V1:
|
|
278 break;
|
|
279
|
|
280 case S_BPREL_V1:
|
|
281 break;
|
|
282
|
|
283 case S_LDATA_V1:
|
|
284 case S_GDATA_V1:
|
|
285 case S_PUB_V1:
|
|
286 CvData data = void;
|
|
287
|
|
288 with(sym.data_v1) {
|
|
289 // TODO: its bad to assume 2 to always be the only code segment!
|
|
290 if(segment != 2) break;
|
|
291
|
|
292 data.offset = offset;
|
|
293 data.name = name.name;
|
|
294 }
|
|
295
|
|
296 codeSymbols ~= data;
|
|
297 break;
|
|
298
|
|
299 case S_LPROC_V1:
|
|
300 case S_GPROC_V1:
|
|
301 CvProc proc = void;
|
|
302
|
|
303 with(sym.proc_v1) {
|
|
304 proc.offset = offset;
|
|
305 proc.length = procLength;
|
|
306 proc.name = name.name;
|
|
307 }
|
|
308
|
|
309 procSymbols ~= proc;
|
|
310 break;
|
|
311
|
|
312 case S_PROCREF_V1:
|
|
313 case S_DATAREF_V1:
|
|
314 case S_ALIGN_V1:
|
|
315 break;
|
|
316
|
|
317 case S_END_V1:
|
|
318 case S_ENDARG_V1:
|
|
319 case S_RETURN_V1:
|
|
320 break;
|
|
321
|
|
322 default:
|
|
323 }
|
|
324
|
|
325 sym = cast(CV_SYMBOL*)(cast(void*)sym + sym.header.size + 2);
|
|
326 }
|
|
327
|
|
328 codeSymbols.sort;
|
|
329 }
|
|
330
|
|
331 bool QueryProc(uint rva, SymbolInfo* symbol) const {
|
|
332 if(!procSymbols.length) return false;
|
|
333
|
|
334 cmp_t CmpProc(uint i) {
|
|
335 if(i >= procSymbols.length) return 0;
|
|
336
|
|
337 uint offset = procSymbols[i].offset;
|
|
338 if(offset > rva) return 1;
|
|
339 if(offset + procSymbols[i].length < rva) return -1;
|
|
340 return 0;
|
|
341 }
|
|
342
|
|
343 uint index = BinarySearch(&CmpProc, 0, procSymbols.length - 1);
|
|
344
|
|
345 if(index < procSymbols.length) with(procSymbols[index]) {
|
|
346 symbol.name = name.idup;
|
|
347 symbol.offset = rva - offset;
|
|
348 return true;
|
|
349 }
|
|
350
|
|
351 return false;
|
|
352 }
|
|
353
|
|
354 bool QueryCodeData(uint rva, SymbolInfo* symbol) const {
|
|
355 if(!codeSymbols.length) return false;
|
|
356
|
|
357 cmp_t CmpData(uint i) {
|
|
358 if(i >= codeSymbols.length) return 0;
|
|
359
|
|
360 if(codeSymbols[i].offset > rva) return 1;
|
|
361 if(i + 1 != codeSymbols.length && codeSymbols[i + 1].offset < rva) return -1;
|
|
362 return 0;
|
|
363 }
|
|
364
|
|
365 uint index = BinarySearch(&CmpData, 0, codeSymbols.length - 1);
|
|
366
|
|
367 if(index < codeSymbols.length) with(codeSymbols[index]) {
|
|
368 symbol.name = name.idup;
|
|
369 symbol.offset = rva - offset;
|
|
370 return true;
|
|
371 }
|
|
372
|
|
373 return false;
|
|
374 }
|
|
375 }
|
|
376
|
|
377 struct CvProc {
|
|
378 uint offset;
|
|
379 uint length;
|
|
380 string name;
|
|
381 }
|
|
382
|
|
383 struct CvData {
|
|
384 uint offset;
|
|
385 string name;
|
|
386
|
|
387 cmp_t opCmp(ref const CvData data) const {
|
|
388 if(data.offset < offset) return -1;
|
|
389 return data.offset > offset;
|
|
390 }
|
|
391 }
|
|
392
|
|
393 struct CvSrcModule {
|
|
394 bool Query(uint rva, FileLineInfo* fileLine) const {
|
|
395 if(!codeOffsets.length || rva < codeOffsets[0][0] || rva > codeOffsets[$ - 1][1])
|
|
396 return false;
|
|
397
|
|
398 uint fIndex;
|
|
399
|
|
400 // Get the next CV_SRCFILE record having rva within it's code range
|
|
401 // The code offsets here may overlap over file records, we have to walk
|
|
402 // through them and possibly keep walking if the next section doesn't
|
|
403 // find a matching line record.
|
|
404 NextFile:
|
|
405 if(fIndex == fileOffsets.length) return false;
|
|
406
|
|
407 CV_SRCFILE* srcFile = cast(CV_SRCFILE*)(data + fileOffsets[fIndex++]);
|
|
408 uint[2][] offsets = srcFile.codeOffsets;
|
|
409
|
|
410 if(rva < offsets[0][0] || rva > offsets[$ - 1][1])
|
|
411 goto NextFile;
|
|
412
|
|
413 CV_SRCSEGMENT* srcSeg;
|
|
414
|
|
415 // Address is possibly within this file, now get the CV_SEGMENT record.
|
|
416 cmp_t CmpFile(uint i) {
|
|
417 if(i >= offsets.length) return 0;
|
|
418
|
|
419 if(offsets[i][0] > rva) return 1;
|
|
420 if(offsets[i][1] < rva) return -1;
|
|
421
|
|
422 srcSeg = cast(CV_SRCSEGMENT*)(data + srcFile.lineOffsets[i]);
|
|
423 return 0;
|
|
424 }
|
|
425
|
|
426 // Ignore the return value from BinarySearch, if CmpSegment matched, we
|
|
427 // already have srcSeg set. In some rare cases there may not be a
|
|
428 // matching segment record even if the file's segment range said so.
|
|
429 BinarySearch(&CmpFile, 0, offsets.length - 1);
|
|
430 if(!srcSeg) goto NextFile;
|
|
431
|
|
432 // Finally look within the segment's offsets for a matching record.
|
|
433 uint[] segOffsets = srcSeg.offsets;
|
|
434 ushort[] lineNumbers = srcSeg.lineNumbers;
|
|
435
|
|
436 cmp_t CmpSegment(uint i) {
|
|
437 if(i >= segOffsets.length) return 0;
|
|
438
|
|
439 if(segOffsets[i] > rva) return 1;
|
|
440 if(i + 1 < segOffsets.length && segOffsets[i + 1] < rva) return -1;
|
|
441
|
|
442 return 0;
|
|
443 }
|
|
444
|
|
445 uint sIndex = BinarySearch(&CmpSegment, 0, segOffsets.length - 1);
|
|
446 if(sIndex >= lineNumbers.length) goto NextFile;
|
|
447
|
|
448 // Found our record
|
|
449 fileLine.file = srcFile.name.name.idup;
|
|
450 fileLine.line = srcSeg.lineNumbers[sIndex];
|
|
451
|
|
452 return true;
|
|
453 }
|
|
454
|
|
455 const(void)* data;
|
|
456 const(uint)[] fileOffsets;
|
|
457 const(uint[2])[] codeOffsets;
|
|
458 const(ushort)[] segmentIds;
|
|
459 }
|
|
460
|
|
461 // TODO!
|
|
462 struct CvTypes {
|
|
463 void Init(in CV_GLOBALTYPES* gtypes, in void* end) {
|
|
464 debug(CodeView) TraceA("CvTypes[%p].Init(gtypes=%p, end=%p)",
|
|
465 &this, gtypes, end);
|
|
466
|
|
467 offsets = gtypes.typeOffsets[0 .. gtypes.nTypes].idup;
|
|
468
|
|
469 void* dataStart = gtypes.types;
|
|
470 data = dataStart[0 .. end - dataStart].idup;
|
|
471 }
|
|
472
|
|
473 void GetType(ushort index) {
|
|
474 /+
|
|
475 CheckOffset(typeOffsets[index]);
|
|
476
|
|
477 CV_TYPE* type = cast(CV_TYPE*)(p + typeOffsets[i]);
|
|
478
|
|
479 switch(type.header.type) {
|
|
480 case LF_MODIFIER_V1:
|
|
481 break;
|
|
482
|
|
483 case LF_POINTER_V1:
|
|
484 break;
|
|
485
|
|
486 case LF_ARRAY_V1:
|
|
487 break;
|
|
488
|
|
489 case LF_CLASS_V1:
|
|
490 break;
|
|
491
|
|
492 case LF_STRUCTURE_V1:
|
|
493 break;
|
|
494
|
|
495 case LF_UNION_V1:
|
|
496 break;
|
|
497
|
|
498 case LF_ENUM_V1:
|
|
499 break;
|
|
500
|
|
501 case LF_PROCEDURE_V1:
|
|
502 break;
|
|
503
|
|
504 case LF_MFUNCTION_V1:
|
|
505 break;
|
|
506
|
|
507 case LF_VTSHAPE_V1:
|
|
508 break;
|
|
509
|
|
510 case LF_OEM_V1:
|
|
511 with(type.oem_v1) {
|
|
512 // Ignore unknown OEMs
|
|
513 if(oem != OEM_DIGITALMARS || nIndices != 2) break;
|
|
514
|
|
515 switch(rec) {
|
|
516 case D_DYN_ARRAY:
|
|
517 break;
|
|
518
|
|
519 case D_ASSOC_ARRAY:
|
|
520 break;
|
|
521
|
|
522 case D_DELEGATE:
|
|
523 break;
|
|
524
|
|
525 default:
|
|
526 }
|
|
527 }
|
|
528 break;
|
|
529
|
|
530 case LF_ARGLIST_V1:
|
|
531 break;
|
|
532
|
|
533 case LF_FIELDLIST_V1:
|
|
534 break;
|
|
535
|
|
536 case LF_DERIVED_V1:
|
|
537 break;
|
|
538
|
|
539 case LF_METHODLIST_V1:
|
|
540 break;
|
|
541
|
|
542 default:
|
|
543 TraceA("New leaf %x", cast(uint)type.header.type);
|
|
544 Pause;
|
|
545 }
|
|
546 +/
|
|
547 }
|
|
548
|
|
549 const(uint)[] offsets;
|
|
550 const(void)[] data;
|
|
551 }
|
|
552
|
|
553 // ----------------------------------------------------------------------------
|
|
554 // O M F S t r u c t u r e s
|
|
555 // ----------------------------------------------------------------------------
|
|
556
|
|
557 align(1):
|
|
558
|
|
559 /**
|
|
560 Packed variant header
|
|
561 */
|
|
562 struct OMF_HEADER {
|
|
563 short size;
|
|
564 short type;
|
|
565 }
|
|
566
|
|
567 /**
|
|
568 Packed name, may be 0 padded to maintain alignment
|
|
569 */
|
|
570 struct OMF_NAME {
|
|
571 ubyte len;
|
|
572 //char[1] name;
|
|
573
|
|
574 string name() const {
|
|
575 return (cast(immutable(char)*)(&len + 1))[0 .. len];
|
|
576 }
|
|
577 }
|
|
578
|
|
579 // ----------------------------------------------------------------------------
|
|
580 // C o d e V i e w C o m m o n S t r u c t u r e s
|
|
581 // ----------------------------------------------------------------------------
|
|
582
|
|
583 /**
|
|
584 Version signatures
|
|
585 */
|
|
586 enum : uint {
|
|
587 CV_SIGNATURE_NB09 = 0x3930424E, /// CodeView 4.10
|
|
588 CV_SIGNATURE_NB11 = 0x3131424E, /// CodeView 5.0
|
|
589 CV_SIGNATURE_NB10 = 0x3130424E, /// CodeView PDB 2.0
|
|
590 CV_SIGNATURE_RSDS = 0x53445352 /// CodeView PDB 7.0
|
|
591 }
|
|
592
|
|
593 /**
|
|
594 SubSection Types
|
|
595 */
|
|
596 enum : ushort {
|
|
597 sstModule = 0x0120,
|
|
598 sstTypes = 0x0121,
|
|
599 sstPublic = 0x0122,
|
|
600 sstPublicSym = 0x0123,
|
|
601 sstSymbols = 0x0124,
|
|
602 sstAlignSym = 0x0125,
|
|
603 sstSrcLnSeg = 0x0126,
|
|
604 sstSrcModule = 0x0127,
|
|
605 sstLibraries = 0x0128,
|
|
606 sstGlobalSym = 0x0129,
|
|
607 sstGlobalPub = 0x012A,
|
|
608 sstGlobalTypes = 0x012B,
|
|
609 sstMPC = 0x012C,
|
|
610 sstSegMap = 0x012D,
|
|
611 sstSegName = 0x012E,
|
|
612 sstPreComp = 0x012F,
|
|
613 sstPreCompMap = 0x0130,
|
|
614 sstOffsetMap16 = 0x0131,
|
|
615 sstOffsetMap32 = 0x0132,
|
|
616 sstFileIndex = 0x0133,
|
|
617 sstStaticSym = 0x0134
|
|
618 }
|
|
619
|
|
620 /**
|
|
621 Header used with "NB09" and "NB11"
|
|
622 */
|
|
623 struct CV_HEADER {
|
|
624 uint signature;
|
|
625 int offset;
|
|
626 }
|
|
627
|
|
628 /**
|
|
629 Header used with "NB10"
|
|
630 */
|
|
631 struct CV_HEADER_NB10 {
|
|
632 uint signature;
|
|
633 int offset;
|
|
634 uint timestamp;
|
|
635 uint age;
|
|
636 OMF_NAME name;
|
|
637 }
|
|
638
|
|
639 /**
|
|
640 Header used with "RSDS"
|
|
641 */
|
|
642 /*struct CV_HEADER_RSDS {
|
|
643 uint signature;
|
|
644 GUID guid;
|
|
645 uint age;
|
|
646 OMF_NAME name;
|
|
647 }*/
|
|
648
|
|
649 /**
|
|
650 Directory header
|
|
651 */
|
|
652 struct CV_DIRECTORY {
|
|
653 ushort dirSize;
|
|
654 ushort entrySize;
|
|
655 uint nEntries;
|
|
656 int offset;
|
|
657 uint flags;
|
|
658 //CV_ENTRY[1] entries;
|
|
659
|
|
660 CV_ENTRY[] entries() const {
|
|
661 return (cast(CV_ENTRY*)(&this + 1))[0 .. nEntries];
|
|
662 }
|
|
663 }
|
|
664
|
|
665 /**
|
|
666 Subsection record
|
|
667 */
|
|
668 struct CV_ENTRY {
|
|
669 ushort sst;
|
|
670 ushort modIndex;
|
|
671 int offset;
|
|
672 uint size;
|
|
673 }
|
|
674
|
|
675 // ----------------------------------------------------------------------------
|
|
676 // sstModule
|
|
677 // ----------------------------------------------------------------------------
|
|
678
|
|
679 /**
|
|
680 Module style, always "CV"
|
|
681 */
|
|
682 enum CV_MOD_STYLE = 0x5643;
|
|
683
|
|
684 /**
|
|
685 Module
|
|
686 */
|
|
687 struct CV_MODULE {
|
|
688 ushort overlay;
|
|
689 ushort lib;
|
|
690 ushort nSegments;
|
|
691 ushort style;
|
|
692 //CV_SEGMENT[1] segments;
|
|
693 //OMF_NAME name;
|
|
694
|
|
695 CV_SEGMENT[] segments() const {
|
|
696 return (cast(CV_SEGMENT*)(&style + 1))[0 .. nSegments];
|
|
697 }
|
|
698
|
|
699 OMF_NAME name() const {
|
|
700 return *cast(OMF_NAME*)(cast(void*)segments + nSegments * CV_SEGMENT.sizeof);
|
|
701 }
|
|
702 }
|
|
703
|
|
704 /**
|
|
705 Module segment
|
|
706 */
|
|
707 struct CV_SEGMENT {
|
|
708 ushort segIndex;
|
|
709 ushort padding;
|
|
710 uint offset;
|
|
711 uint size;
|
|
712 }
|
|
713
|
|
714 // ----------------------------------------------------------------------------
|
|
715 // sstGlobalPub, sstStaticSym, sstGlobalSym, sstAlignSym
|
|
716 // ----------------------------------------------------------------------------
|
|
717
|
|
718 /**
|
|
719 Symbol IDs, used by CV_SYMBOL.header.type
|
|
720 */
|
|
721 enum : ushort {
|
|
722 S_COMPILE_V1 = 0x0001,
|
|
723 S_REGISTER_V1 = 0x0002,
|
|
724 S_CONSTANT_V1 = 0x0003,
|
|
725 S_UDT_V1 = 0x0004,
|
|
726 S_SSEARCH_V1 = 0x0005,
|
|
727 S_END_V1 = 0x0006,
|
|
728 S_SKIP_V1 = 0x0007,
|
|
729 S_CVRESERVE_V1 = 0x0008,
|
|
730 S_OBJNAME_V1 = 0x0009,
|
|
731 S_ENDARG_V1 = 0x000A,
|
|
732 S_COBOLUDT_V1 = 0x000B,
|
|
733 S_MANYREG_V1 = 0x000C,
|
|
734 S_RETURN_V1 = 0x000D,
|
|
735 S_ENTRYTHIS_V1 = 0x000E,
|
|
736
|
|
737 S_BPREL_V1 = 0x0200,
|
|
738 S_LDATA_V1 = 0x0201,
|
|
739 S_GDATA_V1 = 0x0202,
|
|
740 S_PUB_V1 = 0x0203,
|
|
741 S_LPROC_V1 = 0x0204,
|
|
742 S_GPROC_V1 = 0x0205,
|
|
743 S_THUNK_V1 = 0x0206,
|
|
744 S_BLOCK_V1 = 0x0207,
|
|
745 S_WITH_V1 = 0x0208,
|
|
746 S_LABEL_V1 = 0x0209,
|
|
747 S_CEXMODEL_V1 = 0x020A,
|
|
748 S_VFTPATH_V1 = 0x020B,
|
|
749 S_REGREL_V1 = 0x020C,
|
|
750 S_LTHREAD_V1 = 0x020D,
|
|
751 S_GTHREAD_V1 = 0x020E,
|
|
752
|
|
753 S_PROCREF_V1 = 0x0400,
|
|
754 S_DATAREF_V1 = 0x0401,
|
|
755 S_ALIGN_V1 = 0x0402,
|
|
756 S_LPROCREF_V1 = 0x0403,
|
|
757
|
|
758 // Variants with 32bit type indices
|
|
759 S_REGISTER_V2 = 0x1001, /// CV_REGISTER_V2
|
|
760 S_CONSTANT_V2 = 0x1002, /// CV_CONSTANT_V2
|
|
761 S_UDT_V2 = 0x1003, /// CV_UDT_V2
|
|
762 S_COBOLUDT_V2 = 0x1004,
|
|
763 S_MANYREG_V2 = 0x1005,
|
|
764 S_BPREL_V2 = 0x1006, /// CV_BPREL_V2
|
|
765 S_LDATA_V2 = 0x1007, /// CV_DATA_V2
|
|
766 S_GDATA_V2 = 0x1008, /// CV_DATA_V2
|
|
767 S_PUB_V2 = 0x1009, /// CV_DATA_V2
|
|
768 S_LPROC_V2 = 0x100A, /// CV_PROC_V2
|
|
769 S_GPROC_V2 = 0x100B, /// CV_PROC_V2
|
|
770 S_VFTTABLE_V2 = 0x100C,
|
|
771 S_REGREL_V2 = 0x100D,
|
|
772 S_LTHREAD_V2 = 0x100E,
|
|
773 S_GTHREAD_V2 = 0x100F,
|
|
774 S_FUNCINFO_V2 = 0x1012,
|
|
775 S_COMPILAND_V2 = 0x1013, /// CV_COMPILE_V2
|
|
776
|
|
777 S_COMPILAND_V3 = 0x1101,
|
|
778 S_THUNK_V3 = 0x1102,
|
|
779 S_BLOCK_V3 = 0x1103,
|
|
780 S_LABEL_V3 = 0x1105,
|
|
781 S_REGISTER_V3 = 0x1106,
|
|
782 S_CONSTANT_V3 = 0x1107,
|
|
783 S_UDT_V3 = 0x1108,
|
|
784 S_BPREL_V3 = 0x110B,
|
|
785 S_LDATA_V3 = 0x110C,
|
|
786 S_GDATA_V3 = 0x110D,
|
|
787 S_PUB_V3 = 0x110E,
|
|
788 S_LPROC_V3 = 0x110F,
|
|
789 S_GPROC_V3 = 0x1110,
|
|
790 S_BPREL_XXXX_V3 = 0x1111, /* not really understood, but looks like bprel... */
|
|
791 S_MSTOOL_V3 = 0x1116, /* compiler command line options and build information */
|
|
792 S_PUB_FUNC1_V3 = 0x1125, /* didn't get the difference between the two */
|
|
793 S_PUB_FUNC2_V3 = 0x1127,
|
|
794 S_SECTINFO_V3 = 0x1136,
|
|
795 S_SUBSECTINFO_V3= 0x1137,
|
|
796 S_ENTRYPOINT_V3 = 0x1138,
|
|
797 S_SECUCOOKIE_V3 = 0x113A,
|
|
798 S_MSTOOLINFO_V3 = 0x113C,
|
|
799 S_MSTOOLENV_V3 = 0x113D
|
|
800 }
|
|
801
|
|
802 /**
|
|
803 Packed symbols header
|
|
804 */
|
|
805 struct CV_SYMHASH {
|
|
806 ushort symIndex;
|
|
807 ushort addrIndex;
|
|
808 uint symInfoSize;
|
|
809 uint symHashSize;
|
|
810 uint addrHashSize;
|
|
811 }
|
|
812
|
|
813 /**
|
|
814 Symbol variant record
|
|
815 */
|
|
816 struct CV_SYMBOL {
|
|
817 OMF_HEADER header;
|
|
818 union {
|
|
819 CV_COMPILE_V1 compile_v1;
|
|
820 CV_COMPILE_V2 compile_v2;
|
|
821 CV_REGISTER_V1 register_v1;
|
|
822 CV_REGISTER_V2 register_v2;
|
|
823 CV_CONSTANT_V1 constant_v1;
|
|
824 CV_CONSTANT_V2 constant_v2;
|
|
825 CV_UDT_V1 udt_v1;
|
|
826 CV_UDT_V2 udt_v2;
|
|
827 CV_SSEARCH ssearch;
|
|
828 CV_STACK_V1 stack_v1;
|
|
829 CV_STACK_V2 stack_v2;
|
|
830 CV_DATA_V1 data_v1;
|
|
831 CV_DATA_V2 data_v2;
|
|
832 CV_PROC_V1 proc_v1;
|
|
833 CV_PROC_V2 proc_v2;
|
|
834 CV_THUNK thunk;
|
|
835 CV_BLOCK block;
|
|
836 CV_LABEL label;
|
|
837 }
|
|
838 }
|
|
839
|
|
840 /**
|
|
841 Compiler information symbol
|
|
842 */
|
|
843 struct CV_COMPILE_V1 {
|
|
844 ubyte machine;
|
|
845 ubyte language;
|
|
846 ushort flags;
|
|
847 OMF_NAME name;
|
|
848 }
|
|
849 struct CV_COMPILE_V2 {
|
|
850 uint[4] unknown1;
|
|
851 ushort unknown2;
|
|
852 OMF_NAME name;
|
|
853 }
|
|
854
|
|
855 /**
|
|
856 Register data symbol
|
|
857 */
|
|
858 struct CV_REGISTER_V1 {
|
|
859 ushort typeIndex;
|
|
860 ushort reg;
|
|
861 OMF_NAME name;
|
|
862 }
|
|
863 struct CV_REGISTER_V2 {
|
|
864 uint typeIndex;
|
|
865 ushort reg;
|
|
866 OMF_NAME name;
|
|
867 }
|
|
868
|
|
869 /**
|
|
870 Constant data symbol
|
|
871 */
|
|
872 struct CV_CONSTANT_V1 {
|
|
873 ushort typeIndex;
|
|
874 ushort value;
|
|
875 OMF_NAME name;
|
|
876 }
|
|
877 struct CV_CONSTANT_V2 {
|
|
878 uint typeIndex;
|
|
879 ushort value;
|
|
880 OMF_NAME name;
|
|
881 }
|
|
882
|
|
883 /**
|
|
884 User defined type Symbol
|
|
885 */
|
|
886 struct CV_UDT_V1 {
|
|
887 ushort typeIndex;
|
|
888 OMF_NAME name;
|
|
889 }
|
|
890 struct CV_UDT_V2 {
|
|
891 uint typeIndex;
|
|
892 OMF_NAME name;
|
|
893 }
|
|
894
|
|
895 /**
|
|
896 Start of Search symbol
|
|
897 */
|
|
898 struct CV_SSEARCH {
|
|
899 uint offset;
|
|
900 ushort segment;
|
|
901 }
|
|
902
|
|
903 /**
|
|
904 Object name symbol
|
|
905 */
|
|
906 struct CV_OBJNAME {
|
|
907 uint signature;
|
|
908 OMF_NAME name;
|
|
909 }
|
|
910
|
|
911 /**
|
|
912 Stack data symbol
|
|
913 */
|
|
914 struct CV_STACK_V1 {
|
|
915 uint offset;
|
|
916 ushort typeIndex;
|
|
917 OMF_NAME name;
|
|
918 }
|
|
919 struct CV_STACK_V2 {
|
|
920 uint offset;
|
|
921 uint typeIndex;
|
|
922 OMF_NAME name;
|
|
923 }
|
|
924
|
|
925 /**
|
|
926 Data symbol
|
|
927 */
|
|
928 struct CV_DATA_V1 {
|
|
929 uint offset;
|
|
930 short segment;
|
|
931 short typeIndex;
|
|
932 OMF_NAME name;
|
|
933 }
|
|
934 struct CV_DATA_V2 {
|
|
935 uint typeIndex;
|
|
936 uint offset;
|
|
937 short segment;
|
|
938 OMF_NAME name;
|
|
939 }
|
|
940
|
|
941 /**
|
|
942 Procedure symbol
|
|
943 */
|
|
944 struct CV_PROC_V1 {
|
|
945 uint parent;
|
|
946 uint end;
|
|
947 uint next;
|
|
948 uint procLength;
|
|
949 uint dbgStart;
|
|
950 uint dbgEnd;
|
|
951 uint offset;
|
|
952 ushort segment;
|
|
953 ushort procType;
|
|
954 ubyte flags;
|
|
955 OMF_NAME name;
|
|
956 }
|
|
957 struct CV_PROC_V2 {
|
|
958 uint parent;
|
|
959 uint end;
|
|
960 uint next;
|
|
961 uint procLength;
|
|
962 uint dbgStart;
|
|
963 uint dbgEnd;
|
|
964 uint procType;
|
|
965 uint offset;
|
|
966 ushort segment;
|
|
967 ubyte flags;
|
|
968 OMF_NAME name;
|
|
969 }
|
|
970
|
|
971 /**
|
|
972 Thunk symbol
|
|
973 */
|
|
974 struct CV_THUNK {
|
|
975 uint parent;
|
|
976 uint end;
|
|
977 uint next;
|
|
978 uint offset;
|
|
979 ushort segment;
|
|
980 ushort size;
|
|
981 ubyte type;
|
|
982 OMF_NAME name;
|
|
983 }
|
|
984
|
|
985 /**
|
|
986 Block symbol
|
|
987 */
|
|
988 struct CV_BLOCK {
|
|
989 uint parent;
|
|
990 uint end;
|
|
991 uint length;
|
|
992 uint offset;
|
|
993 ushort segment;
|
|
994 OMF_NAME name;
|
|
995 }
|
|
996
|
|
997 /**
|
|
998 Label symbol
|
|
999 */
|
|
1000 struct CV_LABEL {
|
|
1001 uint offset;
|
|
1002 ushort segment;
|
|
1003 ubyte flags;
|
|
1004 OMF_NAME name;
|
|
1005 }
|
|
1006
|
|
1007 // ----------------------------------------------------------------------------
|
|
1008 // sstSrcModule
|
|
1009 // ----------------------------------------------------------------------------
|
|
1010
|
|
1011 /**
|
|
1012 Source module header
|
|
1013 */
|
|
1014 struct CV_SRCMODULE {
|
|
1015 ushort nFiles; /// number of CV_SRCFILE records
|
|
1016 ushort nSegments; /// number of segments in module
|
|
1017 //uint[] fileOffsets;
|
|
1018 //uint[2][] codeOffsets;
|
|
1019 //ushort[] segmentIds;
|
|
1020
|
|
1021 /// array of offsets to every CV_SRCFILE record
|
|
1022 uint[] fileOffsets() const {
|
|
1023 return (cast(uint*)(&nSegments + 1))[0 .. nFiles];
|
|
1024 }
|
|
1025
|
|
1026 /// array of segment start/end pairs, length = nSegments
|
|
1027 uint[2][] codeOffsets() const {
|
|
1028 return (cast(uint[2]*)(cast(void*)fileOffsets + nFiles * uint.sizeof))[0 .. nSegments];
|
|
1029 }
|
|
1030
|
|
1031 /// array of linker indices, length = nSegments
|
|
1032 ushort[] segmentIds() const {
|
|
1033 return (cast(ushort*)(cast(void*)codeOffsets + nSegments * (uint[2]).sizeof))[0 .. nSegments];
|
|
1034 }
|
|
1035 }
|
|
1036
|
|
1037 /**
|
|
1038 Source file record
|
|
1039 */
|
|
1040 struct CV_SRCFILE {
|
|
1041 ushort nSegments; /// number of CV_SRCSEGMENT records
|
|
1042 ushort reserved;
|
|
1043 //uint[] lineOffsets;
|
|
1044 //uint[2][] codeOffsets;
|
|
1045 //OMF_NAME name;
|
|
1046
|
|
1047 // array of offsets to every CV_SRCSEGMENT record, length = nSegments
|
|
1048 uint[] lineOffsets() const {
|
|
1049 return (cast(uint*)(&reserved + 1))[0 .. nSegments];
|
|
1050 }
|
|
1051
|
|
1052 /// array of segment start/end pairs, length = nSegments
|
|
1053 uint[2][] codeOffsets() const {
|
|
1054 return (cast(uint[2]*)(cast(void*)lineOffsets + nSegments * uint.sizeof))[0 .. nSegments];
|
|
1055 }
|
|
1056
|
|
1057 /// name of file padded to long boundary
|
|
1058 OMF_NAME* name() const {
|
|
1059 return cast(OMF_NAME*)(cast(void*)codeOffsets + nSegments * (uint[2]).sizeof);
|
|
1060 }
|
|
1061 }
|
|
1062
|
|
1063 /**
|
|
1064 Source segment record
|
|
1065 */
|
|
1066 struct CV_SRCSEGMENT {
|
|
1067 ushort segment; /// linker segment index
|
|
1068 ushort nPairs; /// count of line/offset pairs
|
|
1069 //uint[] offsets;
|
|
1070 //ushort[] lineNumbers;
|
|
1071
|
|
1072 /// array of offsets in segment, length = nPairs
|
|
1073 uint[] offsets() const {
|
|
1074 return (cast(uint*)(&nPairs + 1))[0 .. nPairs];
|
|
1075 }
|
|
1076
|
|
1077 /// array of line lumber in source, length = nPairs
|
|
1078 ushort[] lineNumbers() const {
|
|
1079 return (cast(ushort*)(cast(void*)offsets + nPairs * uint.sizeof))[0 .. nPairs];
|
|
1080 }
|
|
1081 }
|
|
1082
|
|
1083 // ----------------------------------------------------------------------------
|
|
1084 // sstGlobalTypes
|
|
1085 // ----------------------------------------------------------------------------
|
|
1086
|
|
1087 /**
|
|
1088 Basic types
|
|
1089
|
|
1090 Official MS documentation says that type (< 0x4000, so 12 bits) is made of:
|
|
1091
|
|
1092 +----------+------+------+----------+------+
|
|
1093 | 11 | 10-8 | 7-4 | 3 | 2-0 |
|
|
1094 +----------+------+------+----------+------+
|
|
1095 | reserved | mode | type | reserved | size |
|
|
1096 +----------+------+------+----------+------+
|
|
1097 */
|
|
1098
|
|
1099 /**
|
|
1100 Basic type: Type bits
|
|
1101 */
|
|
1102 enum : ubyte {
|
|
1103 T_SPECIAL_BITS = 0x00, /// Special
|
|
1104 T_SIGNED_BITS = 0x10, /// Signed integral value
|
|
1105 T_UNSIGNED_BITS = 0x20, /// Unsigned integral value
|
|
1106 T_BOOLEAN_BITS = 0x30, /// Boolean
|
|
1107 T_REAL_BITS = 0x40, /// Real
|
|
1108 T_COMPLEX_BITS = 0x50, /// Complex
|
|
1109 T_SPECIAL2_BITS = 0x60, /// Special2
|
|
1110 T_INT_BITS = 0x70, /// Real int value
|
|
1111 }
|
|
1112
|
|
1113 /**
|
|
1114 Basic type: Size bits
|
|
1115 */
|
|
1116 enum : ubyte {
|
|
1117 // Special types
|
|
1118 T_NOTYPE_BITS = 0x00, /// No type
|
|
1119 T_ABS_BITS = 0x01, /// Absolute symbol
|
|
1120 T_SEGMENT_BITS = 0x02, /// Segment
|
|
1121 T_VOID_BITS = 0x03, /// Void
|
|
1122 T_CURRENCY_BITS = 0x04, /// Basic 8-byte currency value
|
|
1123 T_NBASICSTR_BITS = 0x05, /// Near Basic string
|
|
1124 T_FBASICSTR_BITS = 0x06, /// Far Basic string
|
|
1125 T_NOTRANS_BITS = 0x07, /// Untranslated type from previous Microsoft symbol formats
|
|
1126
|
|
1127 // Signed/Unsigned/Boolean types
|
|
1128 T_INT08_BITS = 0x00, /// 1 byte
|
|
1129 T_INT16_BITS = 0x01, /// 2 byte
|
|
1130 T_INT32_BITS = 0x02, /// 4 byte
|
|
1131 T_INT64_BITS = 0x03, /// 8 byte
|
|
1132
|
|
1133 // Real/Complex types
|
|
1134 T_REAL32_BITS = 0x00, /// 32 bit
|
|
1135 T_REAL64_BITS = 0x01, /// 64 bit
|
|
1136 T_REAL80_BITS = 0x02, /// 80 bit
|
|
1137 T_REAL128_BITS = 0x03, /// 128 bit
|
|
1138 T_REAL48_BITS = 0x04, /// 48 bit
|
|
1139
|
|
1140 // Special2 types
|
|
1141 T_BIT_BITS = 0x00, /// Bit
|
|
1142 T_PASCHAR_BITS = 0x01, /// Pascal CHAR
|
|
1143
|
|
1144 // Real Int types
|
|
1145 T_CHAR_BITS = 0x00, /// Char
|
|
1146 T_WCHAR_BITS = 0x01, /// Wide character
|
|
1147 T_INT2_BITS = 0x02, /// 2-byte signed integer
|
|
1148 T_UINT2_BITS = 0x03, /// 2-byte unsigned integer
|
|
1149 T_INT4_BITS = 0x04, /// 4-byte signed integer
|
|
1150 T_UINT4_BITS = 0x05, /// 4-byte unsigned integer
|
|
1151 T_INT8_BITS = 0x06, /// 8-byte signed integer
|
|
1152 T_UINT8_BITS = 0x07, /// 8-byte unsigned integer
|
|
1153 T_DCHAR_BITS = 0x08, /// dchar, DigitalMars D extension
|
|
1154 }
|
|
1155
|
|
1156 /**
|
|
1157 Basic type: Mode bits
|
|
1158 */
|
|
1159 enum : ushort {
|
|
1160 T_DIRECT_BITS = 0x0000, /// Direct; not a pointer
|
|
1161 T_NEARPTR_BITS = 0x0100, /// Near pointer
|
|
1162 T_FARPTR_BITS = 0x0200, /// Far pointer
|
|
1163 T_HUGEPTR_BITS = 0x0300, /// Huge pointer
|
|
1164 T_NEAR32PTR_BITS = 0x0400, /// 32-bit near pointer
|
|
1165 T_FAR32PTR_BITS = 0x0500, /// 32-bit far pointer
|
|
1166 T_NEAR64PTR_BITS = 0x0600, /// 64-bit near pointer
|
|
1167 }
|
|
1168
|
|
1169 /**
|
|
1170 Basic type bit masks
|
|
1171 */
|
|
1172 enum : ushort {
|
|
1173 T_TYPE_MASK = 0x00F0, /// type type mask (data treatment mode)
|
|
1174 T_SIZE_MASK = 0x000F, /// type size mask (depends on 'type' value)
|
|
1175 T_MODE_MASK = 0x0700, /// type mode mask (ptr/non-ptr)
|
|
1176 }
|
|
1177
|
|
1178 /**
|
|
1179 Leaf types, used by CV_TYPE.header.type
|
|
1180 */
|
|
1181 enum : ushort {
|
|
1182 // Can be referenced from symbols
|
|
1183 LF_MODIFIER_V1 = 0x0001,
|
|
1184 LF_POINTER_V1 = 0x0002,
|
|
1185 LF_ARRAY_V1 = 0x0003,
|
|
1186 LF_CLASS_V1 = 0x0004,
|
|
1187 LF_STRUCTURE_V1 = 0x0005,
|
|
1188 LF_UNION_V1 = 0x0006,
|
|
1189 LF_ENUM_V1 = 0x0007,
|
|
1190 LF_PROCEDURE_V1 = 0x0008,
|
|
1191 LF_MFUNCTION_V1 = 0x0009,
|
|
1192 LF_VTSHAPE_V1 = 0x000A,
|
|
1193 LF_COBOL0_V1 = 0x000B,
|
|
1194 LF_COBOL1_V1 = 0x000C,
|
|
1195 LF_BARRAY_V1 = 0x000D,
|
|
1196 LF_LABEL_V1 = 0x000E,
|
|
1197 LF_NULL_V1 = 0x000F,
|
|
1198 LF_NOTTRAN_V1 = 0x0010,
|
|
1199 LF_DIMARRAY_V1 = 0x0011,
|
|
1200 LF_VFTPATH_V1 = 0x0012,
|
|
1201 LF_PRECOMP_V1 = 0x0013,
|
|
1202 LF_ENDPRECOMP_V1 = 0x0014,
|
|
1203 LF_OEM_V1 = 0x0015,
|
|
1204 LF_TYPESERVER_V1 = 0x0016,
|
|
1205
|
|
1206 LF_MODIFIER_V2 = 0x1001,
|
|
1207 LF_POINTER_V2 = 0x1002,
|
|
1208 LF_ARRAY_V2 = 0x1003,
|
|
1209 LF_CLASS_V2 = 0x1004,
|
|
1210 LF_STRUCTURE_V2 = 0x1005,
|
|
1211 LF_UNION_V2 = 0x1006,
|
|
1212 LF_ENUM_V2 = 0x1007,
|
|
1213 LF_PROCEDURE_V2 = 0x1008,
|
|
1214 LF_MFUNCTION_V2 = 0x1009,
|
|
1215 LF_COBOL0_V2 = 0x100A,
|
|
1216 LF_BARRAY_V2 = 0x100B,
|
|
1217 LF_DIMARRAY_V2 = 0x100C,
|
|
1218 LF_VFTPATH_V2 = 0x100D,
|
|
1219 LF_PRECOMP_V2 = 0x100E,
|
|
1220 LF_OEM_V2 = 0x100F,
|
|
1221
|
|
1222 // Can be referenced from other type records
|
|
1223 LF_SKIP_V1 = 0x0200,
|
|
1224 LF_ARGLIST_V1 = 0x0201,
|
|
1225 LF_DEFARG_V1 = 0x0202,
|
|
1226 LF_LIST_V1 = 0x0203,
|
|
1227 LF_FIELDLIST_V1 = 0x0204,
|
|
1228 LF_DERIVED_V1 = 0x0205,
|
|
1229 LF_BITFIELD_V1 = 0x0206,
|
|
1230 LF_METHODLIST_V1 = 0x0207,
|
|
1231 LF_DIMCONU_V1 = 0x0208,
|
|
1232 LF_DIMCONLU_V1 = 0x0209,
|
|
1233 LF_DIMVARU_V1 = 0x020A,
|
|
1234 LF_DIMVARLU_V1 = 0x020B,
|
|
1235 LF_REFSYM_V1 = 0x020C,
|
|
1236
|
|
1237 LF_SKIP_V2 = 0x1200,
|
|
1238 LF_ARGLIST_V2 = 0x1201,
|
|
1239 LF_DEFARG_V2 = 0x1202,
|
|
1240 LF_FIELDLIST_V2 = 0x1203,
|
|
1241 LF_DERIVED_V2 = 0x1204,
|
|
1242 LF_BITFIELD_V2 = 0x1205,
|
|
1243 LF_METHODLIST_V2 = 0x1206,
|
|
1244 LF_DIMCONU_V2 = 0x1207,
|
|
1245 LF_DIMCONLU_V2 = 0x1208,
|
|
1246 LF_DIMVARU_V2 = 0x1209,
|
|
1247 LF_DIMVARLU_V2 = 0x120A,
|
|
1248
|
|
1249 // Field lists
|
|
1250 LF_BCLASS_V1 = 0x0400,
|
|
1251 LF_VBCLASS_V1 = 0x0401,
|
|
1252 LF_IVBCLASS_V1 = 0x0402,
|
|
1253 LF_ENUMERATE_V1 = 0x0403,
|
|
1254 LF_FRIENDFCN_V1 = 0x0404,
|
|
1255 LF_INDEX_V1 = 0x0405,
|
|
1256 LF_MEMBER_V1 = 0x0406,
|
|
1257 LF_STMEMBER_V1 = 0x0407,
|
|
1258 LF_METHOD_V1 = 0x0408,
|
|
1259 LF_NESTTYPE_V1 = 0x0409,
|
|
1260 LF_VFUNCTAB_V1 = 0x040A,
|
|
1261 LF_FRIENDCLS_V1 = 0x040B,
|
|
1262 LF_ONEMETHOD_V1 = 0x040C,
|
|
1263 LF_VFUNCOFF_V1 = 0x040D,
|
|
1264 LF_NESTTYPEEX_V1 = 0x040E,
|
|
1265 LF_MEMBERMODIFY_V1 = 0x040F,
|
|
1266
|
|
1267 LF_BCLASS_V2 = 0x1400,
|
|
1268 LF_VBCLASS_V2 = 0x1401,
|
|
1269 LF_IVBCLASS_V2 = 0x1402,
|
|
1270 LF_FRIENDFCN_V2 = 0x1403,
|
|
1271 LF_INDEX_V2 = 0x1404,
|
|
1272 LF_MEMBER_V2 = 0x1405,
|
|
1273 LF_STMEMBER_V2 = 0x1406,
|
|
1274 LF_METHOD_V2 = 0x1407,
|
|
1275 LF_NESTTYPE_V2 = 0x1408,
|
|
1276 LF_VFUNCTAB_V2 = 0x1409,
|
|
1277 LF_FRIENDCLS_V2 = 0x140A,
|
|
1278 LF_ONEMETHOD_V2 = 0x140B,
|
|
1279 LF_VFUNCOFF_V2 = 0x140C,
|
|
1280 LF_NESTTYPEEX_V2 = 0x140D,
|
|
1281
|
|
1282 LF_ENUMERATE_V3 = 0x1502,
|
|
1283 LF_ARRAY_V3 = 0x1503,
|
|
1284 LF_CLASS_V3 = 0x1504,
|
|
1285 LF_STRUCTURE_V3 = 0x1505,
|
|
1286 LF_UNION_V3 = 0x1506,
|
|
1287 LF_ENUM_V3 = 0x1507,
|
|
1288 LF_MEMBER_V3 = 0x150D,
|
|
1289 LF_STMEMBER_V3 = 0x150E,
|
|
1290 LF_METHOD_V3 = 0x150F,
|
|
1291 LF_NESTTYPE_V3 = 0x1510,
|
|
1292 LF_ONEMETHOD_V3 = 0x1511,
|
|
1293
|
|
1294 // Numeric leaf types
|
|
1295 LF_NUMERIC = 0x8000,
|
|
1296 LF_CHAR = 0x8000,
|
|
1297 LF_SHORT = 0x8001,
|
|
1298 LF_USHORT = 0x8002,
|
|
1299 LF_LONG = 0x8003,
|
|
1300 LF_ULONG = 0x8004,
|
|
1301 LF_REAL32 = 0x8005,
|
|
1302 LF_REAL64 = 0x8006,
|
|
1303 LF_REAL80 = 0x8007,
|
|
1304 LF_REAL128 = 0x8008,
|
|
1305 LF_QUADWORD = 0x8009,
|
|
1306 LF_UQUADWORD = 0x800A,
|
|
1307 LF_REAL48 = 0x800B,
|
|
1308 LF_COMPLEX32 = 0x800C,
|
|
1309 LF_COMPLEX64 = 0x800D,
|
|
1310 LF_COMPLEX80 = 0x800E,
|
|
1311 LF_COMPLEX128 = 0x800F,
|
|
1312 LF_VARSTRING = 0x8010,
|
|
1313 LF_DCHAR = 0x8011
|
|
1314 }
|
|
1315
|
|
1316 /**
|
|
1317 Global types header
|
|
1318 */
|
|
1319 struct CV_GLOBALTYPES {
|
|
1320 ubyte[3] unused;
|
|
1321 ubyte flags;
|
|
1322 uint nTypes;
|
|
1323 //uint[1] typeOffsets;
|
|
1324 //CV_TYPE[1] types;
|
|
1325
|
|
1326 /// array of offsets to CV_TYPE records
|
|
1327 uint* typeOffsets() const {
|
|
1328 return cast(uint*)(&nTypes + 1);
|
|
1329 }
|
|
1330
|
|
1331 // Get the first CV_TYPE record
|
|
1332 CV_TYPE* types() const {
|
|
1333 return cast(CV_TYPE*)(cast(void*)(&nTypes + 1) + nTypes * uint.sizeof);
|
|
1334 }
|
|
1335 }
|
|
1336
|
|
1337 /**
|
|
1338 Type variant record
|
|
1339 */
|
|
1340 struct CV_TYPE {
|
|
1341 OMF_HEADER header;
|
|
1342 union {
|
|
1343 // Types
|
|
1344 CV_MODIFIER_V1 modifier_v1;
|
|
1345 CV_MODIFIER_V2 modifier_v2;
|
|
1346 CV_POINTER_V1 pointer_v1;
|
|
1347 CV_POINTER_V2 pointer_v2;
|
|
1348 CV_ARRAY_V1 array_v1;
|
|
1349 CV_ARRAY_V2 array_v2;
|
|
1350 CV_STRUCT_V1 struct_v1;
|
|
1351 CV_STRUCT_V2 struct_v2;
|
|
1352 CV_UNION_V1 union_v1;
|
|
1353 CV_UNION_V2 union_v2;
|
|
1354 CV_ENUM_V1 enum_v1;
|
|
1355 CV_ENUM_V2 enum_v2;
|
|
1356 CV_PROCEDURE_V1 proc_v1;
|
|
1357 CV_PROCEDURE_V2 proc_v2;
|
|
1358 CV_MFUNCTION_V1 method_v1;
|
|
1359 CV_MFUNCTION_V2 method_v2;
|
|
1360 CV_OEM_V1 oem_v1;
|
|
1361 CV_OEM_V2 oem_v2;
|
|
1362
|
|
1363 // Referenced types
|
|
1364 CV_FIELDLIST fieldlist;
|
|
1365 CV_BITFIELD_V1 bitfield_v1;
|
|
1366 CV_BITFIELD_V2 bitfield_v2;
|
|
1367 CV_ARGLIST_V1 arglist_v1;
|
|
1368 CV_ARGLIST_V2 arglist_v2;
|
|
1369 CV_DERIVED_V1 derived_v1;
|
|
1370 CV_DERIVED_V2 derived_v2;
|
|
1371
|
|
1372 // Field types
|
|
1373 }
|
|
1374 }
|
|
1375
|
|
1376 /**
|
|
1377 Modifier type
|
|
1378 */
|
|
1379 struct CV_MODIFIER_V1 {
|
|
1380 ushort attribute;
|
|
1381 ushort type;
|
|
1382 }
|
|
1383 struct CV_MODIFIER_V2 {
|
|
1384 uint type;
|
|
1385 ushort attribute;
|
|
1386 }
|
|
1387
|
|
1388 /**
|
|
1389 Pointer type
|
|
1390 */
|
|
1391 struct CV_POINTER_V1 {
|
|
1392 ushort attribute;
|
|
1393 ushort type;
|
|
1394 OMF_NAME name;
|
|
1395 }
|
|
1396 struct CV_POINTER_V2 {
|
|
1397 uint type;
|
|
1398 uint attribute;
|
|
1399 OMF_NAME name;
|
|
1400 }
|
|
1401
|
|
1402 /**
|
|
1403 Array type
|
|
1404 */
|
|
1405 struct CV_ARRAY_V1 {
|
|
1406 ushort elemType;
|
|
1407 ushort indexType;
|
|
1408 ushort length; /// numeric leaf
|
|
1409 OMF_NAME name;
|
|
1410 }
|
|
1411 struct CV_ARRAY_V2 {
|
|
1412 uint elemType;
|
|
1413 uint indexType;
|
|
1414 ushort length; /// numeric leaf
|
|
1415 OMF_NAME name;
|
|
1416 }
|
|
1417
|
|
1418 /**
|
|
1419 Struct type
|
|
1420 */
|
|
1421 struct CV_STRUCT_V1 {
|
|
1422 ushort nElement;
|
|
1423 ushort fieldlist;
|
|
1424 ushort property;
|
|
1425 ushort derived;
|
|
1426 ushort vshape;
|
|
1427 ushort length; /// numeric leaf
|
|
1428 OMF_NAME name;
|
|
1429 }
|
|
1430 struct CV_STRUCT_V2 {
|
|
1431 ushort nElement;
|
|
1432 ushort property;
|
|
1433 uint fieldlist;
|
|
1434 uint derived;
|
|
1435 uint vshape;
|
|
1436 ushort length; /// numeric leaf
|
|
1437 OMF_NAME name;
|
|
1438 }
|
|
1439
|
|
1440 /**
|
|
1441 Union type
|
|
1442 */
|
|
1443 struct CV_UNION_V1 {
|
|
1444 ushort count;
|
|
1445 ushort fieldlist;
|
|
1446 ushort property;
|
|
1447 ushort length; /// numeric leaf
|
|
1448 OMF_NAME name;
|
|
1449 }
|
|
1450 struct CV_UNION_V2 {
|
|
1451 ushort count;
|
|
1452 ushort property;
|
|
1453 uint fieldlist;
|
|
1454 ushort length; /// numeric leaf
|
|
1455 OMF_NAME name;
|
|
1456 }
|
|
1457
|
|
1458 /**
|
|
1459 Enumeration type
|
|
1460 */
|
|
1461 struct CV_ENUM_V1 {
|
|
1462 ushort length;
|
|
1463 ushort id;
|
|
1464 ushort count;
|
|
1465 ushort type;
|
|
1466 ushort fieldlist;
|
|
1467 ushort property;
|
|
1468 OMF_NAME p_name;
|
|
1469 }
|
|
1470 struct CV_ENUM_V2 {
|
|
1471 ushort length;
|
|
1472 ushort id;
|
|
1473 ushort count;
|
|
1474 ushort property;
|
|
1475 uint type;
|
|
1476 uint fieldlist;
|
|
1477 OMF_NAME p_name;
|
|
1478 }
|
|
1479
|
|
1480 /**
|
|
1481 Procedure type
|
|
1482 */
|
|
1483 struct CV_PROCEDURE_V1 {
|
|
1484 ushort retType;
|
|
1485 ubyte call;
|
|
1486 ubyte reserved;
|
|
1487 ushort nParams;
|
|
1488 ushort argList;
|
|
1489 }
|
|
1490 struct CV_PROCEDURE_V2 {
|
|
1491 uint retType;
|
|
1492 ubyte call;
|
|
1493 ubyte reserved;
|
|
1494 ushort nParams;
|
|
1495 uint argList;
|
|
1496 }
|
|
1497
|
|
1498 /**
|
|
1499 Method type
|
|
1500 */
|
|
1501 struct CV_MFUNCTION_V1 {
|
|
1502 ushort retType;
|
|
1503 ushort classType;
|
|
1504 ushort thisType;
|
|
1505 ubyte call;
|
|
1506 ubyte reserved;
|
|
1507 ushort nParams;
|
|
1508 ushort arglist;
|
|
1509 uint thisAdjust;
|
|
1510 }
|
|
1511 struct CV_MFUNCTION_V2 {
|
|
1512 uint retType;
|
|
1513 uint classType;
|
|
1514 uint thisType;
|
|
1515 ubyte call;
|
|
1516 ubyte reserved;
|
|
1517 ushort nParams;
|
|
1518 uint arglist;
|
|
1519 uint thisAdjust;
|
|
1520 }
|
|
1521
|
|
1522 /**
|
|
1523 OEM type
|
|
1524 */
|
|
1525 struct CV_OEM_V1 {
|
|
1526 ushort oem;
|
|
1527 ushort rec;
|
|
1528 ushort nIndices;
|
|
1529 //ushort[1] indices;
|
|
1530
|
|
1531 ushort* indices() const {
|
|
1532 return cast(ushort*)(&nIndices + 1);
|
|
1533 }
|
|
1534 }
|
|
1535 struct CV_OEM_V2 {
|
|
1536 // UNKNOWN!
|
|
1537 }
|
|
1538
|
|
1539 enum {
|
|
1540 OEM_DIGITALMARS = 0x0042,
|
|
1541 D_DYN_ARRAY = 0x0001,
|
|
1542 D_ASSOC_ARRAY = 0x0002,
|
|
1543 D_DELEGATE = 0x0003
|
|
1544 }
|
|
1545
|
|
1546 struct CV_D_DYNARRAY {
|
|
1547 ushort indexType;
|
|
1548 ushort elemType;
|
|
1549 }
|
|
1550
|
|
1551 struct CV_D_ASSOCARRAY {
|
|
1552 ushort keyType;
|
|
1553 ushort elemType;
|
|
1554 }
|
|
1555
|
|
1556 struct CV_D_DELEGATE {
|
|
1557 ushort thisType;
|
|
1558 ushort funcType;
|
|
1559 }
|
|
1560
|
|
1561 /**
|
|
1562 Field list
|
|
1563 */
|
|
1564 struct CV_FIELDLIST {
|
|
1565 ubyte[1] list;
|
|
1566 }
|
|
1567
|
|
1568 /**
|
|
1569 Bit field
|
|
1570 */
|
|
1571 struct CV_BITFIELD_V1 {
|
|
1572 ubyte nBits;
|
|
1573 ubyte bitOffset;
|
|
1574 ushort type;
|
|
1575 }
|
|
1576 struct CV_BITFIELD_V2 {
|
|
1577 uint type;
|
|
1578 ubyte nBits;
|
|
1579 ubyte bitOffset;
|
|
1580 }
|
|
1581
|
|
1582 /**
|
|
1583 Arguments list
|
|
1584 */
|
|
1585 struct CV_ARGLIST_V1 {
|
|
1586 ushort count;
|
|
1587 ushort[1] args;
|
|
1588 }
|
|
1589 struct CV_ARGLIST_V2 {
|
|
1590 uint count;
|
|
1591 uint[1] args;
|
|
1592 }
|
|
1593
|
|
1594 /**
|
|
1595 Derived
|
|
1596 */
|
|
1597 struct CV_DERIVED_V1 {
|
|
1598 ushort count;
|
|
1599 ushort[1] derivedClasses;
|
|
1600 }
|
|
1601 struct CV_DERIVED_V2 {
|
|
1602 uint count;
|
|
1603 uint[1] derivedClasses;
|
|
1604 }
|
|
1605
|
|
1606 /**
|
|
1607 Class type
|
|
1608 */
|
|
1609 struct CV_CLASS_V1 {
|
|
1610 ushort type;
|
|
1611 ushort attribute;
|
|
1612 ushort offset; /// numeric leaf
|
|
1613 }
|
|
1614 struct CV_CLASS_V2 {
|
|
1615 ushort attribute;
|
|
1616 uint type;
|
|
1617 ushort offset; /// numeric leaf
|
|
1618 }
|
|
1619
|
|
1620 struct CvTypeClass {
|
|
1621 ushort count;
|
|
1622 ushort fieldList;
|
|
1623 ushort flags;
|
|
1624 ushort dList;
|
|
1625 ushort vShape;
|
|
1626 // length
|
|
1627 // name
|
|
1628 }
|
|
1629
|
|
1630 // ----------------------------------------------------------------------------
|
|
1631 // sstSegMap
|
|
1632 // ----------------------------------------------------------------------------
|
|
1633
|
|
1634 struct CV_SEGMAP {
|
|
1635 ushort total;
|
|
1636 ushort logical;
|
|
1637 //CV_SEGMAPDESC[1] descriptors;
|
|
1638
|
|
1639 CV_SEGMAPDESC* descriptors() const {
|
|
1640 return cast(CV_SEGMAPDESC*)(&logical + 1);
|
|
1641 }
|
|
1642 }
|
|
1643
|
|
1644 struct CV_SEGMAPDESC {
|
|
1645 ushort flags;
|
|
1646 ushort overlay;
|
|
1647 ushort group;
|
|
1648 ushort frame;
|
|
1649 ushort name;
|
|
1650 ushort className;
|
|
1651 uint offset;
|
|
1652 uint size;
|
|
1653 }
|
|
1654
|
|
1655 // ----------------------------------------------------------------------------
|
|
1656 // sstPreCompMap
|
|
1657 // ----------------------------------------------------------------------------
|
|
1658
|
|
1659 struct OMFPreCompMap {
|
|
1660 ushort FirstType; // first precompiled type index
|
|
1661 ushort cTypes; // number of precompiled types
|
|
1662 uint signature; // precompiled types signature
|
|
1663 ushort padding;
|
|
1664 //CV_typ_t[] map; // mapping of precompiled types
|
|
1665 }
|
|
1666
|
|
1667 // ----------------------------------------------------------------------------
|
|
1668 // sstOffsetMap16, sstOffsetMap32
|
|
1669 // ----------------------------------------------------------------------------
|
|
1670
|
|
1671 struct OMFOffsetMap16 {
|
|
1672 uint csegment; // Count of physical segments
|
|
1673
|
|
1674 // The next six items are repeated for each segment
|
|
1675
|
|
1676 //uint crangeLog; // Count of logical offset ranges
|
|
1677 //ushort[] rgoffLog; // Array of logical offsets
|
|
1678 //short[] rgbiasLog; // Array of logical->physical bias
|
|
1679 //uint crangePhys; // Count of physical offset ranges
|
|
1680 //ushort[] rgoffPhys; // Array of physical offsets
|
|
1681 //short[] rgbiasPhys; // Array of physical->logical bias
|
|
1682 }
|
|
1683
|
|
1684 struct OMFOffsetMap32 {
|
|
1685 uint csection; // Count of physical sections
|
|
1686
|
|
1687 // The next six items are repeated for each section
|
|
1688
|
|
1689 //uint crangeLog; // Count of logical offset ranges
|
|
1690 //uint[] rgoffLog; // Array of logical offsets
|
|
1691 //int[] rgbiasLog; // Array of logical->physical bias
|
|
1692 //uint crangePhys; // Count of physical offset ranges
|
|
1693 //uint[] rgoffPhys; // Array of physical offsets
|
|
1694 //int[] rgbiasPhys; // Array of physical->logical bias
|
|
1695 }
|
|
1696
|
|
1697 // ----------------------------------------------------------------------------
|
|
1698 // sstFileIndex
|
|
1699 // ----------------------------------------------------------------------------
|
|
1700
|
|
1701 struct OMFFileIndex {
|
|
1702 ushort cmodules; // Number of modules
|
|
1703 ushort cfilerefs; // Number of file references
|
|
1704 //ushort[] modulelist; // Index to beginning of list of files
|
|
1705 // for module i. (0 for module w/o files)
|
|
1706 //ushort[] cfiles; // Number of file names associated
|
|
1707 // with module i.
|
|
1708 //uint[] ulNames; // Offsets from the beginning of this
|
|
1709 // table to the file names
|
|
1710 //char[] Names; // The length prefixed names of files
|
|
1711 }
|
|
1712
|
|
1713 struct OMFMpcDebugInfo {
|
|
1714 ushort cSeg; // number of segments in module
|
|
1715 //ushort[] mpSegFrame; // map seg (zero based) to frame
|
|
1716 }
|
|
1717
|
|
1718
|
|
1719
|
|
1720
|
|
1721
|
|
1722
|
|
1723
|
|
1724 // Procedure flags
|
|
1725 enum {
|
|
1726 PROC_FPO = 1 << 0, // Frame pointer omitted
|
|
1727 PROC_INTERRUPT = 1 << 1, // Interrupt
|
|
1728 PROC_RETURN = 1 << 2, // Far return
|
|
1729 PROC_NEVER = 1 << 3, // Never returns
|
|
1730 }
|
|
1731
|
|
1732 // Procedure calling conventions
|
|
1733 enum {
|
|
1734 CALL_C_NEAR = 0x00,
|
|
1735 CALL_C_FAR = 0x01,
|
|
1736 CALL_PASCAL_NEAR = 0x02,
|
|
1737 CALL_PASCAL_FAR = 0x03,
|
|
1738 CALL_FASTCALL_NEAR = 0x04,
|
|
1739 CALL_FASTCALL_FAR = 0x05,
|
|
1740 CALL_STDCALL_NEAR = 0x07,
|
|
1741 CALL_STDCALL_FAR = 0x08,
|
|
1742 CALL_SYSCALL_NEAR = 0x09,
|
|
1743 CALL_SYSCALL_FAR = 0x10,
|
|
1744 CALL_THIS = 0x11,
|
|
1745 CALL_MIPS = 0x12,
|
|
1746 CALL_GENERIC = 0x13
|
|
1747 }
|
|
1748
|
|
1749 enum {
|
|
1750 STRUCT_PACKED = 1 << 0,
|
|
1751 STRUCT_CTOR = 1 << 1,
|
|
1752 STRUCT_OVERLOADS = 1 << 2,
|
|
1753 STRUCT_IS_NESTED = 1 << 3,
|
|
1754 STRUCT_HAS_NESTED = 1 << 4,
|
|
1755 STRUCT_OPASSIGN = 1 << 5,
|
|
1756 STRUCT_OPCAST = 1 << 6,
|
|
1757 STRUCT_FWDREF = 1 << 7,
|
|
1758 STRUCT_SCOPED = 1 << 8
|
|
1759 }
|