1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2002-2010, 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 SkipExpr (FILE* F)
124 /* Skip an expression from the given file */
126 /* Read the node tag and handle NULL nodes */
127 unsigned char Op = Read8 (F);
128 if (Op == EXPR_NULL) {
132 /* Check the tag and handle the different expression types */
133 if (EXPR_IS_LEAF (Op)) {
137 (void) Read32Signed (F);
141 /* Read the import number */
146 /* Read the segment number */
151 Error ("Invalid expression op: %02X", Op);
157 /* Not a leaf node */
165 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
166 /* Get the export flags as a (static) string */
169 static char TypeDesc[256];
177 switch (Flags & SYM_MASK_TYPE) {
178 case SYM_STD: strcat (TypeDesc, "SYM_STD"); break;
179 case SYM_CHEAP_LOCAL: strcat (TypeDesc, "SYM_CHEAP_LOCAL"); break;
183 switch (Flags & SYM_MASK_LABEL) {
184 case SYM_EQUATE: strcat (TypeDesc, ",SYM_EQUATE"); break;
185 case SYM_LABEL: strcat (TypeDesc, ",SYM_LABEL"); break;
188 /* Type of expression */
189 switch (Flags & SYM_MASK_VAL) {
190 case SYM_CONST: strcat (TypeDesc, ",SYM_CONST"); break;
191 case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
194 /* Constructor/destructor declarations */
195 T = TypeDesc + strlen (TypeDesc);
196 Count = SYM_GET_CONDES_COUNT (Flags);
197 if (Count > 0 && ConDes) {
198 T += sprintf (T, ",SYM_CONDES=");
199 for (I = 0; I < Count; ++I) {
200 unsigned Type = CD_GET_TYPE (ConDes[I]);
201 unsigned Prio = CD_GET_PRIO (ConDes[I]);
205 T += sprintf (T, "[%u,%u]", Type, Prio);
209 /* Return the result */
215 void DumpObjHeader (FILE* F, unsigned long Offset)
216 /* Dump the header of the given object file */
220 /* Seek to the header position */
221 FileSetPos (F, Offset);
223 /* Read the header */
224 ReadObjHeader (F, &H);
226 /* Now dump the information */
228 /* Output a header */
229 printf (" Header:\n");
232 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
235 printf (" Version:%25u\n", H.Version);
238 printf (" Flags:%21s0x%04X (", "", H.Flags);
239 if (H.Flags & OBJ_FLAGS_DBGINFO) {
240 printf ("OBJ_FLAGS_DBGINFO");
245 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
248 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
251 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
254 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
257 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
260 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
263 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
266 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
271 void DumpObjOptions (FILE* F, unsigned long Offset)
272 /* Dump the file options */
275 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
279 /* Seek to the header position and read the header */
280 FileSetPos (F, Offset);
281 ReadObjHeader (F, &H);
283 /* Seek to the start of the string pool and read it */
284 FileSetPos (F, Offset + H.StrPoolOffs);
285 ReadStrPool (F, &StrPool);
287 /* Seek to the start of the options */
288 FileSetPos (F, Offset + H.OptionOffs);
290 /* Output a header */
291 printf (" Options:\n");
293 /* Read the number of options and print it */
295 printf (" Count:%27u\n", Count);
297 /* Read and print all options */
298 for (I = 0; I < Count; ++I) {
303 /* Read the type of the option and the value */
304 unsigned char Type = Read8 (F);
305 unsigned long Val = ReadVar (F);
307 /* Get the type of the argument */
308 unsigned char ArgType = Type & OPT_ARGMASK;
310 /* Determine which option follows */
311 const char* TypeDesc;
313 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
314 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
315 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
316 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
317 case OPT_OS: TypeDesc = "OPT_OS"; break;
318 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
319 default: TypeDesc = "OPT_UNKNOWN"; break;
322 /* Print the header */
323 printf (" Index:%27u\n", I);
326 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
330 ArgStr = GetString (&StrPool, Val);
331 ArgLen = strlen (ArgStr);
332 printf (" Data:%*s\"%s\"\n", (int)(24-ArgLen), "", ArgStr);
336 printf (" Data:%26lu", Val);
337 if (Type == OPT_DATETIME) {
338 /* Print the time as a string */
339 printf (" (%s)", TimeToStr (Val));
345 /* Unknown argument type. This means that we cannot determine
346 * the option length, so we cannot proceed.
348 Error ("Unknown option type: 0x%02X", Type);
353 /* Destroy the string pool */
354 DestroyStrPool (&StrPool);
359 void DumpObjFiles (FILE* F, unsigned long Offset)
360 /* Dump the source files */
363 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
367 /* Seek to the header position and read the header */
368 FileSetPos (F, Offset);
369 ReadObjHeader (F, &H);
371 /* Seek to the start of the string pool and read it */
372 FileSetPos (F, Offset + H.StrPoolOffs);
373 ReadStrPool (F, &StrPool);
375 /* Seek to the start of the source files */
376 FileSetPos (F, Offset + H.FileOffs);
378 /* Output a header */
379 printf (" Files:\n");
381 /* Read the number of files and print it */
383 printf (" Count:%27u\n", Count);
385 /* Read and print all files */
386 for (I = 0; I < Count; ++I) {
388 /* Read the data for one file */
389 const char* Name = GetString (&StrPool, ReadVar (F));
390 unsigned long MTime = Read32 (F);
391 unsigned long Size = Read32 (F);
392 unsigned Len = strlen (Name);
394 /* Print the header */
395 printf (" Index:%27u\n", I);
398 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
399 printf (" Size:%26lu\n", Size);
400 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
403 /* Destroy the string pool */
404 DestroyStrPool (&StrPool);
409 void DumpObjSegments (FILE* F, unsigned long Offset)
410 /* Dump the segments in the object file */
413 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
417 /* Seek to the header position and read the header */
418 FileSetPos (F, Offset);
419 ReadObjHeader (F, &H);
421 /* Seek to the start of the string pool and read it */
422 FileSetPos (F, Offset + H.StrPoolOffs);
423 ReadStrPool (F, &StrPool);
425 /* Seek to the start of the segments */
426 FileSetPos (F, Offset + H.SegOffs);
428 /* Output a header */
429 printf (" Segments:\n");
431 /* Read the number of segments and print it */
433 printf (" Count:%27u\n", Count);
435 /* Read and print all segments */
436 for (I = 0; I < Count; ++I) {
438 /* Read the data for one segments */
439 unsigned long DataSize = Read32 (F);
440 unsigned long NextSeg = ftell (F) + DataSize;
441 const char* Name = GetString (&StrPool, ReadVar (F));
442 unsigned Len = strlen (Name);
443 unsigned long Size = Read32 (F);
444 unsigned Align = (1U << Read8 (F));
445 unsigned char AddrSize = Read8 (F);
446 unsigned long FragCount = ReadVar (F);
448 /* Print the header */
449 printf (" Index:%27u\n", I);
452 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
453 printf (" Size:%26lu\n", Size);
454 printf (" Alignment:%21u\n", Align);
455 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
456 AddrSizeToStr (AddrSize));
457 printf (" Fragment count:%16lu\n", FragCount);
459 /* Seek to the end of the segment data (start of next) */
460 FileSetPos (F, NextSeg);
463 /* Destroy the string pool */
464 DestroyStrPool (&StrPool);
469 void DumpObjImports (FILE* F, unsigned long Offset)
470 /* Dump the imports in the object file */
473 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
478 /* Seek to the header position and read the header */
479 FileSetPos (F, Offset);
480 ReadObjHeader (F, &H);
482 /* Seek to the start of the string pool and read it */
483 FileSetPos (F, Offset + H.StrPoolOffs);
484 ReadStrPool (F, &StrPool);
486 /* Seek to the start of the imports */
487 FileSetPos (F, Offset + H.ImportOffs);
489 /* Output a header */
490 printf (" Imports:\n");
492 /* Read the number of imports and print it */
494 printf (" Count:%27u\n", Count);
496 /* Read and print all imports */
497 for (I = 0; I < Count; ++I) {
499 /* Read the data for one import */
500 unsigned char AddrSize = Read8 (F);
501 const char* Name = GetString (&StrPool, ReadVar (F));
502 unsigned Len = strlen (Name);
503 ReadFilePos (F, &Pos);
505 /* Print the header */
506 printf (" Index:%27u\n", I);
509 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
510 AddrSizeToStr (AddrSize));
511 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
514 /* Destroy the string pool */
515 DestroyStrPool (&StrPool);
520 void DumpObjExports (FILE* F, unsigned long Offset)
521 /* Dump the exports in the object file */
524 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
529 /* Seek to the header position and read the header */
530 FileSetPos (F, Offset);
531 ReadObjHeader (F, &H);
533 /* Seek to the start of the string pool and read it */
534 FileSetPos (F, Offset + H.StrPoolOffs);
535 ReadStrPool (F, &StrPool);
537 /* Seek to the start of the exports */
538 FileSetPos (F, Offset + H.ExportOffs);
540 /* Output a header */
541 printf (" Exports:\n");
543 /* Read the number of exports and print it */
545 printf (" Count:%27u\n", Count);
547 /* Read and print all exports */
548 for (I = 0; I < Count; ++I) {
550 unsigned long Value = 0;
552 unsigned char ConDes [CD_TYPE_COUNT];
557 /* Read the data for one export */
558 unsigned Type = ReadVar (F);
559 unsigned char AddrSize = Read8 (F);
560 ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
561 Name = GetString (&StrPool, ReadVar (F));
563 if (SYM_IS_EXPR (Type)) {
570 ReadFilePos (F, &Pos);
572 /* Print the header */
573 printf (" Index:%27u\n", I);
576 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
577 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
578 AddrSizeToStr (AddrSize));
579 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
581 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
585 /* Destroy the string pool */
586 DestroyStrPool (&StrPool);
591 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
592 /* Dump the debug symbols from an object file */
595 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
600 /* Seek to the header position and read the header */
601 FileSetPos (F, Offset);
602 ReadObjHeader (F, &H);
604 /* Seek to the start of the string pool and read it */
605 FileSetPos (F, Offset + H.StrPoolOffs);
606 ReadStrPool (F, &StrPool);
608 /* Seek to the start of the debug syms */
609 FileSetPos (F, Offset + H.DbgSymOffs);
611 /* Output a header */
612 printf (" Debug symbols:\n");
614 /* Check if the object file was compiled with debug info */
615 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
616 /* Print that there no debug symbols and bail out */
617 printf (" Count:%27u\n", 0);
621 /* Read the number of exports and print it */
623 printf (" Count:%27u\n", Count);
625 /* Read and print all debug symbols */
626 for (I = 0; I < Count; ++I) {
628 unsigned long Value = 0;
631 /* Read the data for one symbol */
632 unsigned Type = ReadVar (F);
633 unsigned char AddrSize = Read8 (F);
634 const char* Name = GetString (&StrPool, ReadVar (F));
635 unsigned Len = strlen (Name);
636 if (SYM_IS_EXPR (Type)) {
643 ReadFilePos (F, &Pos);
645 /* Print the header */
646 printf (" Index:%27u\n", I);
649 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
650 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
651 AddrSizeToStr (AddrSize));
652 printf (" Name:%*s\"%s\"\n", (int)(24-Len), "", Name);
654 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
658 /* Destroy the string pool */
659 DestroyStrPool (&StrPool);
664 void DumpObjLineInfo (FILE* F, unsigned long Offset)
665 /* Dump the line info from an object file */
668 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
672 /* Seek to the header position and read the header */
673 FileSetPos (F, Offset);
674 ReadObjHeader (F, &H);
676 /* Seek to the start of the string pool and read it */
677 FileSetPos (F, Offset + H.StrPoolOffs);
678 ReadStrPool (F, &StrPool);
680 /* Seek to the start of line infos */
681 FileSetPos (F, Offset + H.LineInfoOffs);
683 /* Output a header */
684 printf (" Line info:\n");
686 /* Check if the object file was compiled with debug info */
687 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
688 /* Print that there no line infos and bail out */
689 printf (" Count:%27u\n", 0);
693 /* Read the number of line infos and print it */
695 printf (" Count:%27u\n", Count);
697 /* Read and print all line infos */
698 for (I = 0; I < Count; ++I) {
702 /* Read one line info */
703 ReadFilePos (F, &Pos);
705 /* Print the header */
706 printf (" Index:%27u\n", I);
709 printf (" Line:%26lu\n", Pos.Line);
710 printf (" Col:%27u\n", Pos.Col);
711 printf (" Name:%26u\n", Pos.Name);
714 /* Destroy the string pool */
715 DestroyStrPool (&StrPool);
720 void DumpObjSegSize (FILE* F, unsigned long Offset)
721 /* Dump the sizes of the segment in the object file */
724 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
727 /* Seek to the header position and read the header */
728 FileSetPos (F, Offset);
729 ReadObjHeader (F, &H);
731 /* Seek to the start of the string pool and read it */
732 FileSetPos (F, Offset + H.StrPoolOffs);
733 ReadStrPool (F, &StrPool);
735 /* Seek to the start of the segments */
736 FileSetPos (F, Offset + H.SegOffs);
738 /* Output a header */
739 printf (" Segment sizes:\n");
741 /* Read the number of segments */
744 /* Read and print the sizes of all segments */
747 /* Read the data for one segments */
748 unsigned long DataSize = Read32 (F);
749 unsigned long NextSeg = ftell (F) + DataSize;
750 const char* Name = GetString (&StrPool, ReadVar (F));
751 unsigned Len = strlen (Name);
752 unsigned long Size = Read32 (F);
754 /* Skip alignment, type and fragment count */
759 /* Print the size for this segment */
760 printf (" %s:%*s%6lu\n", Name, (int)(24-Len), "", Size);
762 /* Seek to the end of the segment data (start of next) */
763 FileSetPos (F, NextSeg);
766 /* Destroy the string pool */
767 DestroyStrPool (&StrPool);