]> git.sur5r.net Git - cc65/blob - src/od65/dump.c
208c4bfbced706729d9211dc92495e43f471a528
[cc65] / src / od65 / dump.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  dump.c                                   */
4 /*                                                                           */
5 /*          Dump subroutines for the od65 object file dump utility           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <time.h>
38
39 /* common */
40 #include "addrsize.h"
41 #include "cddefs.h"
42 #include "coll.h"
43 #include "exprdefs.h"
44 #include "filepos.h"
45 #include "objdefs.h"
46 #include "optdefs.h"
47 #include "segdefs.h"
48 #include "symdefs.h"
49 #include "xmalloc.h"
50
51 /* od65 */
52 #include "error.h"
53 #include "fileio.h"
54 #include "dump.h"
55
56
57
58 /*****************************************************************************/
59 /*                                   Code                                    */
60 /*****************************************************************************/
61
62
63
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.
67  */
68 {
69     unsigned I;
70     for (I = 0; I < CollCount (C); ++I) {
71         xfree (CollAtUnchecked (C, I));
72     }
73     DoneCollection (C);
74 }
75
76
77
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
81  * of bounds.
82  */
83 {
84     if (Index >= CollCount (C)) {
85         Error ("Invalid string index (%u) - file corrupt!", Index);
86     }
87     return CollConstAt (C, Index);
88 }
89
90
91
92 static void DumpObjHeaderSection (const char* Name,
93                                   unsigned long Offset,
94                                   unsigned long Size)
95 /* Dump a header section */
96 {
97     printf ("    %s:\n", Name);
98     printf ("      Offset:%24lu\n", Offset);
99     printf ("      Size:  %24lu\n", Size);
100 }
101
102
103
104 static char* TimeToStr (unsigned long Time)
105 /* Convert the time into a string and return it */
106 {
107     /* Get the time and convert to string */
108     time_t T = (time_t) Time;
109     char*  S = asctime (localtime (&T));
110
111     /* Remove the trailing newline */
112     unsigned Len = strlen (S);
113     if (Len > 0 && S[Len-1] == '\n') {
114         S[Len-1 ] = '\0';
115     }
116
117     /* Return the time string */
118     return S;
119 }
120
121
122
123 static void SkipExpr (FILE* F)
124 /* Skip an expression from the given file */
125 {
126     /* Read the node tag and handle NULL nodes */
127     unsigned char Op = Read8 (F);
128     if (Op == EXPR_NULL) {
129         return;
130     }
131
132     /* Check the tag and handle the different expression types */
133     if (EXPR_IS_LEAF (Op)) {
134         switch (Op) {
135
136             case EXPR_LITERAL:
137                 (void) Read32Signed (F);
138                 break;
139
140             case EXPR_SYMBOL:
141                 /* Read the import number */
142                 (void) ReadVar (F);
143                 break;
144
145             case EXPR_SECTION:
146                 /* Read the segment number */
147                 (void) Read8 (F);
148                 break;
149
150             default:
151                 Error ("Invalid expression op: %02X", Op);
152
153         }
154
155     } else {
156
157         /* Not a leaf node */
158         SkipExpr (F);
159         SkipExpr (F);
160     }
161 }
162
163
164
165 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
166 /* Get the export flags as a (static) string */
167 {
168     /* Static buffer */
169     static char TypeDesc[256];
170     static char* T;
171
172     unsigned Count;
173     unsigned I;
174
175     /* Type of expression */
176     TypeDesc[0] = '\0';
177     switch (Flags & EXP_MASK_VAL) {
178         case EXP_CONST: strcat (TypeDesc, "EXP_CONST"); break;
179         case EXP_EXPR:  strcat (TypeDesc, "EXP_EXPR");  break;
180     }
181
182     /* Constructor/destructor declarations */
183     T = TypeDesc + strlen (TypeDesc);
184     Count = GET_EXP_CONDES_COUNT (Flags);
185     if (Count > 0 && ConDes) {
186         T += sprintf (T, ",EXP_CONDES=");
187         for (I = 0; I < Count; ++I) {
188             unsigned Type = CD_GET_TYPE (ConDes[I]);
189             unsigned Prio = CD_GET_PRIO (ConDes[I]);
190             if (I > 0) {
191                 *T++ = ',';
192             }
193             T += sprintf (T, "[%u,%u]", Type, Prio);
194         }
195     }
196
197     /* Return the result */
198     return TypeDesc;
199 }
200
201
202
203 void DumpObjHeader (FILE* F, unsigned long Offset)
204 /* Dump the header of the given object file */
205 {
206     ObjHeader H;
207
208     /* Seek to the header position */
209     FileSetPos (F, Offset);
210
211     /* Read the header */
212     ReadObjHeader (F, &H);
213
214     /* Now dump the information */
215
216     /* Output a header */
217     printf ("  Header:\n");
218
219     /* Magic */
220     printf ("    Magic:%17s0x%08lX\n", "", H.Magic);
221
222     /* Version */
223     printf ("    Version:%25u\n", H.Version);
224
225     /* Flags */
226     printf ("    Flags:%21s0x%04X  (", "", H.Flags);
227     if (H.Flags & OBJ_FLAGS_DBGINFO) {
228         printf ("OBJ_FLAGS_DBGINFO");
229     }
230     printf (")\n");
231
232     /* Options */
233     DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
234
235     /* Files */
236     DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
237
238     /* Segments */
239     DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
240
241     /* Imports */
242     DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
243
244     /* Exports */
245     DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
246
247     /* Debug symbols */
248     DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
249
250     /* Line infos */
251     DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
252
253     /* String pool */
254     DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
255 }
256
257
258
259 void DumpObjOptions (FILE* F, unsigned long Offset)
260 /* Dump the file options */
261 {
262     ObjHeader  H;
263     Collection StrPool = AUTO_COLLECTION_INITIALIZER;
264     unsigned   Count;
265     unsigned   I;
266
267     /* Seek to the header position and read the header */
268     FileSetPos (F, Offset);
269     ReadObjHeader (F, &H);
270
271     /* Seek to the start of the string pool and read it */
272     FileSetPos (F, Offset + H.StrPoolOffs);
273     ReadStrPool (F, &StrPool);
274
275     /* Seek to the start of the options */
276     FileSetPos (F, Offset + H.OptionOffs);
277
278     /* Output a header */
279     printf ("  Options:\n");
280
281     /* Read the number of options and print it */
282     Count = ReadVar (F);
283     printf ("    Count:%27u\n", Count);
284
285     /* Read and print all options */
286     for (I = 0; I < Count; ++I) {
287
288         const char*   ArgStr;
289         unsigned      ArgLen;
290
291         /* Read the type of the option and the value */
292         unsigned char Type = Read8 (F);
293         unsigned long Val  = ReadVar (F);
294
295         /* Get the type of the argument */
296         unsigned char ArgType = Type & OPT_ARGMASK;
297
298         /* Determine which option follows */
299         const char* TypeDesc;
300         switch (Type) {
301             case OPT_COMMENT:   TypeDesc = "OPT_COMMENT";       break;
302             case OPT_AUTHOR:    TypeDesc = "OPT_AUTHOR";        break;
303             case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR";    break;
304             case OPT_COMPILER:  TypeDesc = "OPT_COMPILER";      break;
305             case OPT_OS:        TypeDesc = "OPT_OS";            break;
306             case OPT_DATETIME:  TypeDesc = "OPT_DATETIME";      break;
307             default:            TypeDesc = "OPT_UNKNOWN";       break;
308         }
309
310         /* Print the header */
311         printf ("    Index:%27u\n", I);
312
313         /* Print the data */
314         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, TypeDesc);
315         switch (ArgType) {
316
317             case OPT_ARGSTR:
318                 ArgStr = GetString (&StrPool, Val);
319                 ArgLen = strlen (ArgStr);
320                 printf ("      Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
321                 break;
322
323             case OPT_ARGNUM:
324                 printf ("      Data:%26lu", Val);
325                 if (Type == OPT_DATETIME) {
326                     /* Print the time as a string */
327                     printf ("  (%s)", TimeToStr (Val));
328                 }
329                 printf ("\n");
330                 break;
331
332             default:
333                 /* Unknown argument type. This means that we cannot determine
334                  * the option length, so we cannot proceed.
335                  */
336                 Error ("Unknown option type: 0x%02X", Type);
337                 break;
338         }
339     }
340
341     /* Destroy the string pool */
342     DestroyStrPool (&StrPool);
343 }
344
345
346
347 void DumpObjFiles (FILE* F, unsigned long Offset)
348 /* Dump the source files */
349 {
350     ObjHeader  H;
351     Collection StrPool = AUTO_COLLECTION_INITIALIZER;
352     unsigned   Count;
353     unsigned   I;
354
355     /* Seek to the header position and read the header */
356     FileSetPos (F, Offset);
357     ReadObjHeader (F, &H);
358
359     /* Seek to the start of the string pool and read it */
360     FileSetPos (F, Offset + H.StrPoolOffs);
361     ReadStrPool (F, &StrPool);
362
363     /* Seek to the start of the source files */
364     FileSetPos (F, Offset + H.FileOffs);
365
366     /* Output a header */
367     printf ("  Files:\n");
368
369     /* Read the number of files and print it */
370     Count = ReadVar (F);
371     printf ("    Count:%27u\n", Count);
372
373     /* Read and print all files */
374     for (I = 0; I < Count; ++I) {
375
376         /* Read the data for one file */
377         const char*   Name  = GetString (&StrPool, ReadVar (F));
378         unsigned long MTime = Read32 (F);
379         unsigned long Size  = Read32 (F);
380         unsigned      Len   = strlen (Name);
381
382         /* Print the header */
383         printf ("    Index:%27u\n", I);
384
385         /* Print the data */
386         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
387         printf ("      Size:%26lu\n", Size);
388         printf ("      Modification time:%13lu  (%s)\n", MTime, TimeToStr (MTime));
389     }
390
391     /* Destroy the string pool */
392     DestroyStrPool (&StrPool);
393 }
394
395
396
397 void DumpObjSegments (FILE* F, unsigned long Offset)
398 /* Dump the segments in the object file */
399 {
400     ObjHeader  H;
401     Collection StrPool = AUTO_COLLECTION_INITIALIZER;
402     unsigned   Count;
403     unsigned   I;
404
405     /* Seek to the header position and read the header */
406     FileSetPos (F, Offset);
407     ReadObjHeader (F, &H);
408
409     /* Seek to the start of the string pool and read it */
410     FileSetPos (F, Offset + H.StrPoolOffs);
411     ReadStrPool (F, &StrPool);
412
413     /* Seek to the start of the segments */
414     FileSetPos (F, Offset + H.SegOffs);
415
416     /* Output a header */
417     printf ("  Segments:\n");
418
419     /* Read the number of segments and print it */
420     Count = ReadVar (F);
421     printf ("    Count:%27u\n", Count);
422
423     /* Read and print all segments */
424     for (I = 0; I < Count; ++I) {
425
426         /* Read the data for one segments */
427         unsigned long DataSize  = Read32 (F);
428         unsigned long NextSeg   = ftell (F) + DataSize;
429         const char*   Name      = GetString (&StrPool, ReadVar (F));
430         unsigned      Len       = strlen (Name);
431         unsigned long Size      = Read32 (F);
432         unsigned      Align     = (1U << Read8 (F));
433         unsigned char AddrSize  = Read8 (F);
434         unsigned long FragCount = ReadVar (F);
435
436         /* Print the header */
437         printf ("    Index:%27u\n", I);
438
439         /* Print the data */
440         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
441         printf ("      Size:%26lu\n", Size);
442         printf ("      Alignment:%21u\n", Align);
443         printf ("      Address size:%14s0x%02X  (%s)\n", "", AddrSize,
444                 AddrSizeToStr (AddrSize));
445         printf ("      Fragment count:%16lu\n", FragCount);
446
447         /* Seek to the end of the segment data (start of next) */
448         FileSetPos (F, NextSeg);
449     }
450
451     /* Destroy the string pool */
452     DestroyStrPool (&StrPool);
453 }
454
455
456
457 void DumpObjImports (FILE* F, unsigned long Offset)
458 /* Dump the imports in the object file */
459 {
460     ObjHeader  H;
461     Collection StrPool = AUTO_COLLECTION_INITIALIZER;
462     unsigned   Count;
463     unsigned   I;
464     FilePos    Pos;
465
466     /* Seek to the header position and read the header */
467     FileSetPos (F, Offset);
468     ReadObjHeader (F, &H);
469
470     /* Seek to the start of the string pool and read it */
471     FileSetPos (F, Offset + H.StrPoolOffs);
472     ReadStrPool (F, &StrPool);
473
474     /* Seek to the start of the imports */
475     FileSetPos (F, Offset + H.ImportOffs);
476
477     /* Output a header */
478     printf ("  Imports:\n");
479
480     /* Read the number of imports and print it */
481     Count = ReadVar (F);
482     printf ("    Count:%27u\n", Count);
483
484     /* Read and print all imports */
485     for (I = 0; I < Count; ++I) {
486
487         /* Read the data for one import */
488         unsigned char AddrSize = Read8 (F);
489         const char*   Name     = GetString (&StrPool, ReadVar (F));
490         unsigned      Len      = strlen (Name);
491         ReadFilePos (F, &Pos);
492
493         /* Print the header */
494         printf ("    Index:%27u\n", I);
495
496         /* Print the data */
497         printf ("      Address size:%14s0x%02X  (%s)\n", "", AddrSize,
498                 AddrSizeToStr (AddrSize));
499         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
500     }
501
502     /* Destroy the string pool */
503     DestroyStrPool (&StrPool);
504 }
505
506
507
508 void DumpObjExports (FILE* F, unsigned long Offset)
509 /* Dump the exports in the object file */
510 {
511     ObjHeader   H;
512     Collection  StrPool = AUTO_COLLECTION_INITIALIZER;
513     unsigned    Count;
514     unsigned    I;
515     FilePos     Pos;
516
517     /* Seek to the header position and read the header */
518     FileSetPos (F, Offset);
519     ReadObjHeader (F, &H);
520
521     /* Seek to the start of the string pool and read it */
522     FileSetPos (F, Offset + H.StrPoolOffs);
523     ReadStrPool (F, &StrPool);
524
525     /* Seek to the start of the exports */
526     FileSetPos (F, Offset + H.ExportOffs);
527
528     /* Output a header */
529     printf ("  Exports:\n");
530
531     /* Read the number of exports and print it */
532     Count = ReadVar (F);
533     printf ("    Count:%27u\n", Count);
534
535     /* Read and print all exports */
536     for (I = 0; I < Count; ++I) {
537
538         unsigned long   Value = 0;
539         int             HaveValue;
540         unsigned char   ConDes [CD_TYPE_COUNT];
541         const char*     Name;
542         unsigned        Len;
543
544
545         /* Read the data for one export */
546         unsigned char Type = Read8 (F);
547         unsigned char AddrSize = Read8 (F);
548         ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
549         Name  = GetString (&StrPool, ReadVar (F));
550         Len   = strlen (Name);
551         if (IS_EXP_EXPR (Type)) {
552             SkipExpr (F);
553             HaveValue = 0;
554         } else {
555             Value = Read32 (F);
556             HaveValue = 1;
557         }
558         ReadFilePos (F, &Pos);
559
560         /* Print the header */
561         printf ("    Index:%27u\n", I);
562
563         /* Print the data */
564         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, GetExportFlags (Type, ConDes));
565         printf ("      Address size:%14s0x%02X  (%s)\n", "", AddrSize,
566                 AddrSizeToStr (AddrSize));
567         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
568         if (HaveValue) {
569             printf ("      Value:%15s0x%08lX  (%lu)\n", "", Value, Value);
570         }
571     }
572
573     /* Destroy the string pool */
574     DestroyStrPool (&StrPool);
575 }
576
577
578
579 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
580 /* Dump the debug symbols from an object file */
581 {
582     ObjHeader   H;
583     Collection  StrPool = AUTO_COLLECTION_INITIALIZER;
584     unsigned    Count;
585     unsigned    I;
586     FilePos     Pos;
587
588     /* Seek to the header position and read the header */
589     FileSetPos (F, Offset);
590     ReadObjHeader (F, &H);
591
592     /* Seek to the start of the string pool and read it */
593     FileSetPos (F, Offset + H.StrPoolOffs);
594     ReadStrPool (F, &StrPool);
595
596     /* Seek to the start of the debug syms */
597     FileSetPos (F, Offset + H.DbgSymOffs);
598
599     /* Output a header */
600     printf ("  Debug symbols:\n");
601
602     /* Check if the object file was compiled with debug info */
603     if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
604         /* Print that there no debug symbols and bail out */
605         printf ("    Count:%27u\n", 0);
606         return;
607     }
608
609     /* Read the number of exports and print it */
610     Count = ReadVar (F);
611     printf ("    Count:%27u\n", Count);
612
613     /* Read and print all debug symbols */
614     for (I = 0; I < Count; ++I) {
615
616         unsigned long   Value = 0;
617         int             HaveValue;
618
619         /* Read the data for one symbol */
620         unsigned char Type     = Read8 (F);
621         unsigned char AddrSize = Read8 (F);
622         const char*   Name     = GetString (&StrPool, ReadVar (F));
623         unsigned      Len      = strlen (Name);
624         if (IS_EXP_EXPR (Type)) {
625             SkipExpr (F);
626             HaveValue = 0;
627         } else {
628             Value = Read32 (F);
629             HaveValue = 1;
630         }
631         ReadFilePos (F, &Pos);
632
633         /* Print the header */
634         printf ("    Index:%27u\n", I);
635
636         /* Print the data */
637         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, GetExportFlags (Type, 0));
638         printf ("      Address size:%14s0x%02X  (%s)\n", "", AddrSize,
639                 AddrSizeToStr (AddrSize));
640         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
641         if (HaveValue) {
642             printf ("      Value:%15s0x%08lX  (%lu)\n", "", Value, Value);
643         }
644     }
645
646     /* Destroy the string pool */
647     DestroyStrPool (&StrPool);
648 }
649
650
651
652 void DumpObjLineInfo (FILE* F, unsigned long Offset)
653 /* Dump the line info from an object file */
654 {
655     ObjHeader   H;
656     Collection  StrPool = AUTO_COLLECTION_INITIALIZER;
657     unsigned    Count;
658     unsigned    I;
659
660     /* Seek to the header position and read the header */
661     FileSetPos (F, Offset);
662     ReadObjHeader (F, &H);
663
664     /* Seek to the start of the string pool and read it */
665     FileSetPos (F, Offset + H.StrPoolOffs);
666     ReadStrPool (F, &StrPool);
667
668     /* Seek to the start of line infos */
669     FileSetPos (F, Offset + H.LineInfoOffs);
670
671     /* Output a header */
672     printf ("  Line info:\n");
673
674     /* Check if the object file was compiled with debug info */
675     if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
676         /* Print that there no line infos and bail out */
677         printf ("    Count:%27u\n", 0);
678         return;
679     }
680
681     /* Read the number of line infos and print it */
682     Count = ReadVar (F);
683     printf ("    Count:%27u\n", Count);
684
685     /* Read and print all line infos */
686     for (I = 0; I < Count; ++I) {
687
688         FilePos   Pos;
689
690         /* Read one line info */
691         ReadFilePos (F, &Pos);
692
693         /* Print the header */
694         printf ("    Index:%27u\n", I);
695
696         /* Print the data */
697         printf ("      Line:%26lu\n", Pos.Line);
698         printf ("      Col:%27u\n", Pos.Col);
699         printf ("      Name:%26u\n", Pos.Name);
700     }
701
702     /* Destroy the string pool */
703     DestroyStrPool (&StrPool);
704 }
705
706
707
708 void DumpObjSegSize (FILE* F, unsigned long Offset)
709 /* Dump the sizes of the segment in the object file */
710 {
711     ObjHeader   H;
712     Collection  StrPool = AUTO_COLLECTION_INITIALIZER;
713     unsigned    Count;
714
715     /* Seek to the header position and read the header */
716     FileSetPos (F, Offset);
717     ReadObjHeader (F, &H);
718
719     /* Seek to the start of the string pool and read it */
720     FileSetPos (F, Offset + H.StrPoolOffs);
721     ReadStrPool (F, &StrPool);
722
723     /* Seek to the start of the segments */
724     FileSetPos (F, Offset + H.SegOffs);
725
726     /* Output a header */
727     printf ("  Segment sizes:\n");
728
729     /* Read the number of segments */
730     Count = ReadVar (F);
731
732     /* Read and print the sizes of all segments */
733     while (Count--) {
734
735         /* Read the data for one segments */
736         unsigned long DataSize = Read32 (F);
737         unsigned long NextSeg  = ftell (F) + DataSize;
738         const char*   Name     = GetString (&StrPool, ReadVar (F));
739         unsigned      Len      = strlen (Name);
740         unsigned long Size     = Read32 (F);
741
742         /* Skip alignment, type and fragment count */
743         (void) Read8 (F);
744         (void) Read8 (F);
745         (void) ReadVar (F);
746
747         /* Print the size for this segment */
748         printf ("    %s:%*s%6lu\n", Name, 24-Len, "", Size);
749
750         /* Seek to the end of the segment data (start of next) */
751         FileSetPos (F, NextSeg);
752     }
753
754     /* Destroy the string pool */
755     DestroyStrPool (&StrPool);
756 }
757
758
759