1 /**************************** omf.cpp *********************************
2 * Author: Agner Fog
3 * Date created: 2007-01-29
4 * Last modified: 2018-05-26
5 * Project: objconv
6 * Module: omf.cpp
7 * Description:
8 * Module for reading OMF files
9 *
10 * Class COMF is used for reading, interpreting and dumping OMF files.
11 *
12 * Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
13 *****************************************************************************/
14 #include "stdafx.h"
15
16 // OMF Record type names
17 SIntTxt OMFRecordTypeNames[] = {
18 {OMF_THEADR, "Translator Header"},
19 {OMF_LHEADR, "Library Module Header"},
20 {OMF_COMENT, "Comment"},
21 {OMF_MODEND, "Module End"},
22 {OMF_EXTDEF, "External Names Definition"},
23 {OMF_PUBDEF, "Public Names Definition"},
24 {OMF_LINNUM, "Line Numbers"},
25 {OMF_LNAMES, "List of Names"},
26 {OMF_SEGDEF, "Segment Definition"},
27 {OMF_GRPDEF, "Group Definition"},
28 {OMF_FIXUPP, "Fixup"},
29 {OMF_LEDATA, "Enumerated Data"},
30 {OMF_LIDATA, "Iterated Data"},
31 {OMF_COMDEF, "Communal Names Definition"},
32 {OMF_BAKPAT, "Backpatch"},
33 {OMF_LEXTDEF, "Local External Names"},
34 {OMF_LPUBDEF, "Local Public Names"},
35 {OMF_LCOMDEF, "Local Communal Names"},
36 {OMF_CEXTDEF, "COMDAT External Names"},
37 {OMF_COMDAT, "Initialized Communal Data"},
38 {OMF_LINSYM, "Symbol Line Numbers"},
39 {OMF_ALIAS, "Alias Definition"},
40 {OMF_NBKPAT, "Named Backpatch"},
41 {OMF_LLNAMES, "Local Logical Names"},
42 {OMF_VERNUM, "OMF Version Number"},
43 {OMF_VENDEXT, "Vendor-specific OMF Extension"},
44 {OMF_LIBHEAD, "Library Header"},
45 {OMF_LIBEND, "Library End"}
46 };
47
48 // Segment combination names
49 SIntTxt OMFSegmentCombinationNames[] = {
50 {0, "Private"},
51 {1, "Invalid"},
52 {2, "Public"},
53 {3, "Invalid"},
54 {4, "Public 4"},
55 {5, "Stack"},
56 {6, "Common"},
57 {7, "Public 7"}
58 };
59
60 // Relocation mode names
61 static SIntTxt OMFRelocationModeNames[] = {
62 {0, "Relatv"},
63 {1, "Direct"}
64 };
65
66
67 // Fixup location names
68 static SIntTxt OMFFixupLocationNames[] = {
69 {OMF_Fixup_8bit, "8 bit"}, // 0
70 {OMF_Fixup_16bit, "16 bit"}, // 1
71 {OMF_Fixup_Segment, "segment selector, 16 bit"}, // 2
72 {OMF_Fixup_Far, "far pointer 16+16 bit"}, // 3
73 {OMF_Fixup_Hi8bit, "high 8 bit of 16 bits"}, // 4
74 {OMF_Fixup_16bitLoader, "16 bit loader resolved"}, // 5
75 {OMF_Fixup_Pharlab48, "farword 48 bit, Pharlab only"},// 6
76 {OMF_Fixup_32bit, "32 bit"}, // 9
77 {OMF_Fixup_Farword, "farword 32+16 bit"}, // 11
78 {OMF_Fixup_32bitLoader, "32 bit loader resolved"} // 13
79 };
80
81 // Alignment value translation table
82 static const uint32_t OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
83
84
85 // Class COMF members:
86 // Constructor
87
COMF()88 COMF::COMF() {
89 // Default constructor
90 memset(this, 0, sizeof(*this)); // reset everything
91 }
92
93
ParseFile()94 void COMF::ParseFile() {
95 // Parse file buffer
96 //uint8_t RecordType; // Type of current record
97 uint32_t Checksum; // Record checksum
98 uint32_t ChecksumZero = 0; // Count number of records with zero checksum
99 SOMFRecordPointer rec; // Current record pointer
100
101 // Make first entry zero in name lists
102 LocalNameOffset.PushZero();
103 SegmentNameOffset.PushZero();
104 GroupNameOffset.PushZero();
105 SymbolNameOffset.PushZero();
106
107 // Initialize record pointer
108 rec.Start(Buf(), 0, GetDataSize());
109
110 // Loop through records to set record pointers and store names
111 do {
112 // Read record
113 //RecordType = rec.Type2; // First byte of record = type
114
115 // Compute checksum
116 Checksum = 0; rec.Index = 0;
117 while (rec.Index < rec.End) Checksum += rec.GetByte();
118 uint32_t CheckByte = rec.GetByte();
119 if ((Checksum + CheckByte) & 0xFF) {
120 // Checksum failed
121 if (CheckByte == 0) {
122 ChecksumZero++;
123 }
124 else err.submit(1202); // Checksum error
125 }
126
127 // Store record pointer
128 rec.Index = 3; // Offset to current byte while parsing
129 Records.Push(rec); // Store record pointer in list
130
131 if (rec.Type2 == OMF_LNAMES) {
132 // LNAMES record. Store local names by name index
133 // Loop through strings in record
134 while (rec.Index < rec.End) {
135 char * LocalName = rec.GetString();
136 uint32_t LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
137 LocalNameOffset.Push(LocalNameIndex);// Store local name index
138 }
139 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
140 }
141
142 if (rec.Type2 == OMF_SEGDEF) {
143 // SEGDEF record. Store segment names by segment index
144 OMF_SAttrib Attributes;
145 if (rec.Type2 == OMF_SEGDEF) {
146 Attributes.b = rec.GetByte(); // Read attributes
147 if (Attributes.u.A == 0) {
148 // Frame and Offset only included if A = 0
149 rec.GetWord(); rec.GetByte();
150 }
151 rec.GetNumeric(); // Length
152 }
153 uint32_t NameIndex = rec.GetIndex();
154 if (NameIndex < LocalNameOffset.GetNumEntries()) {
155 SegmentNameOffset.Push(LocalNameOffset[NameIndex]); // List by segment index
156 }
157 }
158
159 if (rec.Type2 == OMF_GRPDEF) {
160 // GRPDEF record. Store group name
161 uint32_t NameIndex = rec.GetIndex();
162 if (NameIndex < LocalNameOffset.GetNumEntries()) {
163 GroupNameOffset.Push(LocalNameOffset[NameIndex]); // List by group index
164 }
165 }
166
167 if (rec.Type2 == OMF_EXTDEF) {
168 // EXTDEF record. Store external symbol names
169 // Loop through strings in record
170 while (rec.Index < rec.End) {
171 char * symbolname = rec.GetString();
172 rec.GetIndex();
173 uint32_t SymbolNameIndex = NameBuffer.PushString(symbolname); // Store external name
174 SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table
175 }
176 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
177 }
178
179 if (rec.Type2 == OMF_CEXTDEF) {
180 // CEXTDEF record. Store communal symbol names
181 // Loop through entries in record
182 uint32_t SymbolNameIndex; // Index into NameBuffer
183 while (rec.Index < rec.End) {
184 uint32_t LIndex = rec.GetIndex(); // Index into preceding LNAMES
185 rec.GetIndex(); // Type index. Ignore
186 // Get name from LocalNameOffset and put into SymbolNameOffset.
187 if (LIndex < LocalNameOffset.GetNumEntries()) {
188 SymbolNameIndex = LocalNameOffset[LIndex];
189 }
190 else SymbolNameIndex = 0;
191 SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table
192 }
193 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
194 }
195 } // Point to next record
196 while (rec.GetNext()); // End of loop through records
197
198 NumRecords = Records.GetNumEntries(); // Number of records
199
200 if (ChecksumZero) printf("\nChecksums are zero"); // This is taken out of the loop to report it only once
201 }
202
203
Dump(int options)204 void COMF::Dump(int options) {
205 // Dump file
206 if (options & DUMP_FILEHDR) DumpRecordTypes(); // Dump summary of record types
207
208 if (options & DUMP_STRINGTB) DumpNames(); // Dump names records
209
210 if (options & DUMP_SYMTAB) DumpSymbols(); // Dump public/external name records
211
212 if (options & DUMP_SECTHDR) DumpSegments(); // Dump segment records
213
214 if (options & DUMP_RELTAB) DumpRelocations(); // Dump fixup records
215
216 if (options & DUMP_COMMENT) DumpComments(); // Dump coment records
217 }
218
DumpRecordTypes()219 void COMF::DumpRecordTypes() {
220 // Dump summary of records
221 printf("\nSummary of records:");
222 for (uint32_t i = 0; i < NumRecords; i++) {
223 // Print record type
224 printf("\n Record %02X, %s%s, total length %i", Records[i].Type,
225 Lookup(OMFRecordTypeNames, Records[i].Type2),
226 (Records[i].Type & 1) ? ".32" : "",
227 Records[i].End+1);
228 }
229 }
230
231
DumpNames()232 void COMF::DumpNames() {
233 // Dump local names records
234 uint32_t i; // Record index
235 uint32_t ln = 0; // Local name index
236 printf("\n\nLocal names:");
237 for (i = 0; i < NumRecords; i++) {
238 if (Records[i].Type2 == OMF_LNAMES) {
239 // LNAMES record. There should be only one
240 // Loop through strings in record
241 while (Records[i].Index < Records[i].End) {
242 printf("\n %2i %s", ++ln, Records[i].GetString());
243 }
244 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
245 }
246
247 if (Records[i].Type2 == OMF_THEADR || Records[i].Type2 == OMF_LHEADR) {
248 // Module header record
249 // Loop through strings in record
250 while (Records[i].Index < Records[i].End) {
251 printf("\n Module: %s\n", Records[i].GetString());
252 }
253 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
254 }
255 if (Records[i].Type2 == OMF_COMDEF) {
256 // COMDEF record. Communal names
257 uint32_t DType, DSize, DNum;
258 printf("\n\n Communal names:");
259
260 // Loop through strings in record
261 while (Records[i].Index < Records[i].End) {
262 printf("\n \"%s\":", Records[i].GetString());
263 printf(" %i", Records[i].GetByte()); // Type index, should be 0
264 DType = Records[i].GetByte(); // Data type
265 switch (DType) {
266 case 0x61:
267 DNum = Records[i].GetLength();
268 DSize = Records[i].GetLength();
269 printf(" FAR: %i*%i bytes", DNum, DSize);
270 break;
271 case 0x62:
272 DSize = Records[i].GetLength();
273 printf(" NEAR: 0x%X bytes", DSize);
274 break;
275 default:
276 DSize = Records[i].GetLength();
277 if (DType < 0x60) { // Borland segment index
278 printf(" segment %i, size 0x%X", DType, DSize);
279 break;
280 }
281 printf(" unknown type %i, size 0x%X", DType, DSize);
282 break;
283 }
284 }
285 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
286 }
287 }
288 }
289
DumpSymbols()290 void COMF::DumpSymbols() {
291 // Dump public, external and communal names records
292 uint32_t i; // Record index
293 uint32_t xn = 0; // External name index
294 char * string;
295 uint32_t TypeIndex;
296 uint32_t Group;
297 uint32_t Segment;
298 uint32_t BaseFrame;
299 uint32_t Offset;
300
301 for (i = 0; i < NumRecords; i++) {
302 if (Records[i].Type2 == OMF_EXTDEF) {
303 // EXTDEF record.
304 Records[i].Index = 3;
305 printf("\n\nExternal names:");
306
307 // Loop through strings in record
308 while (Records[i].Index < Records[i].End) {
309 string = Records[i].GetString();
310 TypeIndex = Records[i].GetIndex();
311 printf("\n %2i %s, Type %i", ++xn, string, TypeIndex);
312 }
313 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
314 }
315
316 if (Records[i].Type2 == OMF_PUBDEF) {
317 // PUBDEF record.
318 printf("\n\nPublic names:");
319 Records[i].Index = 3;
320 Group = Records[i].GetIndex();
321 Segment = Records[i].GetIndex();
322 BaseFrame = 0;
323 if (Segment == 0) BaseFrame = Records[i].GetWord();
324 // Loop through strings in record
325 while (Records[i].Index < Records[i].End) {
326 string = Records[i].GetString();
327 Offset = Records[i].GetNumeric();
328 TypeIndex = Records[i].GetIndex();
329 printf("\n %s, Segment %s, Group %s, Offset 0x%X, Type %i",
330 string, GetSegmentName(Segment), GetGroupName(Group), Offset, TypeIndex);
331 if (BaseFrame) printf(", Frame %i", BaseFrame);
332 }
333 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
334 }
335
336 if (Records[i].Type2 == OMF_CEXTDEF) {
337 // CEXTDEF record.
338 printf("\n\nCommunal names:");
339 Records[i].Index = 3;
340 while (Records[i].Index < Records[i].End) {
341 uint32_t LIndex = Records[i].GetIndex(); // Index into preceding LNAMES
342 uint32_t Type = Records[i].GetIndex(); // Type index. Ignored
343 printf("\n %2i %s, Type %i", ++xn, GetLocalName(LIndex), Type);
344 }
345 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
346 }
347 }
348 }
349
350
DumpSegments()351 void COMF::DumpSegments() {
352 // Dump all segment records
353
354 // Define structure of attributes
355 OMF_SAttrib Attributes;
356
357 // Record values
358 uint32_t Frame, Offset, SegLength, NameIndex, ClassIndex, OverlayIndex;
359
360 uint32_t i; // Record number
361 uint32_t SegNum = 0; // Segment number
362
363 printf("\n\nSegment records:");
364 for (i = 0; i < NumRecords; i++) {
365 if (Records[i].Type2 == OMF_SEGDEF) {
366 // SEGDEF record
367 Records[i].Index = 3;
368 // Loop through entries in record. There should be only 1
369 while (Records[i].Index < Records[i].End) {
370 Attributes.b = Records[i].GetByte(); // Read attributes
371 if (Attributes.u.A == 0) {
372 // Frame and Offset only included if A = 0
373 Frame = Records[i].GetWord(); Offset = Records[i].GetByte();
374 }
375 else Frame = Offset = 0;
376 SegLength = Records[i].GetNumeric();
377 NameIndex = Records[i].GetIndex();
378 ClassIndex = Records[i].GetIndex();
379 OverlayIndex = Records[i].GetIndex();
380
381 printf("\n Segment %2i, Name %s, Class %s, Align %i, %s, %i bit",
382 ++SegNum, GetLocalName(NameIndex), GetLocalName(ClassIndex),
383 OMFAlignTranslate[Attributes.u.A],
384 Lookup(OMFSegmentCombinationNames, Attributes.u.C),
385 Attributes.u.P ? 32 : 16);
386 if (Attributes.u.B) printf(", big");
387 if (Attributes.u.A == 0) printf(", Frame %i, Offset 0x%X", Frame, Offset);
388 printf(", Length %i", SegLength);
389 if (OverlayIndex) printf("\n Overlay %i", OverlayIndex);
390 }
391 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
392 }
393 }
394 printf("\n\nGroup records:");
395 for (i = 0; i < NumRecords; i++) {
396 if (Records[i].Type2 == OMF_GRPDEF) {
397 // GRPDEF record
398 Records[i].Index = 3;
399 ClassIndex = Records[i].GetIndex();
400 printf("\n Group: %s\n Segments:", GetLocalName(ClassIndex));
401
402 // Loop through remaining entries in record
403 while (Records[i].Index < Records[i].End) {
404 uint8_t Type = Records[i].GetByte();
405 if (Type != 0xFF) printf(" Type=%X:", Type);
406 NameIndex = Records[i].GetIndex();
407 printf(" %s", GetSegmentName(NameIndex));
408 }
409 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
410 }
411 }
412 }
413
414
DumpRelocations()415 void COMF::DumpRelocations() {
416 // Dump all LEDATA, LIDATA, COMDAT and FIXUPP records
417 //uint32_t LastDataRecord = 0; // Index to the data record that relocations refer to
418 uint32_t LastDataRecordSize = 0; // Size of the data record that relocations refer to
419 int8_t * LastDataRecordPointer = 0; // Pointer to data in the data record that relocations refer to
420 uint32_t i; // Loop counter
421 uint32_t Segment, Offset, Size; // Contents of LEDATA or LIDATA record
422 uint32_t LastOffset = 0; // Offset of last LEDATA or LIDATA record
423 uint32_t Frame, Target, TargetDisplacement; // Contents of FIXUPP record
424 uint8_t byte1, byte2; // First two bytes of subrecord
425
426 // Bitfields in subrecords
427 OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field
428 OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record
429 OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record
430
431 printf("\n\nLEDATA, LIDATA, COMDAT and FIXUPP records:");
432 for (i = 0; i < NumRecords; i++) {
433 if (Records[i].Type2 == OMF_LEDATA) {
434 // LEDATA record
435 Segment = Records[i].GetIndex(); // Read segment and offset
436 Offset = Records[i].GetNumeric();
437 Size = Records[i].End - Records[i].Index; // Calculate size of data
438 //LastDataRecord = i; // Save for later FIXUPP that refers to this record
439 LastDataRecordSize = Size;
440 LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
441 if (Segment < 0x4000) {
442 printf("\n LEDATA: segment %s, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
443 GetSegmentName(Segment), Offset, Size);
444 LastOffset = Offset;
445 }
446 else { // Undocumented Borland communal section
447 printf("\n LEDATA communal section %i, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
448 (Segment & ~0x4000), Offset, Size);
449 LastOffset = Offset;
450 }
451 }
452
453 if (Records[i].Type2 == OMF_LIDATA) {
454 // LIDATA record
455 Segment = Records[i].GetIndex();
456 Offset = Records[i].GetNumeric();
457 //LastDataRecord = i;
458 LastDataRecordSize = Records[i].End - Records[i].Index; // Size before expansion of repeat blocks
459 LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
460 printf("\n LIDATA: segment %s, Offset 0x%X, Size ",
461 GetSegmentName(Segment), Offset);
462 // Call recursive function to interpret repeat data block
463 Size = Records[i].InterpretLIDATABlock();
464 printf(" = 0x%X", Size);
465 LastOffset = Offset;
466 }
467
468 if (Records[i].Type2 == OMF_COMDAT) {
469 // COMDAT record
470 //uint32_t Flags = Records[i].GetByte(); // 1 = continuation, 2 = iterated, 4 = local, 8 = data in code segment
471 uint32_t Attributes = Records[i].GetByte();
472 uint32_t Base = 0;
473 // 0 = explicit, 1 = far code, 2 = far data, 3 = code32, 4 = data32
474 // 0x00 = no match, 0x10 = pick any, 0x20 = same size, 0x30 = exact match
475 uint32_t Align = Records[i].GetByte(); // Alignment
476 Offset = Records[i].GetNumeric(); // Offset
477 uint32_t TypeIndex = Records[i].GetIndex(); // Type index
478 if ((Attributes & 0x0F) == 0) {
479 Base = Records[i].GetIndex(); // Public base
480 }
481 uint32_t NameIndex = Records[i].GetIndex(); // LNAMES index
482 Size = Records[i].End - Records[i].Index; // Calculate size of data
483
484 printf("\n COMDAT: name %s, Offset 0x%X, Size 0x%X, Attrib 0x%02X, Align %i, Type %i, Base %i",
485 GetLocalName(NameIndex), Offset, Size, Attributes, Align, TypeIndex, Base);
486 LastOffset = Offset;
487 }
488
489 if (Records[i].Type2 == OMF_FIXUPP) {
490 // FIXUPP record
491 printf("\n FIXUPP:");
492 Records[i].Index = 3;
493
494 // Loop through entries in record
495 while (Records[i].Index < Records[i].End) {
496
497 // Read first byte
498 byte1 = Records[i].GetByte();
499 if (byte1 & 0x80) {
500 // This is a FIXUP subrecord
501 Frame = 0; Target = 0; TargetDisplacement = 0;
502
503 // read second byte
504 byte2 = Records[i].GetByte();
505 // swap bytes and put into byte12 bitfield
506 Locat.bytes[1] = byte1;
507 Locat.bytes[0] = byte2;
508 // Read FixData
509 FixData.b = Records[i].GetByte();
510
511 // print mode and location
512 printf("\n %s %s, Offset 0x%X",
513 Lookup(OMFRelocationModeNames, Locat.s.M),
514 Lookup(OMFFixupLocationNames, Locat.s.Location),
515 Locat.s.Offset + LastOffset);
516
517 // Read conditional fields
518 if (FixData.s.F == 0) {
519 if (FixData.s.Frame < 4) {
520 Frame = Records[i].GetIndex();
521 }
522 else Frame = 0;
523
524 switch (FixData.s.Frame) { // Frame method
525 case 0: // F0: segment
526 printf(", segment %s", GetSegmentName(Frame)); break;
527
528 case 1: // F1: group
529 printf(", group %s", GetGroupName(Frame)); break;
530
531 case 2: // F2: external symbol
532 printf(", external frame %s", GetSymbolName(Frame)); break;
533
534 case 4: // F4: frame = source,
535 // or Borland floating point emulation record (undocumented?)
536 printf(", frame = source; or Borland f.p. emulation record");
537 break;
538
539 case 5: // F5: frame = target
540 printf(", frame = target"); break;
541
542 default:
543 printf(", target frame %i method F%i", Frame, FixData.s.Frame);
544 }
545 }
546 else {
547 printf(", frame uses thread %i", FixData.s.Frame);
548 }
549
550 if (FixData.s.T == 0) {
551 // Target specified
552 Target = Records[i].GetIndex();
553 uint32_t TargetMethod = FixData.s.Target + FixData.s.P * 4;
554
555 switch (FixData.s.Target) { // = Target method modulo 4
556 case 0: // T0 and T4: Target = segment
557 case 1: // T1 and T5: Target = segment group
558 printf(". Segment %s (T%i)",
559 GetSegmentName(Target), TargetMethod);
560 break;
561 case 2: // T2 and T6: Target = external symbol
562 printf(". Symbol %s (T%i)",
563 GetSymbolName(Target), TargetMethod);
564 break;
565 default: // Unknown method
566 printf(", target %i unknown method T%i", Target, TargetMethod);
567 }
568 }
569 else {
570 // Target specified in previous thread
571 printf(", target uses thread %i", FixData.s.Target);
572 }
573
574 if (FixData.s.P == 0) {
575 TargetDisplacement = Records[i].GetNumeric();
576 printf("\n target displacement %i", TargetDisplacement);
577 }
578 // Get inline addend
579 if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
580 int8_t * inlinep = LastDataRecordPointer + Locat.s.Offset;
581 switch (Locat.s.Location) {
582 case 0: case 4: // 8 bit
583 printf(", inline 0x%X", *inlinep); break;
584
585 case 1: case 2: case 5: // 16 bit
586 printf(", inline 0x%X", *(int16_t*)inlinep); break;
587
588 case 3: // 16+16 bit
589 printf(", inline 0x%X:0x%X", *(int16_t*)(inlinep+2), *(int16_t*)inlinep); break;
590
591 case 9: case 13: // 32 bit
592 printf(", inline 0x%X", *(int32_t*)inlinep); break;
593
594 case 6: case 11: // 16+32 bit
595 printf(", inline 0x%X:0x%X", *(int16_t*)(inlinep+4), *(int32_t*)inlinep); break;
596 }
597 }
598 }
599 else {
600 // This is a THREAD subrecord
601 TrdDat.b = byte1; // Put byte into bitfield
602
603 uint32_t Index = 0;
604 if (TrdDat.s.Method < 4) {
605 Index = Records[i].GetIndex(); // has index field if method < 4 ?
606 }
607 printf("\n %s Thread %i. Method %s%i, index %i",
608 (TrdDat.s.D ? "Frame" : "Target"), TrdDat.s.Thread,
609 (TrdDat.s.D ? "F" : "T"), TrdDat.s.Method, Index);
610 }
611 } // Finished loop through subrecords
612 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
613 }
614 } // Finished loop through records
615 }
616
617
DumpComments()618 void COMF::DumpComments() {
619 // Dump COMENT records
620 uint32_t i; // Record index
621 int startindex;
622 printf("\n");
623 for (i = 0; i < NumRecords; i++) {
624 if (Records[i].Type2 == OMF_COMENT) {
625 // COMENT record
626 printf("\nCOMENT record:\n");
627 startindex = Records[i].Index;
628 // Print as hex
629 while (Records[i].Index < Records[i].End) {
630 printf("%02X ", Records[i].GetByte());
631 }
632 // Print again as string
633 Records[i].Index = startindex;
634 printf("\n");
635 while (Records[i].Index < Records[i].End) {
636 printf("%c ", Records[i].GetByte());
637 }
638 printf("\n");
639 if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
640 }
641 }
642 }
643
644
PublicNames(CMemoryBuffer * Strings,CSList<SStringEntry> * Index,int m)645 void COMF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
646 // Make list of public names
647 // Strings will receive ASCIIZ strings
648 // Index will receive records of type SStringEntry with Member = m
649 SOMFRecordPointer rec; // Current OMF record
650 char * string; // Symbol name
651 SStringEntry se; // String entry record to save
652
653 // Initialize record pointer
654 rec.Start(Buf(), 0, GetDataSize());
655
656 // Loop through records and search for PUBDEF records
657 do {
658 // Read record
659 if (rec.Type2 == OMF_PUBDEF) {
660
661 // Public symbols definition found
662 rec.GetIndex(); // Read group
663 uint32_t Segment = rec.GetIndex(); // Read segment
664 if (Segment == 0) rec.GetWord(); // Read base frame
665 // Loop through strings in record
666 while (rec.Index < rec.End) {
667 string = rec.GetString(); // Read name
668 rec.GetNumeric(); // Read offset
669 rec.GetIndex(); // Read type
670 // Make SStringEntry record
671 se.Member = m;
672 // Store name
673 se.String = Strings->PushString(string);
674 // Store name index
675 Index->Push(se);
676 }
677 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
678 }
679 if (rec.Type2 == OMF_CEXTDEF) {
680 // CEXTDEF record. Store communal symbol names
681 // Loop through entries in record
682 while (rec.Index < rec.End) {
683 uint32_t LIndex = rec.GetIndex() - 1; // Index into preceding LNAMES
684 rec.GetIndex(); // Type index. Ignore
685 // Check if index valid
686 if (LIndex < LocalNameOffset.GetNumEntries()) {
687 // Make SStringEntry record
688 se.Member = m;
689 // Get name
690 char * name = GetLocalName(LIndex);
691 if (strlen(name) > 0) {
692 // Store name
693 se.String = Strings->PushString(name);
694 // Store name index
695 Index->Push(se);
696 }
697 }
698 }
699 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
700 }
701 if (rec.Type2 == OMF_LNAMES) {
702 // LNAMES record. Check if file has been parsed
703 if (Records.GetNumEntries() == 0) {
704 // ParseFile has not been called. We need to store LNAMES table because
705 // these names may be needed by subsequent EXTDEF records.
706 // Loop through strings in record
707 while (rec.Index < rec.End) {
708 char * LocalName = rec.GetString();
709 uint32_t LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
710 LocalNameOffset.Push(LocalNameIndex);// Store local name index
711 }
712 if (rec.Index != rec.End) err.submit(1203); // Check for consistency
713 }
714 }
715 } // Get next record
716 while (rec.GetNext()); // End of loop through records
717 }
718
GetLocalName(uint32_t i)719 char * COMF::GetLocalName(uint32_t i) {
720 // Get section name or class name by name index
721 if (i == 0 || i >= LocalNameOffset.GetNumEntries()) {
722 i = NameBuffer.PushString("null");
723 return (char*)NameBuffer.Buf() + i;
724 }
725 return (char*)NameBuffer.Buf() + LocalNameOffset[i];
726 }
727
GetLocalNameO(uint32_t i)728 uint32_t COMF::GetLocalNameO(uint32_t i) {
729 // Get section name or class by converting name index offset into NameBuffer
730 if (i > 0 && i < LocalNameOffset.GetNumEntries()) {
731 return LocalNameOffset[i];
732 }
733 return 0;
734 }
735
GetSegmentName(uint32_t i)736 const char * COMF::GetSegmentName(uint32_t i) {
737 // Get section name by segment index
738 if (i == 0) return "none";
739 if ((i & 0xC000) == 0x4000) {
740 // Borland communal section
741 static char text[32];
742 sprintf(text, "communal section %i", i - 0x4000);
743 return text;
744 }
745 if (i <= NumRecords) {
746 return(char*) NameBuffer.Buf() + SegmentNameOffset[i];
747 }
748 return "?";
749 }
750
751
GetSymbolName(uint32_t i)752 const char * COMF::GetSymbolName(uint32_t i) {
753 // Get external symbol name by index
754 if (i == 0) return "null";
755 if (i < SymbolNameOffset.GetNumEntries()) {
756 return (char*)NameBuffer.Buf() + SymbolNameOffset[i];
757 }
758 // return "?";
759 // index out of range
760 static char temp[100];
761 sprintf(temp, "Unknown index %i", i);
762 return temp;
763 }
764
GetGroupName(uint32_t i)765 const char * COMF::GetGroupName(uint32_t i) {
766 // Get group name by index
767 if (i == 0) return "none";
768 if (i <= NumRecords) {
769 return (char*)NameBuffer.Buf() + GroupNameOffset[i];
770 }
771 return "?";
772 }
773
GetRecordTypeName(uint32_t i)774 const char * COMF::GetRecordTypeName(uint32_t i) {
775 // Get record type name
776 return Lookup(OMFRecordTypeNames, i);
777 }
778
779 // Member functions for parsing SOMFRecordPointer
GetByte()780 uint8_t SOMFRecordPointer::GetByte() {
781 // Read next byte from buffer
782 return *(buffer + FileOffset + Index++);
783 }
784
GetWord()785 uint16_t SOMFRecordPointer::GetWord() {
786 // Read next 16 bit word from buffer
787 uint16_t x = *(uint16_t*)(buffer + FileOffset + Index);
788 Index += 2;
789 return x;
790 }
791
GetDword()792 uint32_t SOMFRecordPointer::GetDword() {
793 // Read next 32 bit dword from buffer
794 uint32_t x = *(uint32_t*)(buffer + FileOffset + Index);
795 Index += 4;
796 return x;
797 }
798
GetIndex()799 uint32_t SOMFRecordPointer::GetIndex() {
800 // Read byte or word, depending on sign of first byte
801 uint32_t byte1, byte2;
802 byte1 = GetByte();
803 if (byte1 & 0x80) {
804 // Two byte index
805 byte2 = GetByte();
806 return ((byte1 & 0x7F) << 8) | byte2;
807 }
808 else {
809 // One byte index
810 return byte1;
811 }
812 }
813
GetNumeric()814 uint32_t SOMFRecordPointer::GetNumeric(){
815 // Read word or dword, depending on record type even or odd
816 if (Type & 1) {
817 // Odd record type. Number is 32 bits
818 return GetDword();
819 }
820 else {
821 // Even record type. Number is 16 bit s
822 return GetWord();
823 }
824 }
825
GetLength()826 uint32_t SOMFRecordPointer::GetLength() {
827 // Read 1, 2, 3 or 4 bytes, depending on value of first byte
828 uint32_t x = GetByte();
829 switch (x) {
830 case 0x81: // 16-bit value
831 return GetWord();
832 case 0x82: // 24-bit value
833 x = GetWord();
834 return (GetByte() << 16) + x;
835 case 0x84: // 32-bit value
836 return GetDword();
837 default: // 8-bit value
838 if (x > 0x80) err.submit(1203);
839 return x;
840 }
841 }
842
GetString()843 char * SOMFRecordPointer::GetString() {
844 // Read string and return as ASCIIZ string in static buffer
845 static char String[256];
846 uint8_t Length = GetByte();
847 if (Length == 0 /*|| Length >= sizeof(String)*/) {
848 String[0] = 0;
849 }
850 else {
851 // Copy string
852 memcpy(String, buffer + FileOffset + Index, Length);
853 // Terminate by 0
854 String[Length] = 0;
855 }
856 // Point to next
857 Index += Length;
858
859 return String;
860 }
861
Start(int8_t * Buffer,uint32_t FileOffset,uint32_t FileEnd)862 void SOMFRecordPointer::Start(int8_t * Buffer, uint32_t FileOffset, uint32_t FileEnd) {
863 // Start scanning through records
864 this->buffer = Buffer;
865 this->FileOffset = FileOffset;
866 this->FileEnd = FileEnd;
867 Index = 0;
868 Type = GetByte();
869 Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
870 uint16_t RecordSize = GetWord();
871 End = Index + RecordSize - 1;
872 if (FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
873 }
874
GetNext(uint32_t align)875 uint8_t SOMFRecordPointer::GetNext(uint32_t align) {
876 // Get next record. Returns record type, made even. Returns 0 if finished
877 // align = alignment after MODEND records = page size. Applies to lib files only
878 FileOffset += End + 1;
879
880 // Check if alignment needed
881 if (align > 1 && Type2 == OMF_MODEND) {
882 // Align after MODEND record in library
883 FileOffset = (FileOffset + align - 1) & - (int32_t)align;
884 }
885 if (FileOffset >= FileEnd) return 0; // End of file
886 Index = 0; // Start reading record
887 Type = GetByte(); // Get record type
888 Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
889 uint16_t RecordSize = GetWord(); // Get record size
890 End = Index + RecordSize - 1; // Point to checksum byte
891 if ((uint64_t)FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
892 return Type2;
893 }
894
InterpretLIDATABlock()895 uint32_t SOMFRecordPointer::InterpretLIDATABlock() {
896 // Interpret Data block in LIDATA record recursively
897 // Prints repeat count and returns total size
898 uint32_t RepeatCount = GetNumeric();
899 uint32_t BlockCount = GetWord();
900 uint32_t Size = 0;
901 printf("%i * ", RepeatCount);
902 if (BlockCount == 0) {
903 Size = GetByte();
904 Index += Size;
905 printf("%i", Size);
906 return RepeatCount * Size;
907 }
908 // Nested repeat blocks
909 printf("(");
910 for (uint32_t i = 0; i < BlockCount; i++) {
911 // Recursion
912 Size += InterpretLIDATABlock();
913 if (i+1 < BlockCount) printf(" + ");
914 }
915 printf(")");
916 return RepeatCount * Size;
917 }
918
919
UnpackLIDATABlock(int8_t * destination,uint32_t MaxSize)920 uint32_t SOMFRecordPointer::UnpackLIDATABlock(int8_t * destination, uint32_t MaxSize) {
921 // Unpack Data block in LIDATA record recursively and store data at destination
922 uint32_t RepeatCount = GetNumeric(); // Outer repeat count
923 uint32_t BlockCount = GetWord(); // Inner repeat count
924 uint32_t Size = 0; // Size of data expanded so far
925 uint32_t RSize; // Size of recursively expanded data
926 uint32_t SaveIndex; // Save Index for repetition
927 uint32_t i, j; // Loop counters
928 if (BlockCount == 0) {
929 // Contains one repeated block
930 Size = GetByte(); // Size of repeated block
931 if (RepeatCount * Size > MaxSize) {
932 // Data outside allowed area
933 err.submit(2310); // Error message
934 Index += Size; // Point to after block
935 return 0; // No data stored
936 }
937
938 // Loop RepeatCount times
939 for (i = 0; i < RepeatCount; i++) {
940 // copy data block into destination
941 memcpy(destination, buffer + FileOffset + Index, Size);
942 destination += Size;
943 }
944 Index += Size; // Point to after block
945 return RepeatCount * Size; // Size of expanded data
946 }
947 // Nested repeat blocks
948 SaveIndex = Index;
949 // Loop RepeatCount times
950 for (i = 0; i < RepeatCount; i++) {
951 // Go back and repeat unpacking
952 Index = SaveIndex;
953 // Loop BlockCount times
954 for (j = 0; j < BlockCount; j++) {
955 // Recursion
956 RSize = UnpackLIDATABlock(destination, MaxSize);
957 destination += RSize;
958 MaxSize -= RSize;
959 Size += RSize;
960 }
961 }
962 return Size;
963 }
964
965
966 // Members of COMFFileBuilder, class for building OMF files
COMFFileBuilder()967 COMFFileBuilder::COMFFileBuilder() {
968 // Constructor
969 Index = 0;
970 }
971
StartRecord(uint8_t type)972 void COMFFileBuilder::StartRecord(uint8_t type) {
973 // Start building new record
974 this->Type = type; // Save type
975 RecordStart = Index = GetDataSize(); // Remember start position
976 PutByte(Type); // Put type into record
977 PutWord(0); // Reserve space for size, put in later
978 }
979
EndRecord()980 void COMFFileBuilder::EndRecord() {
981 // Finish building current record
982 // Update length
983 Get<uint16_t>(RecordStart + 1) = GetSize() + 1;
984
985 // Make checksum
986 int8_t checksum = 0;
987 for (uint32_t i = RecordStart; i < Index; i++) checksum += Buf()[i];
988 PutByte(-checksum);
989
990 // Check size limit
991 if (GetSize() > 0x407) {
992 err.submit(9005);
993 }
994 }
995
PutByte(uint8_t x)996 void COMFFileBuilder::PutByte(uint8_t x) {
997 // Put byte into buffer
998 Push(&x, 1);
999 Index++;
1000 }
1001
PutWord(uint16_t x)1002 void COMFFileBuilder::PutWord(uint16_t x) {
1003 // Put 16 bit word into buffer
1004 Push(&x, 2);
1005 Index += 2;
1006 }
1007
PutDword(uint32_t x)1008 void COMFFileBuilder::PutDword(uint32_t x) {
1009 // Put 32 bit dword into buffer
1010 Push(&x, 4);
1011 Index += 4;
1012 }
1013
PutIndex(uint32_t x)1014 void COMFFileBuilder::PutIndex(uint32_t x) {
1015 // Put byte or word into buffer (word if > 0x7F)
1016 if (x < 0x80) {
1017 // One byte
1018 PutByte(x);
1019 }
1020 else {
1021 // Two bytes
1022 if (x > 0x7fff) {
1023 err.submit(2303); // Index out of range
1024 }
1025 PutByte((uint8_t)(x >> 8) | 0x80); // First byte = high byte | 0x80
1026 PutByte(uint8_t(x)); // Second byte = low byte
1027 }
1028 }
1029
PutNumeric(uint32_t x)1030 void COMFFileBuilder::PutNumeric(uint32_t x) {
1031 // Put word or dword into buffer, depending on type being even or odd
1032 if (Type & 1) {
1033 PutDword(x); // Type is odd, put 32 bits
1034 }
1035 else {
1036 if (x > 0xffff) err.submit(2304);// Index out of range
1037 PutWord(uint16_t(x)); // Type is even, put 16 bits
1038 }
1039 }
1040
PutString(const char * s)1041 void COMFFileBuilder::PutString(const char * s) {
1042 // Put ASCII string into buffer, preceded by size
1043 uint32_t len = (uint32_t)strlen(s); // Check length
1044 if (len > 255) {
1045 // String too long
1046 err.submit(1204, s); // Issue warning
1047 len = 255; // Truncate string to 255 characters
1048 }
1049 PutByte(uint8_t(len)); // Store length
1050 Push(s, len); // Store len bytes
1051 Index += len; // Update index
1052 }
1053
PutBinary(void * p,uint32_t Size)1054 void COMFFileBuilder::PutBinary(void * p, uint32_t Size) {
1055 // Put binary data of any length
1056 if (Size > 1024) {err.submit(9000); Size = 1024;} // 1024 bytes size limit
1057 Push(p, Size);
1058 Index += Size;
1059 }
1060
GetSize()1061 uint32_t COMFFileBuilder::GetSize() {
1062 // Get size of data added so far
1063 if (Index <= RecordStart + 3) return 0;
1064 return Index - RecordStart - 3; // Type and size fields not included in size
1065 }
1066