mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-13 23:36:03 +00:00
604 lines
11 KiB
C
604 lines
11 KiB
C
/* Dump and interpret an object file. */
|
|
|
|
/*
|
|
Copyright (c) 2001, Richard Krehbiel
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
o Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
o Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
o Neither the name of the copyright holder nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE.
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#include "rad50.h"
|
|
|
|
#include "util.h"
|
|
|
|
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
|
|
|
|
int psectid = 0;
|
|
char *psects[256];
|
|
|
|
char *readrec(FILE *fp, int *len)
|
|
{
|
|
int c, i;
|
|
int chksum;
|
|
char *buf;
|
|
|
|
chksum = 0;
|
|
|
|
while(c = fgetc(fp), c != EOF && c == 0)
|
|
;
|
|
|
|
if(c == EOF)
|
|
return NULL;
|
|
|
|
if(c != 1)
|
|
{
|
|
fprintf(stderr, "Improperly formatted OBJ file (1)\n");
|
|
return NULL; // Not a properly formatted file.
|
|
}
|
|
|
|
chksum -= c;
|
|
|
|
c = fgetc(fp);
|
|
if(c != 0)
|
|
{
|
|
fprintf(stderr, "Improperly formatted OBJ file (2)\n");
|
|
return NULL; // Not properly formatted
|
|
}
|
|
|
|
chksum -= c; // even though for 0 the checksum isn't changed...
|
|
|
|
c = fgetc(fp);
|
|
if(c == EOF)
|
|
{
|
|
fprintf(stderr, "Improperly formatted OBJ file (3)\n");
|
|
return NULL;
|
|
}
|
|
*len = c;
|
|
|
|
chksum -= c;
|
|
|
|
c = fgetc(fp);
|
|
if(c == EOF)
|
|
{
|
|
fprintf(stderr, "Improperly formatted OBJ file (4)\n");
|
|
return NULL;
|
|
}
|
|
|
|
*len += (c << 8);
|
|
|
|
chksum -= c;
|
|
|
|
*len -= 4; // Subtract header and length bytes from length
|
|
if(*len < 0)
|
|
{
|
|
fprintf(stderr, "Improperly formatted OBJ file (5)\n");
|
|
return NULL;
|
|
}
|
|
|
|
buf = malloc(*len);
|
|
if(buf == NULL)
|
|
{
|
|
fprintf(stderr, "Out of memory allocating %d bytes\n", *len);
|
|
return NULL; // Bad alloc
|
|
}
|
|
|
|
i = fread(buf, 1, *len, fp);
|
|
if(i < *len)
|
|
{
|
|
free(buf);
|
|
fprintf(stderr, "Improperly formatted OBJ file (6)\n");
|
|
return NULL;
|
|
}
|
|
|
|
for(i = 0; i < *len; i++)
|
|
{
|
|
chksum -= (buf[i] & 0xff);
|
|
}
|
|
|
|
c = fgetc(fp);
|
|
c &= 0xff;
|
|
chksum &= 0xff;
|
|
|
|
if(c != chksum)
|
|
{
|
|
free(buf);
|
|
fprintf(stderr, "Bad record checksum, "
|
|
"calculated=%d, recorded=%d\n", chksum, c);
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
void dump_bytes(char *buf, int len)
|
|
{
|
|
int i, j;
|
|
|
|
for(i = 0; i < len; i += 8)
|
|
{
|
|
printf("\t%3.3o: ", i);
|
|
for(j = i; j < len && j < i+8; j++)
|
|
{
|
|
printf("%3.3o ", buf[j] & 0xff);
|
|
}
|
|
|
|
printf("%*s", (i+8 - j) * 4, "");
|
|
|
|
for(j = i; j < len && j < i+8; j++)
|
|
{
|
|
int c = buf[j] & 0xff;
|
|
if(!isprint(c))
|
|
c = '.';
|
|
putchar(c);
|
|
}
|
|
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
void dump_words(unsigned addr, char *buf, int len)
|
|
{
|
|
int i, j;
|
|
|
|
for(i = 0; i < len; i += 8)
|
|
{
|
|
printf("\t%6.6o: ", addr);
|
|
|
|
for(j = i; j < len && j < i+8; j += 2)
|
|
{
|
|
if(len - j >= 2)
|
|
{
|
|
unsigned word = WORD(buf + j);
|
|
printf("%6.6o ", word);
|
|
}
|
|
else
|
|
printf("%3.3o ", buf[j] & 0xff);
|
|
}
|
|
|
|
printf("%*s", (i+8 - j) * 7 / 2, "");
|
|
|
|
for(j = i; j < len && j < i+8; j++)
|
|
{
|
|
int c = buf[j] & 0xff;
|
|
if(!isprint(c))
|
|
c = '.';
|
|
putchar(c);
|
|
}
|
|
|
|
putchar('\n');
|
|
addr += 8;
|
|
}
|
|
}
|
|
|
|
void trim(char *buf)
|
|
{
|
|
char *cp;
|
|
|
|
for(cp = buf + strlen(buf); cp > buf; cp--)
|
|
{
|
|
if(cp[-1] != ' ')
|
|
break;
|
|
}
|
|
*cp = 0;
|
|
}
|
|
|
|
char **all_gsds = NULL;
|
|
int nr_gsds = 0;
|
|
int gsdsize = 0;
|
|
|
|
void add_gsdline(char *line)
|
|
{
|
|
if(nr_gsds >= gsdsize || all_gsds == NULL)
|
|
{
|
|
gsdsize += 128;
|
|
all_gsds = realloc(all_gsds, gsdsize * sizeof(char *));
|
|
if(all_gsds == NULL)
|
|
{
|
|
fprintf(stderr, "Out of memory\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
all_gsds[nr_gsds++] = line;
|
|
}
|
|
|
|
void got_gsd(char *cp, int len)
|
|
{
|
|
int i;
|
|
char *gsdline;
|
|
|
|
for(i = 2; i < len; i += 8)
|
|
{
|
|
char name[8];
|
|
unsigned value;
|
|
unsigned flags;
|
|
|
|
gsdline = malloc(256);
|
|
if(gsdline == NULL)
|
|
{
|
|
fprintf(stderr, "Out of memory\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
unrad50(WORD(cp+i), name);
|
|
unrad50(WORD(cp+i+2), name+3);
|
|
name[6] = 0;
|
|
|
|
value = WORD(cp+i+6);
|
|
flags = cp[i+4] & 0xff;
|
|
|
|
switch(cp[i+5] & 0xff)
|
|
{
|
|
case 0:
|
|
sprintf(gsdline,
|
|
"\tMODNAME %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
case 1:
|
|
sprintf(gsdline,
|
|
"\tCSECT %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
case 2:
|
|
sprintf(gsdline,
|
|
"\tISD %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
case 3:
|
|
sprintf(gsdline,
|
|
"\tXFER %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
case 4:
|
|
sprintf(gsdline,
|
|
"\tGLOBAL %s=%o %s flags=%o\n",
|
|
name, value, cp[i+4] & 8 ? "DEF" : "REF", flags);
|
|
break;
|
|
case 5:
|
|
sprintf(gsdline,
|
|
"\tPSECT %s=%o flags=%o\n", name, value, flags);
|
|
psects[psectid] = strdup(name);
|
|
trim(psects[psectid++]);
|
|
break;
|
|
case 6:
|
|
sprintf(gsdline,
|
|
"\tIDENT %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
case 7:
|
|
sprintf(gsdline,
|
|
"\tVSECT %s=%o flags=%o\n", name, value, flags);
|
|
break;
|
|
default:
|
|
sprintf(gsdline,
|
|
"\t***Unknown GSD entry type %d flags=%o\n",
|
|
cp[i+5] & 0xff, flags);
|
|
break;
|
|
}
|
|
|
|
gsdline = realloc(gsdline, strlen(gsdline)+1);
|
|
add_gsdline(gsdline);
|
|
}
|
|
|
|
}
|
|
|
|
int compare_gsdlines(const void *p1, const void *p2)
|
|
{
|
|
const char * const *l1 = p1, * const *l2 = p2;
|
|
|
|
return strcmp(*l1, *l2);
|
|
}
|
|
|
|
void got_endgsd(char *cp, int len)
|
|
{
|
|
int i;
|
|
|
|
qsort(all_gsds, nr_gsds, sizeof(char *), compare_gsdlines);
|
|
|
|
printf("GSD:\n");
|
|
|
|
for(i = 0; i < nr_gsds; i++)
|
|
{
|
|
fputs(all_gsds[i], stdout);
|
|
free(all_gsds[i]);
|
|
}
|
|
|
|
printf("ENDGSD\n");
|
|
|
|
free(all_gsds);
|
|
}
|
|
|
|
unsigned last_text_addr = 0;
|
|
|
|
void got_text(char *cp, int len)
|
|
{
|
|
unsigned addr = WORD(cp+2);
|
|
|
|
last_text_addr = addr;
|
|
|
|
printf("TEXT ADDR=%o LEN=%o\n", last_text_addr, len-4);
|
|
|
|
dump_words(last_text_addr, cp+4, len-4);
|
|
}
|
|
|
|
void rad50name(char *cp, char *name)
|
|
{
|
|
unrad50(WORD(cp), name);
|
|
unrad50(WORD(cp+2), name+3);
|
|
name[6] = 0;
|
|
trim(name);
|
|
}
|
|
|
|
void got_rld(char *cp, int len)
|
|
{
|
|
int i;
|
|
printf("RLD\n");
|
|
|
|
for(i = 2; i < len;)
|
|
{
|
|
unsigned addr;
|
|
unsigned word;
|
|
unsigned disp = cp[i+1] & 0xff;
|
|
char name[8];
|
|
char *byte;
|
|
|
|
addr = last_text_addr + disp - 4;
|
|
|
|
byte = "";
|
|
if(cp[i] & 0200)
|
|
byte = " byte";
|
|
|
|
switch(cp[i] & 0x7f)
|
|
{
|
|
case 01:
|
|
printf("\tInternal%s %o=%o\n", byte, addr, WORD(cp+i+2));
|
|
i += 4;
|
|
break;
|
|
case 02:
|
|
rad50name(cp+i+2, name);
|
|
printf("\tGlobal%s %o=%s\n", byte, addr, name);
|
|
i += 6;
|
|
break;
|
|
case 03:
|
|
printf("\tInternal displaced%s %o=%o\n", byte, addr, WORD(cp+i+2));
|
|
i += 4;
|
|
break;
|
|
case 04:
|
|
rad50name(cp+i+2, name);
|
|
printf("\tGlobal displaced%s %o=%s\n", byte, addr, name);
|
|
i += 6;
|
|
break;
|
|
case 05:
|
|
rad50name(cp+i+2, name);
|
|
word = WORD(cp+i+6);
|
|
printf("\tGlobal plus offset%s %o=%s+%o\n",
|
|
byte, addr, name, word);
|
|
i += 8;
|
|
break;
|
|
case 06:
|
|
rad50name(cp+i+2, name);
|
|
word = WORD(cp+i+6);
|
|
printf("\tGlobal plus offset displaced%s %o=%s+%o\n",
|
|
byte, addr, name, word);
|
|
i += 8;
|
|
break;
|
|
case 07:
|
|
rad50name(cp+i+2, name);
|
|
word = WORD(cp+i+6);
|
|
printf("\tLocation counter definition %s+%o\n",
|
|
name, word);
|
|
i += 8;
|
|
|
|
last_text_addr = word;
|
|
|
|
break;
|
|
case 010:
|
|
word = WORD(cp+i+2);
|
|
printf("\tLocation counter modification %o\n", word);
|
|
i += 4;
|
|
|
|
last_text_addr = word;
|
|
|
|
break;
|
|
case 011:
|
|
printf("\t.LIMIT %o\n", addr);
|
|
i += 2;
|
|
break;
|
|
|
|
case 012:
|
|
rad50name(cp+i+2, name);
|
|
printf("\tPSECT%s %o=%s\n", byte, addr, name);
|
|
i += 6;
|
|
break;
|
|
case 014:
|
|
rad50name(cp+i+2, name);
|
|
|
|
printf("\tPSECT displaced%s %o=%s+%o\n", byte, addr, name, word);
|
|
i += 6;
|
|
break;
|
|
case 015:
|
|
rad50name(cp+i+2, name);
|
|
word = WORD(cp+i+6);
|
|
printf("\tPSECT plus offset%s %o=%s+%o\n",
|
|
byte, addr, name, word);
|
|
i += 8;
|
|
break;
|
|
case 016:
|
|
rad50name(cp+i+2, name);
|
|
word = WORD(cp+i+6);
|
|
printf("\tPSECT plus offset displaced%s %o=%s+%o\n",
|
|
byte, addr, name, word);
|
|
i += 8;
|
|
break;
|
|
|
|
case 017:
|
|
printf("\tComplex%s %o=", byte, addr);
|
|
i += 2;
|
|
{
|
|
char *xp = cp + i;
|
|
int size;
|
|
for(;;)
|
|
{
|
|
size = 1;
|
|
switch(*xp)
|
|
{
|
|
case 000:
|
|
fputs("nop ", stdout); break;
|
|
case 001:
|
|
fputs("+ ", stdout); break;
|
|
case 002:
|
|
fputs("- ", stdout); break;
|
|
case 003:
|
|
fputs("* ", stdout); break;
|
|
case 004:
|
|
fputs("/ ", stdout); break;
|
|
case 005:
|
|
fputs("& ", stdout); break;
|
|
case 006:
|
|
fputs("! ", stdout); break;
|
|
case 010:
|
|
fputs("neg ", stdout); break;
|
|
case 011:
|
|
fputs("^C ", stdout); break;
|
|
case 012:
|
|
fputs("store ", stdout); break;
|
|
case 013:
|
|
fputs("store{disp} ", stdout); break;
|
|
|
|
case 016:
|
|
rad50name(xp+1, name);
|
|
printf("%s ", name);
|
|
size = 5;
|
|
break;
|
|
|
|
case 017:
|
|
assert((xp[1] & 0377) < psectid);
|
|
printf("%s:%o ",
|
|
psects[xp[1] & 0377],
|
|
WORD(xp+2));
|
|
size = 4;
|
|
break;
|
|
|
|
case 020:
|
|
printf("%o ", WORD(xp+1));
|
|
size = 3;
|
|
break;
|
|
default:
|
|
printf("**UNKNOWN COMPLEX CODE** %o\n", *xp & 0377);
|
|
return;
|
|
}
|
|
i += size;
|
|
if(*xp == 012 || *xp == 013)
|
|
break;
|
|
xp += size;
|
|
}
|
|
fputc('\n', stdout);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
printf("\t***Unknown RLD code %o\n", cp[i] & 0xff);
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void got_isd(char *cp, int len)
|
|
{
|
|
printf("ISD len=%o\n");
|
|
}
|
|
|
|
void got_endmod(char *cp, int len)
|
|
{
|
|
printf("ENDMOD\n");
|
|
}
|
|
|
|
void got_libhdr(char *cp, int len)
|
|
{
|
|
printf("LIBHDR\n");
|
|
}
|
|
|
|
void got_libend(char *cp, int len)
|
|
{
|
|
printf("LIBEND\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int len;
|
|
FILE *fp;
|
|
char *cp;
|
|
|
|
fp = fopen(argv[1], "rb");
|
|
if(fp == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
while((cp = readrec(fp, &len)) != NULL)
|
|
{
|
|
switch(cp[0] & 0xff)
|
|
{
|
|
case 1:
|
|
got_gsd(cp, len);
|
|
break;
|
|
case 2:
|
|
got_endgsd(cp, len);
|
|
break;
|
|
case 3:
|
|
got_text(cp, len);
|
|
break;
|
|
case 4:
|
|
got_rld(cp, len);
|
|
break;
|
|
case 5:
|
|
got_isd(cp, len);
|
|
break;
|
|
case 6:
|
|
got_endmod(cp, len);
|
|
break;
|
|
case 7:
|
|
got_libhdr(cp, len);
|
|
break;
|
|
case 8:
|
|
got_libend(cp, len);
|
|
break;
|
|
default:
|
|
printf("Unknown record type %d\n", cp[0] & 0xff);
|
|
break;
|
|
}
|
|
|
|
free(cp);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|