1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2000-2001 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
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 /*****************************************************************************/
56 /*****************************************************************************/
58 /*****************************************************************************/
62 static void DumpObjHeaderSection (const char* Name,
65 /* Dump a header section */
67 printf (" %s:\n", Name);
68 printf (" Offset:%24lu\n", Offset);
69 printf (" Size: %24lu\n", Size);
74 static char* TimeToStr (unsigned long Time)
75 /* Convert the time into a string and return it */
77 /* Get the time and convert to string */
78 time_t T = (time_t) Time;
79 char* S = asctime (localtime (&T));
81 /* Remove the trailing newline */
82 unsigned Len = strlen (S);
83 if (Len > 0 && S[Len-1] == '\n') {
87 /* Return the time string */
93 static void SkipExpr (FILE* F)
94 /* Skip an expression from the given file */
96 /* Read the node tag and handle NULL nodes */
97 unsigned char Op = Read8 (F);
98 if (Op == EXPR_NULL) {
102 /* Check the tag and handle the different expression types */
103 if (EXPR_IS_LEAF (Op)) {
107 (void) Read32Signed (F);
111 /* Read the import number */
116 /* Read the segment number */
121 Error ("Invalid expression op: %02X", Op);
127 /* Not a leaf node */
136 static unsigned SkipFragment (FILE* F)
137 /* Skip a fragment from the given file and return the size */
142 /* Read the fragment type */
143 unsigned char Type = Read8 (F);
145 /* Handle the different fragment types */
160 Size = Type & FRAG_BYTEMASK;
168 Error ("Unknown fragment type: 0x%02X", Type);
175 /* Now read the fragment data */
176 switch (Type & FRAG_TYPEMASK) {
180 FileSeek (F, ftell (F) + Size);
191 /* Skip the file position of the fragment */
192 ReadFilePos (F, &Pos);
194 /* Skip the additional line info */
197 /* Return the size */
203 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
204 /* Get the export flags as a (static) string */
207 static char TypeDesc[256];
215 switch (Flags & EXP_MASK_SIZE) {
216 case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break;
217 case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break;
220 /* Type of expression */
221 switch (Flags & EXP_MASK_VAL) {
222 case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break;
223 case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break;
226 /* Constructor/destructor declarations */
227 T = TypeDesc + strlen (TypeDesc);
228 Count = GET_EXP_CONDES_COUNT (Flags);
230 T += sprintf (T, ",EXP_CONDES=");
231 for (I = 0; I < Count; ++I) {
232 unsigned Type = CD_GET_TYPE (ConDes[I]);
233 unsigned Prio = CD_GET_PRIO (ConDes[I]);
237 T += sprintf (T, "[%u,%u]", Type, Prio);
241 /* Return the result */
247 void DumpObjHeader (FILE* F, unsigned long Offset)
248 /* Dump the header of the given object file */
252 /* Seek to the header position */
253 FileSeek (F, Offset);
255 /* Read the header */
256 ReadObjHeader (F, &H);
258 /* Now dump the information */
260 /* Output a header */
261 printf (" Header:\n");
264 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
267 printf (" Version:%25u\n", H.Version);
270 printf (" Flags:%21s0x%04X (", "", H.Flags);
271 if (H.Flags & OBJ_FLAGS_DBGINFO) {
272 printf ("OBJ_FLAGS_DBGINFO");
277 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
280 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
283 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
286 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
289 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
292 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
297 void DumpObjOptions (FILE* F, unsigned long Offset)
298 /* Dump the file options */
304 /* Seek to the header position */
305 FileSeek (F, Offset);
307 /* Read the header */
308 ReadObjHeader (F, &H);
310 /* Seek to the start of the options */
311 FileSeek (F, Offset + H.OptionOffs);
313 /* Output a header */
314 printf (" Options:\n");
316 /* Read the number of options and print it */
318 printf (" Count:%27u\n", Count);
320 /* Read and print all options */
321 for (I = 0; I < Count; ++I) {
323 unsigned long ArgNum;
327 /* Read the type of the option */
328 unsigned char Type = Read8 (F);
330 /* Get the type of the argument */
331 unsigned char ArgType = Type & OPT_ARGMASK;
333 /* Determine which option follows */
334 const char* TypeDesc;
336 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
337 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
338 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
339 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
340 case OPT_OS: TypeDesc = "OPT_OS"; break;
341 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
342 default: TypeDesc = "OPT_UNKNOWN"; break;
345 /* Print the header */
346 printf (" Index:%27u\n", I);
349 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
353 ArgStr = ReadStr (F);
354 ArgLen = strlen (ArgStr);
355 printf (" Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
361 printf (" Data:%26lu", ArgNum);
362 if (Type == OPT_DATETIME) {
363 /* Print the time as a string */
364 printf (" (%s)", TimeToStr (ArgNum));
370 /* Unknown argument type. This means that we cannot determine
371 * the option length, so we cannot proceed.
373 Error ("Unknown option type: 0x%02X", Type);
381 void DumpObjFiles (FILE* F, unsigned long Offset)
382 /* Dump the source files */
388 /* Seek to the header position */
389 FileSeek (F, Offset);
391 /* Read the header */
392 ReadObjHeader (F, &H);
394 /* Seek to the start of the source files */
395 FileSeek (F, Offset + H.FileOffs);
397 /* Output a header */
398 printf (" Files:\n");
400 /* Read the number of files and print it */
402 printf (" Count:%27u\n", Count);
404 /* Read and print all files */
405 for (I = 0; I < Count; ++I) {
407 /* Read the data for one file */
408 unsigned long MTime = Read32 (F);
409 unsigned long Size = Read32 (F);
410 char* Name = ReadStr (F);
411 unsigned Len = strlen (Name);
413 /* Print the header */
414 printf (" Index:%27u\n", I);
417 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
418 printf (" Size:%26lu\n", Size);
419 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
428 void DumpObjSegments (FILE* F, unsigned long Offset)
429 /* Dump the segments in the object file */
436 /* Seek to the header position */
437 FileSeek (F, Offset);
439 /* Read the header */
440 ReadObjHeader (F, &H);
442 /* Seek to the start of the segments */
443 FileSeek (F, Offset + H.SegOffs);
445 /* Output a header */
446 printf (" Segments:\n");
448 /* Read the number of segments and print it */
450 printf (" Count:%27u\n", Count);
452 /* Read and print all segments */
453 for (I = 0; I < Count; ++I) {
455 /* Read the data for one segments */
456 char* Name = ReadStr (F);
457 unsigned Len = strlen (Name);
458 unsigned long Size = Read32 (F);
459 unsigned Align = (1U << Read8 (F));
460 unsigned char Type = Read8 (F);
462 /* Get the description for the type */
463 const char* TypeDesc;
465 case SEGTYPE_DEFAULT: TypeDesc = "SEGTYPE_DEFAULT"; break;
466 case SEGTYPE_ABS: TypeDesc = "SEGTYPE_ABS"; break;
467 case SEGTYPE_ZP: TypeDesc = "SEGTYPE_ZP"; break;
468 case SEGTYPE_FAR: TypeDesc = "SEGTYPE_FAR"; break;
469 default: TypeDesc = "SEGTYPE_UNKNOWN"; break;
472 /* Print the header */
473 printf (" Index:%27u\n", I);
476 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
477 printf (" Size:%26lu\n", Size);
478 printf (" Alignment:%21u\n", Align);
479 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
484 /* Skip the fragments for this segment, counting them */
487 unsigned FragSize = SkipFragment (F);
488 if (FragSize > Size) {
489 /* OOPS - file data invalid */
490 Error ("Invalid fragment data - file corrupt!");
496 /* Print the fragment count */
497 printf (" Fragment count:%16u\n", FragCount);
503 void DumpObjImports (FILE* F, unsigned long Offset)
504 /* Dump the imports in the object file */
511 /* Seek to the header position */
512 FileSeek (F, Offset);
514 /* Read the header */
515 ReadObjHeader (F, &H);
517 /* Seek to the start of the imports */
518 FileSeek (F, Offset + H.ImportOffs);
520 /* Output a header */
521 printf (" Imports:\n");
523 /* Read the number of imports and print it */
525 printf (" Count:%27u\n", Count);
527 /* Read and print all imports */
528 for (I = 0; I < Count; ++I) {
530 const char* TypeDesc;
532 /* Read the data for one import */
533 unsigned char Type = Read8 (F);
534 char* Name = ReadStr (F);
535 unsigned Len = strlen (Name);
536 ReadFilePos (F, &Pos);
538 /* Get a description for the type */
540 case IMP_ZP: TypeDesc = "IMP_ZP"; break;
541 case IMP_ABS: TypeDesc = "IMP_ABS"; break;
542 default: TypeDesc = "IMP_UNKNOWN"; break;
545 /* Print the header */
546 printf (" Index:%27u\n", I);
549 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
550 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
559 void DumpObjExports (FILE* F, unsigned long Offset)
560 /* Dump the exports in the object file */
567 /* Seek to the header position */
568 FileSeek (F, Offset);
570 /* Read the header */
571 ReadObjHeader (F, &H);
573 /* Seek to the start of the exports */
574 FileSeek (F, Offset + H.ExportOffs);
576 /* Output a header */
577 printf (" Exports:\n");
579 /* Read the number of exports and print it */
581 printf (" Count:%27u\n", Count);
583 /* Read and print all exports */
584 for (I = 0; I < Count; ++I) {
586 unsigned long Value = 0;
589 unsigned char ConDes [CD_TYPE_COUNT];
594 /* Read the data for one export */
596 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
599 if (IS_EXP_EXPR (Type)) {
606 ReadFilePos (F, &Pos);
608 /* Print the header */
609 printf (" Index:%27u\n", I);
612 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
613 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
615 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
625 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
626 /* Dump the debug symbols from an object file */
633 /* Seek to the header position */
634 FileSeek (F, Offset);
636 /* Read the header */
637 ReadObjHeader (F, &H);
639 /* Seek to the start of the debug syms */
640 FileSeek (F, Offset + H.DbgSymOffs);
642 /* Output a header */
643 printf (" Debug symbols:\n");
645 /* Check if the object file was compiled with debug info */
646 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
647 /* Print that there no debug symbols and bail out */
648 printf (" Count:%27u\n", 0);
652 /* Read the number of exports and print it */
654 printf (" Count:%27u\n", Count);
656 /* Read and print all debug symbols */
657 for (I = 0; I < Count; ++I) {
659 unsigned long Value = 0;
662 unsigned char ConDes [CD_TYPE_COUNT];
666 /* Read the data for one symbol */
668 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
671 if (IS_EXP_EXPR (Type)) {
678 ReadFilePos (F, &Pos);
680 /* Print the header */
681 printf (" Index:%27u\n", I);
684 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
685 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
687 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
697 void DumpObjLineInfo (FILE* F, unsigned long Offset)
698 /* Dump the line info from an object file */
704 /* Seek to the header position */
705 FileSeek (F, Offset);
707 /* Read the header */
708 ReadObjHeader (F, &H);
710 /* Seek to the start of line infos */
711 FileSeek (F, Offset + H.LineInfoOffs);
713 /* Output a header */
714 printf (" Line info:\n");
716 /* Check if the object file was compiled with debug info */
717 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
718 /* Print that there no line infos and bail out */
719 printf (" Count:%27u\n", 0);
723 /* Read the number of line infos and print it */
725 printf (" Count:%27u\n", Count);
727 /* Read and print all line infos */
728 for (I = 0; I < Count; ++I) {
732 /* Read one line info */
733 ReadFilePos (F, &Pos);
735 /* Print the header */
736 printf (" Index:%27u\n", I);
739 printf (" Line:%26lu\n", Pos.Line);
740 printf (" Col:%27u\n", Pos.Col);
741 printf (" Name:%26u\n", Pos.Name);