1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2002-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
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.
70 for (I = 0; I < CollCount (C); ++I) {
71 xfree (CollAtUnchecked (C, I));
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
84 if (Index >= CollCount (C)) {
85 Error ("Invalid string index (%u) - file corrupt!", Index);
87 return CollConstAt (C, Index);
92 static void DumpObjHeaderSection (const char* Name,
95 /* Dump a header section */
97 printf (" %s:\n", Name);
98 printf (" Offset:%24lu\n", Offset);
99 printf (" Size: %24lu\n", Size);
104 static char* TimeToStr (unsigned long Time)
105 /* Convert the time into a string and return it */
107 /* Get the time and convert to string */
108 time_t T = (time_t) Time;
109 char* S = asctime (localtime (&T));
111 /* Remove the trailing newline */
112 unsigned Len = strlen (S);
113 if (Len > 0 && S[Len-1] == '\n') {
117 /* Return the time string */
123 static void SkipExpr (FILE* F)
124 /* Skip an expression from the given file */
126 /* Read the node tag and handle NULL nodes */
127 unsigned char Op = Read8 (F);
128 if (Op == EXPR_NULL) {
132 /* Check the tag and handle the different expression types */
133 if (EXPR_IS_LEAF (Op)) {
137 (void) Read32Signed (F);
141 /* Read the import number */
146 /* Read the segment number */
151 Error ("Invalid expression op: %02X", Op);
157 /* Not a leaf node */
165 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
166 /* Get the export flags as a (static) string */
169 static char TypeDesc[256];
175 /* Type of expression */
177 switch (Flags & EXP_MASK_VAL) {
178 case EXP_CONST: strcat (TypeDesc, "EXP_CONST"); break;
179 case EXP_EXPR: strcat (TypeDesc, "EXP_EXPR"); break;
182 /* Constructor/destructor declarations */
183 T = TypeDesc + strlen (TypeDesc);
184 Count = GET_EXP_CONDES_COUNT (Flags);
185 if (Count > 0 && ConDes) {
186 T += sprintf (T, ",EXP_CONDES=");
187 for (I = 0; I < Count; ++I) {
188 unsigned Type = CD_GET_TYPE (ConDes[I]);
189 unsigned Prio = CD_GET_PRIO (ConDes[I]);
193 T += sprintf (T, "[%u,%u]", Type, Prio);
197 /* Return the result */
203 void DumpObjHeader (FILE* F, unsigned long Offset)
204 /* Dump the header of the given object file */
208 /* Seek to the header position */
209 FileSetPos (F, Offset);
211 /* Read the header */
212 ReadObjHeader (F, &H);
214 /* Now dump the information */
216 /* Output a header */
217 printf (" Header:\n");
220 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
223 printf (" Version:%25u\n", H.Version);
226 printf (" Flags:%21s0x%04X (", "", H.Flags);
227 if (H.Flags & OBJ_FLAGS_DBGINFO) {
228 printf ("OBJ_FLAGS_DBGINFO");
233 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
236 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
239 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
242 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
245 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
248 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
251 DumpObjHeaderSection ("Line infos", H.LineInfoOffs, H.LineInfoSize);
254 DumpObjHeaderSection ("String pool", H.StrPoolOffs, H.StrPoolSize);
259 void DumpObjOptions (FILE* F, unsigned long Offset)
260 /* Dump the file options */
263 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
267 /* Seek to the header position and read the header */
268 FileSetPos (F, Offset);
269 ReadObjHeader (F, &H);
271 /* Seek to the start of the string pool and read it */
272 FileSetPos (F, Offset + H.StrPoolOffs);
273 ReadStrPool (F, &StrPool);
275 /* Seek to the start of the options */
276 FileSetPos (F, Offset + H.OptionOffs);
278 /* Output a header */
279 printf (" Options:\n");
281 /* Read the number of options and print it */
283 printf (" Count:%27u\n", Count);
285 /* Read and print all options */
286 for (I = 0; I < Count; ++I) {
291 /* Read the type of the option and the value */
292 unsigned char Type = Read8 (F);
293 unsigned long Val = ReadVar (F);
295 /* Get the type of the argument */
296 unsigned char ArgType = Type & OPT_ARGMASK;
298 /* Determine which option follows */
299 const char* TypeDesc;
301 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
302 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
303 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
304 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
305 case OPT_OS: TypeDesc = "OPT_OS"; break;
306 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
307 default: TypeDesc = "OPT_UNKNOWN"; break;
310 /* Print the header */
311 printf (" Index:%27u\n", I);
314 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
318 ArgStr = GetString (&StrPool, Val);
319 ArgLen = strlen (ArgStr);
320 printf (" Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
324 printf (" Data:%26lu", Val);
325 if (Type == OPT_DATETIME) {
326 /* Print the time as a string */
327 printf (" (%s)", TimeToStr (Val));
333 /* Unknown argument type. This means that we cannot determine
334 * the option length, so we cannot proceed.
336 Error ("Unknown option type: 0x%02X", Type);
341 /* Destroy the string pool */
342 DestroyStrPool (&StrPool);
347 void DumpObjFiles (FILE* F, unsigned long Offset)
348 /* Dump the source files */
351 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
355 /* Seek to the header position and read the header */
356 FileSetPos (F, Offset);
357 ReadObjHeader (F, &H);
359 /* Seek to the start of the string pool and read it */
360 FileSetPos (F, Offset + H.StrPoolOffs);
361 ReadStrPool (F, &StrPool);
363 /* Seek to the start of the source files */
364 FileSetPos (F, Offset + H.FileOffs);
366 /* Output a header */
367 printf (" Files:\n");
369 /* Read the number of files and print it */
371 printf (" Count:%27u\n", Count);
373 /* Read and print all files */
374 for (I = 0; I < Count; ++I) {
376 /* Read the data for one file */
377 const char* Name = GetString (&StrPool, ReadVar (F));
378 unsigned long MTime = Read32 (F);
379 unsigned long Size = Read32 (F);
380 unsigned Len = strlen (Name);
382 /* Print the header */
383 printf (" Index:%27u\n", I);
386 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
387 printf (" Size:%26lu\n", Size);
388 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
391 /* Destroy the string pool */
392 DestroyStrPool (&StrPool);
397 void DumpObjSegments (FILE* F, unsigned long Offset)
398 /* Dump the segments in the object file */
401 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
405 /* Seek to the header position and read the header */
406 FileSetPos (F, Offset);
407 ReadObjHeader (F, &H);
409 /* Seek to the start of the string pool and read it */
410 FileSetPos (F, Offset + H.StrPoolOffs);
411 ReadStrPool (F, &StrPool);
413 /* Seek to the start of the segments */
414 FileSetPos (F, Offset + H.SegOffs);
416 /* Output a header */
417 printf (" Segments:\n");
419 /* Read the number of segments and print it */
421 printf (" Count:%27u\n", Count);
423 /* Read and print all segments */
424 for (I = 0; I < Count; ++I) {
426 /* Read the data for one segments */
427 unsigned long DataSize = Read32 (F);
428 unsigned long NextSeg = ftell (F) + DataSize;
429 const char* Name = GetString (&StrPool, ReadVar (F));
430 unsigned Len = strlen (Name);
431 unsigned long Size = Read32 (F);
432 unsigned Align = (1U << Read8 (F));
433 unsigned char AddrSize = Read8 (F);
434 unsigned long FragCount = ReadVar (F);
436 /* Print the header */
437 printf (" Index:%27u\n", I);
440 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
441 printf (" Size:%26lu\n", Size);
442 printf (" Alignment:%21u\n", Align);
443 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
444 AddrSizeToStr (AddrSize));
445 printf (" Fragment count:%16lu\n", FragCount);
447 /* Seek to the end of the segment data (start of next) */
448 FileSetPos (F, NextSeg);
451 /* Destroy the string pool */
452 DestroyStrPool (&StrPool);
457 void DumpObjImports (FILE* F, unsigned long Offset)
458 /* Dump the imports in the object file */
461 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
466 /* Seek to the header position and read the header */
467 FileSetPos (F, Offset);
468 ReadObjHeader (F, &H);
470 /* Seek to the start of the string pool and read it */
471 FileSetPos (F, Offset + H.StrPoolOffs);
472 ReadStrPool (F, &StrPool);
474 /* Seek to the start of the imports */
475 FileSetPos (F, Offset + H.ImportOffs);
477 /* Output a header */
478 printf (" Imports:\n");
480 /* Read the number of imports and print it */
482 printf (" Count:%27u\n", Count);
484 /* Read and print all imports */
485 for (I = 0; I < Count; ++I) {
487 /* Read the data for one import */
488 unsigned char AddrSize = Read8 (F);
489 const char* Name = GetString (&StrPool, ReadVar (F));
490 unsigned Len = strlen (Name);
491 ReadFilePos (F, &Pos);
493 /* Print the header */
494 printf (" Index:%27u\n", I);
497 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
498 AddrSizeToStr (AddrSize));
499 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
502 /* Destroy the string pool */
503 DestroyStrPool (&StrPool);
508 void DumpObjExports (FILE* F, unsigned long Offset)
509 /* Dump the exports in the object file */
512 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
517 /* Seek to the header position and read the header */
518 FileSetPos (F, Offset);
519 ReadObjHeader (F, &H);
521 /* Seek to the start of the string pool and read it */
522 FileSetPos (F, Offset + H.StrPoolOffs);
523 ReadStrPool (F, &StrPool);
525 /* Seek to the start of the exports */
526 FileSetPos (F, Offset + H.ExportOffs);
528 /* Output a header */
529 printf (" Exports:\n");
531 /* Read the number of exports and print it */
533 printf (" Count:%27u\n", Count);
535 /* Read and print all exports */
536 for (I = 0; I < Count; ++I) {
538 unsigned long Value = 0;
540 unsigned char ConDes [CD_TYPE_COUNT];
545 /* Read the data for one export */
546 unsigned char Type = Read8 (F);
547 unsigned char AddrSize = Read8 (F);
548 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
549 Name = GetString (&StrPool, ReadVar (F));
551 if (IS_EXP_EXPR (Type)) {
558 ReadFilePos (F, &Pos);
560 /* Print the header */
561 printf (" Index:%27u\n", I);
564 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
565 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
566 AddrSizeToStr (AddrSize));
567 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
569 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
573 /* Destroy the string pool */
574 DestroyStrPool (&StrPool);
579 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
580 /* Dump the debug symbols from an object file */
583 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
588 /* Seek to the header position and read the header */
589 FileSetPos (F, Offset);
590 ReadObjHeader (F, &H);
592 /* Seek to the start of the string pool and read it */
593 FileSetPos (F, Offset + H.StrPoolOffs);
594 ReadStrPool (F, &StrPool);
596 /* Seek to the start of the debug syms */
597 FileSetPos (F, Offset + H.DbgSymOffs);
599 /* Output a header */
600 printf (" Debug symbols:\n");
602 /* Check if the object file was compiled with debug info */
603 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
604 /* Print that there no debug symbols and bail out */
605 printf (" Count:%27u\n", 0);
609 /* Read the number of exports and print it */
611 printf (" Count:%27u\n", Count);
613 /* Read and print all debug symbols */
614 for (I = 0; I < Count; ++I) {
616 unsigned long Value = 0;
619 /* Read the data for one symbol */
620 unsigned char Type = Read8 (F);
621 unsigned char AddrSize = Read8 (F);
622 const char* Name = GetString (&StrPool, ReadVar (F));
623 unsigned Len = strlen (Name);
624 if (IS_EXP_EXPR (Type)) {
631 ReadFilePos (F, &Pos);
633 /* Print the header */
634 printf (" Index:%27u\n", I);
637 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, 0));
638 printf (" Address size:%14s0x%02X (%s)\n", "", AddrSize,
639 AddrSizeToStr (AddrSize));
640 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
642 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
646 /* Destroy the string pool */
647 DestroyStrPool (&StrPool);
652 void DumpObjLineInfo (FILE* F, unsigned long Offset)
653 /* Dump the line info from an object file */
656 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
660 /* Seek to the header position and read the header */
661 FileSetPos (F, Offset);
662 ReadObjHeader (F, &H);
664 /* Seek to the start of the string pool and read it */
665 FileSetPos (F, Offset + H.StrPoolOffs);
666 ReadStrPool (F, &StrPool);
668 /* Seek to the start of line infos */
669 FileSetPos (F, Offset + H.LineInfoOffs);
671 /* Output a header */
672 printf (" Line info:\n");
674 /* Check if the object file was compiled with debug info */
675 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
676 /* Print that there no line infos and bail out */
677 printf (" Count:%27u\n", 0);
681 /* Read the number of line infos and print it */
683 printf (" Count:%27u\n", Count);
685 /* Read and print all line infos */
686 for (I = 0; I < Count; ++I) {
690 /* Read one line info */
691 ReadFilePos (F, &Pos);
693 /* Print the header */
694 printf (" Index:%27u\n", I);
697 printf (" Line:%26lu\n", Pos.Line);
698 printf (" Col:%27u\n", Pos.Col);
699 printf (" Name:%26u\n", Pos.Name);
702 /* Destroy the string pool */
703 DestroyStrPool (&StrPool);
708 void DumpObjSegSize (FILE* F, unsigned long Offset)
709 /* Dump the sizes of the segment in the object file */
712 Collection StrPool = AUTO_COLLECTION_INITIALIZER;
715 /* Seek to the header position and read the header */
716 FileSetPos (F, Offset);
717 ReadObjHeader (F, &H);
719 /* Seek to the start of the string pool and read it */
720 FileSetPos (F, Offset + H.StrPoolOffs);
721 ReadStrPool (F, &StrPool);
723 /* Seek to the start of the segments */
724 FileSetPos (F, Offset + H.SegOffs);
726 /* Output a header */
727 printf (" Segment sizes:\n");
729 /* Read the number of segments */
732 /* Read and print the sizes of all segments */
735 /* Read the data for one segments */
736 unsigned long DataSize = Read32 (F);
737 unsigned long NextSeg = ftell (F) + DataSize;
738 const char* Name = GetString (&StrPool, ReadVar (F));
739 unsigned Len = strlen (Name);
740 unsigned long Size = Read32 (F);
742 /* Skip alignment, type and fragment count */
747 /* Print the size for this segment */
748 printf (" %s:%*s%6lu\n", Name, 24-Len, "", Size);
750 /* Seek to the end of the segment data (start of next) */
751 FileSetPos (F, NextSeg);
754 /* Destroy the string pool */
755 DestroyStrPool (&StrPool);