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