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