]> git.sur5r.net Git - cc65/blob - src/od65/dump.c
Error message for negative array sizes.
[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-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 "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_SECTION:
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     /* Skip the additional line info */
195     (void) ReadVar (F);
196
197     /* Return the size */
198     return Size;
199 }
200
201
202
203 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
204 /* Get the export flags as a (static) string */
205 {
206     /* Static buffer */
207     static char TypeDesc[256];
208     static char* T;
209
210     unsigned Count;
211     unsigned I;
212
213     /* Adressing mode */
214     TypeDesc[0] = '\0';
215     switch (Flags & EXP_MASK_SIZE) {
216         case EXP_ABS:   strcat (TypeDesc, "EXP_ABS");           break;
217         case EXP_ZP:    strcat (TypeDesc, "EXP_ZP");            break;
218     }
219
220     /* Type of expression */
221     switch (Flags & EXP_MASK_VAL) {
222         case EXP_CONST: strcat (TypeDesc, ",EXP_CONST");        break;
223         case EXP_EXPR:  strcat (TypeDesc, ",EXP_EXPR");         break;
224     }
225
226     /* Constructor/destructor declarations */
227     T = TypeDesc + strlen (TypeDesc);
228     Count = GET_EXP_CONDES_COUNT (Flags);
229     if (Count > 0) {
230         T += sprintf (T, ",EXP_CONDES=");
231         for (I = 0; I < Count; ++I) {
232             unsigned Type = CD_GET_TYPE (ConDes[I]);
233             unsigned Prio = CD_GET_PRIO (ConDes[I]);
234             if (I > 0) {
235                 *T++ = ',';
236             }
237             T += sprintf (T, "[%u,%u]", Type, Prio);
238         }
239     }
240
241     /* Return the result */
242     return TypeDesc;
243 }
244
245
246
247 void DumpObjHeader (FILE* F, unsigned long Offset)
248 /* Dump the header of the given object file */
249 {
250     ObjHeader H;
251
252     /* Seek to the header position */
253     FileSeek (F, Offset);
254
255     /* Read the header */
256     ReadObjHeader (F, &H);
257
258     /* Now dump the information */
259
260     /* Output a header */
261     printf ("  Header:\n");
262
263     /* Magic */
264     printf ("    Magic:%17s0x%08lX\n", "", H.Magic);
265
266     /* Version */
267     printf ("    Version:%25u\n", H.Version);
268
269     /* Flags */
270     printf ("    Flags:%21s0x%04X  (", "", H.Flags);
271     if (H.Flags & OBJ_FLAGS_DBGINFO) {
272         printf ("OBJ_FLAGS_DBGINFO");
273     }
274     printf (")\n");
275
276     /* Options */
277     DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
278
279     /* Files */
280     DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
281
282     /* Segments */
283     DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
284
285     /* Imports */
286     DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
287
288     /* Exports */
289     DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
290
291     /* Debug symbols */
292     DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
293 }
294
295
296
297 void DumpObjOptions (FILE* F, unsigned long Offset)
298 /* Dump the file options */
299 {
300     ObjHeader H;
301     unsigned Count;
302     unsigned I;
303
304     /* Seek to the header position */
305     FileSeek (F, Offset);
306
307     /* Read the header */
308     ReadObjHeader (F, &H);
309
310     /* Seek to the start of the options */
311     FileSeek (F, Offset + H.OptionOffs);
312
313     /* Output a header */
314     printf ("  Options:\n");
315
316     /* Read the number of options and print it */
317     Count = ReadVar (F);
318     printf ("    Count:%27u\n", Count);
319
320     /* Read and print all options */
321     for (I = 0; I < Count; ++I) {
322
323         unsigned long ArgNum;
324         char*         ArgStr;
325         unsigned      ArgLen;
326
327         /* Read the type of the option */
328         unsigned char Type = Read8 (F);
329
330         /* Get the type of the argument */
331         unsigned char ArgType = Type & OPT_ARGMASK;
332
333         /* Determine which option follows */
334         const char* TypeDesc;
335         switch (Type) {
336             case OPT_COMMENT:   TypeDesc = "OPT_COMMENT";       break;
337             case OPT_AUTHOR:    TypeDesc = "OPT_AUTHOR";        break;
338             case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR";    break;
339             case OPT_COMPILER:  TypeDesc = "OPT_COMPILER";      break;
340             case OPT_OS:        TypeDesc = "OPT_OS";            break;
341             case OPT_DATETIME:  TypeDesc = "OPT_DATETIME";      break;
342             default:            TypeDesc = "OPT_UNKNOWN";       break;
343         }
344
345         /* Print the header */
346         printf ("    Index:%27u\n", I);
347
348         /* Print the data */
349         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, TypeDesc);
350         switch (ArgType) {
351
352             case OPT_ARGSTR:
353                 ArgStr = ReadStr (F);
354                 ArgLen = strlen (ArgStr);
355                 printf ("      Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
356                 xfree (ArgStr);
357                 break;
358
359             case OPT_ARGNUM:
360                 ArgNum = Read32 (F);
361                 printf ("      Data:%26lu", ArgNum);
362                 if (Type == OPT_DATETIME) {
363                     /* Print the time as a string */
364                     printf ("  (%s)", TimeToStr (ArgNum));
365                 }
366                 printf ("\n");
367                 break;
368
369             default:
370                 /* Unknown argument type. This means that we cannot determine
371                  * the option length, so we cannot proceed.
372                  */
373                 Error ("Unknown option type: 0x%02X", Type);
374                 break;
375         }
376     }
377 }
378
379
380
381 void DumpObjFiles (FILE* F, unsigned long Offset)
382 /* Dump the source files */
383 {
384     ObjHeader H;
385     unsigned Count;
386     unsigned I;
387
388     /* Seek to the header position */
389     FileSeek (F, Offset);
390
391     /* Read the header */
392     ReadObjHeader (F, &H);
393
394     /* Seek to the start of the source files */
395     FileSeek (F, Offset + H.FileOffs);
396
397     /* Output a header */
398     printf ("  Files:\n");
399
400     /* Read the number of files and print it */
401     Count = ReadVar (F);
402     printf ("    Count:%27u\n", Count);
403
404     /* Read and print all files */
405     for (I = 0; I < Count; ++I) {
406
407         /* Read the data for one file */
408         unsigned long MTime = Read32 (F);
409         unsigned long Size  = Read32 (F);
410         char*         Name  = ReadStr (F);
411         unsigned      Len   = strlen (Name);
412
413         /* Print the header */
414         printf ("    Index:%27u\n", I);
415
416         /* Print the data */
417         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
418         printf ("      Size:%26lu\n", Size);
419         printf ("      Modification time:%13lu  (%s)\n", MTime, TimeToStr (MTime));
420
421         /* Free the Name */
422         xfree (Name);
423     }
424 }
425
426
427
428 void DumpObjSegments (FILE* F, unsigned long Offset)
429 /* Dump the segments in the object file */
430 {
431     ObjHeader H;
432     unsigned Count;
433     unsigned I;
434     unsigned FragCount;
435
436     /* Seek to the header position */
437     FileSeek (F, Offset);
438
439     /* Read the header */
440     ReadObjHeader (F, &H);
441
442     /* Seek to the start of the segments */
443     FileSeek (F, Offset + H.SegOffs);
444
445     /* Output a header */
446     printf ("  Segments:\n");
447
448     /* Read the number of segments and print it */
449     Count = ReadVar (F);
450     printf ("    Count:%27u\n", Count);
451
452     /* Read and print all segments */
453     for (I = 0; I < Count; ++I) {
454
455         /* Read the data for one segments */
456         char*         Name  = ReadStr (F);
457         unsigned      Len   = strlen (Name);
458         unsigned long Size  = Read32 (F);
459         unsigned      Align = (1U << Read8 (F));
460         unsigned char Type  = Read8 (F);
461
462         /* Get the description for the type */
463         const char* TypeDesc;
464         switch (Type) {
465             case SEGTYPE_DEFAULT:       TypeDesc = "SEGTYPE_DEFAULT";   break;
466             case SEGTYPE_ABS:           TypeDesc = "SEGTYPE_ABS";       break;
467             case SEGTYPE_ZP:            TypeDesc = "SEGTYPE_ZP";        break;
468             case SEGTYPE_FAR:           TypeDesc = "SEGTYPE_FAR";       break;
469             default:                    TypeDesc = "SEGTYPE_UNKNOWN";   break;
470         }
471
472         /* Print the header */
473         printf ("    Index:%27u\n", I);
474
475         /* Print the data */
476         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
477         printf ("      Size:%26lu\n", Size);
478         printf ("      Alignment:%21u\n", Align);
479         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, TypeDesc);
480
481         /* Free the Name */
482         xfree (Name);
483
484         /* Skip the fragments for this segment, counting them */
485         FragCount = 0;
486         while (Size > 0) {
487             unsigned FragSize = SkipFragment (F);
488             if (FragSize > Size) {
489                 /* OOPS - file data invalid */
490                 Error ("Invalid fragment data - file corrupt!");
491             }
492             Size -= FragSize;
493             ++FragCount;
494         }
495
496         /* Print the fragment count */
497         printf ("      Fragment count:%16u\n", FragCount);
498     }
499 }
500
501
502
503 void DumpObjImports (FILE* F, unsigned long Offset)
504 /* Dump the imports in the object file */
505 {
506     ObjHeader H;
507     unsigned  Count;
508     unsigned  I;
509     FilePos   Pos;
510
511     /* Seek to the header position */
512     FileSeek (F, Offset);
513
514     /* Read the header */
515     ReadObjHeader (F, &H);
516
517     /* Seek to the start of the imports */
518     FileSeek (F, Offset + H.ImportOffs);
519
520     /* Output a header */
521     printf ("  Imports:\n");
522
523     /* Read the number of imports and print it */
524     Count = ReadVar (F);
525     printf ("    Count:%27u\n", Count);
526
527     /* Read and print all imports */
528     for (I = 0; I < Count; ++I) {
529
530         const char* TypeDesc;
531
532         /* Read the data for one import */
533         unsigned char Type  = Read8 (F);
534         char*         Name  = ReadStr (F);
535         unsigned      Len   = strlen (Name);
536         ReadFilePos (F, &Pos);
537
538         /* Get a description for the type */
539         switch (Type) {
540             case IMP_ZP:        TypeDesc = "IMP_ZP";            break;
541             case IMP_ABS:       TypeDesc = "IMP_ABS";           break;
542             default:            TypeDesc = "IMP_UNKNOWN";       break;
543         }
544
545         /* Print the header */
546         printf ("    Index:%27u\n", I);
547
548         /* Print the data */
549         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, TypeDesc);
550         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
551
552         /* Free the Name */
553         xfree (Name);
554     }
555 }
556
557
558
559 void DumpObjExports (FILE* F, unsigned long Offset)
560 /* Dump the exports in the object file */
561 {
562     ObjHeader     H;
563     unsigned      Count;
564     unsigned      I;
565     FilePos       Pos;
566
567     /* Seek to the header position */
568     FileSeek (F, Offset);
569
570     /* Read the header */
571     ReadObjHeader (F, &H);
572
573     /* Seek to the start of the exports */
574     FileSeek (F, Offset + H.ExportOffs);
575
576     /* Output a header */
577     printf ("  Exports:\n");
578
579     /* Read the number of exports and print it */
580     Count = ReadVar (F);
581     printf ("    Count:%27u\n", Count);
582
583     /* Read and print all exports */
584     for (I = 0; I < Count; ++I) {
585
586         unsigned long   Value = 0;
587         int             HaveValue;
588         unsigned char   Type;
589         unsigned char   ConDes [CD_TYPE_COUNT];
590         char*           Name;
591         unsigned        Len;
592
593
594         /* Read the data for one export */
595         Type  = Read8 (F);
596         ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
597         Name  = ReadStr (F);
598         Len   = strlen (Name);
599         if (IS_EXP_EXPR (Type)) {
600             SkipExpr (F);
601             HaveValue = 0;
602         } else {
603             Value = Read32 (F);
604             HaveValue = 1;
605         }
606         ReadFilePos (F, &Pos);
607
608         /* Print the header */
609         printf ("    Index:%27u\n", I);
610
611         /* Print the data */
612         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, GetExportFlags (Type, ConDes));
613         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
614         if (HaveValue) {
615             printf ("      Value:%15s0x%08lX  (%lu)\n", "", Value, Value);
616         }
617
618         /* Free the Name */
619         xfree (Name);
620     }
621 }
622
623
624
625 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
626 /* Dump the debug symbols from an object file */
627 {
628     ObjHeader H;
629     unsigned  Count;
630     unsigned  I;
631     FilePos   Pos;
632
633     /* Seek to the header position */
634     FileSeek (F, Offset);
635
636     /* Read the header */
637     ReadObjHeader (F, &H);
638
639     /* Seek to the start of the debug syms */
640     FileSeek (F, Offset + H.DbgSymOffs);
641
642     /* Output a header */
643     printf ("  Debug symbols:\n");
644
645     /* Check if the object file was compiled with debug info */
646     if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
647         /* Print that there no debug symbols and bail out */
648         printf ("    Count:%27u\n", 0);
649         return;
650     }
651
652     /* Read the number of exports and print it */
653     Count = ReadVar (F);
654     printf ("    Count:%27u\n", Count);
655
656     /* Read and print all debug symbols */
657     for (I = 0; I < Count; ++I) {
658
659         unsigned long   Value = 0;
660         int             HaveValue;
661         unsigned char   Type;
662         unsigned char   ConDes [CD_TYPE_COUNT];
663         char*           Name;
664         unsigned        Len;
665
666         /* Read the data for one symbol */
667         Type  = Read8 (F);
668         ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
669         Name  = ReadStr (F);
670         Len   = strlen (Name);
671         if (IS_EXP_EXPR (Type)) {
672             SkipExpr (F);
673             HaveValue = 0;
674         } else {
675             Value = Read32 (F);
676             HaveValue = 1;
677         }
678         ReadFilePos (F, &Pos);
679
680         /* Print the header */
681         printf ("    Index:%27u\n", I);
682
683         /* Print the data */
684         printf ("      Type:%22s0x%02X  (%s)\n", "", Type, GetExportFlags (Type, ConDes));
685         printf ("      Name:%*s\"%s\"\n", 24-Len, "", Name);
686         if (HaveValue) {
687             printf ("      Value:%15s0x%08lX  (%lu)\n", "", Value, Value);
688         }
689
690         /* Free the Name */
691         xfree (Name);
692     }
693 }
694
695
696
697 void DumpObjLineInfo (FILE* F, unsigned long Offset)
698 /* Dump the line info from an object file */
699 {
700     ObjHeader H;
701     unsigned  Count;
702     unsigned  I;
703
704     /* Seek to the header position */
705     FileSeek (F, Offset);
706
707     /* Read the header */
708     ReadObjHeader (F, &H);
709
710     /* Seek to the start of line infos */
711     FileSeek (F, Offset + H.LineInfoOffs);
712
713     /* Output a header */
714     printf ("  Line info:\n");
715
716     /* Check if the object file was compiled with debug info */
717     if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
718         /* Print that there no line infos and bail out */
719         printf ("    Count:%27u\n", 0);
720         return;
721     }
722
723     /* Read the number of line infos and print it */
724     Count = ReadVar (F);
725     printf ("    Count:%27u\n", Count);
726
727     /* Read and print all line infos */
728     for (I = 0; I < Count; ++I) {
729
730         FilePos   Pos;
731
732         /* Read one line info */
733         ReadFilePos (F, &Pos);
734
735         /* Print the header */
736         printf ("    Index:%27u\n", I);
737
738         /* Print the data */
739         printf ("      Line:%26lu\n", Pos.Line);
740         printf ("      Col:%27u\n", Pos.Col);
741         printf ("      Name:%26u\n", Pos.Name);
742     }
743 }
744
745
746
747 void DumpObjSegSize (FILE* F, unsigned long Offset)
748 /* Dump the sizes of the segment in the object file */
749 {
750     ObjHeader H;
751     unsigned Count;
752
753     /* Seek to the header position */
754     FileSeek (F, Offset);
755
756     /* Read the header */
757     ReadObjHeader (F, &H);
758
759     /* Seek to the start of the segments */
760     FileSeek (F, Offset + H.SegOffs);
761
762     /* Output a header */
763     printf ("  Segment sizes:\n");
764
765     /* Read the number of segments */
766     Count = ReadVar (F);
767
768     /* Read and print the sizes of all segments */
769     while (Count--) {
770
771         /* Read the data for one segments */
772         char*         Name  = ReadStr (F);
773         unsigned      Len   = strlen (Name);
774         unsigned long Size  = Read32 (F);
775
776         /* Skip alignment and type */
777         (void) Read8 (F);
778         (void) Read8 (F);
779
780         /* Print the size for this segment */
781         printf ("    %s:%*s%6lu\n", Name, 24-Len, "", Size);
782
783         /* Free the Name */
784         xfree (Name);
785
786         /* Skip the fragments for this segment, counting them */
787         while (Size > 0) {
788             unsigned FragSize = SkipFragment (F);
789             if (FragSize > Size) {
790                 /* OOPS - file data invalid */
791                 Error ("Invalid fragment data - file corrupt!");
792             }
793             Size -= FragSize;
794         }
795     }
796 }
797
798
799