2000-07-29 22:34:15 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* dump.c */
|
|
|
|
/* */
|
|
|
|
/* Dump subroutines for the od65 object file dump utility */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* (C) 2000 Ullrich von Bassewitz */
|
|
|
|
/* Wacholderweg 14 */
|
|
|
|
/* D-70597 Stuttgart */
|
|
|
|
/* EMail: uz@musoftware.de */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
/* */
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
/* */
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
/* distribution. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-30 14:25:30 +00:00
|
|
|
#include <time.h>
|
|
|
|
|
2000-07-29 22:34:15 +00:00
|
|
|
/* common */
|
|
|
|
#include "objdefs.h"
|
2000-07-30 14:25:30 +00:00
|
|
|
#include "optdefs.h"
|
|
|
|
#include "xmalloc.h"
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* od65 */
|
2000-07-30 14:25:30 +00:00
|
|
|
#include "error.h"
|
2000-07-29 22:34:15 +00:00
|
|
|
#include "fileio.h"
|
|
|
|
#include "dump.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2000-07-30 14:25:30 +00:00
|
|
|
/* Code */
|
2000-07-29 22:34:15 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-30 14:25:30 +00:00
|
|
|
static void DumpObjHeaderSection (const char* Name,
|
|
|
|
unsigned long Offset,
|
|
|
|
unsigned long Size)
|
2000-07-29 22:34:15 +00:00
|
|
|
/* Dump a header section */
|
|
|
|
{
|
|
|
|
printf (" %s:\n", Name);
|
2000-07-30 14:25:30 +00:00
|
|
|
printf (" Offset: %8lu\n", Offset);
|
|
|
|
printf (" Size: %8lu\n", Size);
|
2000-07-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-30 16:15:04 +00:00
|
|
|
static char* TimeToStr (unsigned long Time)
|
|
|
|
/* Convert the time into a string and return it */
|
|
|
|
{
|
|
|
|
/* Get the time and convert to string */
|
|
|
|
time_t T = (time_t) Time;
|
|
|
|
char* S = asctime (localtime (&T));
|
|
|
|
|
|
|
|
/* Remove the trailing newline */
|
|
|
|
unsigned Len = strlen (S);
|
|
|
|
if (Len > 0 && S[Len-1] == '\n') {
|
|
|
|
S[Len-1 ] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the time string */
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-30 14:25:30 +00:00
|
|
|
void DumpObjHeader (FILE* F, unsigned long Offset)
|
2000-07-29 22:34:15 +00:00
|
|
|
/* Dump the header of the given object file */
|
|
|
|
{
|
|
|
|
ObjHeader H;
|
|
|
|
|
|
|
|
/* Seek to the header position */
|
2000-07-30 14:25:30 +00:00
|
|
|
FileSeek (F, Offset);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Read the header */
|
|
|
|
ReadObjHeader (F, &H);
|
|
|
|
|
|
|
|
/* Now dump the information */
|
|
|
|
|
2000-07-30 14:25:30 +00:00
|
|
|
/* Output a header */
|
|
|
|
printf (" Header:\n");
|
|
|
|
|
2000-07-29 22:34:15 +00:00
|
|
|
/* Magic */
|
2000-07-30 14:25:30 +00:00
|
|
|
printf (" Magic: 0x%08lX\n", H.Magic);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Version */
|
2000-07-30 14:25:30 +00:00
|
|
|
printf (" Version: %10u\n", H.Version);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Flags */
|
2000-07-30 14:25:30 +00:00
|
|
|
printf (" Flags: 0x%04X (", H.Flags);
|
2000-07-29 22:34:15 +00:00
|
|
|
if (H.Flags & OBJ_FLAGS_DBGINFO) {
|
2000-07-30 14:25:30 +00:00
|
|
|
printf ("OBJ_FLAGS_DBGINFO");
|
2000-07-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
printf (")\n");
|
|
|
|
|
|
|
|
/* Options */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Options", H.OptionOffs, H.OptionSize);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Files */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Files", H.FileOffs, H.FileSize);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Segments */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Segments", H.SegOffs, H.SegSize);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Imports */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Imports", H.ImportOffs, H.ImportSize);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Exports */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Exports", H.ExportOffs, H.ExportSize);
|
2000-07-29 22:34:15 +00:00
|
|
|
|
|
|
|
/* Debug symbols */
|
2000-07-30 14:25:30 +00:00
|
|
|
DumpObjHeaderSection ("Debug symbols", H.DbgSymOffs, H.DbgSymSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void DumpObjOptions (FILE* F, unsigned long Offset)
|
|
|
|
/* Dump the file options */
|
|
|
|
{
|
|
|
|
ObjHeader H;
|
|
|
|
unsigned Count;
|
|
|
|
unsigned I;
|
|
|
|
|
|
|
|
/* Seek to the header position */
|
|
|
|
FileSeek (F, Offset);
|
|
|
|
|
|
|
|
/* Read the header */
|
|
|
|
ReadObjHeader (F, &H);
|
|
|
|
|
|
|
|
/* Seek to the start of the options */
|
|
|
|
FileSeek (F, Offset + H.OptionOffs);
|
|
|
|
|
|
|
|
/* Output a header */
|
|
|
|
printf (" Options:\n");
|
|
|
|
|
|
|
|
/* Read the number of options and print it */
|
|
|
|
Count = Read16 (F);
|
2000-07-30 16:15:04 +00:00
|
|
|
printf (" Count:%27u\n", Count);
|
2000-07-30 14:25:30 +00:00
|
|
|
|
|
|
|
/* Read and print all options */
|
|
|
|
for (I = 0; I < Count; ++I) {
|
|
|
|
|
|
|
|
unsigned long ArgNum;
|
|
|
|
char* ArgStr;
|
|
|
|
unsigned ArgLen;
|
|
|
|
|
|
|
|
/* Read the type of the option */
|
|
|
|
unsigned char Type = Read8 (F);
|
|
|
|
|
|
|
|
/* Get the type of the argument */
|
|
|
|
unsigned char ArgType = Type & OPT_ARGMASK;
|
|
|
|
|
|
|
|
/* Determine which option follows */
|
|
|
|
const char* TypeDesc;
|
|
|
|
switch (Type) {
|
|
|
|
case OPT_COMMENT: TypeDesc = "OPT_COMMENT"; break;
|
|
|
|
case OPT_AUTHOR: TypeDesc = "OPT_AUTHOR"; break;
|
|
|
|
case OPT_TRANSLATOR:TypeDesc = "OPT_TRANSLATOR"; break;
|
|
|
|
case OPT_COMPILER: TypeDesc = "OPT_COMPILER"; break;
|
|
|
|
case OPT_OS: TypeDesc = "OPT_OS"; break;
|
|
|
|
case OPT_DATETIME: TypeDesc = "OPT_DATETIME"; break;
|
|
|
|
default: TypeDesc = "OPT_UNKNOWN"; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the header */
|
|
|
|
printf (" Option %u:\n", I);
|
|
|
|
|
|
|
|
/* Print the data */
|
|
|
|
printf (" Type: 0x%02X (%s)\n", Type, TypeDesc);
|
|
|
|
switch (ArgType) {
|
|
|
|
|
|
|
|
case OPT_ARGSTR:
|
|
|
|
ArgStr = ReadMallocedStr (F);
|
|
|
|
ArgLen = strlen (ArgStr);
|
|
|
|
printf (" Data:%*s\"%s\"\n", 24-ArgLen, "", ArgStr);
|
|
|
|
xfree (ArgStr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_ARGNUM:
|
|
|
|
ArgNum = Read32 (F);
|
|
|
|
printf (" Data:%26lu", ArgNum);
|
|
|
|
if (Type == OPT_DATETIME) {
|
|
|
|
/* Print the time as a string */
|
2000-07-30 16:15:04 +00:00
|
|
|
printf (" (%s)", TimeToStr (ArgNum));
|
2000-07-30 14:25:30 +00:00
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Unknown argument type. This means that we cannot determine
|
|
|
|
* the option length, so we cannot proceed.
|
|
|
|
*/
|
|
|
|
Error ("Unknown option type: 0x%02X", Type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-07-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-30 16:15:04 +00:00
|
|
|
void DumpObjFiles (FILE* F, unsigned long Offset)
|
|
|
|
/* Dump the source files */
|
|
|
|
{
|
|
|
|
ObjHeader H;
|
|
|
|
unsigned Count;
|
|
|
|
unsigned I;
|
|
|
|
|
|
|
|
/* Seek to the header position */
|
|
|
|
FileSeek (F, Offset);
|
|
|
|
|
|
|
|
/* Read the header */
|
|
|
|
ReadObjHeader (F, &H);
|
|
|
|
|
|
|
|
/* Seek to the start of the options */
|
|
|
|
FileSeek (F, Offset + H.FileOffs);
|
|
|
|
|
|
|
|
/* Output a header */
|
|
|
|
printf (" Files:\n");
|
|
|
|
|
|
|
|
/* Read the number of files and print it */
|
|
|
|
Count = Read8 (F);
|
|
|
|
printf (" Count:%27u\n", Count);
|
|
|
|
|
|
|
|
/* Read and print all options */
|
|
|
|
for (I = 0; I < Count; ++I) {
|
|
|
|
|
|
|
|
/* Read the data for one file */
|
|
|
|
unsigned long MTime = Read32 (F);
|
|
|
|
unsigned long Size = Read32 (F);
|
|
|
|
char* Name = ReadMallocedStr (F);
|
|
|
|
unsigned Len = strlen (Name);
|
|
|
|
|
|
|
|
/* Print the header */
|
|
|
|
printf (" File %u:\n", I);
|
|
|
|
|
|
|
|
/* Print the data */
|
|
|
|
printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
|
|
|
|
printf (" Size:%26lu\n", Size);
|
|
|
|
printf (" Modification time:%13lu (%s)\n", MTime, TimeToStr (MTime));
|
|
|
|
|
|
|
|
/* Free the Name */
|
|
|
|
xfree (Name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|