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