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 /*****************************************************************************/
59 /*****************************************************************************/
61 /*****************************************************************************/
65 static void DestroyStrPool (Collection* C)
66 /* Free all strings in the given pool plus the item pointers. Note: The
67 * collection may not be reused later.
71 for (I = 0; I < CollCount (C); ++I) {
72 xfree (CollAtUnchecked (C, I));
79 static const char* GetString (const Collection* C, unsigned Index)
80 /* Get a string from a collection. In fact, this function calls CollConstAt,
81 * but will print a somewhat more readable error message if the index is out
85 if (Index >= CollCount (C)) {
86 Error ("Invalid string index (%u) - file corrupt!", Index);
88 return CollConstAt (C, Index);
93 static void DumpObjHeaderSection (const char* Name,
96 /* Dump a header section */
98 printf (" %s:\n", Name);
99 printf (" Offset:%24lu\n", Offset);
100 printf (" Size: %24lu\n", Size);
105 static char* TimeToStr (unsigned long Time)
106 /* Convert the time into a string and return it */
108 /* Get the time and convert to string */
109 time_t T = (time_t) Time;
110 char* S = asctime (localtime (&T));
112 /* Remove the trailing newline */
113 unsigned Len = strlen (S);
114 if (Len > 0 && S[Len-1] == '\n') {
118 /* Return the time string */
124 static void SkipLineInfoList (FILE* F)
125 /* Skip a line info list from the given file */
127 /* Count preceeds the list */
128 unsigned long Count = ReadVar (F);
138 static void SkipExpr (FILE* F)
139 /* Skip an expression from the given file */
141 /* Read the node tag and handle NULL nodes */
142 unsigned char Op = Read8 (F);
143 if (Op == EXPR_NULL) {
147 /* Check the tag and handle the different expression types */
148 if (EXPR_IS_LEAF (Op)) {
152 (void) Read32Signed (F);
156 /* Read the import number */
161 /* Read the segment number */
166 Error ("Invalid expression op: %02X", Op);
172 /* Not a leaf node */
180 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
181 /* Get the export flags as a (static) string */
184 static char TypeDesc[256];
192 switch (Flags & SYM_MASK_TYPE) {
193 case SYM_STD: strcat (TypeDesc, "SYM_STD"); break;
194 case SYM_CHEAP_LOCAL: strcat (TypeDesc, "SYM_CHEAP_LOCAL"); break;
198 switch (Flags & SYM_MASK_LABEL) {
199 case SYM_EQUATE: strcat (TypeDesc, ",SYM_EQUATE"); break;
200 case SYM_LABEL: strcat (TypeDesc, ",SYM_LABEL"); break;
203 /* Type of expression */
204 switch (Flags & SYM_MASK_VAL) {
205 case SYM_CONST: strcat (TypeDesc, ",SYM_CONST"); break;
206 case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
209 /* Size available? */
210 if (SYM_HAS_SIZE (Flags)) {
211 strcat (TypeDesc, ",SYM_SIZE");
215 /* Constructor/destructor declarations */
216 T = TypeDesc + strlen (TypeDesc);
217 Count = SYM_GET_CONDES_COUNT (Flags);
218 if (Count > 0 && ConDes) {
219 T += sprintf (T, ",SYM_CONDES=");
220 for (I = 0; I < Count; ++I) {
221 unsigned Type = CD_GET_TYPE (ConDes[I]);
222 unsigned Prio = CD_GET_PRIO (ConDes[I]);
226 T += sprintf (T, "[%u,%u]", Type, Prio);
230 /* Return the result */
236 void DumpObjHeader (FILE* F, unsigned long Offset)
237 /* Dump the header of the given object file */
241 /* Seek to the header position */
242 FileSetPos (F, Offset);
244 /* Read the header */
245 ReadObjHeader (F, &H);
247 /* Now dump the information */
249 /* Output a header */
250 printf (" Header:\n");
253 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
256 printf (" Version:%25u\n", H.Version);
259 printf (" Flags:%21s0x%04X (", "", H.Flags);
260 if (H.Flags & OBJ_FLAGS_DBGINFO) {
261 printf ("OBJ_FLAGS_DBGINFO");
266 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
269 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
272 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
275 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
278 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
281 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
284 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
287 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
292 void DumpObjOptions (FILE* F, unsigned long Offset)
293 /* Dump the file options */
296 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
300 /* Seek to the header position and read the header */
301 FileSetPos (F, Offset);
302 ReadObjHeader (F, &H);
304 /* Seek to the start of the string pool and read it */
305 FileSetPos (F, Offset + H.StrPoolOffs);
306 ReadStrPool (F, &StrPool);
308 /* Seek to the start of the options */
309 FileSetPos (F, Offset + H.OptionOffs);
311 /* Output a header */
312 printf (" Options:\n");
314 /* Read the number of options and print it */
316 printf (" Count:%27u\n", Count);
318 /* Read and print all options */
319 for (I = 0; I < Count; ++I) {
324 /* Read the type of the option and the value */
325 unsigned char Type = Read8 (F);
326 unsigned long Val = ReadVar (F);
328 /* Get the type of the argument */
329 unsigned char ArgType = Type & OPT_ARGMASK;
331 /* Determine which option follows */
332 const char* TypeDesc;
334 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
335 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
336 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
337 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
338 case OPT_OS: TypeDesc = "OPT_OS"; break;
339 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
340 default: TypeDesc = "OPT_UNKNOWN"; break;
343 /* Print the header */
344 printf (" Index:%27u\n", I);
347 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
351 ArgStr = GetString (&StrPool, Val);
352 ArgLen = strlen (ArgStr);
353 printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr);
357 printf (" Data:%26lu", Val);
358 if (Type == OPT_DATETIME) {
359 /* Print the time as a string */
360 printf (" (%s)", TimeToStr (Val));
366 /* Unknown argument type. This means that we cannot determine
367 * the option length, so we cannot proceed.
369 Error ("Unknown option type: 0x%02X", Type);
374 /* Destroy the string pool */
375 DestroyStrPool (&StrPool);
380 void DumpObjFiles (FILE* F, unsigned long Offset)
381 /* Dump the source files */
384 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
388 /* Seek to the header position and read the header */
389 FileSetPos (F, Offset);
390 ReadObjHeader (F, &H);
392 /* Seek to the start of the string pool and read it */
393 FileSetPos (F, Offset + H.StrPoolOffs);
394 ReadStrPool (F, &StrPool);
396 /* Seek to the start of the source files */
397 FileSetPos (F, Offset + H.FileOffs);
399 /* Output a header */
400 printf (" Files:\n");
402 /* Read the number of files and print it */
404 printf (" Count:%27u\n", Count);
406 /* Read and print all files */
407 for (I = 0; I < Count; ++I) {
409 /* Read the data for one file */
410 const char* Name = GetString (&StrPool, ReadVar (F));
411 unsigned long MTime = Read32 (F);
412 unsigned long Size = ReadVar (F);
413 unsigned Len = strlen (Name);
415 /* Print the header */
416 printf (" Index:%27u\n", I);
419 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
420 printf (" Size:%26lu\n", Size);
421 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
424 /* Destroy the string pool */
425 DestroyStrPool (&StrPool);
430 void DumpObjSegments (FILE* F, unsigned long Offset)
431 /* Dump the segments in the object file */
434 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
438 /* Seek to the header position and read the header */
439 FileSetPos (F, Offset);
440 ReadObjHeader (F, &H);
442 /* Seek to the start of the string pool and read it */
443 FileSetPos (F, Offset + H.StrPoolOffs);
444 ReadStrPool (F, &StrPool);
446 /* Seek to the start of the segments */
447 FileSetPos (F, Offset + H.SegOffs);
449 /* Output a header */
450 printf (" Segments:\n");
452 /* Read the number of segments and print it */
454 printf (" Count:%27u\n", Count);
456 /* Read and print all segments */
457 for (I = 0; I < Count; ++I) {
459 /* Read the data for one segments */
460 unsigned long DataSize = Read32 (F);
461 unsigned long NextSeg = ftell (F) + DataSize;
462 const char* Name = GetString (&StrPool, ReadVar (F));
463 unsigned Len = strlen (Name);
464 unsigned long Size = Read32 (F);
465 unsigned Align = (1U << Read8 (F));
466 unsigned char AddrSize = Read8 (F);
467 unsigned long FragCount = ReadVar (F);
469 /* Print the header */
470 printf (" Index:%27u\n", I);
473 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
474 printf (" Size:%26lu\n", Size);
475 printf (" Alignment:%21u\n", Align);
476 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
477 AddrSizeToStr (AddrSize));
478 printf (" Fragment count:%16lu\n", FragCount);
480 /* Seek to the end of the segment data (start of next) */
481 FileSetPos (F, NextSeg);
484 /* Destroy the string pool */
485 DestroyStrPool (&StrPool);
490 void DumpObjImports (FILE* F, unsigned long Offset)
491 /* Dump the imports in the object file */
494 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
498 /* Seek to the header position and read the header */
499 FileSetPos (F, Offset);
500 ReadObjHeader (F, &H);
502 /* Seek to the start of the string pool and read it */
503 FileSetPos (F, Offset + H.StrPoolOffs);
504 ReadStrPool (F, &StrPool);
506 /* Seek to the start of the imports */
507 FileSetPos (F, Offset + H.ImportOffs);
509 /* Output a header */
510 printf (" Imports:\n");
512 /* Read the number of imports and print it */
514 printf (" Count:%27u\n", Count);
516 /* Read and print all imports */
517 for (I = 0; I < Count; ++I) {
519 /* Read the data for one import */
520 unsigned char AddrSize = Read8 (F);
521 const char* Name = GetString (&StrPool, ReadVar (F));
522 unsigned Len = strlen (Name);
524 /* Skip the line infos */
525 SkipLineInfoList (F);
527 /* Print the header */
528 printf (" Index:%27u\n", I);
531 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
532 AddrSizeToStr (AddrSize));
533 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
536 /* Destroy the string pool */
537 DestroyStrPool (&StrPool);
542 void DumpObjExports (FILE* F, unsigned long Offset)
543 /* Dump the exports in the object file */
546 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
550 /* Seek to the header position and read the header */
551 FileSetPos (F, Offset);
552 ReadObjHeader (F, &H);
554 /* Seek to the start of the string pool and read it */
555 FileSetPos (F, Offset + H.StrPoolOffs);
556 ReadStrPool (F, &StrPool);
558 /* Seek to the start of the exports */
559 FileSetPos (F, Offset + H.ExportOffs);
561 /* Output a header */
562 printf (" Exports:\n");
564 /* Read the number of exports and print it */
566 printf (" Count:%27u\n", Count);
568 /* Read and print all exports */
569 for (I = 0; I < Count; ++I) {
571 unsigned long Value = 0;
572 unsigned long Size = 0;
573 unsigned char ConDes[CD_TYPE_COUNT];
578 /* Read the data for one export */
579 unsigned Type = ReadVar (F);
580 unsigned char AddrSize = Read8 (F);
581 ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
582 Name = GetString (&StrPool, ReadVar (F));
584 if (SYM_IS_CONST (Type)) {
589 if (SYM_HAS_SIZE (Type)) {
593 /* Skip the line infos */
594 SkipLineInfoList (F);
596 /* Print the header */
597 printf (" Index:%27u\n", I);
600 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
601 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
602 AddrSizeToStr (AddrSize));
603 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
604 if (SYM_IS_CONST (Type)) {
605 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
607 if (SYM_HAS_SIZE (Type)) {
608 printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size);
612 /* Destroy the string pool */
613 DestroyStrPool (&StrPool);
618 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
619 /* Dump the debug symbols from an object file */
622 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
626 /* Seek to the header position and read the header */
627 FileSetPos (F, Offset);
628 ReadObjHeader (F, &H);
630 /* Seek to the start of the string pool and read it */
631 FileSetPos (F, Offset + H.StrPoolOffs);
632 ReadStrPool (F, &StrPool);
634 /* Seek to the start of the debug syms */
635 FileSetPos (F, Offset + H.DbgSymOffs);
637 /* Output a header */
638 printf (" Debug symbols:\n");
640 /* Check if the object file was compiled with debug info */
641 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
642 /* Print that there no debug symbols and bail out */
643 printf (" Count:%27u\n", 0);
647 /* Read the number of exports and print it */
649 printf (" Count:%27u\n", Count);
651 /* Read and print all debug symbols */
652 for (I = 0; I < Count; ++I) {
654 unsigned long Value = 0;
655 unsigned long Size = 0;
657 /* Read the data for one symbol */
658 unsigned Type = ReadVar (F);
659 unsigned char AddrSize = Read8 (F);
660 const char* Name = GetString (&StrPool, ReadVar (F));
661 unsigned Len = strlen (Name);
662 if (SYM_IS_CONST (Type)) {
667 if (SYM_HAS_SIZE (Type)) {
671 /* Skip the line infos */
672 SkipLineInfoList (F);
674 /* Print the header */
675 printf (" Index:%27u\n", I);
678 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
679 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
680 AddrSizeToStr (AddrSize));
681 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
682 if (SYM_IS_CONST (Type)) {
683 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
685 if (SYM_HAS_SIZE (Type)) {
686 printf (" Size:%16s0x%04lX (%lu)\n", "", Size, Size);
690 /* Destroy the string pool */
691 DestroyStrPool (&StrPool);
696 void DumpObjLineInfo (FILE* F, unsigned long Offset)
697 /* Dump the line info from an object file */
700 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
704 /* Seek to the header position and read the header */
705 FileSetPos (F, Offset);
706 ReadObjHeader (F, &H);
708 /* Seek to the start of the string pool and read it */
709 FileSetPos (F, Offset + H.StrPoolOffs);
710 ReadStrPool (F, &StrPool);
712 /* Seek to the start of line infos */
713 FileSetPos (F, Offset + H.LineInfoOffs);
715 /* Output a header */
716 printf (" Line info:\n");
718 /* Check if the object file was compiled with debug info */
719 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
720 /* Print that there no line infos and bail out */
721 printf (" Count:%27u\n", 0);
725 /* Read the number of line infos and print it */
727 printf (" Count:%27u\n", Count);
729 /* Read and print all line infos */
730 for (I = 0; I < Count; ++I) {
734 /* Type of line info */
735 unsigned Type = ReadVar (F);
737 /* File position of line info */
738 ReadFilePos (F, &Pos);
740 /* Print the header */
741 printf (" Index:%27u\n", I);
744 printf (" Type:%26u\n", LI_GET_TYPE (Type));
745 printf (" Count:%25u\n", LI_GET_COUNT (Type));
746 printf (" Line:%26lu\n", Pos.Line);
747 printf (" Col:%27u\n", Pos.Col);
748 printf (" Name:%26u\n", Pos.Name);
751 /* Destroy the string pool */
752 DestroyStrPool (&StrPool);
757 void DumpObjSegSize (FILE* F, unsigned long Offset)
758 /* Dump the sizes of the segment in the object file */
761 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
764 /* Seek to the header position and read the header */
765 FileSetPos (F, Offset);
766 ReadObjHeader (F, &H);
768 /* Seek to the start of the string pool and read it */
769 FileSetPos (F, Offset + H.StrPoolOffs);
770 ReadStrPool (F, &StrPool);
772 /* Seek to the start of the segments */
773 FileSetPos (F, Offset + H.SegOffs);
775 /* Output a header */
776 printf (" Segment sizes:\n");
778 /* Read the number of segments */
781 /* Read and print the sizes of all segments */
784 /* Read the data for one segments */
785 unsigned long DataSize = Read32 (F);
786 unsigned long NextSeg = ftell (F) + DataSize;
787 const char* Name = GetString (&StrPool, ReadVar (F));
788 unsigned Len = strlen (Name);
789 unsigned long Size = Read32 (F);
791 /* Skip alignment, type and fragment count */
796 /* Print the size for this segment */
797 printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size);
799 /* Seek to the end of the segment data (start of next) */
800 FileSetPos (F, NextSeg);
803 /* Destroy the string pool */
804 DestroyStrPool (&StrPool);