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