1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2002-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 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 /*****************************************************************************/
57 /*****************************************************************************/
59 /*****************************************************************************/
63 static void DestroyStrPool (Collection* C)
64 /* Free all strings in the given pool plus the item pointers. Note: The
65 * collection may not be reused later.
69 for (I = 0; I < CollCount (C); ++I) {
70 xfree (CollAtUnchecked (C, I));
77 static const char* GetString (const Collection* C, unsigned Index)
78 /* Get a string from a collection. In fact, this function calls CollConstAt,
79 * but will print a somewhat more readable error message if the index is out
83 if (Index >= CollCount (C)) {
84 Error ("Invalid string index (%u) - file corrupt!", Index);
86 return CollConstAt (C, Index);
91 static void DumpObjHeaderSection (const char* Name,
94 /* Dump a header section */
96 printf (" %s:\n", Name);
97 printf (" Offset:%24lu\n", Offset);
98 printf (" Size: %24lu\n", Size);
103 static char* TimeToStr (unsigned long Time)
104 /* Convert the time into a string and return it */
106 /* Get the time and convert to string */
107 time_t T = (time_t) Time;
108 char* S = asctime (localtime (&T));
110 /* Remove the trailing newline */
111 unsigned Len = strlen (S);
112 if (Len > 0 && S[Len-1] == '\n') {
116 /* Return the time string */
122 static void SkipExpr (FILE* F)
123 /* Skip an expression from the given file */
125 /* Read the node tag and handle NULL nodes */
126 unsigned char Op = Read8 (F);
127 if (Op == EXPR_NULL) {
131 /* Check the tag and handle the different expression types */
132 if (EXPR_IS_LEAF (Op)) {
136 (void) Read32Signed (F);
140 /* Read the import number */
145 /* Read the segment number */
150 Error ("Invalid expression op: %02X", Op);
156 /* Not a leaf node */
164 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
165 /* Get the export flags as a (static) string */
168 static char TypeDesc[256];
176 switch (Flags & EXP_MASK_SIZE) {
177 case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break;
178 case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break;
181 /* Type of expression */
182 switch (Flags & EXP_MASK_VAL) {
183 case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break;
184 case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break;
187 /* Constructor/destructor declarations */
188 T = TypeDesc + strlen (TypeDesc);
189 Count = GET_EXP_CONDES_COUNT (Flags);
191 T += sprintf (T, ",EXP_CONDES=");
192 for (I = 0; I < Count; ++I) {
193 unsigned Type = CD_GET_TYPE (ConDes[I]);
194 unsigned Prio = CD_GET_PRIO (ConDes[I]);
198 T += sprintf (T, "[%u,%u]", Type, Prio);
202 /* Return the result */
208 void DumpObjHeader (FILE* F, unsigned long Offset)
209 /* Dump the header of the given object file */
213 /* Seek to the header position */
214 FileSetPos (F, Offset);
216 /* Read the header */
217 ReadObjHeader (F, &H);
219 /* Now dump the information */
221 /* Output a header */
222 printf (" Header:\n");
225 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
228 printf (" Version:%25u\n", H.Version);
231 printf (" Flags:%21s0x%04X (", "", H.Flags);
232 if (H.Flags & OBJ_FLAGS_DBGINFO) {
233 printf ("OBJ_FLAGS_DBGINFO");
238 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
241 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
244 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
247 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
250 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
253 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
256 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
259 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
264 void DumpObjOptions (FILE* F, unsigned long Offset)
265 /* Dump the file options */
268 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
272 /* Seek to the header position and read the header */
273 FileSetPos (F, Offset);
274 ReadObjHeader (F, &H);
276 /* Seek to the start of the string pool and read it */
277 FileSetPos (F, Offset + H.StrPoolOffs);
278 ReadStrPool (F, &StrPool);
280 /* Seek to the start of the options */
281 FileSetPos (F, Offset + H.OptionOffs);
283 /* Output a header */
284 printf (" Options:\n");
286 /* Read the number of options and print it */
288 printf (" Count:%27u\n", Count);
290 /* Read and print all options */
291 for (I = 0; I < Count; ++I) {
296 /* Read the type of the option and the value */
297 unsigned char Type = Read8 (F);
298 unsigned long Val = ReadVar (F);
300 /* Get the type of the argument */
301 unsigned char ArgType = Type & OPT_ARGMASK;
303 /* Determine which option follows */
304 const char* TypeDesc;
306 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
307 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
308 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
309 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
310 case OPT_OS: TypeDesc = "OPT_OS"; break;
311 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
312 default: TypeDesc = "OPT_UNKNOWN"; break;
315 /* Print the header */
316 printf (" Index:%27u\n", I);
319 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
323 ArgStr = GetString (&StrPool, Val);
324 ArgLen = strlen (ArgStr);
325 printf (" Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
329 printf (" Data:%26lu", Val);
330 if (Type == OPT_DATETIME) {
331 /* Print the time as a string */
332 printf (" (%s)", TimeToStr (Val));
338 /* Unknown argument type. This means that we cannot determine
339 * the option length, so we cannot proceed.
341 Error ("Unknown option type: 0x%02X", Type);
346 /* Destroy the string pool */
347 DestroyStrPool (&StrPool);
352 void DumpObjFiles (FILE* F, unsigned long Offset)
353 /* Dump the source files */
356 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
360 /* Seek to the header position and read the header */
361 FileSetPos (F, Offset);
362 ReadObjHeader (F, &H);
364 /* Seek to the start of the string pool and read it */
365 FileSetPos (F, Offset + H.StrPoolOffs);
366 ReadStrPool (F, &StrPool);
368 /* Seek to the start of the source files */
369 FileSetPos (F, Offset + H.FileOffs);
371 /* Output a header */
372 printf (" Files:\n");
374 /* Read the number of files and print it */
376 printf (" Count:%27u\n", Count);
378 /* Read and print all files */
379 for (I = 0; I < Count; ++I) {
381 /* Read the data for one file */
382 unsigned long MTime = Read32 (F);
383 unsigned long Size = Read32 (F);
384 char* Name = ReadStr (F);
385 unsigned Len = strlen (Name);
387 /* Print the header */
388 printf (" Index:%27u\n", I);
391 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
392 printf (" Size:%26lu\n", Size);
393 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
399 /* Destroy the string pool */
400 DestroyStrPool (&StrPool);
405 void DumpObjSegments (FILE* F, unsigned long Offset)
406 /* Dump the segments in the object file */
409 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
413 /* Seek to the header position and read the header */
414 FileSetPos (F, Offset);
415 ReadObjHeader (F, &H);
417 /* Seek to the start of the string pool and read it */
418 FileSetPos (F, Offset + H.StrPoolOffs);
419 ReadStrPool (F, &StrPool);
421 /* Seek to the start of the segments */
422 FileSetPos (F, Offset + H.SegOffs);
424 /* Output a header */
425 printf (" Segments:\n");
427 /* Read the number of segments and print it */
429 printf (" Count:%27u\n", Count);
431 /* Read and print all segments */
432 for (I = 0; I < Count; ++I) {
434 /* Read the data for one segments */
435 unsigned long DataSize = Read32 (F);
436 unsigned long NextSeg = ftell (F) + DataSize;
437 const char* Name = GetString (&StrPool, ReadVar (F));
438 unsigned Len = strlen (Name);
439 unsigned long Size = Read32 (F);
440 unsigned Align = (1U << Read8 (F));
441 unsigned char Type = Read8 (F);
442 unsigned long FragCount = ReadVar (F);
444 /* Get the description for the type */
445 const char* TypeDesc;
447 case SEGTYPE_DEFAULT: TypeDesc = "SEGTYPE_DEFAULT"; break;
448 case SEGTYPE_ABS: TypeDesc = "SEGTYPE_ABS"; break;
449 case SEGTYPE_ZP: TypeDesc = "SEGTYPE_ZP"; break;
450 case SEGTYPE_FAR: TypeDesc = "SEGTYPE_FAR"; break;
451 default: TypeDesc = "SEGTYPE_UNKNOWN"; break;
454 /* Print the header */
455 printf (" Index:%27u\n", I);
458 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
459 printf (" Size:%26lu\n", Size);
460 printf (" Alignment:%21u\n", Align);
461 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
462 printf (" Fragment count:%16lu\n", FragCount);
464 /* Seek to the end of the segment data (start of next) */
465 FileSetPos (F, NextSeg);
468 /* Destroy the string pool */
469 DestroyStrPool (&StrPool);
474 void DumpObjImports (FILE* F, unsigned long Offset)
475 /* Dump the imports in the object file */
478 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
483 /* Seek to the header position and read the header */
484 FileSetPos (F, Offset);
485 ReadObjHeader (F, &H);
487 /* Seek to the start of the string pool and read it */
488 FileSetPos (F, Offset + H.StrPoolOffs);
489 ReadStrPool (F, &StrPool);
491 /* Seek to the start of the imports */
492 FileSetPos (F, Offset + H.ImportOffs);
494 /* Output a header */
495 printf (" Imports:\n");
497 /* Read the number of imports and print it */
499 printf (" Count:%27u\n", Count);
501 /* Read and print all imports */
502 for (I = 0; I < Count; ++I) {
504 const char* TypeDesc;
506 /* Read the data for one import */
507 unsigned char Type = Read8 (F);
508 const char* Name = GetString (&StrPool, ReadVar (F));
509 unsigned Len = strlen (Name);
510 ReadFilePos (F, &Pos);
512 /* Get a description for the type */
514 case IMP_ZP: TypeDesc = "IMP_ZP"; break;
515 case IMP_ABS: TypeDesc = "IMP_ABS"; break;
516 default: TypeDesc = "IMP_UNKNOWN"; break;
519 /* Print the header */
520 printf (" Index:%27u\n", I);
523 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
524 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
527 /* Destroy the string pool */
528 DestroyStrPool (&StrPool);
533 void DumpObjExports (FILE* F, unsigned long Offset)
534 /* Dump the exports in the object file */
537 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
542 /* Seek to the header position and read the header */
543 FileSetPos (F, Offset);
544 ReadObjHeader (F, &H);
546 /* Seek to the start of the string pool and read it */
547 FileSetPos (F, Offset + H.StrPoolOffs);
548 ReadStrPool (F, &StrPool);
550 /* Seek to the start of the exports */
551 FileSetPos (F, Offset + H.ExportOffs);
553 /* Output a header */
554 printf (" Exports:\n");
556 /* Read the number of exports and print it */
558 printf (" Count:%27u\n", Count);
560 /* Read and print all exports */
561 for (I = 0; I < Count; ++I) {
563 unsigned long Value = 0;
566 unsigned char ConDes [CD_TYPE_COUNT];
571 /* Read the data for one export */
573 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
574 Name = GetString (&StrPool, ReadVar (F));
576 if (IS_EXP_EXPR (Type)) {
583 ReadFilePos (F, &Pos);
585 /* Print the header */
586 printf (" Index:%27u\n", I);
589 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
590 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
592 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
596 /* Destroy the string pool */
597 DestroyStrPool (&StrPool);
602 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
603 /* Dump the debug symbols from an object file */
606 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
611 /* Seek to the header position and read the header */
612 FileSetPos (F, Offset);
613 ReadObjHeader (F, &H);
615 /* Seek to the start of the string pool and read it */
616 FileSetPos (F, Offset + H.StrPoolOffs);
617 ReadStrPool (F, &StrPool);
619 /* Seek to the start of the debug syms */
620 FileSetPos (F, Offset + H.DbgSymOffs);
622 /* Output a header */
623 printf (" Debug symbols:\n");
625 /* Check if the object file was compiled with debug info */
626 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
627 /* Print that there no debug symbols and bail out */
628 printf (" Count:%27u\n", 0);
632 /* Read the number of exports and print it */
634 printf (" Count:%27u\n", Count);
636 /* Read and print all debug symbols */
637 for (I = 0; I < Count; ++I) {
639 unsigned long Value = 0;
642 unsigned char ConDes [CD_TYPE_COUNT];
646 /* Read the data for one symbol */
648 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
649 Name = GetString (&StrPool, ReadVar (F));
651 if (IS_EXP_EXPR (Type)) {
658 ReadFilePos (F, &Pos);
660 /* Print the header */
661 printf (" Index:%27u\n", I);
664 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
665 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
667 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
671 /* Destroy the string pool */
672 DestroyStrPool (&StrPool);
677 void DumpObjLineInfo (FILE* F, unsigned long Offset)
678 /* Dump the line info from an object file */
681 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
685 /* Seek to the header position and read the header */
686 FileSetPos (F, Offset);
687 ReadObjHeader (F, &H);
689 /* Seek to the start of the string pool and read it */
690 FileSetPos (F, Offset + H.StrPoolOffs);
691 ReadStrPool (F, &StrPool);
693 /* Seek to the start of line infos */
694 FileSetPos (F, Offset + H.LineInfoOffs);
696 /* Output a header */
697 printf (" Line info:\n");
699 /* Check if the object file was compiled with debug info */
700 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
701 /* Print that there no line infos and bail out */
702 printf (" Count:%27u\n", 0);
706 /* Read the number of line infos and print it */
708 printf (" Count:%27u\n", Count);
710 /* Read and print all line infos */
711 for (I = 0; I < Count; ++I) {
715 /* Read one line info */
716 ReadFilePos (F, &Pos);
718 /* Print the header */
719 printf (" Index:%27u\n", I);
722 printf (" Line:%26lu\n", Pos.Line);
723 printf (" Col:%27u\n", Pos.Col);
724 printf (" Name:%26u\n", Pos.Name);
727 /* Destroy the string pool */
728 DestroyStrPool (&StrPool);
733 void DumpObjSegSize (FILE* F, unsigned long Offset)
734 /* Dump the sizes of the segment in the object file */
737 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
740 /* Seek to the header position and read the header */
741 FileSetPos (F, Offset);
742 ReadObjHeader (F, &H);
744 /* Seek to the start of the string pool and read it */
745 FileSetPos (F, Offset + H.StrPoolOffs);
746 ReadStrPool (F, &StrPool);
748 /* Seek to the start of the segments */
749 FileSetPos (F, Offset + H.SegOffs);
751 /* Output a header */
752 printf (" Segment sizes:\n");
754 /* Read the number of segments */
757 /* Read and print the sizes of all segments */
760 /* Read the data for one segments */
761 unsigned long DataSize = Read32 (F);
762 unsigned long NextSeg = ftell (F) + DataSize;
763 const char* Name = GetString (&StrPool, ReadVar (F));
764 unsigned Len = strlen (Name);
765 unsigned long Size = Read32 (F);
767 /* Skip alignment, type and fragment count */
772 /* Print the size for this segment */
773 printf (" %s:%*s%6lu\n", Name, 24-Len, "", Size);
775 /* Seek to the end of the segment data (start of next) */
776 FileSetPos (F, NextSeg);
779 /* Destroy the string pool */
780 DestroyStrPool (&StrPool);