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