1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2002-2011, 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 SkipExpr (FILE* F)
140 /* Skip an expression from the given file */
142 /* Read the node tag and handle NULL nodes */
143 unsigned char Op = Read8 (F);
144 if (Op == EXPR_NULL) {
148 /* Check the tag and handle the different expression types */
149 if (EXPR_IS_LEAF (Op)) {
153 (void) Read32Signed (F);
157 /* Read the import number */
162 /* Read the segment number */
167 Error ("Invalid expression op: %02X", Op);
173 /* Not a leaf node */
181 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
182 /* Get the export flags as a (static) string */
185 static char TypeDesc[256];
193 switch (Flags & SYM_MASK_TYPE) {
194 case SYM_STD: strcat (TypeDesc, "SYM_STD"); break;
195 case SYM_CHEAP_LOCAL: strcat (TypeDesc, "SYM_CHEAP_LOCAL"); break;
199 switch (Flags & SYM_MASK_LABEL) {
200 case SYM_EQUATE: strcat (TypeDesc, ",SYM_EQUATE"); break;
201 case SYM_LABEL: strcat (TypeDesc, ",SYM_LABEL"); break;
204 /* Type of expression */
205 switch (Flags & SYM_MASK_VAL) {
206 case SYM_CONST: strcat (TypeDesc, ",SYM_CONST"); break;
207 case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
210 /* Size available? */
211 if (SYM_HAS_SIZE (Flags)) {
212 strcat (TypeDesc, ",SYM_SIZE");
216 /* Constructor/destructor declarations */
217 T = TypeDesc + strlen (TypeDesc);
218 Count = SYM_GET_CONDES_COUNT (Flags);
219 if (Count > 0 && ConDes) {
220 T += sprintf (T, ",SYM_CONDES=");
221 for (I = 0; I < Count; ++I) {
222 unsigned Type = CD_GET_TYPE (ConDes[I]);
223 unsigned Prio = CD_GET_PRIO (ConDes[I]);
227 T += sprintf (T, "[%u,%u]", Type, Prio);
231 /* Return the result */
237 static const char* GetScopeType (unsigned Type)
238 /* Return the name of a scope type */
241 case SCOPE_GLOBAL: return "Global scope";
242 case SCOPE_FILE: return "File scope";
243 case SCOPE_PROC: return ".PROC";
244 case SCOPE_SCOPE: return ".SCOPE";
245 case SCOPE_STRUCT: return ".STRUCT";
246 case SCOPE_ENUM: return ".ENUM";
247 case SCOPE_UNDEF: return "Undefined";
248 default: return "Unknown scope type";
254 void DumpObjHeader (FILE* F, unsigned long Offset)
255 /* Dump the header of the given object file */
259 /* Seek to the header position */
260 FileSetPos (F, Offset);
262 /* Read the header */
263 ReadObjHeader (F, &H);
265 /* Now dump the information */
267 /* Output a header */
268 printf (" Header:\n");
271 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
274 printf (" Version:%25u\n", H.Version);
277 printf (" Flags:%21s0x%04X (", "", H.Flags);
278 if (H.Flags & OBJ_FLAGS_DBGINFO) {
279 printf ("OBJ_FLAGS_DBGINFO");
284 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
287 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
290 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
293 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
296 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
299 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
302 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
305 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
308 DumpObjHeaderSection ("Assertions", H.AssertOffs, H.AssertSize);
311 DumpObjHeaderSection ("Scopes", H.ScopeOffs, H.ScopeSize);
316 void DumpObjOptions (FILE* F, unsigned long Offset)
317 /* Dump the file options */
320 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
324 /* Seek to the header position and read the header */
325 FileSetPos (F, Offset);
326 ReadObjHeader (F, &H);
328 /* Seek to the start of the string pool and read it */
329 FileSetPos (F, Offset + H.StrPoolOffs);
330 ReadStrPool (F, &StrPool);
332 /* Seek to the start of the options */
333 FileSetPos (F, Offset + H.OptionOffs);
335 /* Output a header */
336 printf (" Options:\n");
338 /* Read the number of options and print it */
340 printf (" Count:%27u\n", Count);
342 /* Read and print all options */
343 for (I = 0; I < Count; ++I) {
348 /* Read the type of the option and the value */
349 unsigned char Type = Read8 (F);
350 unsigned long Val = ReadVar (F);
352 /* Get the type of the argument */
353 unsigned char ArgType = Type & OPT_ARGMASK;
355 /* Determine which option follows */
356 const char* TypeDesc;
358 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
359 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
360 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
361 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
362 case OPT_OS: TypeDesc = "OPT_OS"; break;
363 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
364 default: TypeDesc = "OPT_UNKNOWN"; break;
367 /* Print the header */
368 printf (" Index:%27u\n", I);
371 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
375 ArgStr = GetString (&StrPool, Val);
376 ArgLen = strlen (ArgStr);
377 printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr);
381 printf (" Data:%26lu", Val);
382 if (Type == OPT_DATETIME) {
383 /* Print the time as a string */
384 printf (" (%s)", TimeToStr (Val));
390 /* Unknown argument type. This means that we cannot determine
391 * the option length, so we cannot proceed.
393 Error ("Unknown option type: 0x%02X", Type);
398 /* Destroy the string pool */
399 DestroyStrPool (&StrPool);
404 void DumpObjFiles (FILE* F, unsigned long Offset)
405 /* Dump the source files */
408 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
412 /* Seek to the header position and read the header */
413 FileSetPos (F, Offset);
414 ReadObjHeader (F, &H);
416 /* Seek to the start of the string pool and read it */
417 FileSetPos (F, Offset + H.StrPoolOffs);
418 ReadStrPool (F, &StrPool);
420 /* Seek to the start of the source files */
421 FileSetPos (F, Offset + H.FileOffs);
423 /* Output a header */
424 printf (" Files:\n");
426 /* Read the number of files and print it */
428 printf (" Count:%27u\n", Count);
430 /* Read and print all files */
431 for (I = 0; I < Count; ++I) {
433 /* Read the data for one file */
434 const char* Name = GetString (&StrPool, ReadVar (F));
435 unsigned long MTime = Read32 (F);
436 unsigned long Size = ReadVar (F);
437 unsigned Len = strlen (Name);
439 /* Print the header */
440 printf (" Index:%27u\n", I);
443 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
444 printf (" Size:%26lu\n", Size);
445 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
448 /* Destroy the string pool */
449 DestroyStrPool (&StrPool);
454 void DumpObjSegments (FILE* F, unsigned long Offset)
455 /* Dump the segments in the object file */
458 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
462 /* Seek to the header position and read the header */
463 FileSetPos (F, Offset);
464 ReadObjHeader (F, &H);
466 /* Seek to the start of the string pool and read it */
467 FileSetPos (F, Offset + H.StrPoolOffs);
468 ReadStrPool (F, &StrPool);
470 /* Seek to the start of the segments */
471 FileSetPos (F, Offset + H.SegOffs);
473 /* Output a header */
474 printf (" Segments:\n");
476 /* Read the number of segments and print it */
478 printf (" Count:%27u\n", Count);
480 /* Read and print all segments */
481 for (I = 0; I < Count; ++I) {
483 /* Read the data for one segments */
484 unsigned long DataSize = Read32 (F);
485 unsigned long NextSeg = ftell (F) + DataSize;
486 const char* Name = GetString (&StrPool, ReadVar (F));
487 unsigned Len = strlen (Name);
488 unsigned long Size = Read32 (F);
489 unsigned Align = (1U << Read8 (F));
490 unsigned char AddrSize = Read8 (F);
491 unsigned long FragCount = ReadVar (F);
493 /* Print the header */
494 printf (" Index:%27u\n", I);
497 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
498 printf (" Size:%26lu\n", Size);
499 printf (" Alignment:%21u\n", Align);
500 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
501 AddrSizeToStr (AddrSize));
502 printf (" Fragment count:%16lu\n", FragCount);
504 /* Seek to the end of the segment data (start of next) */
505 FileSetPos (F, NextSeg);
508 /* Destroy the string pool */
509 DestroyStrPool (&StrPool);
514 void DumpObjImports (FILE* F, unsigned long Offset)
515 /* Dump the imports in the object file */
518 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
522 /* Seek to the header position and read the header */
523 FileSetPos (F, Offset);
524 ReadObjHeader (F, &H);
526 /* Seek to the start of the string pool and read it */
527 FileSetPos (F, Offset + H.StrPoolOffs);
528 ReadStrPool (F, &StrPool);
530 /* Seek to the start of the imports */
531 FileSetPos (F, Offset + H.ImportOffs);
533 /* Output a header */
534 printf (" Imports:\n");
536 /* Read the number of imports and print it */
538 printf (" Count:%27u\n", Count);
540 /* Read and print all imports */
541 for (I = 0; I < Count; ++I) {
543 /* Read the data for one import */
544 unsigned char AddrSize = Read8 (F);
545 const char* Name = GetString (&StrPool, ReadVar (F));
546 unsigned Len = strlen (Name);
548 /* Skip the line infos */
549 SkipLineInfoList (F);
551 /* Print the header */
552 printf (" Index:%27u\n", I);
555 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
556 AddrSizeToStr (AddrSize));
557 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
560 /* Destroy the string pool */
561 DestroyStrPool (&StrPool);
566 void DumpObjExports (FILE* F, unsigned long Offset)
567 /* Dump the exports in the object file */
570 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
574 /* Seek to the header position and read the header */
575 FileSetPos (F, Offset);
576 ReadObjHeader (F, &H);
578 /* Seek to the start of the string pool and read it */
579 FileSetPos (F, Offset + H.StrPoolOffs);
580 ReadStrPool (F, &StrPool);
582 /* Seek to the start of the exports */
583 FileSetPos (F, Offset + H.ExportOffs);
585 /* Output a header */
586 printf (" Exports:\n");
588 /* Read the number of exports and print it */
590 printf (" Count:%27u\n", Count);
592 /* Read and print all exports */
593 for (I = 0; I < Count; ++I) {
595 unsigned long Value = 0;
596 unsigned long Size = 0;
597 unsigned char ConDes[CD_TYPE_COUNT];
602 /* Read the data for one export */
603 unsigned Type = ReadVar (F);
604 unsigned char AddrSize = Read8 (F);
605 ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
606 Name = GetString (&StrPool, ReadVar (F));
608 if (SYM_IS_CONST (Type)) {
613 if (SYM_HAS_SIZE (Type)) {
617 /* Skip the line infos */
618 SkipLineInfoList (F);
620 /* Print the header */
621 printf (" Index:%27u\n", I);
624 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
625 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
626 AddrSizeToStr (AddrSize));
627 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
628 if (SYM_IS_CONST (Type)) {
629 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
631 if (SYM_HAS_SIZE (Type)) {
632 printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size);
636 /* Destroy the string pool */
637 DestroyStrPool (&StrPool);
642 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
643 /* Dump the debug symbols from an object file */
646 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
650 /* Seek to the header position and read the header */
651 FileSetPos (F, Offset);
652 ReadObjHeader (F, &H);
654 /* Seek to the start of the string pool and read it */
655 FileSetPos (F, Offset + H.StrPoolOffs);
656 ReadStrPool (F, &StrPool);
658 /* Seek to the start of the debug syms */
659 FileSetPos (F, Offset + H.DbgSymOffs);
661 /* Output a header */
662 printf (" Debug symbols:\n");
664 /* Check if the object file was compiled with debug info */
665 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
666 /* Print that there no debug symbols and bail out */
667 printf (" Count:%27u\n", 0);
671 /* Read the number of exports and print it */
673 printf (" Count:%27u\n", Count);
675 /* Read and print all debug symbols */
676 for (I = 0; I < Count; ++I) {
678 unsigned long Value = 0;
679 unsigned long Size = 0;
681 /* Read the data for one symbol */
682 unsigned Type = ReadVar (F);
683 unsigned char AddrSize = Read8 (F);
684 unsigned long Owner = ReadVar (F);
685 const char* Name = GetString (&StrPool, ReadVar (F));
686 unsigned Len = strlen (Name);
687 if (SYM_IS_CONST (Type)) {
692 if (SYM_HAS_SIZE (Type)) {
696 /* Skip the line infos */
697 SkipLineInfoList (F);
699 /* Print the header */
700 printf (" Index:%27u\n", I);
703 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
704 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
705 AddrSizeToStr (AddrSize));
706 printf (" Owner:%25lu\n", Owner);
707 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
708 if (SYM_IS_CONST (Type)) {
709 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
711 if (SYM_HAS_SIZE (Type)) {
712 printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size);
716 /* Destroy the string pool */
717 DestroyStrPool (&StrPool);
722 void DumpObjLineInfo (FILE* F, unsigned long Offset)
723 /* Dump the line info from an object file */
726 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
730 /* Seek to the header position and read the header */
731 FileSetPos (F, Offset);
732 ReadObjHeader (F, &H);
734 /* Seek to the start of the string pool and read it */
735 FileSetPos (F, Offset + H.StrPoolOffs);
736 ReadStrPool (F, &StrPool);
738 /* Seek to the start of line infos */
739 FileSetPos (F, Offset + H.LineInfoOffs);
741 /* Output a header */
742 printf (" Line info:\n");
744 /* Check if the object file was compiled with debug info */
745 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
746 /* Print that there no line infos and bail out */
747 printf (" Count:%27u\n", 0);
751 /* Read the number of line infos and print it */
753 printf (" Count:%27u\n", Count);
755 /* Read and print all line infos */
756 for (I = 0; I < Count; ++I) {
760 /* Type of line info */
761 unsigned Type = ReadVar (F);
763 /* File position of line info */
764 ReadFilePos (F, &Pos);
766 /* Print the header */
767 printf (" Index:%27u\n", I);
770 printf (" Type:%26u\n", LI_GET_TYPE (Type));
771 printf (" Count:%25u\n", LI_GET_COUNT (Type));
772 printf (" Line:%26lu\n", Pos.Line);
773 printf (" Col:%27u\n", Pos.Col);
774 printf (" Name:%26u\n", Pos.Name);
777 /* Destroy the string pool */
778 DestroyStrPool (&StrPool);
783 void DumpObjScopes (FILE* F, unsigned long Offset)
784 /* Dump the scopes from an object file */
787 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
791 /* Seek to the header position and read the header */
792 FileSetPos (F, Offset);
793 ReadObjHeader (F, &H);
795 /* Seek to the start of the string pool and read it */
796 FileSetPos (F, Offset + H.StrPoolOffs);
797 ReadStrPool (F, &StrPool);
799 /* Seek to the start of scopes */
800 FileSetPos (F, Offset + H.ScopeOffs);
802 /* Output a header */
803 printf (" Scopes:\n");
805 /* Check if the object file was compiled with debug info */
806 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
807 /* Print that there no scopes and bail out */
808 printf (" Count:%27u\n", 0);
812 /* Read the number of scopes and print it */
814 printf (" Count:%27u\n", Count);
816 /* Read and print all scopes */
817 for (I = 0; I < Count; ++I) {
825 unsigned ParentId = ReadVar (F);
826 unsigned LexicalLevel = ReadVar (F);
827 unsigned Flags = ReadVar (F);
828 const char* ScopeType = GetScopeType (ReadVar (F));
830 /* Print the header */
831 printf (" Index:%27u\n", I);
834 printf (" Parent id:%21u\n", ParentId);
835 printf (" Lexical level:%17u\n", LexicalLevel);
836 printf (" Flags:%21s0x%02X\n", "", Flags);
837 printf (" Type:%26s\n", ScopeType);
839 /* Resolve and print the name */
840 Name = GetString (&StrPool, ReadVar (F));
842 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
845 if (SCOPE_HAS_SIZE (Flags)) {
846 unsigned long Size = ReadVar (F);
847 printf (" Size:%20s0x%04lX (%lu)\n", "", Size, Size);
851 SegCount = ReadVar (F);
852 printf (" Segment ranges:\n");
853 printf (" Count:%23u\n", SegCount);
855 for (J = 0; J < SegCount; ++J) {
856 printf (" Index:%23u\n", J);
857 printf (" Segment:%19lu\n", ReadVar (F));
858 printf (" Start:%13s0x%06lX\n", "", ReadVar (F));
859 printf (" End:%15s0x%06lX\n", "", ReadVar (F));
863 /* Destroy the string pool */
864 DestroyStrPool (&StrPool);
869 void DumpObjSegSize (FILE* F, unsigned long Offset)
870 /* Dump the sizes of the segment in the object file */
873 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
876 /* Seek to the header position and read the header */
877 FileSetPos (F, Offset);
878 ReadObjHeader (F, &H);
880 /* Seek to the start of the string pool and read it */
881 FileSetPos (F, Offset + H.StrPoolOffs);
882 ReadStrPool (F, &StrPool);
884 /* Seek to the start of the segments */
885 FileSetPos (F, Offset + H.SegOffs);
887 /* Output a header */
888 printf (" Segment sizes:\n");
890 /* Read the number of segments */
893 /* Read and print the sizes of all segments */
896 /* Read the data for one segments */
897 unsigned long DataSize = Read32 (F);
898 unsigned long NextSeg = ftell (F) + DataSize;
899 const char* Name = GetString (&StrPool, ReadVar (F));
900 unsigned Len = strlen (Name);
901 unsigned long Size = Read32 (F);
903 /* Skip alignment, type and fragment count */
908 /* Print the size for this segment */
909 printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size);
911 /* Seek to the end of the segment data (start of next) */
912 FileSetPos (F, NextSeg);
915 /* Destroy the string pool */
916 DestroyStrPool (&StrPool);