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