1 /*****************************************************************************/
5 /* Dump subroutines for the od65 object file dump utility */
9 /* (C) 2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /* Return the size */
200 static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
201 /* Get the export flags as a (static) string */
204 static char TypeDesc[256];
212 switch (Flags & EXP_MASK_SIZE) {
213 case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break;
214 case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break;
217 /* Type of expression */
218 switch (Flags & EXP_MASK_VAL) {
219 case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break;
220 case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break;
223 /* Constructor/destructor declarations */
224 T = TypeDesc + strlen (TypeDesc);
225 Count = GET_EXP_CONDES_COUNT (Flags);
227 T += sprintf (T, ",EXP_CONDES=");
228 for (I = 0; I < Count; ++I) {
229 unsigned Type = CD_GET_TYPE (ConDes[I]);
230 unsigned Prio = CD_GET_PRIO (ConDes[I]);
234 T += sprintf (T, "[%u,%u]", Type, Prio);
238 /* Return the result */
244 void DumpObjHeader (FILE* F, unsigned long Offset)
245 /* Dump the header of the given object file */
249 /* Seek to the header position */
250 FileSeek (F, Offset);
252 /* Read the header */
253 ReadObjHeader (F, &H);
255 /* Now dump the information */
257 /* Output a header */
258 printf (" Header:\n");
261 printf (" Magic:%17s0x%08lX\n", "", H.Magic);
264 printf (" Version:%25u\n", H.Version);
267 printf (" Flags:%21s0x%04X (", "", H.Flags);
268 if (H.Flags & OBJ_FLAGS_DBGINFO) {
269 printf ("OBJ_FLAGS_DBGINFO");
274 DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
277 DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
280 DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
283 DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
286 DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
289 DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
294 void DumpObjOptions (FILE* F, unsigned long Offset)
295 /* Dump the file options */
301 /* Seek to the header position */
302 FileSeek (F, Offset);
304 /* Read the header */
305 ReadObjHeader (F, &H);
307 /* Seek to the start of the options */
308 FileSeek (F, Offset + H.OptionOffs);
310 /* Output a header */
311 printf (" Options:\n");
313 /* Read the number of options and print it */
315 printf (" Count:%27u\n", Count);
317 /* Read and print all options */
318 for (I = 0; I < Count; ++I) {
320 unsigned long ArgNum;
324 /* Read the type of the option */
325 unsigned char Type = Read8 (F);
327 /* Get the type of the argument */
328 unsigned char ArgType = Type & OPT_ARGMASK;
330 /* Determine which option follows */
331 const char* TypeDesc;
333 case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
334 case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
335 case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
336 case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
337 case OPT_OS: TypeDesc = "OPT_OS"; break;
338 case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
339 default: TypeDesc = "OPT_UNKNOWN"; break;
342 /* Print the header */
343 printf (" Index:%27u\n", I);
346 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
350 ArgStr = ReadStr (F);
351 ArgLen = strlen (ArgStr);
352 printf (" Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
358 printf (" Data:%26lu", ArgNum);
359 if (Type == OPT_DATETIME) {
360 /* Print the time as a string */
361 printf (" (%s)", TimeToStr (ArgNum));
367 /* Unknown argument type. This means that we cannot determine
368 * the option length, so we cannot proceed.
370 Error ("Unknown option type: 0x%02X", Type);
378 void DumpObjFiles (FILE* F, unsigned long Offset)
379 /* Dump the source files */
385 /* Seek to the header position */
386 FileSeek (F, Offset);
388 /* Read the header */
389 ReadObjHeader (F, &H);
391 /* Seek to the start of the options */
392 FileSeek (F, Offset + H.FileOffs);
394 /* Output a header */
395 printf (" Files:\n");
397 /* Read the number of files and print it */
399 printf (" Count:%27u\n", Count);
401 /* Read and print all files */
402 for (I = 0; I < Count; ++I) {
404 /* Read the data for one file */
405 unsigned long MTime = Read32 (F);
406 unsigned long Size = Read32 (F);
407 char* Name = ReadStr (F);
408 unsigned Len = strlen (Name);
410 /* Print the header */
411 printf (" Index:%27u\n", I);
414 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
415 printf (" Size:%26lu\n", Size);
416 printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
425 void DumpObjSegments (FILE* F, unsigned long Offset)
426 /* Dump the segments in the object file */
433 /* Seek to the header position */
434 FileSeek (F, Offset);
436 /* Read the header */
437 ReadObjHeader (F, &H);
439 /* Seek to the start of the options */
440 FileSeek (F, Offset + H.SegOffs);
442 /* Output a header */
443 printf (" Segments:\n");
445 /* Read the number of segments and print it */
447 printf (" Count:%27u\n", Count);
449 /* Read and print all segments */
450 for (I = 0; I < Count; ++I) {
452 /* Read the data for one segments */
453 char* Name = ReadStr (F);
454 unsigned Len = strlen (Name);
455 unsigned long Size = Read32 (F);
456 unsigned Align = (1U << Read8 (F));
457 unsigned char Type = Read8 (F);
459 /* Get the description for the type */
460 const char* TypeDesc;
462 case SEGTYPE_DEFAULT: TypeDesc = "SEGTYPE_DEFAULT"; break;
463 case SEGTYPE_ABS: TypeDesc = "SEGTYPE_ABS"; break;
464 case SEGTYPE_ZP: TypeDesc = "SEGTYPE_ZP"; break;
465 case SEGTYPE_FAR: TypeDesc = "SEGTYPE_FAR"; break;
466 default: TypeDesc = "SEGTYPE_UNKNOWN"; break;
469 /* Print the header */
470 printf (" Index:%27u\n", I);
473 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
474 printf (" Size:%26lu\n", Size);
475 printf (" Alignment:%21u\n", Align);
476 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
481 /* Skip the fragments for this segment, counting them */
484 unsigned FragSize = SkipFragment (F);
485 if (FragSize > Size) {
486 /* OOPS - file data invalid */
487 Error ("Invalid fragment data - file corrupt!");
493 /* Print the fragment count */
494 printf (" Fragment count:%16u\n", FragCount);
500 void DumpObjImports (FILE* F, unsigned long Offset)
501 /* Dump the imports in the object file */
508 /* Seek to the header position */
509 FileSeek (F, Offset);
511 /* Read the header */
512 ReadObjHeader (F, &H);
514 /* Seek to the start of the options */
515 FileSeek (F, Offset + H.ImportOffs);
517 /* Output a header */
518 printf (" Imports:\n");
520 /* Read the number of imports and print it */
522 printf (" Count:%27u\n", Count);
524 /* Read and print all imports */
525 for (I = 0; I < Count; ++I) {
527 const char* TypeDesc;
529 /* Read the data for one import */
530 unsigned char Type = Read8 (F);
531 char* Name = ReadStr (F);
532 unsigned Len = strlen (Name);
533 ReadFilePos (F, &Pos);
535 /* Get a description for the type */
537 case IMP_ZP: TypeDesc = "IMP_ZP"; break;
538 case IMP_ABS: TypeDesc = "IMP_ABS"; break;
539 default: TypeDesc = "IMP_UNKNOWN"; break;
542 /* Print the header */
543 printf (" Index:%27u\n", I);
546 printf (" Type:%22s0x%02X (%s)\n", "", Type, TypeDesc);
547 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
556 void DumpObjExports (FILE* F, unsigned long Offset)
557 /* Dump the exports in the object file */
564 /* Seek to the header position */
565 FileSeek (F, Offset);
567 /* Read the header */
568 ReadObjHeader (F, &H);
570 /* Seek to the start of the options */
571 FileSeek (F, Offset + H.ExportOffs);
573 /* Output a header */
574 printf (" Exports:\n");
576 /* Read the number of exports and print it */
578 printf (" Count:%27u\n", Count);
580 /* Read and print all exports */
581 for (I = 0; I < Count; ++I) {
583 unsigned long Value = 0;
586 unsigned char ConDes [CD_TYPE_COUNT];
591 /* Read the data for one export */
593 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
596 if (IS_EXP_EXPR (Type)) {
603 ReadFilePos (F, &Pos);
605 /* Print the header */
606 printf (" Index:%27u\n", I);
609 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
610 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
612 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
622 void DumpObjDbgSyms (FILE* F, unsigned long Offset)
623 /* Dump the debug symbols from an object file */
630 /* Seek to the header position */
631 FileSeek (F, Offset);
633 /* Read the header */
634 ReadObjHeader (F, &H);
636 /* Seek to the start of the options */
637 FileSeek (F, Offset + H.DbgSymOffs);
639 /* Output a header */
640 printf (" Debug symbols:\n");
642 /* Check if the object file was compiled with debug info */
643 if ((H.Flags & OBJ_FLAGS_DBGINFO) == 0) {
644 /* Print that there no debug symbols and bail out */
645 printf (" Count:%27u\n", 0);
649 /* Read the number of exports and print it */
651 printf (" Count:%27u\n", Count);
653 /* Read and print all debug symbols */
654 for (I = 0; I < Count; ++I) {
656 unsigned long Value = 0;
659 unsigned char ConDes [CD_TYPE_COUNT];
663 /* Read the data for one symbol */
665 ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
668 if (IS_EXP_EXPR (Type)) {
675 ReadFilePos (F, &Pos);
677 /* Print the header */
678 printf (" Index:%27u\n", I);
681 printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
682 printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
684 printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);