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 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 static void DestroyStrPool (Collection* C)
65 /* Free all strings in the given pool plus the item pointers. Note: The
66 * collection may not be reused later.
70 for (I = 0; I < CollCount (C); ++I) {
71 xfree (CollAtUnchecked (C, I));
78 static const char* GetString (const Collection* C, unsigned Index)
79 /* Get a string from a collection. In fact, this function calls CollConstAt,
80 * but will print a somewhat more readable error message if the index is out
84 if (Index >= CollCount (C)) {
85 Error ("Invalid string index (%u) - file corrupt!", Index);
87 return CollConstAt (C, Index);
92 static void DumpObjHeaderSection (const char* Name,
95 /* Dump a header section */
97 printf (" %s:\n", Name);
98 printf (" Offset:%24lu\n", Offset);
99 printf (" Size: %24lu\n", Size);
104 static char* TimeToStr (unsigned long Time)
105 /* Convert the time into a string and return it */
107 /* Get the time and convert to string */
108 time_t T = (time_t) Time;
109 char* S = asctime (localtime (&T));
111 /* Remove the trailing newline */
112 unsigned Len = strlen (S);
113 if (Len > 0 && S[Len-1] == '\n') {
117 /* Return the time string */
123 static void SkipLineInfoList (FILE* F)
124 /* Skip a line info list from the given file */
126 /* Count preceeds the list */
127 unsigned long Count = ReadVar (F);
137 static void SkipExpr (FILE* F)
138 /* Skip an expression from the given file */
140 /* Read the node tag and handle NULL nodes */
141 unsigned char Op = Read8 (F);
142 if (Op == EXPR_NULL) {
146 /* Check the tag and handle the different expression types */
147 if (EXPR_IS_LEAF (Op)) {
151 (void) Read32Signed (F);
155 /* Read the import number */
160 /* Read the segment number */
165 Error ("Invalid expression op: %02X", Op);
171 /* Not a leaf node */
179 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
180 /* Get the export flags as a (static) string */
183 static char TypeDesc[256];
191 switch (Flags & SYM_MASK_TYPE) {
192 case SYM_STD: strcat (TypeDesc, "SYM_STD"); break;
193 case SYM_CHEAP_LOCAL: strcat (TypeDesc, "SYM_CHEAP_LOCAL"); break;
197 switch (Flags & SYM_MASK_LABEL) {
198 case SYM_EQUATE: strcat (TypeDesc, ",SYM_EQUATE"); break;
199 case SYM_LABEL: strcat (TypeDesc, ",SYM_LABEL"); break;
202 /* Type of expression */
203 switch (Flags & SYM_MASK_VAL) {
204 case SYM_CONST: strcat (TypeDesc, ",SYM_CONST"); break;
205 case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
208 /* Constructor/destructor declarations */
209 T = TypeDesc + strlen (TypeDesc);
210 Count = SYM_GET_CONDES_COUNT (Flags);
211 if (Count > 0 && ConDes) {
212 T += sprintf (T, ",SYM_CONDES=");
213 for (I = 0; I < Count; ++I) {
214 unsigned Type = CD_GET_TYPE (ConDes[I]);
215 unsigned Prio = CD_GET_PRIO (ConDes[I]);
219 T += sprintf (T, "[%u,%u]", Type, Prio);
223 /* Return the result */
229 void DumpObjHeader (FILE* F, unsigned long Offset)
230 /* Dump the header of the given object file */
234 /* Seek to the header position */
235 FileSetPos (F, Offset);
237 /* Read the header */
238 ReadObjHeader (F, &H);
240 /* Now dump the information */
242 /* Output a header */
243 printf (" Header:\n");
246 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
249 printf (" Version:%25u\n", H.Version);
252 printf (" Flags:%21s0x%04X (", "", H.Flags);
253 if (H.Flags & OBJ_FLAGS_DBGINFO) {
254 printf ("OBJ_FLAGS_DBGINFO");
259 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
262 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
265 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
268 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
271 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
274 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
277 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
280 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
285 void DumpObjOptions (FILE* F, unsigned long Offset)
286 /* Dump the file options */
289 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
293 /* Seek to the header position and read the header */
294 FileSetPos (F, Offset);
295 ReadObjHeader (F, &H);
297 /* Seek to the start of the string pool and read it */
298 FileSetPos (F, Offset + H.StrPoolOffs);
299 ReadStrPool (F, &StrPool);
301 /* Seek to the start of the options */
302 FileSetPos (F, Offset + H.OptionOffs);
304 /* Output a header */
305 printf (" Options:\n");
307 /* Read the number of options and print it */
309 printf (" Count:%27u\n", Count);
311 /* Read and print all options */
312 for (I = 0; I < Count; ++I) {
317 /* Read the type of the option and the value */
318 unsigned char Type = Read8 (F);
319 unsigned long Val = ReadVar (F);
321 /* Get the type of the argument */
322 unsigned char ArgType = Type & OPT_ARGMASK;
324 /* Determine which option follows */
325 const char* TypeDesc;
327 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
328 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
329 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
330 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
331 case OPT_OS: TypeDesc = "OPT_OS"; break;
332 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
333 default: TypeDesc = "OPT_UNKNOWN"; break;
336 /* Print the header */
337 printf (" Index:%27u\n", I);
340 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
344 ArgStr = GetString (&StrPool, Val);
345 ArgLen = strlen (ArgStr);
346 printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr);
350 printf (" Data:%26lu", Val);
351 if (Type == OPT_DATETIME) {
352 /* Print the time as a string */
353 printf (" (%s)", TimeToStr (Val));
359 /* Unknown argument type. This means that we cannot determine
360 * the option length, so we cannot proceed.
362 Error ("Unknown option type: 0x%02X", Type);
367 /* Destroy the string pool */
368 DestroyStrPool (&StrPool);
373 void DumpObjFiles (FILE* F, unsigned long Offset)
374 /* Dump the source files */
377 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
381 /* Seek to the header position and read the header */
382 FileSetPos (F, Offset);
383 ReadObjHeader (F, &H);
385 /* Seek to the start of the string pool and read it */
386 FileSetPos (F, Offset + H.StrPoolOffs);
387 ReadStrPool (F, &StrPool);
389 /* Seek to the start of the source files */
390 FileSetPos (F, Offset + H.FileOffs);
392 /* Output a header */
393 printf (" Files:\n");
395 /* Read the number of files and print it */
397 printf (" Count:%27u\n", Count);
399 /* Read and print all files */
400 for (I = 0; I < Count; ++I) {
402 /* Read the data for one file */
403 const char* Name = GetString (&StrPool, ReadVar (F));
404 unsigned long MTime = Read32 (F);
405 unsigned long Size = ReadVar (F);
406 unsigned Len = strlen (Name);
408 /* Print the header */
409 printf (" Index:%27u\n", I);
412 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
413 printf (" Size:%26lu\n", Size);
414 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
417 /* Destroy the string pool */
418 DestroyStrPool (&StrPool);
423 void DumpObjSegments (FILE* F, unsigned long Offset)
424 /* Dump the segments in the object file */
427 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
431 /* Seek to the header position and read the header */
432 FileSetPos (F, Offset);
433 ReadObjHeader (F, &H);
435 /* Seek to the start of the string pool and read it */
436 FileSetPos (F, Offset + H.StrPoolOffs);
437 ReadStrPool (F, &StrPool);
439 /* Seek to the start of the segments */
440 FileSetPos (F, Offset + H.SegOffs);
442 /* Output a header */
443 printf (" Segments:\n");
445 /* Read the number of segments and print it */
447 printf (" Count:%27u\n", Count);
449 /* Read and print all segments */
450 for (I = 0; I < Count; ++I) {
452 /* Read the data for one segments */
453 unsigned long DataSize = Read32 (F);
454 unsigned long NextSeg = ftell (F) + DataSize;
455 const char* Name = GetString (&StrPool, ReadVar (F));
456 unsigned Len = strlen (Name);
457 unsigned long Size = Read32 (F);
458 unsigned Align = (1U << Read8 (F));
459 unsigned char AddrSize = Read8 (F);
460 unsigned long FragCount = ReadVar (F);
462 /* Print the header */
463 printf (" Index:%27u\n", I);
466 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
467 printf (" Size:%26lu\n", Size);
468 printf (" Alignment:%21u\n", Align);
469 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
470 AddrSizeToStr (AddrSize));
471 printf (" Fragment count:%16lu\n", FragCount);
473 /* Seek to the end of the segment data (start of next) */
474 FileSetPos (F, NextSeg);
477 /* Destroy the string pool */
478 DestroyStrPool (&StrPool);
483 void DumpObjImports (FILE* F, unsigned long Offset)
484 /* Dump the imports in the object file */
487 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
491 /* Seek to the header position and read the header */
492 FileSetPos (F, Offset);
493 ReadObjHeader (F, &H);
495 /* Seek to the start of the string pool and read it */
496 FileSetPos (F, Offset + H.StrPoolOffs);
497 ReadStrPool (F, &StrPool);
499 /* Seek to the start of the imports */
500 FileSetPos (F, Offset + H.ImportOffs);
502 /* Output a header */
503 printf (" Imports:\n");
505 /* Read the number of imports and print it */
507 printf (" Count:%27u\n", Count);
509 /* Read and print all imports */
510 for (I = 0; I < Count; ++I) {
512 /* Read the data for one import */
513 unsigned char AddrSize = Read8 (F);
514 const char* Name = GetString (&StrPool, ReadVar (F));
515 unsigned Len = strlen (Name);
517 /* Skip the line infos */
518 SkipLineInfoList (F);
520 /* Print the header */
521 printf (" Index:%27u\n", I);
524 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
525 AddrSizeToStr (AddrSize));
526 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
529 /* Destroy the string pool */
530 DestroyStrPool (&StrPool);
535 void DumpObjExports (FILE* F, unsigned long Offset)
536 /* Dump the exports in the object file */
539 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
543 /* Seek to the header position and read the header */
544 FileSetPos (F, Offset);
545 ReadObjHeader (F, &H);
547 /* Seek to the start of the string pool and read it */
548 FileSetPos (F, Offset + H.StrPoolOffs);
549 ReadStrPool (F, &StrPool);
551 /* Seek to the start of the exports */
552 FileSetPos (F, Offset + H.ExportOffs);
554 /* Output a header */
555 printf (" Exports:\n");
557 /* Read the number of exports and print it */
559 printf (" Count:%27u\n", Count);
561 /* Read and print all exports */
562 for (I = 0; I < Count; ++I) {
564 unsigned long Value = 0;
566 unsigned char ConDes [CD_TYPE_COUNT];
571 /* Read the data for one export */
572 unsigned Type = ReadVar (F);
573 unsigned char AddrSize = Read8 (F);
574 ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
575 Name = GetString (&StrPool, ReadVar (F));
577 if (SYM_IS_EXPR (Type)) {
585 /* Skip the line infos */
586 SkipLineInfoList (F);
588 /* Print the header */
589 printf (" Index:%27u\n", I);
592 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
593 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
594 AddrSizeToStr (AddrSize));
595 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
597 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
601 /* Destroy the string pool */
602 DestroyStrPool (&StrPool);
607 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
608 /* Dump the debug symbols from an object file */
611 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
615 /* Seek to the header position and read the header */
616 FileSetPos (F, Offset);
617 ReadObjHeader (F, &H);
619 /* Seek to the start of the string pool and read it */
620 FileSetPos (F, Offset + H.StrPoolOffs);
621 ReadStrPool (F, &StrPool);
623 /* Seek to the start of the debug syms */
624 FileSetPos (F, Offset + H.DbgSymOffs);
626 /* Output a header */
627 printf (" Debug symbols:\n");
629 /* Check if the object file was compiled with debug info */
630 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
631 /* Print that there no debug symbols and bail out */
632 printf (" Count:%27u\n", 0);
636 /* Read the number of exports and print it */
638 printf (" Count:%27u\n", Count);
640 /* Read and print all debug symbols */
641 for (I = 0; I < Count; ++I) {
643 unsigned long Value = 0;
646 /* Read the data for one symbol */
647 unsigned Type = ReadVar (F);
648 unsigned char AddrSize = Read8 (F);
649 const char* Name = GetString (&StrPool, ReadVar (F));
650 unsigned Len = strlen (Name);
651 if (SYM_IS_EXPR (Type)) {
659 /* Skip the line infos */
660 SkipLineInfoList (F);
662 /* Print the header */
663 printf (" Index:%27u\n", I);
666 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
667 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
668 AddrSizeToStr (AddrSize));
669 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
671 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
675 /* Destroy the string pool */
676 DestroyStrPool (&StrPool);
681 void DumpObjLineInfo (FILE* F, unsigned long Offset)
682 /* Dump the line info from an object file */
685 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
689 /* Seek to the header position and read the header */
690 FileSetPos (F, Offset);
691 ReadObjHeader (F, &H);
693 /* Seek to the start of the string pool and read it */
694 FileSetPos (F, Offset + H.StrPoolOffs);
695 ReadStrPool (F, &StrPool);
697 /* Seek to the start of line infos */
698 FileSetPos (F, Offset + H.LineInfoOffs);
700 /* Output a header */
701 printf (" Line info:\n");
703 /* Check if the object file was compiled with debug info */
704 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
705 /* Print that there no line infos and bail out */
706 printf (" Count:%27u\n", 0);
710 /* Read the number of line infos and print it */
712 printf (" Count:%27u\n", Count);
714 /* Read and print all line infos */
715 for (I = 0; I < Count; ++I) {
717 /* Read one line info */
719 ReadFilePos (F, &Pos);
721 /* Print the header */
722 printf (" Index:%27u\n", I);
725 printf (" Line:%26lu\n", Pos.Line);
726 printf (" Col:%27u\n", Pos.Col);
727 printf (" Name:%26u\n", Pos.Name);
730 /* Destroy the string pool */
731 DestroyStrPool (&StrPool);
736 void DumpObjSegSize (FILE* F, unsigned long Offset)
737 /* Dump the sizes of the segment in the object file */
740 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
743 /* Seek to the header position and read the header */
744 FileSetPos (F, Offset);
745 ReadObjHeader (F, &H);
747 /* Seek to the start of the string pool and read it */
748 FileSetPos (F, Offset + H.StrPoolOffs);
749 ReadStrPool (F, &StrPool);
751 /* Seek to the start of the segments */
752 FileSetPos (F, Offset + H.SegOffs);
754 /* Output a header */
755 printf (" Segment sizes:\n");
757 /* Read the number of segments */
760 /* Read and print the sizes of all segments */
763 /* Read the data for one segments */
764 unsigned long DataSize = Read32 (F);
765 unsigned long NextSeg = ftell (F) + DataSize;
766 const char* Name = GetString (&StrPool, ReadVar (F));
767 unsigned Len = strlen (Name);
768 unsigned long Size = Read32 (F);
770 /* Skip alignment, type and fragment count */
775 /* Print the size for this segment */
776 printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size);
778 /* Seek to the end of the segment data (start of next) */
779 FileSetPos (F, NextSeg);
782 /* Destroy the string pool */
783 DestroyStrPool (&StrPool);