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