1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2002-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
48 #include "scopedefs.h"
60 /*****************************************************************************/
62 /*****************************************************************************/
66 static void DestroyStrPool (Collection* C)
67 /* Free all strings in the given pool plus the item pointers. Note: The
68 * collection may not be reused later.
72 for (I = 0; I < CollCount (C); ++I) {
73 xfree (CollAtUnchecked (C, I));
80 static const char* GetString (const Collection* C, unsigned Index)
81 /* Get a string from a collection. In fact, this function calls CollConstAt,
82 * but will print a somewhat more readable error message if the index is out
86 if (Index >= CollCount (C)) {
87 Error ("Invalid string index (%u) - file corrupt!", Index);
89 return CollConstAt (C, Index);
94 static void DumpObjHeaderSection (const char* Name,
97 /* Dump a header section */
99 printf (" %s:\n", Name);
100 printf (" Offset:%24lu\n", Offset);
101 printf (" Size: %24lu\n", Size);
106 static char* TimeToStr (unsigned long Time)
107 /* Convert the time into a string and return it */
109 /* Get the time and convert to string */
110 time_t T = (time_t) Time;
111 char* S = asctime (localtime (&T));
113 /* Remove the trailing newline */
114 unsigned Len = strlen (S);
115 if (Len > 0 && S[Len-1] == '\n') {
119 /* Return the time string */
125 static void SkipLineInfoList (FILE* F)
126 /* Skip a line info list from the given file */
128 /* Count preceeds the list */
129 unsigned long Count = ReadVar (F);
139 static void SkipSpanList (FILE* F)
140 /* Skip a span list from the given file */
142 /* Count preceeds the list */
143 unsigned long Count = ReadVar (F);
153 static void SkipExpr (FILE* F)
154 /* Skip an expression from the given file */
156 /* Read the node tag and handle NULL nodes */
157 unsigned char Op = Read8 (F);
158 if (Op == EXPR_NULL) {
162 /* Check the tag and handle the different expression types */
163 if (EXPR_IS_LEAF (Op)) {
167 (void) Read32Signed (F);
171 /* Read the import number */
177 /* Read the segment number */
182 Error ("Invalid expression op: %02X", Op);
188 /* Not a leaf node */
196 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
197 /* Get the export flags as a (static) string */
200 static char TypeDesc[256];
208 switch (Flags & SYM_MASK_TYPE) {
209 case SYM_STD: strcat (TypeDesc, "SYM_STD"); break;
210 case SYM_CHEAP_LOCAL: strcat (TypeDesc, "SYM_CHEAP_LOCAL"); break;
214 switch (Flags & SYM_MASK_LABEL) {
215 case SYM_EQUATE: strcat (TypeDesc, ",SYM_EQUATE"); break;
216 case SYM_LABEL: strcat (TypeDesc, ",SYM_LABEL"); break;
219 /* Type of expression */
220 switch (Flags & SYM_MASK_VAL) {
221 case SYM_CONST: strcat (TypeDesc, ",SYM_CONST"); break;
222 case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
225 /* Size available? */
226 if (SYM_HAS_SIZE (Flags)) {
227 strcat (TypeDesc, ",SYM_SIZE");
231 /* Constructor/destructor declarations */
232 T = TypeDesc + strlen (TypeDesc);
233 Count = SYM_GET_CONDES_COUNT (Flags);
234 if (Count > 0 && ConDes) {
235 T += sprintf (T, ",SYM_CONDES=");
236 for (I = 0; I < Count; ++I) {
237 unsigned Type = CD_GET_TYPE (ConDes[I]);
238 unsigned Prio = CD_GET_PRIO (ConDes[I]);
242 T += sprintf (T, "[%u,%u]", Type, Prio);
246 /* Return the result */
252 static const char* GetScopeType (unsigned Type)
253 /* Return the name of a scope type */
256 case SCOPE_GLOBAL: return "Global scope";
257 case SCOPE_FILE: return "File scope";
258 case SCOPE_SCOPE: return ".SCOPE or .PROC";
259 case SCOPE_STRUCT: return ".STRUCT";
260 case SCOPE_ENUM: return ".ENUM";
261 case SCOPE_UNDEF: return "Undefined";
262 default: return "Unknown scope type";
268 void DumpObjHeader (FILE* F, unsigned long Offset)
269 /* Dump the header of the given object file */
273 /* Seek to the header position */
274 FileSetPos (F, Offset);
276 /* Read the header */
277 ReadObjHeader (F, &H);
279 /* Now dump the information */
281 /* Output a header */
282 printf (" Header:\n");
285 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
288 printf (" Version:%25u\n", H.Version);
291 printf (" Flags:%21s0x%04X (", "", H.Flags);
292 if (H.Flags & OBJ_FLAGS_DBGINFO) {
293 printf ("OBJ_FLAGS_DBGINFO");
298 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
301 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
304 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
307 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
310 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
313 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
316 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
319 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
322 DumpObjHeaderSection ("Assertions", H.AssertOffs, H.AssertSize);
325 DumpObjHeaderSection ("Scopes", H.ScopeOffs, H.ScopeSize);
330 void DumpObjOptions (FILE* F, unsigned long Offset)
331 /* Dump the file options */
334 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
338 /* Seek to the header position and read the header */
339 FileSetPos (F, Offset);
340 ReadObjHeader (F, &H);
342 /* Seek to the start of the string pool and read it */
343 FileSetPos (F, Offset + H.StrPoolOffs);
344 ReadStrPool (F, &StrPool);
346 /* Seek to the start of the options */
347 FileSetPos (F, Offset + H.OptionOffs);
349 /* Output a header */
350 printf (" Options:\n");
352 /* Read the number of options and print it */
354 printf (" Count:%27u\n", Count);
356 /* Read and print all options */
357 for (I = 0; I < Count; ++I) {
362 /* Read the type of the option and the value */
363 unsigned char Type = Read8 (F);
364 unsigned long Val = ReadVar (F);
366 /* Get the type of the argument */
367 unsigned char ArgType = Type & OPT_ARGMASK;
369 /* Determine which option follows */
370 const char* TypeDesc;
372 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
373 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
374 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
375 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
376 case OPT_OS: TypeDesc = "OPT_OS"; break;
377 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
378 default: TypeDesc = "OPT_UNKNOWN"; break;
381 /* Print the header */
382 printf (" Index:%27u\n", I);
385 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
389 ArgStr = GetString (&StrPool, Val);
390 ArgLen = strlen (ArgStr);
391 printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr);
395 printf (" Data:%26lu", Val);
396 if (Type == OPT_DATETIME) {
397 /* Print the time as a string */
398 printf (" (%s)", TimeToStr (Val));
404 /* Unknown argument type. This means that we cannot determine
405 * the option length, so we cannot proceed.
407 Error ("Unknown option type: 0x%02X", Type);
412 /* Destroy the string pool */
413 DestroyStrPool (&StrPool);
418 void DumpObjFiles (FILE* F, unsigned long Offset)
419 /* Dump the source files */
422 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
426 /* Seek to the header position and read the header */
427 FileSetPos (F, Offset);
428 ReadObjHeader (F, &H);
430 /* Seek to the start of the string pool and read it */
431 FileSetPos (F, Offset + H.StrPoolOffs);
432 ReadStrPool (F, &StrPool);
434 /* Seek to the start of the source files */
435 FileSetPos (F, Offset + H.FileOffs);
437 /* Output a header */
438 printf (" Files:\n");
440 /* Read the number of files and print it */
442 printf (" Count:%27u\n", Count);
444 /* Read and print all files */
445 for (I = 0; I < Count; ++I) {
447 /* Read the data for one file */
448 const char* Name = GetString (&StrPool, ReadVar (F));
449 unsigned long MTime = Read32 (F);
450 unsigned long Size = ReadVar (F);
451 unsigned Len = strlen (Name);
453 /* Print the header */
454 printf (" Index:%27u\n", I);
457 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
458 printf (" Size:%26lu\n", Size);
459 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
462 /* Destroy the string pool */
463 DestroyStrPool (&StrPool);
468 void DumpObjSegments (FILE* F, unsigned long Offset)
469 /* Dump the segments in the object file */
472 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
476 /* Seek to the header position and read the header */
477 FileSetPos (F, Offset);
478 ReadObjHeader (F, &H);
480 /* Seek to the start of the string pool and read it */
481 FileSetPos (F, Offset + H.StrPoolOffs);
482 ReadStrPool (F, &StrPool);
484 /* Seek to the start of the segments */
485 FileSetPos (F, Offset + H.SegOffs);
487 /* Output a header */
488 printf (" Segments:\n");
490 /* Read the number of segments and print it */
492 printf (" Count:%27u\n", Count);
494 /* Read and print all segments */
495 for (I = 0; I < Count; ++I) {
497 /* Read the data for one segments */
498 unsigned long DataSize = Read32 (F);
499 unsigned long NextSeg = ftell (F) + DataSize;
500 const char* Name = GetString (&StrPool, ReadVar (F));
501 unsigned Len = strlen (Name);
502 unsigned long Size = ReadVar (F);
503 unsigned long Align = ReadVar (F);
504 unsigned char AddrSize = Read8 (F);
505 unsigned long FragCount = ReadVar (F);
507 /* Print the header */
508 printf (" Index:%27u\n", I);
511 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
512 printf (" Size:%26lu\n", Size);
513 printf (" Alignment:%21lu\n", Align);
514 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
515 AddrSizeToStr (AddrSize));
516 printf (" Fragment count:%16lu\n", FragCount);
518 /* Seek to the end of the segment data (start of next) */
519 FileSetPos (F, NextSeg);
522 /* Destroy the string pool */
523 DestroyStrPool (&StrPool);
528 void DumpObjImports (FILE* F, unsigned long Offset)
529 /* Dump the imports in the object file */
532 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
536 /* Seek to the header position and read the header */
537 FileSetPos (F, Offset);
538 ReadObjHeader (F, &H);
540 /* Seek to the start of the string pool and read it */
541 FileSetPos (F, Offset + H.StrPoolOffs);
542 ReadStrPool (F, &StrPool);
544 /* Seek to the start of the imports */
545 FileSetPos (F, Offset + H.ImportOffs);
547 /* Output a header */
548 printf (" Imports:\n");
550 /* Read the number of imports and print it */
552 printf (" Count:%27u\n", Count);
554 /* Read and print all imports */
555 for (I = 0; I < Count; ++I) {
557 /* Read the data for one import */
558 unsigned char AddrSize = Read8 (F);
559 const char* Name = GetString (&StrPool, ReadVar (F));
560 unsigned Len = strlen (Name);
562 /* Skip both line info lists */
563 SkipLineInfoList (F);
564 SkipLineInfoList (F);
566 /* Print the header */
567 printf (" Index:%27u\n", I);
570 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
571 AddrSizeToStr (AddrSize));
572 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
575 /* Destroy the string pool */
576 DestroyStrPool (&StrPool);
581 void DumpObjExports (FILE* F, unsigned long Offset)
582 /* Dump the exports in the object file */
585 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
589 /* Seek to the header position and read the header */
590 FileSetPos (F, Offset);
591 ReadObjHeader (F, &H);
593 /* Seek to the start of the string pool and read it */
594 FileSetPos (F, Offset + H.StrPoolOffs);
595 ReadStrPool (F, &StrPool);
597 /* Seek to the start of the exports */
598 FileSetPos (F, Offset + H.ExportOffs);
600 /* Output a header */
601 printf (" Exports:\n");
603 /* Read the number of exports and print it */
605 printf (" Count:%27u\n", Count);
607 /* Read and print all exports */
608 for (I = 0; I < Count; ++I) {
610 unsigned long Value = 0;
611 unsigned long Size = 0;
612 unsigned char ConDes[CD_TYPE_COUNT];
617 /* Read the data for one export */
618 unsigned Type = ReadVar (F);
619 unsigned char AddrSize = Read8 (F);
620 ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
621 Name = GetString (&StrPool, ReadVar (F));
623 if (SYM_IS_CONST (Type)) {
628 if (SYM_HAS_SIZE (Type)) {
632 /* Skip both line infos lists */
633 SkipLineInfoList (F);
634 SkipLineInfoList (F);
636 /* Print the header */
637 printf (" Index:%27u\n", I);
640 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
641 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
642 AddrSizeToStr (AddrSize));
643 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
644 if (SYM_IS_CONST (Type)) {
645 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
647 if (SYM_HAS_SIZE (Type)) {
648 printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size);
652 /* Destroy the string pool */
653 DestroyStrPool (&StrPool);
658 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
659 /* Dump the debug symbols from an object file */
662 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
666 /* Seek to the header position and read the header */
667 FileSetPos (F, Offset);
668 ReadObjHeader (F, &H);
670 /* Seek to the start of the string pool and read it */
671 FileSetPos (F, Offset + H.StrPoolOffs);
672 ReadStrPool (F, &StrPool);
674 /* Seek to the start of the debug syms */
675 FileSetPos (F, Offset + H.DbgSymOffs);
677 /* Output a header */
678 printf (" Debug symbols:\n");
680 /* Check if the object file was compiled with debug info */
681 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
682 /* Print that there no debug symbols and bail out */
683 printf (" Count:%27u\n", 0);
687 /* Read the number of exports and print it */
689 printf (" Count:%27u\n", Count);
691 /* Read and print all debug symbols */
692 for (I = 0; I < Count; ++I) {
694 unsigned long Value = 0;
695 unsigned long Size = 0;
696 unsigned ImportId = 0;
697 unsigned ExportId = 0;
699 /* Read the data for one symbol */
700 unsigned Type = ReadVar (F);
701 unsigned char AddrSize = Read8 (F);
702 unsigned long Owner = ReadVar (F);
703 const char* Name = GetString (&StrPool, ReadVar (F));
704 unsigned Len = strlen (Name);
705 if (SYM_IS_CONST (Type)) {
710 if (SYM_HAS_SIZE (Type)) {
713 if (SYM_IS_IMPORT (Type)) {
714 ImportId = ReadVar (F);
716 if (SYM_IS_EXPORT (Type)) {
717 ExportId = ReadVar (F);
720 /* Skip both line info lists */
721 SkipLineInfoList (F);
722 SkipLineInfoList (F);
724 /* Print the header */
725 printf (" Index:%27u\n", I);
728 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
729 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
730 AddrSizeToStr (AddrSize));
731 printf (" Owner:%25lu\n", Owner);
732 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
733 if (SYM_IS_CONST (Type)) {
734 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
736 if (SYM_HAS_SIZE (Type)) {
737 printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size);
739 if (SYM_IS_IMPORT (Type)) {
740 printf (" Import:%24u\n", ImportId);
742 if (SYM_IS_EXPORT (Type)) {
743 printf (" Export:%24u\n", ExportId);
747 /* Destroy the string pool */
748 DestroyStrPool (&StrPool);
753 void DumpObjLineInfo (FILE* F, unsigned long Offset)
754 /* Dump the line info from an object file */
757 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
761 /* Seek to the header position and read the header */
762 FileSetPos (F, Offset);
763 ReadObjHeader (F, &H);
765 /* Seek to the start of the string pool and read it */
766 FileSetPos (F, Offset + H.StrPoolOffs);
767 ReadStrPool (F, &StrPool);
769 /* Seek to the start of line infos */
770 FileSetPos (F, Offset + H.LineInfoOffs);
772 /* Output a header */
773 printf (" Line info:\n");
775 /* Check if the object file was compiled with debug info */
776 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
777 /* Print that there no line infos and bail out */
778 printf (" Count:%27u\n", 0);
782 /* Read the number of line infos and print it */
784 printf (" Count:%27u\n", Count);
786 /* Read and print all line infos */
787 for (I = 0; I < Count; ++I) {
792 /* File position of line info */
793 ReadFilePos (F, &Pos);
795 /* Type of line info */
801 /* Print the header */
802 printf (" Index:%27u\n", I);
805 printf (" Type:%26u\n", LI_GET_TYPE (Type));
806 printf (" Count:%25u\n", LI_GET_COUNT (Type));
807 printf (" Line:%26u\n", Pos.Line);
808 printf (" Col:%27u\n", Pos.Col);
809 printf (" Name:%26u\n", Pos.Name);
812 /* Destroy the string pool */
813 DestroyStrPool (&StrPool);
818 void DumpObjScopes (FILE* F, unsigned long Offset)
819 /* Dump the scopes from an object file */
822 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
826 /* Seek to the header position and read the header */
827 FileSetPos (F, Offset);
828 ReadObjHeader (F, &H);
830 /* Seek to the start of the string pool and read it */
831 FileSetPos (F, Offset + H.StrPoolOffs);
832 ReadStrPool (F, &StrPool);
834 /* Seek to the start of scopes */
835 FileSetPos (F, Offset + H.ScopeOffs);
837 /* Output a header */
838 printf (" Scopes:\n");
840 /* Check if the object file was compiled with debug info */
841 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
842 /* Print that there no scopes and bail out */
843 printf (" Count:%27u\n", 0);
847 /* Read the number of scopes and print it */
849 printf (" Count:%27u\n", Count);
851 /* Read and print all scopes */
852 for (I = 0; I < Count; ++I) {
858 unsigned ParentId = ReadVar (F);
859 unsigned LexicalLevel = ReadVar (F);
860 unsigned Flags = ReadVar (F);
861 const char* ScopeType = GetScopeType (ReadVar (F));
863 /* Print the header */
864 printf (" Index:%27u\n", I);
867 printf (" Parent id:%21u\n", ParentId);
868 printf (" Lexical level:%17u\n", LexicalLevel);
869 printf (" Flags:%21s0x%02X\n", "", Flags);
870 printf (" Type:%26s\n", ScopeType);
872 /* Resolve and print the name */
873 Name = GetString (&StrPool, ReadVar (F));
875 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
878 if (SCOPE_HAS_SIZE (Flags)) {
879 unsigned long Size = ReadVar (F);
880 printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size);
884 if (SCOPE_HAS_LABEL (Flags)) {
885 unsigned LabelId = ReadVar (F);
886 printf (" Label id:%22u\n", LabelId);
893 /* Destroy the string pool */
894 DestroyStrPool (&StrPool);
899 void DumpObjSegSize (FILE* F, unsigned long Offset)
900 /* Dump the sizes of the segment in the object file */
903 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
906 /* Seek to the header position and read the header */
907 FileSetPos (F, Offset);
908 ReadObjHeader (F, &H);
910 /* Seek to the start of the string pool and read it */
911 FileSetPos (F, Offset + H.StrPoolOffs);
912 ReadStrPool (F, &StrPool);
914 /* Seek to the start of the segments */
915 FileSetPos (F, Offset + H.SegOffs);
917 /* Output a header */
918 printf (" Segment sizes:\n");
920 /* Read the number of segments */
923 /* Read and print the sizes of all segments */
926 /* Read the data for one segments */
927 unsigned long DataSize = Read32 (F);
928 unsigned long NextSeg = ftell (F) + DataSize;
929 const char* Name = GetString (&StrPool, ReadVar (F));
930 unsigned Len = strlen (Name);
931 unsigned long Size = ReadVar (F);
933 /* Skip alignment, type and fragment count */
938 /* Print the size for this segment */
939 printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size);
941 /* Seek to the end of the segment data (start of next) */
942 FileSetPos (F, NextSeg);
945 /* Destroy the string pool */
946 DestroyStrPool (&StrPool);