1 using System;
2 using System.IO;
3 using System.Collections;
4 using cmsx.machine;
5
6 namespace cmsx.object
7 {
8 public const char objectFileVersion_1 = '1';
9 public const char objectFileVersion_2 = '2';
10 public const char objectFileVersion_3 = '3';
11 public const char libraryFileVersion_1 = '1';
12 public const char libraryFileVersion_2 = '2';
13 public const char libraryFileVersion_3 = '3';
14 public const char executableFileVersion_1 = '1';
15 public const char executableFileVersion_2 = '2';
16 public const char executableFileVersion_3 = '3';
17
18 public const char currentObjectFileVersion = objectFileVersion_3;
19 public const char currentLibraryFileVersion = libraryFileVersion_3;
20 public const char currentExecutableFileVersion = executableFileVersion_3;
21
22 public const ulong fileBlockSize = 4096u;
23
24 public string ObjectFileVersionStr()
25 {
26 return string(currentObjectFileVersion);
27 }
28
29 public string LibraryFileVersionStr()
30 {
31 return string(currentLibraryFileVersion);
32 }
33
34 public string ExecutableFileVersionStr()
35 {
36 return string(currentExecutableFileVersion);
37 }
38
39 public string ReadHeaderName(const string& fileName, System.IO.BinaryReader& reader, int length)
40 {
41 string result;
42 for (int i = 0; i < length; ++i;)
43 {
44 int x = reader.ReadByteOrEnd();
45 if (x == -1)
46 {
47 throw Exception("unexpected end of file " + fileName + " while reading header name, length is " + ToString(length));
48 }
49 result.Append(cast<char>(x));
50 }
51 return result;
52 }
53
54 public void WriteHeaderName(System.IO.BinaryWriter& writer, const string& headerName)
55 {
56 for (char c : headerName)
57 {
58 writer.Write(c);
59 }
60 }
61
62 public ulong ReadULong(const string& fileName, System.IO.BinaryReader& reader)
63 {
64 List<byte> b;
65 for (int i = 0; i < 8; ++i;)
66 {
67 int x = reader.ReadByteOrEnd();
68 if (x == -1)
69 {
70 throw Exception("unexpected end of file " + fileName);
71 }
72 b.Add(cast<byte>(x));
73 }
74 ulong x = (cast<ulong>(b[0]) << 56u) | (cast<ulong>(b[1]) << 48u) | (cast<ulong>(b[2]) << 40u) | (cast<ulong>(b[3]) << 32u) | (cast<ulong>(b[4]) << 24u) | (cast<ulong>(b[5]) << 16u) |
75 (cast<ulong>(b[6]) << 8u) | cast<ulong>(b[7]);
76 return x;
77 }
78
79 public void WriteULong(System.IO.BinaryWriter& writer, ulong x)
80 {
81 byte x0 = cast<byte>(x);
82 x = x >> 8u;
83 byte x1 = cast<byte>(x);
84 x = x >> 8u;
85 byte x2 = cast<byte>(x);
86 x = x >> 8u;
87 byte x3 = cast<byte>(x);
88 x = x >> 8u;
89 byte x4 = cast<byte>(x);
90 x = x >> 8u;
91 byte x5 = cast<byte>(x);
92 x = x >> 8u;
93 byte x6 = cast<byte>(x);
94 x = x >> 8u;
95 byte x7 = cast<byte>(x);
96 x = x >> 8u;
97 writer.Write(x7);
98 writer.Write(x6);
99 writer.Write(x5);
100 writer.Write(x4);
101 writer.Write(x3);
102 writer.Write(x2);
103 writer.Write(x1);
104 writer.Write(x0);
105 }
106
107 public enum ReadOption : int
108 {
109 readAll = 0, readHeadersOnly = 1
110 }
111
112 public UniquePtr<BinaryFile> ReadBinaryFile(System.IO.BinaryReader& reader, const string& fileName, ReadOption readOption)
113 {
114 UniquePtr<BinaryFile> file;
115 ulong fileOffset = cast<ulong>(reader.Tell());
116 if (fileOffset > 0u)
117 {
118 fileOffset = ((fileOffset - 1u) / fileBlockSize + 1u) * fileBlockSize;
119 }
120 reader.Seek(cast<long>(fileOffset), Origin.seekSet);
121 string fileHeaderName = ReadHeaderName(fileName, reader, 8);
122 string headerBaseName = fileHeaderName.Substring(0, fileHeaderName.Length() - 1);
123 string fileVersion = fileHeaderName.Substring(fileHeaderName.Length() - 1, 1);
124 if (headerBaseName == "CMSXOBJ")
125 {
126 if (fileVersion == ObjectFileVersionStr())
127 {
128 file.Reset(new ObjectFile(fileName, false, false));
129 }
130 else
131 {
132 throw Exception("invalid file " + fileName + " " + headerBaseName + " version " + fileVersion + " read, version " + ObjectFileVersionStr() + " expected");
133 }
134 }
135 else if (headerBaseName == "CMSXLIB")
136 {
137 if (fileVersion == LibraryFileVersionStr())
138 {
139 file.Reset(new LibraryFile(fileName, false, false));
140 }
141 else
142 {
143 throw Exception("invalid file " + fileName + " " + headerBaseName + " version " + fileVersion + " read, version " + LibraryFileVersionStr() + " expected");
144 }
145 }
146 else if (headerBaseName == "CMSXEXE")
147 {
148 if (fileVersion == ExecutableFileVersionStr())
149 {
150 file.Reset(new ExecutableFile(fileName, false, false, 0u, 0u, 0u, 0u));
151 }
152 else
153 {
154 throw Exception("invalid file " + fileName + " " + headerBaseName + " version " + fileVersion + " read, version " + ExecutableFileVersionStr() + " expected");
155 }
156 }
157 else
158 {
159 throw Exception("invalid file " + fileName + " header '" + headerBaseName + "' not CMSXOBJ, CMSXLIB or CMSXEXE");
160 }
161 file->Read(reader, readOption);
162 return file;
163 }
164
165 public UniquePtr<BinaryFile> ReadBinaryFile(System.IO.BinaryReader& reader, const string& fileName)
166 {
167 return ReadBinaryFile(reader, fileName, ReadOption.readAll);
168 }
169
170 public UniquePtr<BinaryFile> ReadBinaryFile(const string& fileName)
171 {
172 System.IO.BinaryReader reader = System.IO.File.OpenBinary(fileName);
173 return ReadBinaryFile(reader, fileName);
174 }
175
176 public class BinaryFileFormatter : Formatter
177 {
178 public nothrow BinaryFileFormatter(BinaryFile& file_) : file(file_)
179 {
180 }
181 public override string FormatRegisterNumber(byte x)
182 {
183 Symbol* registerSymbol = file.GetSymbolTable().GetRegisterSymbol(x);
184 if (registerSymbol != null)
185 {
186 return registerSymbol->name;
187 }
188 else
189 {
190 return base->FormatRegisterNumber(x);
191 }
192 }
193 public override string GetLabel(ulong address)
194 {
195 Symbol* symbol = file.GetSymbolTable().GetSymbolByAddress(address);
196 if (symbol != null)
197 {
198 if (!symbol->localName.IsEmpty())
199 {
200 return symbol->localName;
201 }
202 else
203 {
204 return symbol->name;
205 }
206 }
207 else
208 {
209 return string();
210 }
211 }
212 private BinaryFile& file;
213 }
214
215 public class BinaryFile
216 {
217 public nothrow BinaryFile(const string& fileName_, Section* headerSection_, bool initSymbolTable) : fileName(fileName_), headerSection(headerSection_), symbolTable(this, initSymbolTable)
218 {
219 }
220 public virtual default ~BinaryFile();
221 public virtual void Finalize()
222 {
223 for (const UniquePtr<Section>& section : sections)
224 {
225 section->Finalize();
226 }
227 }
228 public virtual void AddSection(Section* section)
229 {
230 section->file = this;
231 sections.Add(UniquePtr<Section>(section));
232 }
233 public nothrow Section* GetHeaderSection() const
234 {
235 return headerSection.Get();
236 }
237 public virtual nothrow Section* GetCodeSection() const
238 {
239 return null;
240 }
241 public virtual nothrow Section* GetDataSection() const
242 {
243 return null;
244 }
245 public virtual nothrow Section* GetSymbolSection() const
246 {
247 return null;
248 }
249 public Section* CreateSection(const string& sectionName)
250 {
251 if (sectionName == "CODE")
252 {
253 return new CodeSection(this);
254 }
255 else if (sectionName == "DATA")
256 {
257 return new DataSection(this);
258 }
259 else if (sectionName == "SYMB")
260 {
261 return new SymbolSection(this);
262 }
263 else if (sectionName == "LINK")
264 {
265 return new LinkSection(this);
266 }
267 else if (sectionName == "DBUG")
268 {
269 return new DebugSection(this);
270 }
271 else
272 {
273 throw Exception("unknown section '" + sectionName + " in file " + fileName);
274 }
275 }
276 public void Write()
277 {
278 System.IO.BinaryWriter writer = System.IO.File.CreateBinary(fileName);
279 Write(writer);
280 }
281 public void WriteHeader(System.IO.BinaryWriter& writer)
282 {
283 WriteHeaderName(writer, headerSection->name);
284 headerSection->Write(writer);
285 ulong numSections = cast<ulong>(sections.Count());
286 WriteULong(writer, numSections);
287 for (const UniquePtr<Section>& section : sections)
288 {
289 WriteHeaderName(writer, section->name);
290 writer.Write(section->fileOffset);
291 writer.Write(section->length);
292 }
293 WriteExtendedHeader(writer);
294 }
295 public virtual void WriteExtendedHeader(System.IO.BinaryWriter& writer)
296 {
297 }
298 public void ReadHeader(System.IO.BinaryReader& reader)
299 {
300 headerSection->Read(reader);
301 ulong numSections = ReadULong(fileName, reader);
302 for (ulong i = 0u; i < numSections; ++i;)
303 {
304 string sectionName = ReadHeaderName(fileName, reader, 4);
305 Section* section = CreateSection(sectionName);
306 section->fileOffset = reader.ReadULong();
307 section->length = reader.ReadULong();
308 AddSection(section);
309 }
310 ReadExtendedHeader(reader);
311 }
312 public virtual void ReadExtendedHeader(System.IO.BinaryReader& reader)
313 {
314 }
315 public void Write(System.IO.BinaryWriter& writer)
316 {
317 ulong prevFileOffset = cast<ulong>(writer.Tell());
318 if (prevFileOffset > 0u)
319 {
320 prevFileOffset = ((prevFileOffset - 1u) / fileBlockSize + 1u) * fileBlockSize;
321 }
322 writer.Seek(cast<long>(prevFileOffset), Origin.seekSet);
323 WriteHeader(writer);
324 for (const UniquePtr<Section>& section : sections)
325 {
326 ulong sectionFileOffset = cast<ulong>(writer.Tell());
327 if (sectionFileOffset > 0u)
328 {
329 sectionFileOffset = ((sectionFileOffset - 1u) / fileBlockSize + 1u) * fileBlockSize;
330 }
331 writer.Seek(cast<long>(sectionFileOffset), Origin.seekSet);
332 section->fileOffset = sectionFileOffset;
333 section->Write(writer);
334 }
335 ulong currentFileOffset = cast<ulong>(writer.Tell());
336 if (currentFileOffset > 0u)
337 {
338 currentFileOffset = ((currentFileOffset - 1u) / fileBlockSize + 1u) * fileBlockSize;
339 }
340 writer.Seek(cast<long>(prevFileOffset), Origin.seekSet);
341 WriteHeader(writer);
342 writer.Seek(cast<long>(currentFileOffset), Origin.seekSet);
343 WriteExtended(writer);
344 }
345 public virtual void WriteExtended(System.IO.BinaryWriter& writer)
346 {
347 }
348 public void Read(System.IO.BinaryReader& reader, ReadOption readOption)
349 {
350 ReadHeader(reader);
351 if (readOption == ReadOption.readAll)
352 {
353 long n = sections.Count();
354 for (long i = 0; i < n; ++i;)
355 {
356 Section* section = sections[i].Get();
357 reader.Seek(cast<long>(section->fileOffset), Origin.seekSet);
358 section->Read(reader);
359 }
360 ReadExtended(reader);
361 }
362 }
363 public virtual void ReadExtended(System.IO.BinaryReader& reader)
364 {
365 }
366 public virtual void AddSymbolsToAddressMap()
367 {
368 }
369 public virtual void Dump(StreamWriter& writer)
370 {
371 headerSection->Dump(writer);
372 for (const UniquePtr<Section>& section : sections)
373 {
374 section->Dump(writer);
375 writer.WriteLine();
376 }
377 }
378 public nothrow SymbolTable& GetSymbolTable()
379 {
380 return symbolTable;
381 }
382 public nothrow const string& FileName() const
383 {
384 return fileName;
385 }
386 public virtual void ReplaceLinkSection(UniquePtr<Section>& newLinkSection)
387 {
388 for (UniquePtr<Section>& section : sections)
389 {
390 if (section.Get() is LinkSection*)
391 {
392 Swap(section, newLinkSection);
393 return;
394 }
395 }
396 }
397 private string fileName;
398 private UniquePtr<Section> headerSection;
399 private List<UniquePtr<Section>> sections;
400 private SymbolTable symbolTable;
401 }
402
403 public class ObjectFile : BinaryFile
404 {
405 public ObjectFile(const string& fileName_, bool createSections_, bool initSymbolTable) : base(fileName_, new ObjectFileHeaderSection(this), initSymbolTable)
406 {
407 if (createSections_)
408 {
409 AddSection(new CodeSection(this));
410 AddSection(new DataSection(this));
411 AddSection(new SymbolSection(this));
412 AddSection(new LinkSection(this));
413 AddSection(new DebugSection(this));
414 }
415 }
416 public ObjectFile(const string& fileName_, bool initSymbolTable) : this(fileName_, true, initSymbolTable)
417 {
418 }
419 public override void AddSection(Section* section)
420 {
421 base->AddSection(section);
422 if (section is CodeSection*)
423 {
424 codeSection = section;
425 }
426 else if (section is DataSection*)
427 {
428 dataSection = section;
429 }
430 else if (section is SymbolSection*)
431 {
432 symbolSection = section;
433 }
434 else if (section is LinkSection*)
435 {
436 linkSection = section;
437 }
438 else if (section is DebugSection*)
439 {
440 debugSection = section;
441 }
442 }
443 public override nothrow Section* GetCodeSection() const
444 {
445 return codeSection;
446 }
447 public override nothrow Section* GetDataSection() const
448 {
449 return dataSection;
450 }
451 public override nothrow Section* GetSymbolSection() const
452 {
453 return symbolSection;
454 }
455 public override void AddSymbolsToAddressMap()
456 {
457 symbolSection->AddSymbolsToAddressMap();
458 }
459 public override void ReplaceLinkSection(UniquePtr<Section>& newLinkSection)
460 {
461 linkSection = newLinkSection.Get();
462 base->ReplaceLinkSection(newLinkSection);
463 }
464 public Section* codeSection;
465 public Section* dataSection;
466 public Section* symbolSection;
467 public Section* linkSection;
468 public Section* debugSection;
469 }
470
471 public class LibraryFile : BinaryFile
472 {
473 public LibraryFile(const string& fileName_, bool createSections_, bool initSymbolTable) : base(fileName_, new LibraryFileHeaderSection(this), initSymbolTable)
474 {
475 }
476 public LibraryFile(const string& fileName_, bool initSymbolTable) : this(fileName_, true, initSymbolTable)
477 {
478 }
479 public override void WriteExtendedHeader(System.IO.BinaryWriter& writer)
480 {
481 ulong numObjectFiles = cast<ulong>(objectFiles.Count());
482 WriteULong(writer, numObjectFiles);
483 for (const UniquePtr<ObjectFile>& objectFile : objectFiles)
484 {
485 writer.Write(objectFile->FileName());
486 }
487 }
488 public override void WriteExtended(System.IO.BinaryWriter& writer)
489 {
490 for (const UniquePtr<ObjectFile>& objectFile : objectFiles)
491 {
492 objectFile->Write(writer);
493 }
494 }
495 public override void ReadExtendedHeader(System.IO.BinaryReader& reader)
496 {
497 ulong numObjectFiles = ReadULong(FileName(), reader);
498 for (ulong i = 0u; i < numObjectFiles; ++i;)
499 {
500 string objectFileName = reader.ReadString();
501 objectFileNames.Add(objectFileName);
502 }
503 }
504 public override void ReadExtended(System.IO.BinaryReader& reader)
505 {
506 long n = objectFileNames.Count();
507 for (long i = 0u; i < n; ++i;)
508 {
509 const string& objectFileName = objectFileNames[i];
510 UniquePtr<BinaryFile> binaryFile = ReadBinaryFile(reader, objectFileName);
511 if (binaryFile.Get() is ObjectFile*)
512 {
513 objectFiles.Add(UniquePtr<ObjectFile>(cast<ObjectFile*>(binaryFile.Release())));
514 }
515 else
516 {
517 throw Exception("object file expected");
518 }
519 }
520 }
521 public override void Dump(StreamWriter& writer)
522 {
523 writer.WriteLine(ToString(objectFiles.Count()) + " object files:");
524 for (UniquePtr<ObjectFile>& objectFile : objectFiles)
525 {
526 writer.WriteLine(objectFile->FileName() + ":");
527 objectFile->Dump(writer);
528 writer.WriteLine();
529 }
530 }
531 public List<UniquePtr<ObjectFile>> objectFiles;
532 public List<string> objectFileNames;
533 }
534
535 public class ExecutableFile : BinaryFile
536 {
537 public ExecutableFile(const string& fileName_, bool createSections_, bool initSymbolTable, ulong minStackSize_, ulong maxStackSize_, ulong stackSizeIncrement_, ulong initialPoolSize_) :
538 base(fileName_, new ExecutableFileHeaderSection(this, minStackSize_, maxStackSize_, stackSizeIncrement_, initialPoolSize_), initSymbolTable)
539 {
540 if (createSections_)
541 {
542 AddSection(new CodeSection(this));
543 AddSection(new DataSection(this));
544 AddSection(new SymbolSection(this));
545 }
546 }
547 public ExecutableFile(const string& fileName_, bool initSymbolTable, ulong minStackSize_, ulong maxStackSize_, ulong stackSizeIncrement_, ulong initialPoolSize_) :
548 this(fileName_, true, initSymbolTable, minStackSize_, maxStackSize_, stackSizeIncrement_, initialPoolSize_)
549 {
550 }
551 public nothrow ulong MinStackSize() const
552 {
553 Section* headerSection = GetHeaderSection();
554 if (headerSection is ExecutableFileHeaderSection*)
555 {
556 ExecutableFileHeaderSection* executableFileHeaderSection = cast<ExecutableFileHeaderSection*>(headerSection);
557 return executableFileHeaderSection->minStackSize;
558 }
559 else
560 {
561 return 0u;
562 }
563 }
564 public nothrow ulong MaxStackSize() const
565 {
566 Section* headerSection = GetHeaderSection();
567 if (headerSection is ExecutableFileHeaderSection*)
568 {
569 ExecutableFileHeaderSection* executableFileHeaderSection = cast<ExecutableFileHeaderSection*>(headerSection);
570 return executableFileHeaderSection->maxStackSize;
571 }
572 else
573 {
574 return 0u;
575 }
576 }
577 public nothrow ulong StackSizeIncrement() const
578 {
579 Section* headerSection = GetHeaderSection();
580 if (headerSection is ExecutableFileHeaderSection*)
581 {
582 ExecutableFileHeaderSection* executableFileHeaderSection = cast<ExecutableFileHeaderSection*>(headerSection);
583 return executableFileHeaderSection->stackSizeIncrement;
584 }
585 else
586 {
587 return 0u;
588 }
589 }
590 public nothrow ulong InitialPoolSize() const
591 {
592 Section* headerSection = GetHeaderSection();
593 if (headerSection is ExecutableFileHeaderSection*)
594 {
595 ExecutableFileHeaderSection* executableFileHeaderSection = cast<ExecutableFileHeaderSection*>(headerSection);
596 return executableFileHeaderSection->initialPoolSize;
597 }
598 else
599 {
600 return 0u;
601 }
602 }
603 public override nothrow Section* GetCodeSection() const
604 {
605 return codeSection;
606 }
607 public override nothrow Section* GetDataSection() const
608 {
609 return dataSection;
610 }
611 public override nothrow Section* GetSymbolSection() const
612 {
613 return symbolSection;
614 }
615 public override void AddSymbolsToAddressMap()
616 {
617 symbolSection->AddSymbolsToAddressMap();
618 }
619 public override void AddSection(Section* section)
620 {
621 base->AddSection(section);
622 if (section is CodeSection*)
623 {
624 codeSection = section;
625 }
626 else if (section is DataSection*)
627 {
628 dataSection = section;
629 }
630 else if (section is SymbolSection*)
631 {
632 symbolSection = section;
633 }
634 }
635 public Section* codeSection;
636 public Section* dataSection;
637 public Section* symbolSection;
638 }
639
640 public class Section
641 {
642 public nothrow Section() : file(null), name(), pos(0), baseAddress(0u), length(0u), dataLength(0u), copyStartPos(0u), removeOffset(0u), fileOffset(0u)
643 {
644 }
645 public nothrow Section(BinaryFile* file_, const string& name_) : file(file_), name(name_), pos(0), baseAddress(0u), length(0u), dataLength(0u), copyStartPos(0u), removeOffset(0u), fileOffset(0u)
646 {
647 }
648 public virtual default ~Section();
649 public virtual void Finalize()
650 {
651 }
652 public virtual void AddSymbol(Symbol* symbol)
653 {
654 }
655 public virtual void AddSymbolsToAddressMap()
656 {
657 }
658 public nothrow ulong Address() const
659 {
660 return cast<ulong>(pos);
661 }
662 public nothrow ulong BaseAddress() const
663 {
664 return baseAddress;
665 }
666 public nothrow void SetBaseAddress(ulong baseAddress_)
667 {
668 baseAddress = baseAddress_;
669 }
670 public nothrow ulong DataLength() const
671 {
672 return cast<ulong>(data.Count());
673 }
674 public void Write(System.IO.BinaryWriter& writer)
675 {
676 length = cast<ulong>(data.Count()) + 2u * 8u;
677 dataLength = cast<ulong>(data.Count());
678 WriteULong(writer, dataLength);
679 WriteULong(writer, baseAddress);
680 for (byte b : data)
681 {
682 writer.Write(b);
683 }
684 WriteExtended(writer);
685 }
686 public virtual void WriteExtended(System.IO.BinaryWriter& writer)
687 {
688 }
689 public void Read(System.IO.BinaryReader& reader)
690 {
691 dataLength = reader.ReadULong();
692 baseAddress = ReadULong(file->FileName(), reader);
693 for (ulong i = 0u; i < dataLength; ++i;)
694 {
695 int x = reader.ReadByteOrEnd();
696 if (x == -1)
697 {
698 throw Exception("unexpected end of " + name + " section of file '" + file->FileName() + "': dataLength=" + ToString(dataLength) + ", " + ToString(i) + " bytes read.");
699 }
700 data.Add(cast<byte>(x));
701 }
702 ReadExtended(reader);
703 }
704 public virtual void ReadExtended(System.IO.BinaryReader& reader)
705 {
706 }
707 public virtual void Dump(StreamWriter& writer)
708 {
709 writer.WriteLine(name + " section");
710 if ((this is CodeSection*) || (this is DataSection*))
711 {
712 writer.WriteLine(Format("base address:", 17) + " #" + ToHexString(baseAddress));
713 }
714 writer.WriteLine(Format("length:", 17) + " #" + ToHexString(dataLength));
715 }
716 public nothrow int GetByte()
717 {
718 if (pos < data.Count())
719 {
720 return data[pos++];
721 }
722 else
723 {
724 return -1;
725 }
726 }
727 public void EmitByte(byte b)
728 {
729 if (pos == data.Count())
730 {
731 data.Add(b);
732 ++pos;
733 }
734 else if (pos < data.Count())
735 {
736 data[pos++] = b;
737 }
738 else
739 {
740 throw Exception("invalid pos for file " + file->FileName() + " " + name + " section: " + ToString(pos));
741 }
742 }
743 public void EmitByte(ulong address, byte b)
744 {
745 long prevPos = pos;
746 pos = cast<long>(address);
747 EmitByte(b);
748 pos = prevPos;
749 }
750 public nothrow void EmitLongOffset(ulong address, uint longOffset)
751 {
752 long prevPos = pos;
753 pos = cast<long>(address + 1u);
754 EmitLongOffset(longOffset);
755 pos = prevPos;
756 }
757 public nothrow void EmitShortOffset(ulong address, ushort shortOffset)
758 {
759 long prevPos = pos;
760 pos = cast<long>(address + 2u);
761 EmitShortOffset(shortOffset);
762 pos = prevPos;
763 }
764 public nothrow void EmitULong(ulong address, ulong x)
765 {
766 long prevPos = pos;
767 pos = cast<long>(address);
768 EmitULong(x);
769 pos = prevPos;
770 }
771 public string GetString()
772 {
773 string result;
774 int x = GetByte();
775 while (x != -1 && x != 0)
776 {
777 result.Append(cast<char>(x));
778 x = GetByte();
779 }
780 if (x == -1)
781 {
782 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
783 }
784 return result;
785 }
786 public void EmitString(const string& s)
787 {
788 for (char c : s)
789 {
790 EmitByte(cast<byte>(c));
791 }
792 EmitByte(0u);
793 }
794 public void EmitShortOffset(ushort offset)
795 {
796 byte b0 = cast<byte>(offset);
797 offset = offset >> 8u;
798 byte b1 = cast<byte>(offset);
799 offset = offset >> 8u;
800 #assert(offset == 0u);
801 EmitByte(b1);
802 EmitByte(b0);
803 }
804 public void EmitLongOffset(uint offset)
805 {
806 byte b0 = cast<byte>(offset);
807 offset = offset >> 8u;
808 byte b1 = cast<byte>(offset);
809 offset = offset >> 8u;
810 byte b2 = cast<byte>(offset);
811 offset = offset >> 8u;
812 EmitByte(b2);
813 EmitByte(b1);
814 EmitByte(b0);
815 }
816 public uint GetUInt()
817 {
818 List<byte> b;
819 for (int i = 0; i < 4; ++i;)
820 {
821 int x = GetByte();
822 if (x == -1)
823 {
824 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
825 }
826 b.Add(cast<byte>(x));
827 }
828 uint u = (cast<uint>(b[0]) << 24u) | (cast<uint>(b[1]) << 16u) | (cast<uint>(b[2]) << 8u) | cast<uint>(b[3]);
829 return u;
830 }
831 public void EmitUInt(uint x)
832 {
833 byte b0 = cast<byte>(x);
834 x = x >> 8u;
835 byte b1 = cast<byte>(x);
836 x = x >> 8u;
837 byte b2 = cast<byte>(x);
838 x = x >> 8u;
839 byte b3 = cast<byte>(x);
840 x = x >> 8u;
841 #assert(x == 0u);
842 EmitByte(b3);
843 EmitByte(b2);
844 EmitByte(b1);
845 EmitByte(b0);
846 }
847 public void EmitUInt(ulong address, uint x)
848 {
849 long prevPos = pos;
850 pos = cast<long>(address);
851 EmitUInt(x);
852 pos = prevPos;
853 }
854 public ulong GetULong()
855 {
856 List<byte> b;
857 for (int i = 0; i < 8; ++i;)
858 {
859 int x = GetByte();
860 if (x == -1)
861 {
862 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
863 }
864 b.Add(cast<byte>(x));
865 }
866 ulong u = (cast<ulong>(b[0]) << 56u) | (cast<ulong>(b[1]) << 48u) | (cast<ulong>(b[2]) << 40u) | (cast<ulong>(b[3]) << 32u) | (cast<ulong>(b[4]) << 24u) | (cast<ulong>(b[5]) << 16u) |
867 (cast<ulong>(b[6]) << 8u) | cast<ulong>(b[7]);
868 return u;
869 }
870 public void EmitULong(ulong x)
871 {
872 byte b0 = cast<byte>(x);
873 x = x >> 8u;
874 byte b1 = cast<byte>(x);
875 x = x >> 8u;
876 byte b2 = cast<byte>(x);
877 x = x >> 8u;
878 byte b3 = cast<byte>(x);
879 x = x >> 8u;
880 byte b4 = cast<byte>(x);
881 x = x >> 8u;
882 byte b5 = cast<byte>(x);
883 x = x >> 8u;
884 byte b6 = cast<byte>(x);
885 x = x >> 8u;
886 byte b7 = cast<byte>(x);
887 x = x >> 8u;
888 #assert(x == 0u);
889 EmitByte(b7);
890 EmitByte(b6);
891 EmitByte(b5);
892 EmitByte(b4);
893 EmitByte(b3);
894 EmitByte(b2);
895 EmitByte(b1);
896 EmitByte(b0);
897 }
898 public void Align(ulong alignment)
899 {
900 ulong at = Address();
901 ulong a = at & (alignment - 1u);
902 if (a != 0u)
903 {
904 ulong offset = alignment - a;
905 for (ulong i = 0u; i < offset; ++i;)
906 {
907 EmitByte(0u);
908 }
909 }
910 }
911 public BinaryFile* file;
912 public string name;
913 public List<byte> data;
914 public long pos;
915 public ulong baseAddress;
916 public ulong length;
917 public ulong dataLength;
918 public ulong copyStartPos;
919 public ulong removeOffset;
920 public Section* copyTargetSection;
921 public ulong fileOffset;
922 }
923
924 public class ObjectFileHeaderSection : Section
925 {
926 public nothrow ObjectFileHeaderSection(BinaryFile* file_) : base(file_, "CMSXOBJ" + ObjectFileVersionStr())
927 {
928 }
929 public override void Dump(StreamWriter& writer)
930 {
931 }
932 }
933
934 public class LibraryFileHeaderSection : Section
935 {
936 public nothrow LibraryFileHeaderSection(BinaryFile* file_) : base(file_, "CMSXLIB" + LibraryFileVersionStr())
937 {
938 }
939 public override void Dump(StreamWriter& writer)
940 {
941 }
942 }
943
944 public class ExecutableFileHeaderSection : Section
945 {
946 public nothrow ExecutableFileHeaderSection(BinaryFile* file_, ulong minStackSize_, ulong maxStackSize_, ulong stackSizeIncrement_, ulong initialPoolSize_) :
947 base(file_, "CMSXEXE" + ExecutableFileVersionStr()), minStackSize(minStackSize_), maxStackSize(maxStackSize_), stackSizeIncrement(stackSizeIncrement_), initialPoolSize(initialPoolSize_)
948 {
949 }
950 public override void WriteExtended(System.IO.BinaryWriter& writer)
951 {
952 WriteULong(writer, minStackSize);
953 WriteULong(writer, maxStackSize);
954 WriteULong(writer, stackSizeIncrement);
955 WriteULong(writer, initialPoolSize);
956 length = length + 4u * 8u;
957 }
958 public override void ReadExtended(System.IO.BinaryReader& reader)
959 {
960 minStackSize = ReadULong(file->FileName(), reader);
961 maxStackSize = ReadULong(file->FileName(), reader);
962 stackSizeIncrement = ReadULong(file->FileName(), reader);
963 initialPoolSize = ReadULong(file->FileName(), reader);
964 }
965 public override void Dump(StreamWriter& writer)
966 {
967 writer.WriteLine("HEADER section");
968 writer.WriteLine(Format("min stack size:", 17) + " #" + ToHexString(minStackSize));
969 writer.WriteLine(Format("max stack size:", 17) + " #" + ToHexString(maxStackSize));
970 writer.WriteLine(Format("initial pool size:", 17) + " #" + ToHexString(initialPoolSize));
971 writer.WriteLine();
972 }
973 public ulong minStackSize;
974 public ulong maxStackSize;
975 public ulong stackSizeIncrement;
976 public ulong initialPoolSize;
977 }
978
979 public class CodeSection : Section
980 {
981 public nothrow CodeSection(BinaryFile* file_) : base(file_, "CODE")
982 {
983 }
984 public override void Dump(StreamWriter& writer)
985 {
986 if (file == null)
987 {
988 throw Exception("file is null");
989 }
990 BinaryFileFormatter formatter(*file);
991 base->Dump(writer);
992 pos = 0;
993 ulong address = 0u;
994 int opc = GetByte();
995 while (opc != -1)
996 {
997 byte opCode = cast<byte>(opc);
998 int x = GetByte();
999 int y = GetByte();
1000 int z = GetByte();
1001 if (x != -1 && y != -1 && z != -1)
1002 {
1003 byte xx = cast<byte>(x);
1004 byte yy = cast<byte>(y);
1005 byte zz = cast<byte>(z);
1006 string instructionLine = FormatInstruction(BaseAddress() + address, opCode, xx, yy, zz, formatter);
1007 writer.WriteLine(instructionLine);
1008 }
1009 else
1010 {
1011 throw Exception("unexpected end of data of file " + file->FileName());
1012 }
1013 address = address + 4u;
1014 opc = GetByte();
1015 }
1016 }
1017 }
1018
1019 public class DataSection : Section
1020 {
1021 public nothrow DataSection(BinaryFile* file_) : base(file_, "DATA")
1022 {
1023 SetBaseAddress(cmsx.machine.dataSegmentBaseAddress);
1024 }
1025 public override void AddSymbol(Symbol* symbol)
1026 {
1027 symbols.Add(symbol);
1028 }
1029 public override void WriteExtended(System.IO.BinaryWriter& writer)
1030 {
1031 long n = symbols.Count();
1032 writer.Write(cast<ulong>(n));
1033 for (long i = 0; i < n; ++i;)
1034 {
1035 Symbol* symbol = symbols[i];
1036 ulong startOffset = symbol->start;
1037 writer.Write(startOffset);
1038 }
1039 length = length + (cast<ulong>(n) + 1u) * 8u;
1040 }
1041 public override void ReadExtended(System.IO.BinaryReader& reader)
1042 {
1043 ulong n = reader.ReadULong();
1044 for (ulong i = 0u; i < n; ++i;)
1045 {
1046 ulong startOffset = reader.ReadULong();
1047 startOffsets.Add(startOffset);
1048 }
1049 }
1050 public override void Dump(StreamWriter& writer)
1051 {
1052 if (file == null)
1053 {
1054 throw Exception("file is null");
1055 }
1056 Symbol* debugInfoSymbol = file->GetSymbolTable().GetSymbol("@debug_info");
1057 long maxPos = MaxValue<long>();
1058 if (debugInfoSymbol != null)
1059 {
1060 maxPos = cast<long>(debugInfoSymbol->value.value);
1061 }
1062 BinaryFileFormatter formatter(*file);
1063 base->Dump(writer);
1064 ulong startOffset = cast<ulong>(-1);
1065 long startOffsetIndex = 0;
1066 if (!startOffsets.IsEmpty())
1067 {
1068 startOffset = startOffsets[0];
1069 ++startOffsetIndex;
1070 if (startOffsetIndex < startOffsets.Count())
1071 {
1072 startOffset = startOffsets[startOffsetIndex];
1073 ++startOffsetIndex;
1074 }
1075 else
1076 {
1077 startOffset = cast<ulong>(-1);
1078 }
1079 }
1080 pos = 0;
1081 ulong address = 0u;
1082 ulong baseAddr = BaseAddress() + address;
1083 string currentBytes;
1084 string currentChars;
1085 string currentHeader = "#" + ToHexString(baseAddr) + " " + Format(formatter.GetLabel(baseAddr), 80, FormatWidth.min);
1086 int b = GetByte();
1087 while (b != -1)
1088 {
1089 if (pos >= maxPos)
1090 {
1091 break;
1092 }
1093 baseAddr = BaseAddress() + address;
1094 if (baseAddr == startOffset)
1095 {
1096 writer.WriteLine(currentHeader + " " + currentBytes + " " + currentChars);
1097 currentBytes.Clear();
1098 currentChars.Clear();
1099 currentHeader = "#" + ToHexString(baseAddr) + " " + Format(formatter.GetLabel(baseAddr), 80, FormatWidth.min);
1100 if (startOffsetIndex < startOffsets.Count())
1101 {
1102 startOffset = startOffsets[startOffsetIndex];
1103 ++startOffsetIndex;
1104 }
1105 else
1106 {
1107 startOffset = cast<ulong>(-1);
1108 }
1109 }
1110 if (!currentBytes.IsEmpty())
1111 {
1112 currentBytes.Append(" ");
1113 }
1114 currentBytes.Append(ToHexString(cast<byte>(b)));
1115 char c = '.';
1116 if (b >= 32u && b < 127u)
1117 {
1118 c = cast<char>(b);
1119 }
1120 currentChars.Append(c);
1121 b = GetByte();
1122 ++address;
1123 }
1124 if (!currentBytes.IsEmpty())
1125 {
1126 writer.WriteLine(currentHeader + " " + currentBytes + " " + currentChars);
1127 }
1128 writer.WriteLine();
1129 if (debugInfoSymbol != null)
1130 {
1131 writer.WriteLine("DEBUG INFO");
1132 writer.WriteLine("start: " + ToHexString(debugInfoSymbol->start));
1133 writer.WriteLine("length: " + ToHexString(debugInfoSymbol->length));
1134 writer.WriteLine();
1135 Symbol* functionTableSymbol = file->GetSymbolTable().GetSymbol("@function_table");
1136 DumpFunctionTable(functionTableSymbol, writer);
1137 }
1138 }
1139 public override void Finalize()
1140 {
1141 Align(8u);
1142 }
1143 private void DumpFunctionTable(Symbol* functionTableSymbol, StreamWriter& writer)
1144 {
1145 writer.WriteLine("FUNCTION TABLE");
1146 writer.WriteLine("start: " + ToHexString(functionTableSymbol->start));
1147 writer.WriteLine("length: " + ToHexString(functionTableSymbol->length));
1148 writer.WriteLine();
1149 long prevPos = pos;
1150 long functionTableStartPos = cast<long>(functionTableSymbol->value.value);
1151 long functionTableEndPos = functionTableStartPos + cast<long>(functionTableSymbol->length);
1152 pos = functionTableStartPos;
1153 while (pos < functionTableEndPos)
1154 {
1155 DumpFunctionTableEntry(writer);
1156 }
1157 }
1158 private void DumpFunctionTableEntry(StreamWriter& writer)
1159 {
1160 writer.WriteLine("FUNCTION TABLE ENTRY");
1161 ulong start = GetULong();
1162 Symbol* functionSymbol = file->GetSymbolTable().GetSymbolByAddress(start);
1163 ulong length = GetULong();
1164 ulong mangledNameAddress = GetULong();
1165 ulong fullNameAddress = GetULong();
1166 ulong sourceFileNameAddress = GetULong();
1167 ulong lineNumberTableStartAddress = GetULong();
1168 ulong lineNumberTableEndAddress = GetULong();
1169 ulong exceptionTableAddress = GetULong();
1170 writer.Write(" start: " + ToHexString(start));
1171 if (functionSymbol != null)
1172 {
1173 writer.Write(" " + functionSymbol->name);
1174 }
1175 writer.WriteLine();
1176 writer.WriteLine(" length: " + ToHexString(length));
1177 writer.WriteLine(" mangledName: " + ToHexString(mangledNameAddress) + " " + GetString(mangledNameAddress));
1178 writer.WriteLine(" fullName: " + ToHexString(fullNameAddress) + " " + GetString(fullNameAddress));
1179 writer.WriteLine(" sourceFileName: " + ToHexString(sourceFileNameAddress) + " " + GetString(sourceFileNameAddress));
1180 writer.WriteLine(" lineNumberTableStart: " + ToHexString(lineNumberTableStartAddress));
1181 writer.WriteLine(" lineNumberTableEnd: " + ToHexString(lineNumberTableEndAddress));
1182 writer.Write( " lineNumberTable: ");
1183 DumpLineNumberTable(lineNumberTableStartAddress, lineNumberTableEndAddress, writer);
1184 writer.WriteLine();
1185 writer.WriteLine("exceptionTableAddress: " + ToHexString(exceptionTableAddress));
1186 if (exceptionTableAddress != 0u)
1187 {
1188 DumpExceptionTable(exceptionTableAddress, writer);
1189 }
1190 writer.WriteLine();
1191 }
1192 private string GetString(ulong address)
1193 {
1194 long prevPos = pos;
1195 pos = cast<long>(address);
1196 string s = GetString();
1197 pos = prevPos;
1198 return s;
1199 }
1200 private void DumpLineNumberTable(ulong lineNumberTableStartAddress, ulong lineNumberTableEndAddress, StreamWriter& writer)
1201 {
1202 if (lineNumberTableStartAddress == lineNumberTableEndAddress) return;
1203 writer.Write("[");
1204 long prevPos = pos;
1205 pos = cast<long>(lineNumberTableStartAddress);
1206 bool first = true;
1207 while (pos < cast<long>(lineNumberTableEndAddress))
1208 {
1209 if (first)
1210 {
1211 first = false;
1212 }
1213 else
1214 {
1215 writer.Write(" : ");
1216 }
1217 uint offset = GetUInt();
1218 uint line = GetUInt();
1219 writer.Write("offset: " + ToString(offset) + ", line: " + ToString(line));
1220 }
1221 writer.Write("]");
1222 pos = prevPos;
1223 }
1224 private void DumpExceptionTable(ulong exceptionTableAddress, StreamWriter& writer)
1225 {
1226 writer.WriteLine();
1227 writer.WriteLine("EXCEPTION TABLE " + ToHexString(exceptionTableAddress));
1228 long prevPos = pos;
1229 pos = cast<long>(exceptionTableAddress);
1230 ulong frameSize = GetUInt();
1231 writer.WriteLine("frame size: " + ToString(frameSize));
1232 ulong numDispatchTableEntries = GetUInt();
1233 writer.WriteLine();
1234 writer.WriteLine("DISPATCH TABLE (" + ToString(numDispatchTableEntries) + " entries)");
1235 Set<ulong> exceptionBlockTableAddressSet;
1236 for (ulong i = 0u; i < numDispatchTableEntries; ++i;)
1237 {
1238 uint offset = GetUInt();
1239 uint length = GetUInt();
1240 ulong exceptionBlockTableAddress = GetULong();
1241 writer.WriteLine(ToString(i) + ": offset: " + ToString(offset) + ", length: " + ToString(length) + ", exception block table address: " + ToHexString(exceptionBlockTableAddress));
1242 exceptionBlockTableAddressSet.Insert(exceptionBlockTableAddress);
1243 }
1244 while (!exceptionBlockTableAddressSet.IsEmpty())
1245 {
1246 Set<ulong> newExceptionBlockTableAddressSet;
1247 for (ulong exceptionBlockTableAddress : exceptionBlockTableAddressSet)
1248 {
1249 writer.WriteLine();
1250 writer.WriteLine("EXCEPTION BLOCK TABLE " + ToHexString(exceptionBlockTableAddress));
1251 long prevPos = pos;
1252 pos = cast<long>(exceptionBlockTableAddress);
1253 while (true)
1254 {
1255 ulong discriminator = GetULong();
1256 if (discriminator == handlerBlockDiscriminator)
1257 {
1258 writer.WriteLine();
1259 writer.WriteLine("HANDLER BLOCK");
1260 ulong catchedClassId = GetULong();
1261 ulong handlerAddress = GetULong();
1262 writer.WriteLine("catched class id: " + ToString(catchedClassId));
1263 writer.Write("handlerAddress: " + ToHexString(handlerAddress) + " ");
1264 Symbol* handlerSymbol = file->GetSymbolTable().GetSymbolByAddress(handlerAddress);
1265 if (handlerSymbol != null)
1266 {
1267 writer.Write(handlerSymbol->name);
1268 }
1269 writer.WriteLine();
1270 }
1271 else if (discriminator == cleanupBlockDiscriminator)
1272 {
1273 writer.WriteLine();
1274 writer.WriteLine("CLEANUP BLOCK");
1275 ulong cleanupAddress = GetULong();
1276 ulong parentTableAddress = GetULong();
1277 writer.Write("cleanup address: " + ToHexString(cleanupAddress) + " ");
1278 Symbol* cleanupSymbol = file->GetSymbolTable().GetSymbolByAddress(cleanupAddress);
1279 if (cleanupSymbol != null)
1280 {
1281 writer.Write(cleanupSymbol->name);
1282 }
1283 writer.WriteLine();
1284 writer.WriteLine("parent table addr: " + ToHexString(parentTableAddress));
1285 if (parentTableAddress != 0u)
1286 {
1287 newExceptionBlockTableAddressSet.Insert(parentTableAddress);
1288 }
1289 }
1290 else if (discriminator == endBlockDiscriminator)
1291 {
1292 break;
1293 }
1294 else
1295 {
1296 throw Exception("unknonwn exception block table discriminator " + ToString(discriminator));
1297 }
1298 }
1299 pos = prevPos;
1300 }
1301 Swap(exceptionBlockTableAddressSet, newExceptionBlockTableAddressSet);
1302 }
1303 pos = prevPos;
1304 }
1305 private List<Symbol*> symbols;
1306 private List<ulong> startOffsets;
1307 }
1308
1309 public class SymbolSection : Section
1310 {
1311 public nothrow SymbolSection(BinaryFile* file_) : base(file_, "SYMB")
1312 {
1313 }
1314 public override void Finalize()
1315 {
1316 if (file is ExecutableFile*)
1317 {
1318 SymbolTable& symbolTable = file->GetSymbolTable();
1319 for (const UniquePtr<Symbol>& symbol : symbolTable.Symbols())
1320 {
1321 if (symbol->section != null)
1322 {
1323 if (symbol->section is CodeSection*)
1324 {
1325 symbol->value.value = symbol->start - file->GetCodeSection()->BaseAddress();
1326 }
1327 else if (symbol->section is DataSection*)
1328 {
1329 symbol->value.value = symbol->start - file->GetDataSection()->BaseAddress();
1330 }
1331 }
1332 }
1333 }
1334 EmitSymbols();
1335 }
1336 public Segment GetSegment()
1337 {
1338 int segment = GetByte();
1339 if (segment == -1)
1340 {
1341 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
1342 }
1343 return cast<Segment>(cast<byte>(segment));
1344 }
1345 public Linkage GetLinkage()
1346 {
1347 int linkage = GetByte();
1348 if (linkage == -1)
1349 {
1350 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
1351 }
1352 return cast<Linkage>(cast<byte>(linkage));
1353 }
1354 public Value.Flag GetValueFlags()
1355 {
1356 int flags = GetByte();
1357 if (flags == -1)
1358 {
1359 throw Exception("unexpected end of " + name + " section of file " + file->FileName());
1360 }
1361 return cast<Value.Flag>(cast<byte>(flags));
1362 }
1363 public Value GetValue()
1364 {
1365 Value.Flag flags = GetValueFlags();
1366 ulong v = GetULong();
1367 Value value(flags, v, null);
1368 return value;
1369 }
1370 public override void ReadExtended(System.IO.BinaryReader& reader)
1371 {
1372 pos = 0;
1373 ulong numSymbols = GetULong();
1374 for (ulong i = 0u; i < numSymbols; ++i;)
1375 {
1376 uint symbolIndex = GetUInt();
1377 string symbolName = GetString();
1378 string symbolLocalName = GetString();
1379 Segment segment = GetSegment();
1380 Section* section = null;
1381 if (segment == Segment.text)
1382 {
1383 section = file->GetCodeSection();
1384 }
1385 else if (segment == Segment.data)
1386 {
1387 section = file->GetDataSection();
1388 }
1389 Linkage linkage = GetLinkage();
1390 Value value = GetValue();
1391 ulong start = GetULong();
1392 ulong length = GetULong();
1393 Symbol* symbol = new Symbol();
1394 symbol->index = cast<int>(symbolIndex);
1395 symbol->name = symbolName;
1396 symbol->localName = symbolLocalName;
1397 symbol->segment = segment;
1398 symbol->linkage = linkage;
1399 symbol->value = value;
1400 symbol->start = start;
1401 symbol->length = length;
1402 symbol->section = section;
1403 uint parentIndex = GetUInt();
1404 symbol->parentIndex = cast<int>(parentIndex);
1405 uint linkStart = GetUInt();
1406 uint linkEnd = GetUInt();
1407 symbol->linkStart = cast<int>(linkStart);
1408 symbol->linkEnd = cast<int>(linkEnd);
1409 int alignment = GetByte();
1410 symbol->alignment = cast<byte>(alignment);
1411 file->GetSymbolTable().AddSymbol(symbol, false);
1412 }
1413 ulong numInternalSymbols = GetULong();
1414 for (ulong i = 0u; i < numInternalSymbols; ++i;)
1415 {
1416 uint symbolIndex = GetUInt();
1417 string symbolName = GetString();
1418 string symbolLocalName = GetString();
1419 Segment segment = GetSegment();
1420 Section* section = null;
1421 if (segment == Segment.text)
1422 {
1423 section = file->GetCodeSection();
1424 }
1425 else if (segment == Segment.data)
1426 {
1427 section = file->GetDataSection();
1428 }
1429 Linkage linkage = GetLinkage();
1430 Value value = GetValue();
1431 ulong start = GetULong();
1432 ulong length = GetULong();
1433 Symbol* symbol = new Symbol();
1434 symbol->index = cast<int>(symbolIndex);
1435 symbol->name = symbolName;
1436 symbol->localName = symbolLocalName;
1437 symbol->segment = segment;
1438 symbol->linkage = linkage;
1439 symbol->value = value;
1440 symbol->start = start;
1441 symbol->length = length;
1442 symbol->section = section;
1443 uint parentIndex = GetUInt();
1444 symbol->parentIndex = cast<int>(parentIndex);
1445 uint linkStart = GetUInt();
1446 uint linkEnd = GetUInt();
1447 symbol->linkStart = cast<int>(linkStart);
1448 symbol->linkEnd = cast<int>(linkEnd);
1449 int alignment = GetByte();
1450 symbol->alignment = cast<byte>(alignment);
1451 file->GetSymbolTable().AddInternalSymbol(symbol, false);
1452 }
1453 }
1454 public void EmitSymbols()
1455 {
1456 if (file == null)
1457 {
1458 throw Exception("file is null");
1459 }
1460 SymbolTable& symbolTable = file->GetSymbolTable();
1461 EmitULong(cast<ulong>(symbolTable.Symbols().Count()));
1462 for (const UniquePtr<Symbol>& symbol : symbolTable.Symbols())
1463 {
1464 EmitSymbol(symbol.Get());
1465 }
1466 EmitULong(cast<ulong>(symbolTable.InternalSymbols().Count()));
1467 for (const UniquePtr<Symbol>& symbol : symbolTable.InternalSymbols())
1468 {
1469 EmitSymbol(symbol.Get());
1470 }
1471 }
1472 public void EmitSymbol(Symbol* symbol)
1473 {
1474 EmitUInt(cast<uint>(symbol->index));
1475 EmitString(symbol->name);
1476 EmitString(symbol->localName);
1477 EmitByte(symbol->segment);
1478 EmitByte(symbol->linkage);
1479 EmitValue(symbol->value);
1480 EmitULong(symbol->start);
1481 EmitULong(symbol->length);
1482 EmitUInt(cast<uint>(symbol->parentIndex));
1483 EmitUInt(cast<uint>(symbol->linkStart));
1484 EmitUInt(cast<uint>(symbol->linkEnd));
1485 EmitByte(symbol->alignment);
1486 }
1487 public void EmitValue(const Value& value)
1488 {
1489 EmitByte(value.flags);
1490 EmitULong(value.value);
1491 }
1492 public override void AddSymbolsToAddressMap()
1493 {
1494 SymbolTable& symbolTable = file->GetSymbolTable();
1495 for (const UniquePtr<Symbol>& symbol : symbolTable.Symbols())
1496 {
1497 symbolTable.AddSymbolToAddressMap(symbol.Get());
1498 }
1499 }
1500 public override void Dump(StreamWriter& writer)
1501 {
1502 base->Dump(writer);
1503 SymbolTable& symbolTable = file->GetSymbolTable();
1504 for (const UniquePtr<Symbol>& symbol : symbolTable.Symbols())
1505 {
1506 string symbolLine;
1507 string absoluteAddress;
1508 if (symbol->value.GetFlag(Value.Flag.pure))
1509 {
1510 absoluteAddress = "#" + ToHexString(symbol->start);
1511 }
1512 symbolLine.Append(Format(absoluteAddress, 17));
1513 symbolLine.Append(" ").Append(Format(ToString(symbol->index), 11));
1514 symbolLine.Append(" ").Append(Format(symbol->name, 80, FormatWidth.min));
1515 symbolLine.Append(" ").Append(Format(SegmentStr(symbol->segment), 7));
1516 symbolLine.Append(" ").Append(Format(LinkageStr(symbol->linkage), 9));
1517 symbolLine.Append(" ").Append(ValueStr(symbol->value));
1518 if (symbol->value.GetFlag(Value.Flag.function) || symbol->value.GetFlag(Value.Flag.structure))
1519 {
1520 symbolLine.Append(" ").Append("#").Append(ToHexString(symbol->start));
1521 symbolLine.Append(" ").Append("#").Append(ToHexString(symbol->length));
1522 symbolLine.Append(" ").Append(ToString(symbol->linkStart));
1523 symbolLine.Append(" ").Append(ToString(symbol->linkEnd));
1524 }
1525 symbolLine.Append(" ").Append(ToString(symbol->alignment));
1526 writer.WriteLine(symbolLine);
1527 }
1528 for (const UniquePtr<Symbol>& symbol : symbolTable.InternalSymbols())
1529 {
1530 string symbolLine;
1531 string absoluteAddress;
1532 if (symbol->value.GetFlag(Value.Flag.pure))
1533 {
1534 absoluteAddress = "#" + ToHexString(symbol->start);
1535 }
1536 symbolLine.Append(Format(absoluteAddress, 17));
1537 symbolLine.Append(" ").Append(Format(ToString(symbol->index), 11));
1538 symbolLine.Append(" ").Append(Format(symbol->name, 80, FormatWidth.min));
1539 symbolLine.Append(" ").Append(Format(SegmentStr(symbol->segment), 7));
1540 symbolLine.Append(" ").Append(Format(LinkageStr(symbol->linkage), 9));
1541 symbolLine.Append(" ").Append(ValueStr(symbol->value));
1542 if (symbol->value.GetFlag(Value.Flag.function) || symbol->value.GetFlag(Value.Flag.structure))
1543 {
1544 symbolLine.Append(" ").Append("#").Append(ToHexString(symbol->start));
1545 symbolLine.Append(" ").Append("#").Append(ToHexString(symbol->length));
1546 }
1547 symbolLine.Append(" ").Append(ToString(symbol->alignment));
1548 writer.WriteLine(symbolLine);
1549 }
1550 }
1551 }
1552
1553 public class LinkSection : Section
1554 {
1555 public nothrow LinkSection(BinaryFile* file_) : base(file_, "LINK")
1556 {
1557 }
1558 public override void Dump(StreamWriter& writer)
1559 {
1560 if (file == null)
1561 {
1562 throw Exception("file is null");
1563 }
1564 BinaryFileFormatter formatter(*file);
1565 base->Dump(writer);
1566 pos = 0;
1567 long p = pos;
1568 int x = GetByte();
1569 while (x != -1)
1570 {
1571 LinkCode linkCode = cast<LinkCode>(cast<byte>(x));
1572 if (linkCode == LinkCode.end)
1573 {
1574 break;
1575 }
1576 string linkLine = Format(ToString(p), 5, FormatWidth.min, FormatJustify.right);
1577 linkLine.Append(" ").Append(Format(LinkCodeStr(linkCode), maxLinkCodeStrLength));
1578 switch (linkCode)
1579 {
1580 case LinkCode.forwardLongJump:
1581 {
1582 uint index = GetUInt();
1583 linkLine.Append(" ").Append(Format(ToString(index), 5, FormatWidth.min, FormatJustify.right));
1584 Symbol* s = file->GetSymbolTable().GetSymbol(cast<int>(index));
1585 linkLine.Append(" ").Append(s->name);
1586 ulong address = GetULong();
1587 linkLine.Append(" #").Append(ToHexString(address));
1588 break;
1589 }
1590 case LinkCode.forwardShortJump:
1591 {
1592 uint index = GetUInt();
1593 linkLine.Append(" ").Append(Format(ToString(index), 5, FormatWidth.min, FormatJustify.right));
1594 Symbol* s = file->GetSymbolTable().GetSymbol(cast<int>(index));
1595 linkLine.Append(" ").Append(s->name);
1596 ulong address = GetULong();
1597 linkLine.Append(" #").Append(ToHexString(address));
1598 break;
1599 }
1600 case LinkCode.absoluteAddrValue:
1601 {
1602 uint index = GetUInt();
1603 linkLine.Append(" ").Append(Format(ToString(index), 5, FormatWidth.min, FormatJustify.right));
1604 Symbol* s = file->GetSymbolTable().GetSymbol(cast<int>(index));
1605 linkLine.Append(" ").Append(s->name);
1606 ulong address = GetULong();
1607 linkLine.Append(" #").Append(ToHexString(address));
1608 break;
1609 }
1610 case LinkCode.farJump:
1611 {
1612 uint index = GetUInt();
1613 linkLine.Append(" ").Append(Format(ToString(index), 5, FormatWidth.min, FormatJustify.right));
1614 Symbol* s = file->GetSymbolTable().GetSymbol(cast<int>(index));
1615 linkLine.Append(" ").Append(s->name);
1616 ulong address = GetULong();
1617 linkLine.Append(" #").Append(ToHexString(address));
1618 break;
1619 }
1620 case LinkCode.farOcta:
1621 {
1622 uint index = GetUInt();
1623 linkLine.Append(" ").Append(Format(ToString(index), 5, FormatWidth.min, FormatJustify.right));
1624 Symbol* s = file->GetSymbolTable().GetSymbol(cast<int>(index));
1625 linkLine.Append(" ").Append(s->name);
1626 ulong address = GetULong();
1627 linkLine.Append(" #").Append(ToHexString(address));
1628 break;
1629 }
1630 case LinkCode.clsid:
1631 {
1632 ulong address = GetULong();
1633 linkLine.Append(" #").Append(ToHexString(address));
1634 ulong typeId1 = GetULong();
1635 ulong typeId2 = GetULong();
1636 Uuid typeId(typeId1, typeId2);
1637 linkLine.Append(" #").Append(ToString(typeId));
1638 break;
1639 }
1640 }
1641 writer.WriteLine(linkLine);
1642 p = pos;
1643 x = GetByte();
1644 }
1645 }
1646 public override void Finalize()
1647 {
1648 EmitByte(LinkCode.end);
1649 }
1650 }
1651
1652 public class DebugSection : Section
1653 {
1654 public nothrow DebugSection(BinaryFile* file_) : base(file_, "DBUG")
1655 {
1656 }
1657 public override void Dump(StreamWriter& writer)
1658 {
1659 BinaryFileFormatter formatter(*file);
1660 base->Dump(writer);
1661 pos = 0;
1662 int x = GetByte();
1663 while (x != -1)
1664 {
1665 DebugRecordCode debugRecordCode = cast<DebugRecordCode>(cast<byte>(x));
1666 if (debugRecordCode == DebugRecordCode.end)
1667 {
1668 break;
1669 }
1670 string debugLine = Format(DebugRecordCodeStr(debugRecordCode), maxDebugCodeStrLength);
1671 if (debugRecordCode == DebugRecordCode.fileInfo)
1672 {
1673 string sourceFileName = GetString();
1674 uint sourceFileNameId = GetUInt();
1675 debugLine.Append(" ").Append(sourceFileName).Append(" ").Append(ToString(sourceFileNameId));
1676 }
1677 else if (debugRecordCode == DebugRecordCode.functionInfo)
1678 {
1679 uint functionSymbolIndex = GetUInt();
1680 string functionFullName = GetString();
1681 uint sourceFileNameId = GetUInt();
1682 uint frameSize = GetUInt();
1683 debugLine.Append(" ").Append(ToString(functionSymbolIndex)).Append(' ').Append(functionFullName).Append(' ').Append(ToString(sourceFileNameId)).Append(' ').Append(ToString(frameSize));
1684 }
1685 else if (debugRecordCode == DebugRecordCode.startFunc)
1686 {
1687 uint functionSymbolIndex = GetUInt();
1688 Symbol* functionSymbol = file->GetSymbolTable().GetSymbol(cast<int>(functionSymbolIndex));
1689 debugLine.Append(" ").Append(ToString(functionSymbolIndex)).Append(' ').Append(functionSymbol->name);
1690 }
1691 else if (debugRecordCode == DebugRecordCode.endFunc)
1692 {
1693 uint functionSymbolIndex = GetUInt();
1694 Symbol* functionSymbol = file->GetSymbolTable().GetSymbol(cast<int>(functionSymbolIndex));
1695 debugLine.Append(" ").Append(ToString(functionSymbolIndex)).Append(' ').Append(functionSymbol->name);
1696 }
1697 else if (debugRecordCode == DebugRecordCode.lineInfo)
1698 {
1699 uint offset = GetUInt();
1700 uint line = GetUInt();
1701 debugLine.Append(" ").Append(ToString(offset)).Append(' ').Append(ToString(line));
1702 }
1703 else if (debugRecordCode == DebugRecordCode.beginTry)
1704 {
1705 uint tryBlockId = GetUInt();
1706 uint parentTryBlockId = GetUInt();
1707 uint offset = GetUInt();
1708 debugLine.Append(" ").Append(ToString(tryBlockId)).Append(' ').Append(ToString(parentTryBlockId)).Append(' ').Append(ToString(offset));
1709 }
1710 else if (debugRecordCode == DebugRecordCode.endTry)
1711 {
1712 uint tryBlockId = GetUInt();
1713 uint offset = GetUInt();
1714 debugLine.Append(" ").Append(ToString(tryBlockId)).Append(' ').Append(ToString(offset));
1715 }
1716 else if (debugRecordCode == DebugRecordCode.catch_)
1717 {
1718 uint catchBlockId = GetUInt();
1719 uint tryBlockId = GetUInt();
1720 ulong catchTypeId1 = GetULong();
1721 ulong catchTypeId2 = GetULong();
1722 Uuid catchedTypeId(catchTypeId1, catchTypeId2);
1723 debugLine.Append(" ").Append(ToString(catchBlockId)).Append(' ').Append(ToString(tryBlockId)).Append(' ').Append(ToString(catchedTypeId));
1724 }
1725 else if (debugRecordCode == DebugRecordCode.beginCleanup)
1726 {
1727 uint cleanupBlockId = GetUInt();
1728 uint tryBlockId = GetUInt();
1729 uint offset = GetUInt();
1730 debugLine.Append(" ").Append(ToString(cleanupBlockId)).Append(' ').Append(ToString(cast<int>(tryBlockId))).Append(' ').Append(ToString(offset));
1731 }
1732 else if (debugRecordCode == DebugRecordCode.endCleanup)
1733 {
1734 uint cleanupBlockId = GetUInt();
1735 uint offset = GetUInt();
1736 debugLine.Append(" ").Append(ToString(cleanupBlockId)).Append(' ').Append(' ').Append(ToString(offset));
1737 }
1738 else
1739 {
1740 throw Exception("unknown debug record code " + ToString(debugRecordCode));
1741 }
1742 writer.WriteLine(debugLine);
1743 x = GetByte();
1744 }
1745 }
1746 public void EmitFunctionInfo(const FunctionInfo& functionInfo)
1747 {
1748 EmitByte(cast<byte>(DebugRecordCode.functionInfo));
1749 EmitUInt(functionInfo.functionSymbolIndex);
1750 EmitString(functionInfo.fullName);
1751 EmitUInt(functionInfo.sourceFileNameId);
1752 EmitUInt(functionInfo.frameSize);
1753 }
1754 public void EmitLineInfo(const LineInfo& lineInfo)
1755 {
1756 EmitByte(cast<byte>(DebugRecordCode.lineInfo));
1757 EmitUInt(lineInfo.offset);
1758 EmitUInt(lineInfo.lineNumber);
1759 }
1760 public void EmitSourceFileName(const string& sourceFileName, uint sourceFileNameId)
1761 {
1762 EmitByte(cast<byte>(DebugRecordCode.fileInfo));
1763 EmitString(sourceFileName);
1764 EmitUInt(sourceFileNameId);
1765 }
1766 public void EmitStartFunc(uint functionSymbolIndex)
1767 {
1768 EmitByte(cast<byte>(DebugRecordCode.startFunc));
1769 EmitUInt(functionSymbolIndex);
1770 }
1771 public void EmitEndFunc(uint functionSymbolIndex)
1772 {
1773 EmitByte(cast<byte>(DebugRecordCode.endFunc));
1774 EmitUInt(functionSymbolIndex);
1775 }
1776 public void EmitBeginTry(uint tryBlockId, uint parentTryBlockId, uint offset)
1777 {
1778 EmitByte(cast<byte>(DebugRecordCode.beginTry));
1779 EmitUInt(tryBlockId);
1780 EmitUInt(parentTryBlockId);
1781 EmitUInt(offset);
1782 }
1783 public void EmitEndTry(uint tryBlockId, uint offset)
1784 {
1785 EmitByte(cast<byte>(DebugRecordCode.endTry));
1786 EmitUInt(tryBlockId);
1787 EmitUInt(offset);
1788 }
1789 public void EmitCatch(uint catchBlockId, uint tryBlockId, ulong catchedTypeId1, ulong catchedTypeId2)
1790 {
1791 EmitByte(cast<byte>(DebugRecordCode.catch_));
1792 EmitUInt(catchBlockId);
1793 EmitUInt(tryBlockId);
1794 EmitULong(catchedTypeId1);
1795 EmitULong(catchedTypeId2);
1796 }
1797 public void EmitBeginCleanup(uint cleanupBlockId, uint tryBlockId, uint offset)
1798 {
1799 EmitByte(cast<byte>(DebugRecordCode.beginCleanup));
1800 EmitUInt(cleanupBlockId);
1801 EmitUInt(tryBlockId);
1802 EmitUInt(offset);
1803 }
1804 public void EmitEndCleanup(uint cleanupBlockId, uint offset)
1805 {
1806 EmitByte(cast<byte>(DebugRecordCode.endCleanup));
1807 EmitUInt(cleanupBlockId);
1808 EmitUInt(offset);
1809 }
1810 public override void Finalize()
1811 {
1812 EmitByte(DebugRecordCode.end);
1813 }
1814 }
1815 }