Move tools directory to amigaos-dev-toolkit repository.
This commit is contained in:
parent
39f0b27679
commit
524a261187
|
@ -1,4 +0,0 @@
|
|||
GccFindHit
|
||||
hunk2aout
|
||||
elf2hunk
|
||||
*.pyc
|
|
@ -1,308 +0,0 @@
|
|||
/* GccFindHit V1.2.1, 07/12/96
|
||||
*
|
||||
* The same than FindHit by Michael Sinz, but for GCC users
|
||||
* Usage: GccFindHit <executable file> <list of offsets in hexadecimal>
|
||||
* The file should have been linked with the '-g' flag passed to gcc
|
||||
* to turn on debugging information (the 'stabs')
|
||||
*
|
||||
* GccFindHit outputs the line numbers matching with the offsets given by
|
||||
* Enforcer (or whatever). Currently, there is no need
|
||||
* to provide the hunk number because it should always be zero.
|
||||
*
|
||||
* Copyright (C) 1995 Daniel Verite -- daniel@brainstorm.eu.org
|
||||
* This program is distributed under the General GNU Public License version 2
|
||||
* See the file COPYING for information about the GPL
|
||||
*
|
||||
* v1.2.1, 07/12/96
|
||||
* David Zaroski, cz253@cleveland.Freenet.Edu:
|
||||
* o use BYTE_ORDER from system includes to get the host's endianness
|
||||
*
|
||||
* Daniel Verite, daniel@brainstorm.eu.org:
|
||||
* o removed references to LITTLE_ENDIAN in Makefile.in
|
||||
*
|
||||
* v1.2, 30/12/95
|
||||
*
|
||||
* Daniel Verite, daniel@brainstorm.eu.org:
|
||||
* o added handling of HUNK_NAME
|
||||
* o fixed a small glitch in the strings seeks
|
||||
*
|
||||
* v1.1, 28/09/95
|
||||
*
|
||||
* Hans Verkuil, hans@wyst.hobby.nl:
|
||||
* o GccFindHit no longer reads the strings into memory, but seek()s them
|
||||
* instead, saving lots of memory.
|
||||
* o added version string.
|
||||
*
|
||||
* v1.0, 22/05/95
|
||||
*
|
||||
* First release
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
typedef struct nlist BSD_SYM;
|
||||
|
||||
static int ExeFile,NbOffs;
|
||||
static int32_t *SearchOffs;
|
||||
|
||||
const char version_id[] = "\000$VER: GccFindHit 1.2.1 (07.12.96)";
|
||||
|
||||
int Read4 (int32_t *buf)
|
||||
{
|
||||
if (read (ExeFile,buf,4)==4) {
|
||||
*buf = GETLONG(*buf);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Header *ReadHeader ()
|
||||
{
|
||||
int32_t nb,size;
|
||||
struct Header *h;
|
||||
int i;
|
||||
|
||||
/* skip hunk names */
|
||||
while (Read4 (&size) && size)
|
||||
lseek (ExeFile, size<<2, SEEK_CUR);
|
||||
|
||||
/* reads the number of hunks */
|
||||
if (!Read4(&nb))
|
||||
return NULL;
|
||||
h = (struct Header*)malloc(sizeof(struct Header)+(nb-1)*sizeof(int32_t));
|
||||
if (!h)
|
||||
return NULL;
|
||||
h->nb_hunks = nb;
|
||||
if (Read4 (&h->first) && Read4 (&h->last)) {
|
||||
for (i=0; i<nb; i++)
|
||||
if (!Read4 (&h->sizes[i])) {
|
||||
free (h);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
} /* ReadHeader() */
|
||||
|
||||
int long_cmp (int32_t *e1,int32_t *e2)
|
||||
{
|
||||
return (*e1)<(*e2);
|
||||
}
|
||||
|
||||
void SkipRelocation ()
|
||||
{
|
||||
int32_t no; /* number of offsets */
|
||||
int32_t h; /* hunk number */
|
||||
while (Read4 (&no) && no && Read4 (&h))
|
||||
lseek (ExeFile, no<<2, SEEK_CUR);
|
||||
}
|
||||
|
||||
/* this function hasn't been tested; AFAIK, ld won't output short relocs,
|
||||
so it's useless for now */
|
||||
void SkipShortRel ()
|
||||
{
|
||||
int32_t no;
|
||||
int16_t h;
|
||||
while (Read4 (&no) && no && read (ExeFile, &h, sizeof h))
|
||||
lseek (ExeFile, no<<1, SEEK_CUR);
|
||||
}
|
||||
|
||||
/* can be slow if I/O buffering doesn't do some read-ahead */
|
||||
void SkipSymbols ()
|
||||
{
|
||||
int32_t nl; /* name length in long words */
|
||||
while (Read4 (&nl) && nl) {
|
||||
/* skips the name + the value */
|
||||
lseek (ExeFile, (nl+1)<<2, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
/* skip hunks such as HUNK_NAME that have their size in the first long */
|
||||
void SkipHunk ()
|
||||
{
|
||||
int32_t size;
|
||||
if (Read4 (&size))
|
||||
lseek (ExeFile, size<<2, SEEK_CUR);
|
||||
}
|
||||
|
||||
char *get_string(int32_t offset)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
lseek(ExeFile, offset, SEEK_SET);
|
||||
read(ExeFile, buf, 255);
|
||||
buf[255] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void GetLines (int32_t symsz, BSD_SYM *syms, int32_t string_offset)
|
||||
{
|
||||
int32_t nbsyms = symsz / sizeof(BSD_SYM);
|
||||
BSD_SYM *sym = syms;
|
||||
uint8_t prev_type;
|
||||
int32_t srcname = 0, prev_src = 0;
|
||||
uint16_t prev_line = 0;
|
||||
uint32_t offs , prev_offs = -1UL;
|
||||
int i;
|
||||
|
||||
while (nbsyms--) {
|
||||
switch (sym->n_type) {
|
||||
case N_SO:
|
||||
case N_SOL:
|
||||
srcname = GETLONG (sym->n_un.n_strx);
|
||||
break;
|
||||
case N_SLINE:
|
||||
offs = OFFSET_N_SLINE (GETLONG (sym->n_value));
|
||||
for (i = 0; i < NbOffs; i++) {
|
||||
if (SearchOffs[i] >= prev_offs && SearchOffs[i] < offs) {
|
||||
printf ("%s: line %hd, offset 0x%x\n", get_string(prev_src +
|
||||
string_offset), prev_line, prev_offs);
|
||||
}
|
||||
}
|
||||
prev_offs = offs;
|
||||
prev_line = GETWORD (sym->n_desc);
|
||||
prev_src = srcname;
|
||||
break;
|
||||
}
|
||||
prev_type = sym->n_type;
|
||||
sym++;
|
||||
}
|
||||
/* the last SLINE is a special case */
|
||||
for (i = 0; i < NbOffs; i++) {
|
||||
if (SearchOffs[i] == prev_offs) {
|
||||
printf ("%s: line %hd, offset 0x%x\n",
|
||||
get_string(prev_src + string_offset), prev_line,
|
||||
prev_offs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HunkDebug (void)
|
||||
{
|
||||
int32_t hunksz, symsz, strsz;
|
||||
struct bsd_header hdr;
|
||||
int32_t pos, init_pos = lseek (ExeFile, 0, SEEK_CUR);
|
||||
char *syms;
|
||||
|
||||
if (init_pos < 0)
|
||||
return;
|
||||
if (Read4(&hunksz) && read (ExeFile, &hdr, sizeof(hdr)) == sizeof(hdr)) {
|
||||
if (GETLONG(hdr.magic)==ZMAGIC) {
|
||||
/* seems to be gcc-compiled */
|
||||
strsz = GETLONG (hdr.strsz);
|
||||
symsz = GETLONG (hdr.symsz);
|
||||
if (strsz + symsz != 0) {
|
||||
syms = (char*)malloc (symsz);
|
||||
if (syms) {
|
||||
if (read (ExeFile, syms, symsz) == symsz) {
|
||||
pos = lseek(ExeFile, strsz, SEEK_CUR);
|
||||
if (pos > 0)
|
||||
GetLines (symsz, (BSD_SYM*)syms, pos - strsz);
|
||||
}
|
||||
free (syms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* go to the end of the hunk whatever happened before */
|
||||
lseek (ExeFile, init_pos+((hunksz+1)<<2), SEEK_SET);
|
||||
}
|
||||
|
||||
void DoHunks (struct Header *h)
|
||||
{
|
||||
int32_t hnum,size,nsec=0;
|
||||
while (Read4 (&hnum)) {
|
||||
switch (hnum) {
|
||||
case HUNK_NAME:
|
||||
SkipHunk ();
|
||||
break;
|
||||
case HUNK_CODE:
|
||||
case HUNK_DATA:
|
||||
if (Read4 (&size)) {
|
||||
nsec++;
|
||||
lseek (ExeFile, (size&0x3fffffff)<<2, SEEK_CUR);
|
||||
}
|
||||
break;
|
||||
case HUNK_BSS:
|
||||
nsec++;
|
||||
Read4 (&size);
|
||||
case HUNK_END:
|
||||
case HUNK_BREAK:
|
||||
break;
|
||||
case HUNK_RELOC32:
|
||||
case HUNK_RELOC16:
|
||||
case HUNK_RELOC8:
|
||||
case HUNK_DREL32:
|
||||
case HUNK_DREL16:
|
||||
case HUNK_DREL8:
|
||||
SkipRelocation();
|
||||
break;
|
||||
case HUNK_RELOC32SHORT:
|
||||
SkipShortRel ();
|
||||
break;
|
||||
case HUNK_SYMBOL:
|
||||
SkipSymbols();
|
||||
break;
|
||||
case HUNK_DEBUG: /* here we are... */
|
||||
HunkDebug ();
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unexpected hunk 0x%x\n", hnum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} /* DoHunks() */
|
||||
|
||||
void Out(int code)
|
||||
{
|
||||
if (ExeFile>0) close (ExeFile);
|
||||
if (SearchOffs) free (SearchOffs);
|
||||
exit (code);
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
int32_t HunkNum;
|
||||
struct Header *header=NULL;
|
||||
int i;
|
||||
|
||||
if (argc<3) {
|
||||
fprintf (stderr,"Usage: %s <file> <hex offsets>\n",argv[0]);
|
||||
Out (1);
|
||||
}
|
||||
ExeFile = open (argv[1], O_RDONLY);
|
||||
if (ExeFile<0) {
|
||||
fprintf (stderr,"can't open %s:%s\n", argv[1], strerror (errno));
|
||||
Out (1);
|
||||
}
|
||||
NbOffs = argc-2;
|
||||
SearchOffs = (int32_t*)malloc (sizeof (int32_t)*NbOffs);
|
||||
if (!SearchOffs) {
|
||||
fprintf (stderr,"No memory\n");
|
||||
Out (1);
|
||||
}
|
||||
for (i=0; i<NbOffs; i++) {
|
||||
if (sscanf (argv[i+2],"%x",&SearchOffs[i])!=1) {
|
||||
fprintf (stderr, "Operand %s is not an hex offset\n", argv[i+2]);
|
||||
Out (1);
|
||||
}
|
||||
}
|
||||
if (!Read4(&HunkNum) || HunkNum!=HUNK_HEADER || !(header=ReadHeader())) {
|
||||
fprintf (stderr, "%s is not an amigaos executable\n", argv[1]);
|
||||
Out (1);
|
||||
}
|
||||
DoHunks (header);
|
||||
free (header);
|
||||
Out (0);
|
||||
return 0; /* another brick in the -Wall */
|
||||
} /* main() */
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
README for GccFindHit V1.2, 25/05/95
|
||||
|
||||
This tool should be used in conjunction with Enforcer.
|
||||
Its purpose is to find the source name/line corresponding to a given offset
|
||||
in the executable. Very simple to use:
|
||||
when your program named, say, 'prog', is a bad boy
|
||||
and makes Enforcer hit(s), remember the offset(s) of the hit(s) displayed
|
||||
by Enforcer and run the command 'GccFindHit prog <list of offsets in hex>'
|
||||
The offsets are separated by blanks.
|
||||
Enforcer gives also the hunk number, but it should always be zero.
|
||||
If it's not and your program is compiled by gcc, please let me know
|
||||
about it.
|
||||
GccFindHit understands the stabs from the aout format encapsulated
|
||||
in the debug hunk of the AmigaOS executable, so it will work as
|
||||
long as ld outputs its debug information this way.
|
||||
Source code is included and it is distributed under the GPL
|
||||
See the file COPYING for details about the GPL. If it's not in
|
||||
the archive, please contact the site/person/organization you got
|
||||
this program from, and tell them it is *required*
|
||||
|
||||
Daniel Verite -- daniel@brainstorm.eu.org
|
|
@ -1,15 +0,0 @@
|
|||
CC = gcc -m32
|
||||
CFLAGS = -g -O2 -Wall -I../target/os-include
|
||||
|
||||
BINS = GccFindHit hunk2aout elf2hunk
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
GccFindHit.o: GccFindHit.c defs.h a.out.h
|
||||
hunk2aout.o: hunk2aout.c a.out.h
|
||||
elf2hunk.o: elf2hunk.c
|
||||
|
||||
clean:
|
||||
rm -f $(BINS) *.o *~
|
||||
|
||||
# vim: set noexpandtab ts=8 sw=8 :
|
112
tools/a.out.h
112
tools/a.out.h
|
@ -1,112 +0,0 @@
|
|||
#ifndef _AOUT_H_
|
||||
#define _AOUT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Header prepended to each a.out file. */
|
||||
struct exec {
|
||||
uint16_t a_mid; /* machine ID */
|
||||
uint16_t a_magic; /* magic number */
|
||||
uint32_t a_text; /* text segment size */
|
||||
uint32_t a_data; /* initialized data size */
|
||||
uint32_t a_bss; /* uninitialized data size */
|
||||
uint32_t a_syms; /* symbol table size */
|
||||
uint32_t a_entry; /* entry point */
|
||||
uint32_t a_trsize; /* text relocation size */
|
||||
uint32_t a_drsize; /* data relocation size */
|
||||
};
|
||||
|
||||
/* a_magic */
|
||||
#define OMAGIC 0407 /* old impure format */
|
||||
#define NMAGIC 0410 /* read-only text */
|
||||
#define ZMAGIC 0413 /* demand load format */
|
||||
|
||||
/* a_mid */
|
||||
#define MID_ZERO 0 /* unknown - implementation dependent */
|
||||
#define MID_SUN010 1 /* sun 68010/68020 binary */
|
||||
#define MID_SUN020 2 /* sun 68020-only binary */
|
||||
#define MID_HP200 200 /* hp200 (68010) BSD binary */
|
||||
#define MID_HP300 300 /* hp300 (68020+68881) BSD binary */
|
||||
#define MID_HPUX 0x20C /* hp200/300 HP-UX binary */
|
||||
#define MID_HPUX800 0x20B /* hp800 HP-UX binary */
|
||||
|
||||
#define __LDPGSZ 8192
|
||||
|
||||
/* Valid magic number check. */
|
||||
#define N_BADMAG(ex) \
|
||||
((ex).a_magic != NMAGIC && (ex).a_magic != OMAGIC && \
|
||||
(ex).a_magic != ZMAGIC)
|
||||
|
||||
/* Address of the bottom of the text segment. */
|
||||
#define N_TXTADDR(ex) ((ex).a_magic == ZMAGIC ? __LDPGSZ : 0)
|
||||
|
||||
/* Address of the bottom of the data segment. */
|
||||
#define N_DATADDR(ex) \
|
||||
(N_TXTADDR(ex) + ((ex).a_magic == OMAGIC ? (ex).a_text \
|
||||
: __LDPGSZ + ((ex).a_text - 1 & ~(__LDPGSZ - 1))))
|
||||
|
||||
#define N_BSSADDR(ex) (N_DATADDR(ex)+(ex).a_data)
|
||||
|
||||
/* Text segment offset. */
|
||||
#define N_TXTOFF(ex) \
|
||||
((ex).a_magic == ZMAGIC ? 0 : sizeof(struct exec))
|
||||
|
||||
/* Data segment offset. */
|
||||
#define N_DATOFF(ex) \
|
||||
(N_TXTOFF(ex) + ((ex).a_magic != ZMAGIC ? (ex).a_text \
|
||||
: __LDPGSZ + ((ex).a_text - 1 & ~(__LDPGSZ - 1))))
|
||||
|
||||
/* Symbol table offset. */
|
||||
#define N_SYMOFF(ex) \
|
||||
(N_TXTOFF(ex) + (ex).a_text + (ex).a_data + (ex).a_trsize + \
|
||||
(ex).a_drsize)
|
||||
|
||||
/* String table offset. */
|
||||
#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms)
|
||||
|
||||
/* Relocation format. */
|
||||
struct relocation_info {
|
||||
int r_address; /* offset in text or data segment */
|
||||
unsigned int r_symbolnum : 24, /* ordinal number of add symbol */
|
||||
r_pcrel : 1, /* 1 if value should be pc-relative */
|
||||
r_length : 2, /* log base 2 of value's width */
|
||||
r_extern : 1, /* 1 if need to add symbol to value */
|
||||
r_baserel : 1, /* 1 if linkage table relative */
|
||||
r_jmptable : 1, /* 1 if pc-relative to jump table */
|
||||
: 2; /* reserved */
|
||||
};
|
||||
|
||||
/*
|
||||
* Symbol table entry format.
|
||||
*/
|
||||
|
||||
#define N_UNDF 0x00 /* undefined */
|
||||
#define N_EXT 0x01 /* external (global) bit, OR'ed in */
|
||||
#define N_ABS 0x02 /* absolute address */
|
||||
#define N_TEXT 0x04 /* text segment */
|
||||
#define N_DATA 0x06 /* data segment */
|
||||
#define N_BSS 0x08 /* bss segment */
|
||||
#define N_INDR 0x0a /* alias definition */
|
||||
#define N_SIZE 0x0c /* pseudo type, defines a symbol's size */
|
||||
#define N_COMM 0x12 /* common reference */
|
||||
#define N_FN 0x1e /* file name (N_EXT on) */
|
||||
#define N_WARN 0x1e /* warning message (N_EXT off) */
|
||||
#define N_TYPE 0x1e /* mask for all the type bits */
|
||||
#define N_SLINE 0x44 /* line number in text segment */
|
||||
#define N_SO 0x64 /* name of main source file */
|
||||
#define N_SOL 0x84 /* name of sub-source file (#include file) */
|
||||
#define N_STAB 0xe0 /* mask for debugger symbols -- stab(5) */
|
||||
|
||||
struct nlist {
|
||||
union {
|
||||
char *n_name; /* symbol name (in memory) */
|
||||
int32_t n_strx; /* file string table offset (on disk) */
|
||||
} n_un;
|
||||
|
||||
uint8_t n_type; /* type defines */
|
||||
int8_t n_other; /* spare */
|
||||
int16_t n_desc; /* used by stab entries */
|
||||
uint32_t n_value; /* address/value of the symbol */
|
||||
};
|
||||
|
||||
#endif /* !_AOUT_H_ */
|
44
tools/defs.h
44
tools/defs.h
|
@ -1,44 +0,0 @@
|
|||
/* defs.h -- this file is part of GccFindHit
|
||||
* Copyright (C) 1995 Daniel Verite -- daniel@brainstorm.eu.org
|
||||
* This program is distributed under the General GNU Public License version 2
|
||||
* See the file COPYING for information about the GPL
|
||||
*/
|
||||
|
||||
#ifndef _DEFS_H_
|
||||
#define _DEFS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <dos/doshunks.h>
|
||||
|
||||
#include "a.out.h"
|
||||
|
||||
#define GETWORD(x) ntohs(x)
|
||||
#define GETLONG(x) ntohl(x)
|
||||
#define PUTWORD(x) htons(x)
|
||||
#define PUTLONG(x) htonl(x)
|
||||
|
||||
/* Converts an SLINE value to an offset in the text section.
|
||||
This definition is OK for ld 1.8, currently used on the Amiga AFAIK,
|
||||
but you may change that for another linker */
|
||||
#define OFFSET_N_SLINE(x) (x)
|
||||
|
||||
/* amigaos hunk header structure */
|
||||
struct Header {
|
||||
int32_t nb_hunks;
|
||||
int32_t first;
|
||||
int32_t last;
|
||||
int32_t sizes[1];
|
||||
};
|
||||
|
||||
/* bsd header structure */
|
||||
struct bsd_header{
|
||||
int32_t magic;
|
||||
int32_t symsz;
|
||||
int32_t strsz;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,15 +0,0 @@
|
|||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from objtools import aout
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
obj = aout.Aout()
|
||||
obj.read(path)
|
||||
obj.dump()
|
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from objtools import hunk
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
print 'Parsing "%s".' % path
|
||||
print ''
|
||||
|
||||
for h in hunk.ReadFile(path):
|
||||
h.dump()
|
||||
print ''
|
1134
tools/elf2hunk.c
1134
tools/elf2hunk.c
File diff suppressed because it is too large
Load Diff
102
tools/filedb.py
102
tools/filedb.py
|
@ -1,102 +0,0 @@
|
|||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import sha
|
||||
import sys
|
||||
from UserDict import UserDict
|
||||
|
||||
from objtools import ar, aout, hunk
|
||||
|
||||
|
||||
def ShaSum(data):
|
||||
return sha.new(data).digest().encode('hex')
|
||||
|
||||
|
||||
class Database(UserDict):
|
||||
def __init__(self, topdir):
|
||||
UserDict.__init__(self)
|
||||
self.topdir = topdir
|
||||
|
||||
def name(self, filepath):
|
||||
return filepath[len(self.topdir):]
|
||||
|
||||
def addFile(self, filepath, filetype):
|
||||
with open(filepath) as f:
|
||||
cksum = ShaSum(f.read())
|
||||
size = os.path.getsize(filepath)
|
||||
name = self.name(filepath)
|
||||
self.data[name] = {'size': size, 'sha': cksum, 'type': filetype}
|
||||
|
||||
def addArchive(self, filepath, archive):
|
||||
objects = [(obj.name, {'size': len(obj.data), 'sha': ShaSum(obj.data)})
|
||||
for obj in archive]
|
||||
name = self.name(filepath)
|
||||
self.data[name] = {'objects': dict(objects), 'type': 'archive'}
|
||||
|
||||
def dumps(self):
|
||||
return json.dumps(self.data, indent=2, sort_keys=True)
|
||||
|
||||
def readAout(self, filepath):
|
||||
try:
|
||||
aout.ReadFile(filepath)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
self.addFile(filepath, 'a.out')
|
||||
return True
|
||||
|
||||
def readHunk(self, filepath):
|
||||
try:
|
||||
hs = hunk.ReadFile(filepath)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
if hs[0].type == 'HUNK_UNIT':
|
||||
units = sum(1 for h in hs if h.type == 'HUNK_UNIT')
|
||||
if units > 1:
|
||||
filetype = 'ALink'
|
||||
else:
|
||||
filetype = 'Amiga Hunk object'
|
||||
elif hs[0].type == 'HUNK_LIB':
|
||||
filetype = 'BLink'
|
||||
elif hs[0].type == 'HUNK_HEADER':
|
||||
filetype = 'Amiga Hunk executable'
|
||||
|
||||
self.addFile(filepath, filetype)
|
||||
return True
|
||||
|
||||
def readAr(self, filepath):
|
||||
try:
|
||||
archive = ar.ReadFile(filepath)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
self.addArchive(filepath, archive)
|
||||
return True
|
||||
|
||||
def build(self):
|
||||
for path, _, filenames in os.walk(self.topdir):
|
||||
for filename in filenames:
|
||||
filepath = os.path.join(path, filename)
|
||||
|
||||
if os.path.islink(filepath):
|
||||
continue
|
||||
|
||||
if self.readAout(filepath):
|
||||
continue
|
||||
|
||||
if self.readHunk(filepath):
|
||||
continue
|
||||
|
||||
if self.readAr(filepath):
|
||||
continue
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
|
||||
db = Database(sys.argv[1])
|
||||
db.build()
|
||||
print db.dumps()
|
|
@ -1,986 +0,0 @@
|
|||
/*
|
||||
* Convert amiga object files in the hunk format into a.out-object files.
|
||||
* ALINK style (ie. concatenated) libraries are supported as well, in that
|
||||
* case a collection of object files is generated, you'll have to run
|
||||
* `ar rs libfoo.a obj.*' on them to make an a.out-style library out of
|
||||
* them.
|
||||
*
|
||||
* Currently untested are:
|
||||
* o base-relative relocs and references
|
||||
* I'll first have to teach gnu-ld how to deal with them ;-)
|
||||
* o conversion of load files...
|
||||
* o common symbols, amiga objects normally don't use them, sigh
|
||||
*
|
||||
* Currently not implemented are:
|
||||
* o BLINK style indexed libraries (HUNK_LIB and HUNK_INDEX). If you're
|
||||
* generating such libraries yourself, you can as well generate oldstyle
|
||||
* libraries, and the libraries from Commodore-Amiga are in ALINK format
|
||||
* (amiga.lib and friends).
|
||||
* This index-format is so weird and complicated that I didn't bother
|
||||
* long to decide not to support it. If someone volunteers (you got
|
||||
* the source;-)) please send me enhancements!
|
||||
*
|
||||
* V1.0 91-10-08 M.Wild first hack
|
||||
* V1.1 91-10-19 M.Wild add support for CHIP hunk attribute in
|
||||
* DATA/BSS hunks (not CODE, ever used??)
|
||||
* Now, when are multiple hunks supported ? ;-)
|
||||
* V2.0 97-03-01 fnf Change name to hunk2aout, apply patch from
|
||||
* Hans Verkuil, use standard AmigaOS versioning.
|
||||
*
|
||||
* This is free software. This means that I don't care what you do with it
|
||||
* as long as you don't claim you wrote it. If you enhance it, please
|
||||
* send me your diffs!
|
||||
* Oh, of course, you use this stuff entirely at your own risk, I'm not
|
||||
* responsible for any damage this program might cause to you, your computer,
|
||||
* your data, your cat, your whateveryoucanthinkof, no warranty whatsoever is
|
||||
* granted.
|
||||
*
|
||||
* I can be reached on internet as: wild@nessie.cs.id.ethz.ch (Markus Wild)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
/* strangely enough, this is missing from the doshunks.h file */
|
||||
#define HUNK_ATTRIBUTE(h) ((h) >> 30)
|
||||
#define HUNK_VALUE(h) ((h) & 0x3fffffff)
|
||||
#define HUNK_ATTR_CHIP 0x01
|
||||
|
||||
/* These are the symbol names we are generating to denote the limit between
|
||||
* the `normal' and `chip' data/bss.
|
||||
*/
|
||||
#define CHIP_DATA_START "__chip_data"
|
||||
#define CHIP_BSS_START "__chip_bss"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define DP(a) printf a
|
||||
#else
|
||||
#define DP(a)
|
||||
#endif
|
||||
|
||||
char *version_tag = "\0$VER: hunk2aout 2.0 (1.3.97)\r\n";
|
||||
|
||||
static uint32_t *file_buf = 0;
|
||||
|
||||
/* if set no progress reports are output */
|
||||
static int silent_mode = 0;
|
||||
|
||||
struct reloc {
|
||||
/* at which offset to relocate */
|
||||
int offset;
|
||||
/* based on which hunk base */
|
||||
int from_hunk, to_hunk;
|
||||
int size;
|
||||
int pcrel;
|
||||
int baserel;
|
||||
/* if != -1, the "to_hunk" field is not used */
|
||||
int sym_num;
|
||||
};
|
||||
|
||||
/* NOTE: this symbol definition is compatible with struct nlist, and it will
|
||||
* be converted into a struct nlist in 'emit_aout_obj' */
|
||||
struct symbol {
|
||||
int name; /* string as offset into string table */
|
||||
uint8_t type;
|
||||
uint8_t pad1; /* really n_other */
|
||||
short hunk_num; /* really n_desc */
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
struct table {
|
||||
void *base;
|
||||
int el_size;
|
||||
int i;
|
||||
int max_el;
|
||||
};
|
||||
|
||||
static void emit_aout_file(int fd, void *text, void *data, void *chip_data,
|
||||
struct exec *hdr, int chip_data_size,
|
||||
int chip_bss_size, struct table *ch_tab,
|
||||
struct table *dh_tab, struct table *bh_tab,
|
||||
struct table *cdh_tab, struct table *cbh_tab,
|
||||
struct table *reloc_tab, struct table *symbol_tab,
|
||||
int max_hunk);
|
||||
|
||||
#define TAB_START_SIZE 1024
|
||||
|
||||
/* advance the hunk-pointer to the next hunk. Assumes the hunk-pointer is
|
||||
* pointing at the length-field currently
|
||||
*/
|
||||
static void next_hunk(uint32_t **hp)
|
||||
{
|
||||
/* skip over the length field and the there given length */
|
||||
*hp += 1 + GETLONG(**hp);
|
||||
}
|
||||
|
||||
|
||||
/* save a lot of space for duplicate string, that all say "only.. with size.. */
|
||||
static void limit_hunk (char *hunk_name)
|
||||
{
|
||||
fprintf (stderr, "only one %s hunk with size!=0 supported.\n", hunk_name);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* these two function maintain the string table. You may only free the last
|
||||
* string allocated. (This could be done with an obstack as well, but I really
|
||||
* don't need the whole functionality of an obstack, so I kept it simple ;-))
|
||||
* Only use the offset, since the table itself may be reallocated.
|
||||
*/
|
||||
static char *str_table = 0;
|
||||
static int strtab_size, strtab_index;
|
||||
|
||||
static int stralloc (int len)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* always include the zero terminator */
|
||||
len++;
|
||||
|
||||
if (! str_table)
|
||||
{
|
||||
strtab_size = TAB_START_SIZE;
|
||||
/* start the table at index 4, leaving space to later fill in the
|
||||
* size of the table */
|
||||
strtab_index = 4;
|
||||
str_table = malloc (strtab_size);
|
||||
}
|
||||
|
||||
while (strtab_index + len > strtab_size)
|
||||
{
|
||||
strtab_size <<= 1;
|
||||
str_table = realloc (str_table, strtab_size);
|
||||
}
|
||||
|
||||
res = strtab_index;
|
||||
strtab_index += len;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void strfree (int str)
|
||||
{
|
||||
strtab_index = str;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static void add_table (struct table *tab, void *el)
|
||||
{
|
||||
if (tab->i == tab->max_el)
|
||||
{
|
||||
if (! tab->base)
|
||||
{
|
||||
tab->max_el = TAB_START_SIZE;
|
||||
tab->base = malloc (tab->max_el * tab->el_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
tab->max_el <<= 1;
|
||||
tab->base = realloc (tab->base, tab->max_el * tab->el_size);
|
||||
}
|
||||
if (! tab->base)
|
||||
{
|
||||
fprintf (stderr, "Out of memory adding to table.\n");
|
||||
/* exit does close all outstanding files ;-) */
|
||||
exit (20);
|
||||
}
|
||||
}
|
||||
bcopy (el, (uint8_t *)tab->base + (tab->i++ * tab->el_size), tab->el_size);
|
||||
}
|
||||
|
||||
static void add_reloc (struct table *tab, int from, int to, int offset,
|
||||
int size, int pcrel, int baserel, int sym_num)
|
||||
{
|
||||
struct reloc r;
|
||||
|
||||
DP(("reloc: from=%d, to=%d, off=%d, size=%d, pc=%d, ba=%d, syn=%d\n",
|
||||
from, to, offset, size, pcrel, baserel, sym_num));
|
||||
|
||||
r.from_hunk = from;
|
||||
r.to_hunk = to;
|
||||
r.offset = offset;
|
||||
r.size = size;
|
||||
r.pcrel = pcrel;
|
||||
r.baserel = baserel;
|
||||
r.sym_num = sym_num;
|
||||
add_table (tab, &r);
|
||||
}
|
||||
|
||||
static void add_symbol (struct table *tab, int num, uint32_t type,
|
||||
int value, char *name)
|
||||
{
|
||||
struct symbol s;
|
||||
|
||||
s.hunk_num = num;
|
||||
s.type = type >> 24;
|
||||
s.value = value;
|
||||
s.name = stralloc ((type & 0xffffff)<<2);
|
||||
bcopy (name, str_table+s.name, (type & 0xffffff)<<2);
|
||||
(str_table+s.name)[(type & 0xffffff)<<2] = 0;
|
||||
|
||||
/* some (really stupid..) compilers mention symbols twice, once as
|
||||
* a definition, and once as an EXT_SYMB. So we really have to search
|
||||
* the symbol_table before adding an EXT_SYMB and check if a symbol of this name
|
||||
* isn't already defined for this value. If this hack should slow down
|
||||
* the conversion dramatically, I'll have to resort to hashing, I don't
|
||||
* like that idea... */
|
||||
if (s.type == EXT_SYMB)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tab->i; i++)
|
||||
/* we have CSE in the compiler, right? ;-)) */
|
||||
if (((struct symbol *)tab->base)[i].value == s.value &&
|
||||
((struct symbol *)tab->base)[i].hunk_num == s.hunk_num &&
|
||||
! strcmp (str_table+((struct symbol *)tab->base)[i].name,
|
||||
str_table+s.name))
|
||||
{
|
||||
strfree (s.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
add_table (tab, &s);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static void digest_objfile (uint32_t **file_pptr, uint32_t *max_fp)
|
||||
{
|
||||
/* this makes it less clumsy.. */
|
||||
uint32_t *file_ptr = *file_pptr;
|
||||
static int obj_file_num = 0;
|
||||
int units = 0;
|
||||
int fd = -1;
|
||||
/* if processed hunk has a CHIP attribute */
|
||||
int is_chip;
|
||||
|
||||
/* buffer-pointers, where text & data sections are stored.
|
||||
* Currently only one hunk with size!=0 of type text/data/bss each is
|
||||
* supported.
|
||||
* There is now an additional buffer to support one chip hunk as well.
|
||||
* (chip-bss is supported too, but doesn't need a buffer ;-))
|
||||
*/
|
||||
uint8_t *text, *data, *chip_data;
|
||||
uint32_t chip_data_size, chip_bss_size;
|
||||
struct exec hdr;
|
||||
|
||||
/* hunk numbers, needed to associate reloc blocks with segments */
|
||||
int hunk_num;
|
||||
static struct table code_hunks = { 0, 4, 0, 0 };
|
||||
static struct table data_hunks = { 0, 4, 0, 0 };
|
||||
static struct table bss_hunks = { 0, 4, 0, 0 };
|
||||
static struct table chip_data_hunks = { 0, 4, 0, 0 };
|
||||
static struct table chip_bss_hunks = { 0, 4, 0, 0 };
|
||||
|
||||
/* static so that no initialization code is required */
|
||||
static struct table reloc_tab = { 0, sizeof (struct reloc), 0, 0 };
|
||||
static struct table symbol_tab = { 0, sizeof (struct symbol), 0, 0 };
|
||||
|
||||
/* (re) init tables */
|
||||
strtab_index = 4;
|
||||
code_hunks.i = 0;
|
||||
data_hunks.i = 0;
|
||||
bss_hunks.i = 0;
|
||||
chip_data_hunks.i = 0;
|
||||
reloc_tab.i = 0;
|
||||
symbol_tab.i = 0;
|
||||
|
||||
while (units < 2)
|
||||
{
|
||||
switch (HUNK_VALUE(GETLONG(*file_ptr++)))
|
||||
{
|
||||
case HUNK_UNIT:
|
||||
DP(("HUNK_UNIT: units = %d\n", units));
|
||||
if (units++) break;
|
||||
#if 0
|
||||
if (! file_ptr[0])
|
||||
#endif
|
||||
{
|
||||
/* need [], not *, so that gcc allocates a fresh copy for
|
||||
* mkstemp() to modify! */
|
||||
char tmp_nam[] = "obj.YYYY.XXXXXX";
|
||||
/* this trick makes mkstemp() lots faster ;-) */
|
||||
sprintf (tmp_nam, "obj.%04d.XXXXXX", obj_file_num++);
|
||||
if ((fd = mkstemp (tmp_nam)) < 0)
|
||||
fprintf (stderr, "Can't create %s (%s). Ignoring it.\n",
|
||||
tmp_nam, strerror (errno));
|
||||
}
|
||||
#if 0
|
||||
/* this idea was too good.. there are so many stupid (and duplicate!) names
|
||||
* of program units, that this generated ridiculous results... */
|
||||
|
||||
else
|
||||
{
|
||||
char *file_name;
|
||||
file_name = alloca (file_ptr[0] + 1);
|
||||
strncpy (file_name, (char *)&file_ptr[1], file_ptr[0]);
|
||||
if ((fd = open (file_name, O_RDWR|O_CREAT|O_EXCL, 0666)) < 0)
|
||||
fprintf (stderr, "Can't create %s: %s. Ignoring it.\n",
|
||||
file_name, strerror (errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* init data for new object file */
|
||||
text = data = chip_data = 0;
|
||||
bzero (&hdr, sizeof (hdr));
|
||||
chip_data_size = chip_bss_size = 0;
|
||||
/* if someone want's to use'em on a sun, why shouldn't we make
|
||||
* the files sun-conformant? */
|
||||
hdr.a_mid = MID_SUN010;
|
||||
hdr.a_magic = OMAGIC;
|
||||
hunk_num = 0;
|
||||
next_hunk (& file_ptr);
|
||||
if (silent_mode)
|
||||
{
|
||||
putchar ('.');
|
||||
fflush (stdout);
|
||||
}
|
||||
break;
|
||||
|
||||
case HUNK_NAME:
|
||||
case HUNK_DEBUG:
|
||||
DP(("HUNK_NAME/DEBUG\n"));
|
||||
/* this hunk is silently ignored ;-) */
|
||||
next_hunk (& file_ptr);
|
||||
break;
|
||||
|
||||
case HUNK_OVERLAY:
|
||||
fprintf (stderr, "warning: overlay hunk ignored!\n");
|
||||
next_hunk (& file_ptr);
|
||||
break;
|
||||
|
||||
case HUNK_BREAK:
|
||||
fprintf (stderr, "warning: break hunk ignored!\n");
|
||||
break;
|
||||
|
||||
case HUNK_HEADER:
|
||||
fprintf (stderr, "warning: load file header encountered.\n");
|
||||
fprintf (stderr, " are you sure this is an object file?\n");
|
||||
/* nevertheless, we go on. perhaps some day I need this feature to
|
||||
* be able to convert a loadfile into an object file?! */
|
||||
|
||||
/* skip (never used) resident library names */
|
||||
while (GETLONG(file_ptr[0])) next_hunk (& file_ptr);
|
||||
/* skip null-word, table_size, F & L, and size-table */
|
||||
file_ptr += 4 + (GETLONG(file_ptr[1]) - GETLONG(file_ptr[2]) + 1);
|
||||
break;
|
||||
|
||||
case HUNK_CODE:
|
||||
DP(("HUNK_CODE, size = $%x\n", GETLONG(file_ptr[0]) << 2));
|
||||
is_chip = HUNK_ATTRIBUTE(GETLONG(file_ptr[-1])) == HUNK_ATTR_CHIP;
|
||||
if (is_chip)
|
||||
fprintf (stderr, "CHIP code hunks are not supported, "
|
||||
"ignoring CHIP attribute\n");
|
||||
if (GETLONG(file_ptr[0]))
|
||||
{
|
||||
/* only accept one code hunk with size != 0 */
|
||||
if (hdr.a_text)
|
||||
limit_hunk ("code");
|
||||
else
|
||||
{
|
||||
text = (uint8_t *)&file_ptr[1];
|
||||
hdr.a_text = GETLONG(file_ptr[0]) << 2;
|
||||
}
|
||||
}
|
||||
next_hunk (& file_ptr);
|
||||
add_table (& code_hunks, &hunk_num);
|
||||
hunk_num++;
|
||||
break;
|
||||
|
||||
case HUNK_DATA:
|
||||
DP(("HUNK_DATA, size = $%x\n", GETLONG(file_ptr[0]) << 2));
|
||||
is_chip = HUNK_ATTRIBUTE(GETLONG(file_ptr[-1])) == HUNK_ATTR_CHIP;
|
||||
if (GETLONG(file_ptr[0]))
|
||||
{
|
||||
/* only accept one data hunk with size != 0 */
|
||||
if (is_chip)
|
||||
{
|
||||
if (chip_data_size)
|
||||
limit_hunk ("chip data");
|
||||
else
|
||||
{
|
||||
chip_data = (uint8_t *) &file_ptr[1];
|
||||
chip_data_size = GETLONG(file_ptr[0]) << 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdr.a_data)
|
||||
limit_hunk ("data");
|
||||
else
|
||||
{
|
||||
data = (uint8_t *)&file_ptr[1];
|
||||
hdr.a_data = GETLONG(file_ptr[0]) << 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
next_hunk (& file_ptr);
|
||||
add_table (is_chip ? & chip_data_hunks : & data_hunks, & hunk_num);
|
||||
hunk_num++;
|
||||
break;
|
||||
|
||||
case HUNK_BSS:
|
||||
DP(("HUNK_BSS, size = $%x\n", GETLONG(file_ptr[0]) << 2));
|
||||
is_chip = HUNK_ATTRIBUTE(file_ptr[-1]) == HUNK_ATTR_CHIP;
|
||||
if (GETLONG(file_ptr[0]))
|
||||
{
|
||||
/* only accept one bss hunk with size != 0 */
|
||||
if (is_chip)
|
||||
{
|
||||
if (chip_bss_size)
|
||||
limit_hunk ("chip bss");
|
||||
else
|
||||
chip_bss_size = GETLONG(file_ptr[0]) << 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdr.a_bss)
|
||||
limit_hunk ("bss");
|
||||
else
|
||||
hdr.a_bss = GETLONG(file_ptr[0]) << 2;
|
||||
}
|
||||
}
|
||||
file_ptr++;
|
||||
add_table (is_chip ? & chip_bss_hunks : & bss_hunks, & hunk_num);
|
||||
hunk_num++;
|
||||
break;
|
||||
|
||||
case HUNK_RELOC8:
|
||||
case HUNK_RELOC16:
|
||||
case HUNK_RELOC32:
|
||||
/* do they work like this? don't know... */
|
||||
case HUNK_DREL8:
|
||||
case HUNK_DREL16:
|
||||
case HUNK_DREL32:
|
||||
{
|
||||
int size, brel;
|
||||
|
||||
brel = GETLONG(file_ptr[-1]) >= HUNK_DREL32;
|
||||
size = (brel ? HUNK_DREL8 : HUNK_RELOC8) - GETLONG(file_ptr[-1]);
|
||||
DP(("HUNK_RELOC/DREL ($%x), brel = %d, size = %d\n", GETLONG(file_ptr[-1]), brel, size));
|
||||
|
||||
while (GETLONG(file_ptr[0]))
|
||||
{
|
||||
long to_reloc = GETLONG(file_ptr[1]);
|
||||
long n = GETLONG(file_ptr[0]);
|
||||
|
||||
while (n--)
|
||||
/* amiga relocs are automatically pcrel, when size < 2
|
||||
* according to the AmigaDOS-Manual 2nd ed. */
|
||||
add_reloc (&reloc_tab, hunk_num-1, to_reloc, GETLONG(file_ptr[n+2]),
|
||||
size, size != 2, brel, -1);
|
||||
|
||||
file_ptr += GETLONG(file_ptr[0]) + 2;
|
||||
}
|
||||
}
|
||||
file_ptr++;
|
||||
break;
|
||||
|
||||
case HUNK_SYMBOL:
|
||||
case HUNK_EXT:
|
||||
DP(("HUNK_SYMBOL/EXT\n"));
|
||||
while (GETLONG(file_ptr[0]))
|
||||
{
|
||||
int n, size, brel;
|
||||
|
||||
#if 0
|
||||
DP((" EXT_: %d, %-*.*s\n", file_ptr[0] >> 24,
|
||||
4*(file_ptr[0] & 0xffffff), 4*(file_ptr[0] & 0xffffff), &file_ptr[1]));
|
||||
#endif
|
||||
|
||||
switch (GETLONG(file_ptr[0]) >> 24)
|
||||
{
|
||||
case EXT_SYMB:
|
||||
case EXT_DEF:
|
||||
case EXT_ABS:
|
||||
case EXT_RES:
|
||||
add_symbol (&symbol_tab, hunk_num-1,
|
||||
GETLONG(file_ptr[0]),
|
||||
file_ptr[1+(GETLONG(file_ptr[0]) & 0xffffff)],
|
||||
(char *)&file_ptr[1]);
|
||||
file_ptr += 2+(GETLONG(file_ptr[0]) & 0xffffff);
|
||||
break;
|
||||
|
||||
case EXT_COMMON:
|
||||
/* first define the common symbol, then add the relocs */
|
||||
add_symbol (&symbol_tab, hunk_num-1,
|
||||
GETLONG(file_ptr[0]),
|
||||
file_ptr[1+(GETLONG(file_ptr[0]) & 0xffffff)],
|
||||
(char *)&file_ptr[1]);
|
||||
file_ptr += 2+(GETLONG(file_ptr[0]) & 0xffffff);
|
||||
|
||||
/* now the references, translated into relocs */
|
||||
for (n = file_ptr[0]; n--; )
|
||||
add_reloc (&reloc_tab, hunk_num - 1, -1, GETLONG(file_ptr[n]),
|
||||
2, 0, 0, symbol_tab.i - 1);
|
||||
next_hunk (&file_ptr);
|
||||
break;
|
||||
|
||||
case EXT_REF8:
|
||||
case EXT_REF16:
|
||||
case EXT_REF32:
|
||||
case EXT_DEXT8:
|
||||
case EXT_DEXT16:
|
||||
case EXT_DEXT32:
|
||||
size = GETLONG(file_ptr[0]) >> 24;
|
||||
brel = size >= EXT_DEXT32;
|
||||
size = (size == EXT_REF32 || size == EXT_DEXT32) ? 2 :
|
||||
((size == EXT_REF16 || size == EXT_DEXT16) ? 1 : 0);
|
||||
/* first define the symbol (as undefined ;-)),
|
||||
* then add the relocs */
|
||||
add_symbol (&symbol_tab, hunk_num-1, GETLONG(file_ptr[0]),
|
||||
0, (char *)&file_ptr[1]);
|
||||
file_ptr += 1+(GETLONG(file_ptr[0]) & 0xffffff);
|
||||
|
||||
/* now the references, translated into relocs */
|
||||
for (n = GETLONG(file_ptr[0]); n; n--)
|
||||
add_reloc (&reloc_tab, hunk_num - 1, -1, GETLONG(file_ptr[n]),
|
||||
size, size < 2, brel, symbol_tab.i - 1);
|
||||
next_hunk (&file_ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr,
|
||||
"Unknown symbol type %d, don't know how to handle!\n",
|
||||
GETLONG(file_ptr[0]) >> 24);
|
||||
/* can't continue, don't know how much to advance the file_ptr
|
||||
* to reach the next valid hunk/block */
|
||||
exit(20);
|
||||
}
|
||||
}
|
||||
file_ptr++;
|
||||
break;
|
||||
|
||||
case HUNK_END:
|
||||
DP(("HUNK_END\n"));
|
||||
break;
|
||||
|
||||
case HUNK_LIB:
|
||||
case HUNK_INDEX:
|
||||
fprintf (stderr, "Convert this library into ALINK (join type) format.\n");
|
||||
exit (20);
|
||||
|
||||
default:
|
||||
fprintf (stderr, "Unknown hunk type $%x, unit offset = $%x.\n",
|
||||
GETLONG(file_ptr[-1]), ((file_ptr-1)-*file_pptr) * 2);
|
||||
/* can't continue, don't know how much to advance the file_ptr
|
||||
* to reach the next valid hunk/block */
|
||||
exit(20);
|
||||
}
|
||||
|
||||
if (file_ptr >= max_fp) break;
|
||||
}
|
||||
|
||||
*file_pptr = file_ptr >= max_fp ? max_fp : file_ptr-1;
|
||||
|
||||
if (fd != -1)
|
||||
emit_aout_file (fd, text, data, chip_data,
|
||||
& hdr, chip_data_size, chip_bss_size,
|
||||
& code_hunks, & data_hunks, & bss_hunks,
|
||||
& chip_data_hunks, & chip_bss_hunks,
|
||||
& reloc_tab, & symbol_tab, hunk_num);
|
||||
}
|
||||
|
||||
|
||||
static void emit_aout_file (int fd, void *text, void *data, void *chip_data,
|
||||
struct exec *hdr, int chip_data_size,
|
||||
int chip_bss_size, struct table *ch_tab,
|
||||
struct table *dh_tab, struct table *bh_tab,
|
||||
struct table *cdh_tab, struct table *cbh_tab,
|
||||
struct table *reloc_tab, struct table *symbol_tab,
|
||||
int max_hunk)
|
||||
{
|
||||
int *code_hunks = ch_tab->base;
|
||||
int *data_hunks = dh_tab->base;
|
||||
int *bss_hunks = bh_tab->base;
|
||||
int *chip_data_hunks = cdh_tab->base;
|
||||
int *chip_bss_hunks = cbh_tab->base;
|
||||
|
||||
char htype[max_hunk];
|
||||
int i;
|
||||
struct reloc *r;
|
||||
struct symbol *s;
|
||||
static struct table text_relocs = { 0, sizeof (struct relocation_info), 0, 0 };
|
||||
static struct table data_relocs = { 0, sizeof (struct relocation_info), 0, 0 };
|
||||
|
||||
text_relocs.i = data_relocs.i = 0;
|
||||
|
||||
/* convert hunk-numbers into N_TEXT,N_DATA,N_BSS types
|
||||
* I temporarily use N_EXT to really mean `N_CHIP'
|
||||
*/
|
||||
for (i = 0; i < ch_tab->i; i++) htype[code_hunks[i]] = N_TEXT;
|
||||
for (i = 0; i < dh_tab->i; i++) htype[data_hunks[i]] = N_DATA;
|
||||
for (i = 0; i < bh_tab->i; i++) htype[bss_hunks[i]] = N_BSS;
|
||||
for (i = 0; i < cdh_tab->i; i++) htype[chip_data_hunks[i]] = N_DATA|N_EXT;
|
||||
for (i = 0; i < cbh_tab->i; i++) htype[chip_bss_hunks[i]] = N_BSS|N_EXT;
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (i = 0; i < max_hunk; i++) DP(("htype[%d] = %d\n", i, htype[i]));
|
||||
#endif
|
||||
|
||||
/* first conversion run. Change all hunk-numbers into N_TEXT, N_DATA and
|
||||
* N_BSS rsp.
|
||||
* (If you wanted to support multi-hunk files (ie. files with more than
|
||||
* one code/data/bss hunk with size > 0) you'd want to do the necessary
|
||||
* conversions here.)
|
||||
* A less general solution is currently implemented: one chip data and one
|
||||
* chip bss hunk are supported as well. Multiple hunks should work analogous,
|
||||
* but with tables instead of variables like `chip_data_size' and `data'.
|
||||
*/
|
||||
for (i = 0, r = (struct reloc *)reloc_tab->base; i < reloc_tab->i; i++, r++)
|
||||
{
|
||||
/* have to convert the destination hunk before the source hunk, since I
|
||||
* need the information, whether I have to change a data or a chip data
|
||||
* source. */
|
||||
|
||||
/* Convert the destination hunk, if this is a local reloc. If it has
|
||||
* an associated symbol, that symbol will be converted from CHIP to whatever
|
||||
* is needed
|
||||
* If the target lies in a chip hunk, we have to change the offset in the
|
||||
* source hunk to include the `hunk-gap' between source and target
|
||||
*/
|
||||
if (r->to_hunk > -1)
|
||||
{
|
||||
/* the base address of the used source hunk */
|
||||
void *base_hunk = NULL;
|
||||
/* this is the mentioned hunk-gap */
|
||||
uint32_t offset = 0;
|
||||
|
||||
switch (htype[r->from_hunk])
|
||||
{
|
||||
case N_TEXT:
|
||||
base_hunk = text;
|
||||
break;
|
||||
|
||||
case N_DATA:
|
||||
base_hunk = data;
|
||||
break;
|
||||
|
||||
case N_DATA|N_EXT:
|
||||
base_hunk = chip_data;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "Local reloc from illegal hunk ($%x)!\n",
|
||||
htype[r->from_hunk]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* account for an eventual shift of the former N_BSS space by
|
||||
* chip_data_size bytes */
|
||||
switch (htype[r->to_hunk])
|
||||
{
|
||||
/* those don't need a shift */
|
||||
case N_TEXT:
|
||||
case N_DATA:
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
case N_BSS:
|
||||
offset = chip_data_size;
|
||||
break;
|
||||
|
||||
case N_DATA|N_EXT:
|
||||
offset = hdr->a_data;
|
||||
break;
|
||||
|
||||
case N_BSS|N_EXT:
|
||||
offset = chip_data_size + hdr->a_bss;
|
||||
break;
|
||||
}
|
||||
|
||||
DP(("r->from = %d, r->to = %d, base = %d, offset = %d\n", r->from_hunk, r->to_hunk, htype[r->from_hunk], offset));
|
||||
|
||||
/* I really don't know how much sense non-long relocs make here,
|
||||
* but it's easy to support, so .. ;-) */
|
||||
switch (r->size)
|
||||
{
|
||||
case 2:
|
||||
*(long *)(base_hunk + r->offset) += (long)offset;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*(short *)(base_hunk + r->offset) += (short)offset;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
*(char *)(base_hunk + r->offset) += (char)offset;
|
||||
break;
|
||||
}
|
||||
|
||||
r->to_hunk = htype[r->to_hunk] & ~N_EXT;
|
||||
}
|
||||
|
||||
/* if it's a CHIP hunk, I have to increment the relocation address by
|
||||
* the size of the base hunk */
|
||||
if (htype[r->from_hunk] & N_EXT)
|
||||
{
|
||||
/* only N_DATA should come here, since there is no such thing as a
|
||||
* reloc originating from BSS space, but we nevertheless check for it.. */
|
||||
if (htype[r->from_hunk] == (N_DATA|N_EXT))
|
||||
r->offset += hdr->a_data;
|
||||
else
|
||||
fprintf (stderr, "Reloc from CHIP-BSS space, undefined!!\n");
|
||||
}
|
||||
r->from_hunk = htype[r->from_hunk] & ~N_EXT;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* now convert the symbols into nlist's */
|
||||
for (i = 0, s = (struct symbol *)symbol_tab->base; i < symbol_tab->i; i++, s++)
|
||||
{
|
||||
int nl_type = 0;
|
||||
|
||||
/* change hunk numbers into types */
|
||||
s->hunk_num = htype[s->hunk_num];
|
||||
|
||||
switch (s->type)
|
||||
{
|
||||
case EXT_DEF:
|
||||
/* externally visible symbol */
|
||||
nl_type = N_EXT;
|
||||
/* fall into */
|
||||
|
||||
case EXT_SYMB:
|
||||
nl_type |= s->hunk_num & ~N_EXT;
|
||||
/* adjust multi-hunk values to the one-seg model */
|
||||
if (s->hunk_num == N_DATA)
|
||||
s->value += hdr->a_text;
|
||||
else if (s->hunk_num == N_BSS)
|
||||
s->value += hdr->a_text + hdr->a_data + chip_data_size;
|
||||
else if (s->hunk_num == (N_DATA|N_EXT))
|
||||
s->value += hdr->a_text + hdr->a_data;
|
||||
else if (s->hunk_num == (N_BSS|N_EXT))
|
||||
s->value += hdr->a_text + hdr->a_data + chip_data_size + hdr->a_bss;
|
||||
break;
|
||||
|
||||
case EXT_ABS:
|
||||
nl_type = N_ABS | N_EXT;
|
||||
break;
|
||||
|
||||
case EXT_COMMON:
|
||||
/* ok for common as well, because the value field is only setup
|
||||
* for common-symbols */
|
||||
|
||||
case EXT_REF32:
|
||||
case EXT_REF16:
|
||||
case EXT_REF8:
|
||||
case EXT_DEXT32:
|
||||
case EXT_DEXT16:
|
||||
case EXT_DEXT8:
|
||||
nl_type = N_UNDF | N_EXT;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "What kind of symbol is THAT? (%d)\n", s->type);
|
||||
break;
|
||||
}
|
||||
|
||||
s->type = nl_type;
|
||||
s->pad1 = s->hunk_num = 0; /* clear nl_other & nl_desc fields */
|
||||
}
|
||||
|
||||
/* now convert the reloc table. Adjust (like above) data/bss values to the
|
||||
* one-segment model for local relocations */
|
||||
for (i = 0, r = (struct reloc *)reloc_tab->base; i < reloc_tab->i; i++, r++)
|
||||
{
|
||||
struct relocation_info rel;
|
||||
uint8_t *core_addr;
|
||||
uint32_t delta;
|
||||
|
||||
memset(&rel, 0, sizeof(rel));
|
||||
rel.r_address = r->offset;
|
||||
core_addr = (r->from_hunk == N_TEXT) ? text :
|
||||
((r->offset < hdr->a_data) ? data : chip_data);
|
||||
/* r->offset has already been corrected to point at the chip data part
|
||||
* appended to the data part. Since we don't physically join these
|
||||
* segments (we just write them out after each other) we have to
|
||||
* ignore these changes for patches, this is what DELTA is used for. */
|
||||
delta = (core_addr == chip_data) ? hdr->a_data : 0;
|
||||
|
||||
DP(("r_add = $%x, core = %s, delta = %d, ", rel.r_address,
|
||||
(core_addr == text) ? "text" : ((core_addr == data) ? "data" : "chip_data"),delta));
|
||||
|
||||
if (r->to_hunk == N_DATA) {
|
||||
if (r->size == 2)
|
||||
*(uint32_t *)(core_addr + rel.r_address - delta) += hdr->a_text;
|
||||
else
|
||||
fprintf (stderr, "%s reloc into N_DATA, what should I do?\n",
|
||||
r->size == 1 ? "Short" : "Byte");
|
||||
} else if (r->to_hunk == N_BSS) {
|
||||
if (r->size == 2)
|
||||
*(uint32_t *)(core_addr + rel.r_address - delta) += hdr->a_text + hdr->a_data;
|
||||
else
|
||||
fprintf (stderr, "%s reloc into N_BSS, what should I do?\n",
|
||||
r->size == 1 ? "Short" : "Byte");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* don't know, what went wrong, but this conversion surely converts
|
||||
* _LVO calls wrong. I'm sure leaving this out will generate other bugs..
|
||||
* sigh... */
|
||||
|
||||
|
||||
/* hmm... amigadog-hunks seem to do this in a strange way...
|
||||
* Those relocs *are* treated as pcrel relocs by the linker (blink),
|
||||
* but they're not setup as such... geez, this hunk format.. */
|
||||
if (r->pcrel)
|
||||
switch (r->size)
|
||||
{
|
||||
case 2:
|
||||
*(long *)(core_addr + rel.r_address - delta) -= rel.r_address;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*(short *)(core_addr + rel.r_address - delta) -= (short)rel.r_address;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
*(char *)(core_addr + rel.r_address - delta) -= (char)rel.r_address;
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
rel.r_symbolnum = r->sym_num > -1 ? r->sym_num : r->to_hunk;
|
||||
rel.r_pcrel = r->pcrel;
|
||||
rel.r_length = r->size;
|
||||
rel.r_extern = r->sym_num > -1;
|
||||
rel.r_baserel = r->baserel;
|
||||
rel.r_jmptable = /* rel.r_relative = */ 0;
|
||||
|
||||
DP(("r68: %s reloc\n", (r->from_hunk == N_TEXT) ? "text" : "data"));
|
||||
add_table ((r->from_hunk == N_TEXT) ? & text_relocs : & data_relocs,
|
||||
&rel);
|
||||
}
|
||||
|
||||
DP(("r68: #tr = %d, #dr = %d\n", text_relocs.i, data_relocs.i));
|
||||
|
||||
/* depending on whether we had any actual CHIP data, we have to adjust
|
||||
* some of the header data, and we have to generate symbols containing the
|
||||
* real size of the non-chip section(s) */
|
||||
if (chip_data_size)
|
||||
{
|
||||
/* slightly different syntax, now that we directly add an nlist symbol */
|
||||
add_symbol (symbol_tab, 0, (N_ABS << 24) | ((sizeof (CHIP_DATA_START)+3)>>2),
|
||||
hdr->a_data, CHIP_DATA_START);
|
||||
hdr->a_data += chip_data_size;
|
||||
}
|
||||
if (chip_bss_size)
|
||||
{
|
||||
add_symbol (symbol_tab, 0, (N_ABS << 24) | ((sizeof (CHIP_BSS_START)+3)>>2),
|
||||
hdr->a_bss, CHIP_BSS_START);
|
||||
hdr->a_bss += chip_bss_size;
|
||||
}
|
||||
|
||||
/* oky, fill out the rest of the header and dump everything */
|
||||
hdr->a_syms = symbol_tab->i * sizeof (struct nlist);
|
||||
hdr->a_trsize = text_relocs.i * sizeof (struct relocation_info);
|
||||
hdr->a_drsize = data_relocs.i * sizeof (struct relocation_info);
|
||||
*(uint32_t *)str_table = PUTLONG(strtab_index);
|
||||
{
|
||||
struct exec hdr_be;;
|
||||
|
||||
hdr_be.a_mid = PUTWORD(hdr->a_mid);
|
||||
hdr_be.a_magic = PUTWORD(hdr->a_magic);
|
||||
hdr_be.a_text = PUTLONG(hdr->a_text);
|
||||
hdr_be.a_data = PUTLONG(hdr->a_data);
|
||||
hdr_be.a_bss = PUTLONG(hdr->a_bss);
|
||||
hdr_be.a_syms = PUTLONG(hdr->a_syms);
|
||||
hdr_be.a_entry = PUTLONG(hdr->a_entry);
|
||||
hdr_be.a_trsize = PUTLONG(hdr->a_trsize);
|
||||
hdr_be.a_drsize = PUTLONG(hdr->a_drsize);
|
||||
|
||||
write (fd, (char *)&hdr_be, sizeof (hdr_be));
|
||||
}
|
||||
if (hdr->a_text) write (fd, text, hdr->a_text);
|
||||
if (hdr->a_data - chip_data_size > 0)
|
||||
write (fd, data, hdr->a_data - chip_data_size);
|
||||
if (chip_data_size) write (fd, chip_data, chip_data_size);
|
||||
if (hdr->a_trsize) write (fd, text_relocs.base, hdr->a_trsize);
|
||||
if (hdr->a_drsize) write (fd, data_relocs.base, hdr->a_drsize);
|
||||
if (hdr->a_syms) write (fd, symbol_tab->base, hdr->a_syms);
|
||||
write (fd, str_table, strtab_index);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct stat stb;
|
||||
int ret_val = 0;
|
||||
uint32_t *obj_pointer;
|
||||
|
||||
FILE *fp;
|
||||
|
||||
/* loop over all arguments. Can be either
|
||||
* o object files
|
||||
* o libraries (ALINK style for now)
|
||||
*/
|
||||
while (*++argv)
|
||||
{
|
||||
if (! strcmp (*argv, "-s"))
|
||||
{
|
||||
silent_mode = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat (*argv, &stb) == -1)
|
||||
{
|
||||
fprintf (stderr, "%s: %s\n", *argv, strerror (errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
file_buf = file_buf ? realloc (file_buf, stb.st_size)
|
||||
: malloc (stb.st_size);
|
||||
if (! file_buf)
|
||||
{
|
||||
fprintf (stderr, "%s: can't allocate %d byte of memory.\n",
|
||||
*argv, (int)stb.st_size);
|
||||
ret_val = 20;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(fp = fopen (*argv, "r")))
|
||||
{
|
||||
fprintf (stderr, "Can't open %s: %s.\n", *argv, strerror (errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read the file in at once */
|
||||
if (fread (file_buf, stb.st_size, 1, fp) != 1)
|
||||
{
|
||||
fprintf (stderr, "Can't read %s: %s.\n", *argv, strerror (errno));
|
||||
fclose (fp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! silent_mode)
|
||||
printf ("Converting %s:\n", *argv);
|
||||
|
||||
/* oky, now digest the file (possibly more than one object file) */
|
||||
for (obj_pointer = file_buf;
|
||||
obj_pointer < (uint32_t *)((uint8_t *)file_buf + stb.st_size); )
|
||||
digest_objfile (&obj_pointer, (uint32_t *)((uint8_t *)file_buf + stb.st_size));
|
||||
|
||||
if (! silent_mode)
|
||||
putchar ('\n');
|
||||
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from objtools import ar
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig()
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
print '%s:' % path
|
||||
for num, entry in enumerate(ar.ReadFile(path), start=1):
|
||||
print '%5d:' % num, entry.name, '(length: %d)' % len(entry.data)
|
||||
print ''
|
|
@ -1,247 +0,0 @@
|
|||
import logging
|
||||
import os
|
||||
import struct
|
||||
|
||||
from cStringIO import StringIO
|
||||
from collections import namedtuple, Sequence
|
||||
|
||||
from util import hexdump
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Header(namedtuple('Header', ('mid', 'magic', 'text', 'data', 'bss',
|
||||
'syms', 'entry', 'trsize', 'drsize'))):
|
||||
magic_map = {'OMAGIC': 0407, 'NMAGIC': 0410, 'ZMAGIC': 0413}
|
||||
mid_map = {'ZERO': 0, 'SUN010': 1, 'SUN020': 2, 'HP200': 200,
|
||||
'HP300': 300, 'HPUX': 0x20C, 'HPUX800': 0x20B}
|
||||
|
||||
@classmethod
|
||||
def decode(cls, fh):
|
||||
data = fh.read(32)
|
||||
|
||||
if len(data) != 32:
|
||||
raise ValueError('Not a valid a.out header!')
|
||||
|
||||
mid, magic, text, data, bss, syms, entry, trsize, drsize = \
|
||||
struct.unpack('>HHIIIIIII', data)
|
||||
|
||||
for name, value in cls.magic_map.items():
|
||||
if magic == value:
|
||||
magic = name
|
||||
break
|
||||
|
||||
for name, value in cls.mid_map.items():
|
||||
if mid == value:
|
||||
mid = name
|
||||
break
|
||||
|
||||
if magic not in cls.magic_map or mid not in cls.mid_map:
|
||||
raise ValueError('Not a valid a.out header!')
|
||||
|
||||
return cls(mid, magic, text, data, bss, syms, entry, trsize, drsize)
|
||||
|
||||
|
||||
class RelocInfo(namedtuple('RelocInfo', ('address', 'symbolnum', 'pcrel',
|
||||
'length', 'extern', 'baserel',
|
||||
'jmptable', 'relative', 'copy'))):
|
||||
@classmethod
|
||||
def decode(cls, data):
|
||||
r_address, info = struct.unpack('>II', data)
|
||||
r_symbolnum = (info >> 8) & 0xffffff
|
||||
r_pcrel = bool(info & 128)
|
||||
r_length = (info >> 5) & 3
|
||||
r_extern = bool(info & 16)
|
||||
r_baserel = bool(info & 8)
|
||||
r_jmptable = bool(info & 4)
|
||||
r_relative = bool(info & 2)
|
||||
r_copy = bool(info & 1)
|
||||
|
||||
return cls(r_address, r_symbolnum, r_pcrel, r_length, r_extern, r_baserel,
|
||||
r_jmptable, r_relative, r_copy)
|
||||
|
||||
def as_string(self, strings):
|
||||
t = '{0}{1}'.format('BASE' if self.baserel else '', 8 * (1 << self.length))
|
||||
try:
|
||||
s = strings[self.symbolnum]
|
||||
except IndexError:
|
||||
if self.symbolnum == 4:
|
||||
s = '.text'
|
||||
elif self.symbolnum == 6:
|
||||
s = '.data'
|
||||
elif self.symbolnum == 8:
|
||||
s = '.bss'
|
||||
else:
|
||||
s = str(self.symbolnum)
|
||||
return '{0:08x} {1:>6} {2}'.format(self.address, t, s)
|
||||
|
||||
|
||||
class SymbolInfo(namedtuple('SymbolInfo', ('strx', 'type', 'other', 'desc',
|
||||
'value'))):
|
||||
# http://sourceware.org/gdb/current/onlinedocs/stabs/Stab-Types.html
|
||||
type_map = [
|
||||
('UNDF', 0x00), ('EXT', 0x01), ('ABS', 0x02), ('TEXT', 0x04),
|
||||
('DATA', 0x06), ('BSS', 0x08), ('INDR', 0x0a), ('SIZE', 0x0c),
|
||||
('COMM', 0x12), ('SETA', 0x14), ('SETT', 0x16), ('SETD', 0x18),
|
||||
('SETB', 0x1a), ('SETV', 0x1c), ('WARNING', 0x1e), ('FN', 0x1f),
|
||||
('GSYM', 0x20), ('FNAME', 0x22), ('FUN', 0x24), ('STSYM', 0x26),
|
||||
('LCSYM', 0x28), ('MAIN', 0x2a), ('ROSYM', 0x2c), ('PC', 0x30),
|
||||
('NSYMS', 0x32), ('NOMAP', 0x34), ('MAC_DEFINE', 0x36), ('OBJ', 0x38),
|
||||
('MAC_UNDEF', 0x3a), ('OPT', 0x3c), ('RSYM', 0x40), ('SLINE', 0x44),
|
||||
('DSLINE', 0x46), ('BSLINE', 0x48), ('FLINE', 0x4c), ('EHDECL', 0x50),
|
||||
('CATCH', 0x54), ('SSYM', 0x60), ('ENDM', 0x62), ('SO', 0x64),
|
||||
('LSYM', 0x80), ('BINCL', 0x82), ('SOL', 0x84), ('PSYM', 0xa0),
|
||||
('EINCL', 0xa2), ('ENTRY', 0xa4), ('LBRAC', 0xc0), ('EXCL', 0xc2),
|
||||
('SCOPE', 0xc4), ('RBRAC', 0xe0), ('BCOMM', 0xe2), ('ECOMM', 0xe4),
|
||||
('ECOML', 0xe8), ('WITH', 0xea), ('NBTEXT', 0xf0), ('NBDATA', 0xf2),
|
||||
('NBBSS', 0xf4), ('NBSTS', 0xf6), ('NBLCS', 0xf8)]
|
||||
|
||||
@classmethod
|
||||
def decode(cls, data):
|
||||
n_strx, n_type, n_other, n_desc, n_value = \
|
||||
struct.unpack('>iBbhI', data)
|
||||
|
||||
return cls(n_strx, n_type, n_other, n_desc, n_value)
|
||||
|
||||
@property
|
||||
def external(self):
|
||||
return bool(self.type & 1)
|
||||
|
||||
@property
|
||||
def type_str(self):
|
||||
for t, v in self.type_map:
|
||||
if (self.type & ~1) == v:
|
||||
return t
|
||||
return 'DEBUG'
|
||||
|
||||
def as_string(self, strings):
|
||||
visibility = 'g' if self.external else 'l'
|
||||
symbolnum = strings.offsetToIndex(self.strx)
|
||||
if symbolnum == -1:
|
||||
symbol = ''
|
||||
else:
|
||||
symbol = strings[symbolnum]
|
||||
return '{3:08x} {5} {0:<5} {2:04x} {1:02x} {6:02x} {4}'.format(
|
||||
self.type_str, self.other, self.desc, self.value, symbol,
|
||||
visibility, self.type)
|
||||
|
||||
|
||||
class StringTable(Sequence):
|
||||
def __init__(self):
|
||||
self._map = {}
|
||||
self._table = []
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self._table[index]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._table)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._table)
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._table
|
||||
|
||||
def addString(self, offset, text):
|
||||
self._map[offset] = len(self._table)
|
||||
self._table.append(text)
|
||||
|
||||
@classmethod
|
||||
def decode(cls, data):
|
||||
strings = cls()
|
||||
s = 0
|
||||
while True:
|
||||
e = data.find('\0', s)
|
||||
if e == -1:
|
||||
strings.addString(s + 4, data[s:])
|
||||
break
|
||||
else:
|
||||
strings.addString(s + 4, data[s:e])
|
||||
s = e + 1
|
||||
return strings
|
||||
|
||||
def offsetToIndex(self, offset):
|
||||
return self._map.get(offset, -1)
|
||||
|
||||
|
||||
class Aout(object):
|
||||
def __init__(self):
|
||||
self._path = None
|
||||
self._header = None
|
||||
self._text = ''
|
||||
self._data = ''
|
||||
self._symbols = []
|
||||
self._text_relocs = []
|
||||
self._data_relocs = []
|
||||
self._strings = None
|
||||
|
||||
def read(self, path):
|
||||
self._path = path
|
||||
|
||||
with open(path) as fh:
|
||||
log.debug('Reading %r of size %d bytes.', path, os.path.getsize(path))
|
||||
|
||||
data = StringIO(fh.read())
|
||||
|
||||
self._header = Header.decode(data)
|
||||
|
||||
self._text = data.read(self._header.text)
|
||||
self._data = data.read(self._header.data)
|
||||
text_reloc = data.read(self._header.trsize)
|
||||
data_reloc = data.read(self._header.drsize)
|
||||
symbols = data.read(self._header.syms)
|
||||
str_size = struct.unpack('>I', data.read(4))[0]
|
||||
strings = data.read()
|
||||
|
||||
if str_size != len(strings):
|
||||
log.warn('Wrong size of string table!')
|
||||
|
||||
self._strings = StringTable.decode(strings)
|
||||
|
||||
for i in range(0, len(symbols), 12):
|
||||
self._symbols.append(SymbolInfo.decode(symbols[i:i + 12]))
|
||||
|
||||
for i in range(0, len(text_reloc), 8):
|
||||
self._text_relocs.append(RelocInfo.decode(text_reloc[i:i + 8]))
|
||||
|
||||
for i in range(0, len(data_reloc), 8):
|
||||
self._data_relocs.append(RelocInfo.decode(data_reloc[i:i + 8]))
|
||||
|
||||
def dump(self):
|
||||
print self._header
|
||||
print ''
|
||||
|
||||
if self._text:
|
||||
print 'Text:'
|
||||
hexdump(self._text)
|
||||
print ''
|
||||
|
||||
if self._data:
|
||||
print 'Data:'
|
||||
hexdump(self._data)
|
||||
print ''
|
||||
|
||||
print 'Symbols:'
|
||||
for symbol in self._symbols:
|
||||
print ' ', symbol.as_string(self._strings)
|
||||
print ''
|
||||
|
||||
if self._text_relocs:
|
||||
print 'Text relocations:'
|
||||
for reloc in self._text_relocs:
|
||||
print ' ', reloc.as_string(self._strings)
|
||||
print ''
|
||||
|
||||
if self._data_relocs:
|
||||
print 'Data relocations:'
|
||||
for reloc in self._text_relocs:
|
||||
print ' ', reloc.as_string(self._strings)
|
||||
print ''
|
||||
|
||||
|
||||
def ReadFile(path):
|
||||
aout = Aout()
|
||||
aout.read(path)
|
||||
return aout
|
|
@ -1,72 +0,0 @@
|
|||
import logging
|
||||
import os
|
||||
import struct
|
||||
|
||||
from cStringIO import StringIO
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ArEntry(namedtuple('ArEntry',
|
||||
'name modtime owner group mode data')):
|
||||
@classmethod
|
||||
def decode(cls, fh):
|
||||
data = fh.read(60)
|
||||
|
||||
if len(data) != 60:
|
||||
raise ValueError('Not a valid ar archive header!')
|
||||
|
||||
name, modtime, owner, group, mode, length, magic = \
|
||||
struct.unpack('16s12s6s6s8s10s2s', data)
|
||||
|
||||
if magic != '`\n':
|
||||
raise ValueError('Not a valid ar archive header!')
|
||||
|
||||
length = int(length.strip())
|
||||
modtime = int(modtime.strip() or '0')
|
||||
owner = int(owner.strip() or '0')
|
||||
group = int(group.strip() or '0')
|
||||
mode = mode.strip() or '100644'
|
||||
|
||||
if name.startswith('#1/'):
|
||||
name_length = int(name[3:])
|
||||
name = fh.read(name_length).strip('\0')
|
||||
else:
|
||||
name_length = 0
|
||||
name = name.strip()
|
||||
|
||||
data = fh.read(length - name_length)
|
||||
|
||||
log.debug('entry: file %r, size %d,', name, len(data))
|
||||
|
||||
# next block starts at even boundary
|
||||
if length & 1:
|
||||
fh.seek(1, os.SEEK_CUR)
|
||||
|
||||
return cls(name, modtime, owner, group, mode, data)
|
||||
|
||||
|
||||
def ReadFile(path):
|
||||
entries = []
|
||||
|
||||
with open(path) as fh:
|
||||
data = StringIO(fh.read())
|
||||
|
||||
if data.read(8) != '!<arch>\n':
|
||||
raise ValueError('%s is not an ar archive' % path)
|
||||
|
||||
size = os.path.getsize(path)
|
||||
|
||||
log.debug('Reading ar archive %r of size %d bytes.', path, size)
|
||||
|
||||
while data.tell() < size:
|
||||
# Some archives have version information attached at the end of file,
|
||||
# that confuses ArEntry parser, so just skip it.
|
||||
try:
|
||||
entries.append(ArEntry.decode(data))
|
||||
except struct.error:
|
||||
break
|
||||
|
||||
return entries
|
|
@ -1,633 +0,0 @@
|
|||
import logging
|
||||
import os
|
||||
import struct
|
||||
import textwrap
|
||||
|
||||
from collections import defaultdict, namedtuple
|
||||
from contextlib import contextmanager
|
||||
|
||||
import util
|
||||
from aout import StringTable, SymbolInfo
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
HunkMap = {
|
||||
'HUNK_UNIT': 999,
|
||||
'HUNK_NAME': 1000,
|
||||
'HUNK_CODE': 1001,
|
||||
'HUNK_DATA': 1002,
|
||||
'HUNK_BSS': 1003,
|
||||
'HUNK_RELOC32': 1004,
|
||||
'HUNK_RELOC16': 1005,
|
||||
'HUNK_RELOC8': 1006,
|
||||
'HUNK_EXT': 1007,
|
||||
'HUNK_SYMBOL': 1008,
|
||||
'HUNK_DEBUG': 1009,
|
||||
'HUNK_END': 1010,
|
||||
'HUNK_HEADER': 1011,
|
||||
'HUNK_OVERLAY': 1013,
|
||||
'HUNK_BREAK': 1014,
|
||||
'HUNK_DREL32': 1015,
|
||||
'HUNK_DREL16': 1016,
|
||||
'HUNK_DREL8': 1017,
|
||||
'HUNK_LIB': 1018,
|
||||
'HUNK_INDEX': 1019,
|
||||
'HUNK_RELOC32SHORT': 1020,
|
||||
'HUNK_RELRELOC32': 1021,
|
||||
'HUNK_ABSRELOC16': 1022
|
||||
}
|
||||
|
||||
HunkMapRev = dict((v, k) for k, v in HunkMap.items())
|
||||
|
||||
HunkExtMap = {
|
||||
'EXT_SYMB': 0, # symbol table
|
||||
'EXT_DEF': 1, # relocatable definition
|
||||
'EXT_ABS': 2, # Absolute definition
|
||||
'EXT_RES': 3, # no longer supported
|
||||
'EXT_REF32': 129, # 32 bit absolute reference to symbol
|
||||
'EXT_COMMON': 130, # 32 bit absolute reference to COMMON block
|
||||
'EXT_REF16': 131, # 16 bit PC-relative reference to symbol
|
||||
'EXT_REF8': 132, # 8 bit PC-relative reference to symbol
|
||||
'EXT_DEXT32': 133, # 32 bit data relative reference
|
||||
'EXT_DEXT16': 134, # 16 bit data relative reference
|
||||
'EXT_DEXT8': 135, # 8 bit data relative reference
|
||||
'EXT_RELREF32': 136, # 32 bit PC-relative reference to symbol
|
||||
'EXT_RELCOMMON': 137, # 32 bit PC-relative reference to COMMON block
|
||||
'EXT_ABSREF16': 138, # 16 bit absolute reference to symbol
|
||||
'EXT_ABSREF8': 139 # 8 bit absolute reference to symbol
|
||||
}
|
||||
|
||||
HunkExtMapRev = dict((v, k) for k, v in HunkExtMap.items())
|
||||
|
||||
# Any hunks that have the HUNKB_ADVISORY bit set will be ignored if they
|
||||
# aren't understood. When ignored, they're treated like HUNK_DEBUG hunks.
|
||||
# NOTE: this handling of HUNKB_ADVISORY started as of V39 dos.library! If
|
||||
# lading such executables is attempted under <V39 dos, it will fail with a
|
||||
# bad hunk type.
|
||||
HUNKB_ADVISORY = 29
|
||||
HUNKB_CHIP = 30
|
||||
HUNKB_FAST = 31
|
||||
|
||||
HunkFlagsMap = {
|
||||
'HUNKF_ADVISORY': 1 << HUNKB_ADVISORY,
|
||||
'HUNKF_CHIP': 1 << HUNKB_CHIP,
|
||||
'HUNKF_FAST': 1 << HUNKB_FAST
|
||||
}
|
||||
|
||||
|
||||
Symbol = namedtuple('Symbol', 'name size refs')
|
||||
|
||||
|
||||
class Hunk(object):
|
||||
def __init__(self, type_):
|
||||
self.type = type_
|
||||
|
||||
@staticmethod
|
||||
def getType(number):
|
||||
number &= 0x1fffffff
|
||||
|
||||
try:
|
||||
return HunkMapRev[number]
|
||||
except KeyError:
|
||||
raise ValueError('Unknown Hunk: %d' % number)
|
||||
|
||||
@staticmethod
|
||||
def getFlags(number):
|
||||
return [name for name, value in HunkFlagsMap.items() if value & number]
|
||||
|
||||
|
||||
class HunkSep(Hunk):
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
type_, _ = hf.readHunk('HUNK_END', 'HUNK_BREAK')
|
||||
return cls(type_)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
|
||||
|
||||
class HunkStr(Hunk):
|
||||
def __init__(self, type_, name=''):
|
||||
Hunk.__init__(self, type_)
|
||||
self.name = name
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
type_, _ = hf.readHunk('HUNK_NAME', 'HUNK_UNIT')
|
||||
return cls(type_, hf.readString())
|
||||
|
||||
def dump(self):
|
||||
if self.type == 'HUNK_UNIT':
|
||||
print '-' * 80
|
||||
print ''
|
||||
|
||||
print self.type
|
||||
print ' ' + repr(self.name)
|
||||
|
||||
|
||||
class HunkBinary(Hunk):
|
||||
def __init__(self, type_, flags=None, data=''):
|
||||
Hunk.__init__(self, type_)
|
||||
self.flags = flags or []
|
||||
self.data = data
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
type_, flags = hf.readHunk('HUNK_DATA', 'HUNK_CODE')
|
||||
return cls(type_, flags, hf.readBytes())
|
||||
|
||||
def dump(self):
|
||||
print '{0} {1}'.format(self.type, ', '.join(self.flags))
|
||||
if self.data:
|
||||
util.hexdump(self.data)
|
||||
else:
|
||||
print ' [empty]'
|
||||
|
||||
|
||||
class HunkDebug(Hunk):
|
||||
def __init__(self, fmt='?', data=''):
|
||||
Hunk.__init__(self, 'HUNK_DEBUG')
|
||||
self.fmt = fmt
|
||||
self.data = data
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_DEBUG')
|
||||
length = hf.readLong() * 4
|
||||
|
||||
with hf.rollback():
|
||||
fmt1 = hf.readLong()
|
||||
fmt2 = hf.readString(4)
|
||||
|
||||
if fmt1 == 0x10b:
|
||||
# magic-number: 0x10b
|
||||
# symtabsize strtabsize
|
||||
# symtabdata [length=symtabsize]
|
||||
# strtabdata [length=strtabsize]
|
||||
# [pad bytes]
|
||||
hf.skip(4)
|
||||
symtabsize = hf.readLong()
|
||||
strtabsize = hf.readLong()
|
||||
symtab = hf.read(symtabsize)
|
||||
hf.skip(4)
|
||||
strtab = hf.read(strtabsize)
|
||||
|
||||
symbols = []
|
||||
for i in range(0, symtabsize, 12):
|
||||
symbols.append(SymbolInfo.decode(symtab[i:i + 12]))
|
||||
|
||||
strings = StringTable.decode(strtab)
|
||||
|
||||
if strtabsize & 3:
|
||||
hf.skip(4 - strtabsize & 3)
|
||||
|
||||
return cls('GNU', (symbols, strings))
|
||||
elif fmt2 == 'OPTS':
|
||||
hf.skip(8)
|
||||
return cls('SAS/C opts', hf.read(length - 8))
|
||||
|
||||
return cls('?', hf.read(length))
|
||||
|
||||
def dump(self):
|
||||
print '{0} (format: {1!r})'.format(self.type, self.fmt)
|
||||
|
||||
if self.fmt is 'GNU':
|
||||
for symbol in self.data[0]:
|
||||
print ' ', symbol.as_string(self.data[1])
|
||||
else:
|
||||
util.hexdump(self.data)
|
||||
|
||||
|
||||
class HunkOverlay(Hunk):
|
||||
def __init__(self):
|
||||
Hunk.__init__(self, 'HUNK_OVERLAY')
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_OVERLAY')
|
||||
hf.skip(hf.readLong() * 4 + 4)
|
||||
return cls()
|
||||
|
||||
|
||||
class HunkBss(Hunk):
|
||||
def __init__(self, flags=None, size=0):
|
||||
Hunk.__init__(self, 'HUNK_BSS')
|
||||
self.flags = flags or []
|
||||
self.size = size
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
_, flags = hf.readHunk('HUNK_BSS')
|
||||
return cls(flags, hf.readLong() * 4)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
print ' {0} bytes'.format(self.size)
|
||||
|
||||
|
||||
class HunkLib(Hunk):
|
||||
def __init__(self, size=0):
|
||||
Hunk.__init__(self, 'HUNK_LIB')
|
||||
self.size = size
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
_, flags = hf.readHunk('HUNK_LIB')
|
||||
return cls(hf.readLong() * 4)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
|
||||
|
||||
class HunkReloc(Hunk):
|
||||
def __init__(self, type_, relocs=None):
|
||||
Hunk.__init__(self, type_)
|
||||
self.relocs = relocs or {}
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
type_, _ = hf.readHunk('HUNK_RELOC32', 'HUNK_RELOC16', 'HUNK_RELOC8',
|
||||
'HUNK_DREL32', 'HUNK_DREL16', 'HUNK_DREL8')
|
||||
|
||||
if hf.type is 'executable' and type_ in ['HUNK_DREL32', 'HUNK_DREL16',
|
||||
'HUNK_DREL8']:
|
||||
relocs = hf.readShortRelocs()
|
||||
else:
|
||||
relocs = hf.readRelocs()
|
||||
|
||||
return cls(type_, relocs)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
for k, nums in self.relocs.items():
|
||||
prefix = ' %d: ' % k
|
||||
print textwrap.fill('[' + ', '.join(str(n) for n in sorted(nums)) + ']',
|
||||
width=68, initial_indent=prefix,
|
||||
subsequent_indent=' ' * (len(prefix) + 1))
|
||||
|
||||
|
||||
class HunkSymbol(Hunk):
|
||||
def __init__(self, symbols=None):
|
||||
Hunk.__init__(self, 'HUNK_SYMBOL')
|
||||
self.symbols = symbols or []
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_SYMBOL')
|
||||
return cls(hf.readSymbols())
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
|
||||
l = max(len(s.name) for s in self.symbols) + 1
|
||||
|
||||
for s in sorted(self.symbols, key=lambda s: s.name):
|
||||
print ' {0}: {1}'.format(s.name.ljust(l, ' '), s.refs)
|
||||
|
||||
|
||||
class HunkHeader(Hunk):
|
||||
def __init__(self, residents=None, hunks=0, first=0, last=0,
|
||||
specifiers=None):
|
||||
Hunk.__init__(self, 'HUNK_HEADER')
|
||||
self.residents = residents or []
|
||||
self.hunks = hunks
|
||||
self.first = first
|
||||
self.last = last
|
||||
self.specifiers = specifiers or []
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_HEADER')
|
||||
|
||||
residents = []
|
||||
|
||||
while True:
|
||||
longs = hf.readLong()
|
||||
|
||||
if not longs:
|
||||
break
|
||||
|
||||
residents.append(hf.readString(longs * 4))
|
||||
|
||||
hunks, first, last = hf.readLong(), hf.readLong(), hf.readLong()
|
||||
specifiers = [hf.readLong() for i in range(last - first + 1)]
|
||||
|
||||
return cls(residents, hunks, first, last, specifiers)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
print ' hunks={0}, first={1}, last={2}'.format(self.hunks, self.first,
|
||||
self.last)
|
||||
print ' residents : ' + repr(self.residents)
|
||||
print ' specifiers : ' + repr(self.specifiers)
|
||||
|
||||
|
||||
class HunkExt(Hunk):
|
||||
def __init__(self, hunks=None):
|
||||
Hunk.__init__(self, 'HUNK_EXT')
|
||||
self.hunks = hunks or defaultdict(list)
|
||||
|
||||
@staticmethod
|
||||
def getType(number):
|
||||
try:
|
||||
return HunkExtMapRev[number]
|
||||
except KeyError:
|
||||
raise ValueError('Unknown HunkExt: %d' % number)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_EXT')
|
||||
|
||||
hunks = defaultdict(list)
|
||||
|
||||
while True:
|
||||
longs = hf.readLong()
|
||||
|
||||
if not longs:
|
||||
break
|
||||
|
||||
length = (longs & 0xffffff) * 4
|
||||
extName = HunkExt.getType(longs >> 24)
|
||||
|
||||
if extName in ['EXT_DEF', 'EXT_ABS', 'EXT_REL']:
|
||||
symbol = hf.readSymbol(length)
|
||||
elif extName in ['EXT_REF32', 'EXT_REF16', 'EXT_REF8',
|
||||
'EXT_DEXT32', 'EXT_DEXT16', 'EXT_DEXT8']:
|
||||
symbol = hf.readString(length)
|
||||
count = hf.readLong()
|
||||
refs = [hf.readLong() for i in range(count)]
|
||||
symbol = Symbol(symbol, None, refs)
|
||||
elif extName in ['EXT_COMMON']:
|
||||
name = hf.readString(length)
|
||||
size = hf.readLong()
|
||||
refs_num = hf.readLong()
|
||||
refs = [hf.readLong() for i in range(refs_num)]
|
||||
symbol = Symbol(name, size, refs)
|
||||
else:
|
||||
raise NotImplementedError('%s not handled.' % extName)
|
||||
|
||||
hunks[extName].append(symbol)
|
||||
|
||||
return cls(hunks)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
|
||||
for name, symbols in self.hunks.items():
|
||||
print ' ', name
|
||||
sl = max(len(s.name) for s in symbols)
|
||||
for symbol, size, value in symbols:
|
||||
print ' ', symbol.ljust(sl, ' '),
|
||||
if value is not None:
|
||||
print '=', sorted(value) if isinstance(value, list) else value
|
||||
else:
|
||||
print ':', repr(size)
|
||||
|
||||
|
||||
class HunkIndex(Hunk):
|
||||
def __init__(self, units=None):
|
||||
Hunk.__init__(self, 'HUNK_INDEX')
|
||||
self.units = units or []
|
||||
|
||||
@classmethod
|
||||
def parse(cls, hf):
|
||||
hf.readHunk('HUNK_INDEX')
|
||||
|
||||
length = hf.readLong() * 4
|
||||
last = hf.tell() + length
|
||||
|
||||
strsize = hf.readWord()
|
||||
strdata = hf.read(strsize)
|
||||
names = {}
|
||||
|
||||
s = 0
|
||||
|
||||
while True:
|
||||
e = strdata.find('\0', s, strsize)
|
||||
|
||||
if e == -1:
|
||||
names[s] = strdata[s:]
|
||||
break
|
||||
|
||||
if e > s:
|
||||
names[s] = strdata[s:e]
|
||||
|
||||
s = e + 1
|
||||
|
||||
units = []
|
||||
|
||||
while hf.tell() < last:
|
||||
unit_name = names[hf.readWord()]
|
||||
first_hunk = hf.readWord() * 4
|
||||
|
||||
hunks_count = hf.readWord()
|
||||
hunks = []
|
||||
|
||||
for i in range(hunks_count):
|
||||
h_name = names[hf.readWord()]
|
||||
h_size = hf.readWord() * 4
|
||||
h_type = hf.readWord()
|
||||
|
||||
refs_count = hf.readWord()
|
||||
refs = []
|
||||
|
||||
for i in range(refs_count):
|
||||
n = hf.readWord()
|
||||
try:
|
||||
refs.append(names[n])
|
||||
except KeyError:
|
||||
refs.append(names[n + 1])
|
||||
|
||||
symbols_count = hf.readWord()
|
||||
symbols = []
|
||||
|
||||
for i in range(symbols_count):
|
||||
s_name = names[hf.readWord()]
|
||||
s_value = hf.readWord()
|
||||
s_type = hf.readWord()
|
||||
symbols.append((s_name, s_value, s_type))
|
||||
|
||||
hunks.append((h_name, h_size, h_type, refs, symbols))
|
||||
|
||||
units.append((unit_name, first_hunk, hunks))
|
||||
|
||||
return cls(units)
|
||||
|
||||
def dump(self):
|
||||
print self.type
|
||||
|
||||
for u in self.units:
|
||||
print ' ', 'UNIT', repr(u[0]), u[1]
|
||||
for h in u[2]:
|
||||
print ' ', Hunk.getType(h[2]), repr(h[0]), h[1]
|
||||
if h[3]:
|
||||
print ' ', 'REFS'
|
||||
for s in sorted(h[3]):
|
||||
print ' ', s
|
||||
if h[4]:
|
||||
print ' ', 'DEFS'
|
||||
l = max(len(s[0]) for s in h[4])
|
||||
for s in sorted(h[4], key=lambda x: x[1]):
|
||||
print ' ', s[0].ljust(l), '=', s[1]
|
||||
print ''
|
||||
|
||||
|
||||
class HunkFile(file):
|
||||
def __init__(self, *args, **kwargs):
|
||||
file.__init__(self, *args, **kwargs)
|
||||
|
||||
self.size = os.path.getsize(self.name)
|
||||
self.type = 'object'
|
||||
|
||||
@contextmanager
|
||||
def rollback(self):
|
||||
pos = self.tell()
|
||||
yield self
|
||||
self.seek(pos, os.SEEK_SET)
|
||||
|
||||
def readWord(self):
|
||||
return struct.unpack_from('>H', self.read(2))[0]
|
||||
|
||||
def readLong(self):
|
||||
return struct.unpack_from('>I', self.read(4))[0]
|
||||
|
||||
def readInt(self):
|
||||
return struct.unpack_from('>i', self.read(4))[0]
|
||||
|
||||
def readBytes(self):
|
||||
return self.read(self.readLong() * 4)
|
||||
|
||||
def readString(self, n=None):
|
||||
if n:
|
||||
s = self.read(n)
|
||||
else:
|
||||
s = self.readBytes()
|
||||
return s.strip('\0')
|
||||
|
||||
def readSymbol(self, length):
|
||||
symbol = self.readString(length)
|
||||
value = self.readInt()
|
||||
return Symbol(symbol, None, value)
|
||||
|
||||
def readSymbols(self):
|
||||
symbols = []
|
||||
|
||||
while True:
|
||||
length = self.readLong() * 4
|
||||
|
||||
if not length:
|
||||
break
|
||||
|
||||
symbols.append(self.readSymbol(length))
|
||||
|
||||
return symbols
|
||||
|
||||
def readHunk(self, *types):
|
||||
hunkId = self.readLong()
|
||||
hunkType = Hunk.getType(hunkId)
|
||||
hunkFlags = Hunk.getFlags(hunkId)
|
||||
|
||||
if types:
|
||||
if hunkType not in types:
|
||||
raise ValueError('Unexpected hunk type: %s', hunkType)
|
||||
|
||||
return hunkType, hunkFlags
|
||||
|
||||
def readRelocs(self):
|
||||
relocs = {}
|
||||
|
||||
while True:
|
||||
longs = self.readLong()
|
||||
|
||||
if not longs:
|
||||
break
|
||||
|
||||
hunkRef = self.readLong()
|
||||
offsets = [self.readLong() for i in range(longs)]
|
||||
relocs[hunkRef] = offsets
|
||||
|
||||
return relocs
|
||||
|
||||
def readShortRelocs(self):
|
||||
start = self.tell()
|
||||
relocs = {}
|
||||
|
||||
while True:
|
||||
words = self.readWord()
|
||||
|
||||
if not words:
|
||||
break
|
||||
|
||||
hunkRef = self.readWord()
|
||||
offsets = [self.readWord() for i in range(words)]
|
||||
relocs[hunkRef] = offsets
|
||||
|
||||
if (self.tell() - start) & 3:
|
||||
self.skip(2)
|
||||
|
||||
return relocs
|
||||
|
||||
def skip(self, n):
|
||||
self.seek(n, os.SEEK_CUR)
|
||||
|
||||
def eof(self):
|
||||
return self.tell() == self.size
|
||||
|
||||
|
||||
HunkClassMap = {
|
||||
'HUNK_END': HunkSep,
|
||||
'HUNK_BREAK': HunkSep,
|
||||
'HUNK_EXT': HunkExt,
|
||||
'HUNK_SYMBOL': HunkSymbol,
|
||||
'HUNK_HEADER': HunkHeader,
|
||||
'HUNK_INDEX': HunkIndex,
|
||||
'HUNK_NAME': HunkStr,
|
||||
'HUNK_UNIT': HunkStr,
|
||||
'HUNK_CODE': HunkBinary,
|
||||
'HUNK_DATA': HunkBinary,
|
||||
'HUNK_OVERLAY': HunkOverlay,
|
||||
'HUNK_BSS': HunkBss,
|
||||
'HUNK_LIB': HunkLib,
|
||||
'HUNK_RELOC32': HunkReloc,
|
||||
'HUNK_RELOC16': HunkReloc,
|
||||
'HUNK_RELOC8': HunkReloc,
|
||||
'HUNK_DREL32': HunkReloc,
|
||||
'HUNK_DREL16': HunkReloc,
|
||||
'HUNK_DREL8': HunkReloc,
|
||||
'HUNK_DEBUG': HunkDebug
|
||||
}
|
||||
|
||||
|
||||
def ReadFile(path):
|
||||
with HunkFile(path) as hf:
|
||||
hunks = []
|
||||
units = 0
|
||||
|
||||
while not hf.eof():
|
||||
with hf.rollback():
|
||||
hunkId = hf.readLong()
|
||||
|
||||
type_ = Hunk.getType(hunkId)
|
||||
|
||||
if type_ is 'HUNK_HEADER':
|
||||
hf.type = 'executable'
|
||||
|
||||
if type_ is 'HUNK_UNIT':
|
||||
units += 1
|
||||
if units > 1:
|
||||
hf.type = 'library'
|
||||
|
||||
hunk = HunkClassMap.get(type_, None)
|
||||
|
||||
if not hunk:
|
||||
raise NotImplementedError('%s not handled.' % type_)
|
||||
|
||||
try:
|
||||
hunks.append(hunk.parse(hf))
|
||||
except ValueError:
|
||||
log.error('Parse error at position 0x%x.', hf.tell())
|
||||
util.hexdump(hf.read())
|
||||
|
||||
return hunks
|
|
@ -1,14 +0,0 @@
|
|||
def hexdump(data):
|
||||
hexch = ['%.2x' % ord(c) for c in data]
|
||||
|
||||
ascii = []
|
||||
for c in data:
|
||||
if ord(c) >= 32 and ord(c) < 127:
|
||||
ascii.append(c)
|
||||
else:
|
||||
ascii.append('.')
|
||||
|
||||
for i in range(0, len(hexch), 16):
|
||||
hexstr = ' '.join(hexch[i:i + 16])
|
||||
asciistr = ''.join(ascii[i:i + 16])
|
||||
print ' {2:04} | {0} |{1}|'.format(hexstr.ljust(47, ' '), asciistr, i)
|
389
tools/sadfe.py
389
tools/sadfe.py
|
@ -1,389 +0,0 @@
|
|||
#!/usr/bin/env python2.7 -B
|
||||
|
||||
import cmd
|
||||
import socket
|
||||
import sys
|
||||
import select
|
||||
import threading
|
||||
import tempfile
|
||||
import subprocess
|
||||
import struct
|
||||
|
||||
|
||||
def make_srec(addr, code):
|
||||
header = 'S00600004844521B'
|
||||
terminate = 'S9030000FC'
|
||||
addr = '%.8x' % addr
|
||||
code = code.encode('hex').upper()
|
||||
length = '%.2x' % (len(code.decode('hex')) + 5)
|
||||
srec = length + addr + code
|
||||
|
||||
bytesum = sum(ord(i) for i in srec.decode('hex'))
|
||||
cksum = "%.2X" % (~bytesum & 0xFF)
|
||||
|
||||
return '\n'.join([header, 'S3' + srec + cksum, terminate])
|
||||
|
||||
|
||||
class SimpleAmigaDebuggerConnection(object):
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
|
||||
def recv(self, size=None):
|
||||
recv = lambda: self.server.recv(8192)
|
||||
|
||||
if not size:
|
||||
return recv()
|
||||
|
||||
buf = ""
|
||||
|
||||
while len(buf) < size:
|
||||
data = recv()
|
||||
if not len(data):
|
||||
break
|
||||
buf += data
|
||||
|
||||
if len(buf) != size:
|
||||
raise ValueError(buf)
|
||||
|
||||
return buf
|
||||
|
||||
def send(self, data):
|
||||
self.server.send(data)
|
||||
|
||||
def send_cmd(self, cmd, payload=None):
|
||||
self.send(struct.pack('>BB', 0xAF, cmd))
|
||||
|
||||
if payload is not None:
|
||||
return self.send(payload)
|
||||
|
||||
def close(self):
|
||||
self.server.close()
|
||||
|
||||
def expect(self, data):
|
||||
recv_data = self.recv(len(data))
|
||||
assert recv_data == data
|
||||
|
||||
def expect_ack(self, cmd):
|
||||
self.expect(struct.pack('>BB', 0x00, cmd))
|
||||
|
||||
def expect_done(self, cmd, datalen=0):
|
||||
self.expect(struct.pack('>BB', 0x1F, cmd))
|
||||
|
||||
if datalen:
|
||||
data = self.recv(datalen)
|
||||
else:
|
||||
data = None
|
||||
|
||||
self.expect("SAD?")
|
||||
|
||||
return data
|
||||
|
||||
def nop(self):
|
||||
self.send_cmd(0)
|
||||
|
||||
def write_byte(self, ptr, val):
|
||||
self.send_cmd(1, struct.pack('>IB', ptr, val))
|
||||
self.expect_ack(1)
|
||||
self.expect_done(1)
|
||||
|
||||
def write_word(self, ptr, val):
|
||||
self.send_cmd(2, struct.pack('>IH', ptr, val))
|
||||
self.expect_ack(2)
|
||||
self.expect_done(2)
|
||||
|
||||
def write_long(self, ptr, val):
|
||||
self.send_cmd(3, struct.pack('>II', ptr, val))
|
||||
self.expect_ack(3)
|
||||
self.expect_done(3)
|
||||
|
||||
def read_byte(self, ptr):
|
||||
self.send_cmd(4, struct.pack('>I', ptr))
|
||||
self.expect_ack(4)
|
||||
data = self.expect_done(4, 1)
|
||||
return struct.unpack('>B', data)[0]
|
||||
|
||||
def read_word(self, ptr):
|
||||
self.send_cmd(5, struct.pack('>I', ptr))
|
||||
self.expect_ack(5)
|
||||
data = self.expect_done(5, 2)
|
||||
return struct.unpack('>H', data)[0]
|
||||
|
||||
def read_long(self, ptr):
|
||||
self.send_cmd(6, struct.pack('>I', ptr))
|
||||
self.expect_ack(6)
|
||||
data = self.expect_done(6, 4)
|
||||
return struct.unpack('>I', data)[0]
|
||||
|
||||
def call_address(self, ptr):
|
||||
self.send_cmd(7, struct.pack('>I', ptr))
|
||||
self.expect_ack(7)
|
||||
self.expect_done(7)
|
||||
|
||||
def return_to_system(self):
|
||||
self.send_cmd(8, struct.pack('>I', 0))
|
||||
self.expect_ack(8)
|
||||
|
||||
def get_context_frame(self):
|
||||
self.send_cmd(9)
|
||||
self.expect_ack(9)
|
||||
data = self.expect_done(9, 4)
|
||||
return struct.unpack('>I', data)[0]
|
||||
|
||||
def allocate_memory(self, size, memtype):
|
||||
self.send_cmd(10, struct.pack('>II', size, memtype))
|
||||
self.expect_ack(10)
|
||||
data = self.expect_done(10, 4)
|
||||
return struct.unpack('>I', data)[0]
|
||||
|
||||
def free_memory(self, ptr):
|
||||
self.send_cmd(11, struct.pack('>I', ptr))
|
||||
self.expect_ack(11)
|
||||
self.expect_done(11)
|
||||
|
||||
def turn_on_single(self):
|
||||
self.send_cmd(12)
|
||||
self.expect_ack(12)
|
||||
data = self.expect_done(12, 4)
|
||||
return struct.unpack('>I', data)[0]
|
||||
|
||||
def turn_off_single(self, ptr):
|
||||
self.send_cmd(13, struct.pack('>I', ptr))
|
||||
self.expect_ack(13)
|
||||
self.expect_done(13)
|
||||
|
||||
def write_array(self, ptr, data):
|
||||
self.send_cmd(14, struct.pack('>IIs', ptr, len(data), data))
|
||||
self.expect_ack(14)
|
||||
self.expect_done(14)
|
||||
|
||||
def read_array(self, ptr, size):
|
||||
self.send_cmd(15, struct.pack('>II', ptr, size))
|
||||
self.expect_ack(15)
|
||||
return self.expect_done(15, size)
|
||||
|
||||
def reset(self):
|
||||
self.send_cmd(16)
|
||||
self.expect_ack(16)
|
||||
|
||||
|
||||
class SimpleAmigaDebuggerFrontEnd(cmd.Cmd):
|
||||
def __init__(self, sad):
|
||||
cmd.Cmd.__init__(self)
|
||||
self.prompt = '>>> '
|
||||
self.sad = sad
|
||||
|
||||
def parse_args(self, args, *types):
|
||||
args = args.split(' ')
|
||||
|
||||
if len(args) != len(types):
|
||||
print 'Wrong number of arguments!'
|
||||
return None
|
||||
|
||||
values = []
|
||||
|
||||
for v, t in zip(args, types):
|
||||
if t == 'ptr':
|
||||
v = int(v, 16)
|
||||
assert (v >= 0 or v < 2 ** 32)
|
||||
elif t == 'byte':
|
||||
v = int(v, 10)
|
||||
assert (v >= 0 or v < 2 ** 8)
|
||||
elif t == 'word':
|
||||
v = int(v, 10)
|
||||
assert (v >= 0 or v < 2 ** 16)
|
||||
elif t == 'long':
|
||||
v = int(v, 10)
|
||||
assert (v >= 0 or v < 2 ** 32)
|
||||
elif t == 'data':
|
||||
v = v.decode('hex')
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
values.append(v)
|
||||
|
||||
return values
|
||||
|
||||
def do_quit(self, args):
|
||||
return True
|
||||
|
||||
def do_wb(self, args):
|
||||
""" write byte """
|
||||
ptr, byte = self.parse_args(args, 'ptr', 'byte')
|
||||
self.sad.write_byte(ptr, byte)
|
||||
|
||||
def do_ww(self, args):
|
||||
""" write word """
|
||||
ptr, word = self.parse_args(args, 'ptr', 'word')
|
||||
self.sad.write_word(ptr, word)
|
||||
|
||||
def do_wl(self, args):
|
||||
""" write long """
|
||||
ptr, long_ = self.parse_args(args, 'ptr', 'long')
|
||||
self.sad.write_long(ptr, long_)
|
||||
|
||||
def do_rb(self, args):
|
||||
""" read byte """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
byte = self.sad.read_byte(ptr)
|
||||
print "%.2x" % byte
|
||||
|
||||
def do_rw(self, args):
|
||||
""" read word """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
word = self.sad.read_word(ptr)
|
||||
print "%.4x" % word
|
||||
|
||||
def do_rl(self, args):
|
||||
""" read long """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
long_ = self.sad.read_long(ptr)
|
||||
print "%.8x" % long_
|
||||
|
||||
def do_call(self, args):
|
||||
""" call address """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
self.sad.call_address(ptr)
|
||||
|
||||
def do_return(self, _):
|
||||
""" return to system """
|
||||
self.sad.return_to_system()
|
||||
return True
|
||||
|
||||
def do_frame(self, _):
|
||||
""" get context frame """
|
||||
ptr = self.sad.get_context_frame()
|
||||
data = self.sad.read_array(ptr, 21 * 4 + 2)
|
||||
data = struct.unpack('>IIIIIIIIIIIIIIIIIIIIHI', data)
|
||||
desc = ['VBR', 'AttnFlags', 'ExecBase', 'USP', 'D0', 'D1', 'D2', 'D3',
|
||||
'D4', 'D5', 'D6', 'D7', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6',
|
||||
'Prompt', 'SR', 'PC']
|
||||
|
||||
for k, v in zip(desc, data):
|
||||
print k.ljust(max(len(d) for d in desc)), "%.8x" % v
|
||||
|
||||
def do_alloc(self, args):
|
||||
""" allocate memory """
|
||||
size = self.parse_args(args, 'long')[0]
|
||||
ptr = self.sad.allocate_memory(size, 0)
|
||||
print "%.8x" % ptr
|
||||
|
||||
def do_free(self, args):
|
||||
""" free memory """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
self.sad.free_memory(ptr)
|
||||
|
||||
def do_trace(self, _):
|
||||
""" turn on single """
|
||||
ptr = self.sad.turn_on_single()
|
||||
print "%.8x" % ptr
|
||||
|
||||
def do_notrace(self, args):
|
||||
""" turn off single """
|
||||
ptr = self.parse_args(args, 'ptr')[0]
|
||||
self.sad.turn_off_single(ptr)
|
||||
|
||||
def do_wr(self, args):
|
||||
""" write array """
|
||||
ptr, data = self.parse_args(args, 'ptr', 'data')
|
||||
self.sad.write_array(ptr, data)
|
||||
|
||||
def do_rr(self, args):
|
||||
""" read array """
|
||||
ptr, size = self.parse_args(args, 'ptr', 'long')
|
||||
data = self.sad.read_array(ptr, size)
|
||||
print data.encode('hex')
|
||||
|
||||
def do_dis(self, args):
|
||||
""" disassemble """
|
||||
ptr, size = self.parse_args(args, 'ptr', 'long')
|
||||
data = self.sad.read_array(ptr, size)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as srec:
|
||||
srec.write(make_srec(ptr, data))
|
||||
srec.flush()
|
||||
output = subprocess.check_output(
|
||||
['m68k-amigaos-objdump', '-b', 'srec', '-m', '68020', '-D', srec.name])
|
||||
print '\n'.join(output.split('\n')[7:-1])
|
||||
|
||||
def do_reset(self, _):
|
||||
""" reset """
|
||||
self.sad.reset()
|
||||
|
||||
|
||||
class SimpleAmigaDebuggerThread(threading.Thread):
|
||||
def __init__(self, server):
|
||||
threading.Thread.__init__(self)
|
||||
self.sad = SimpleAmigaDebuggerConnection(server)
|
||||
|
||||
def run(self):
|
||||
sadfe = SimpleAmigaDebuggerFrontEnd(self.sad)
|
||||
sadfe.cmdloop()
|
||||
self.sad.close()
|
||||
|
||||
|
||||
class SimpleAmigaDebuggerClient(object):
|
||||
def __init__(self):
|
||||
self.socket = None
|
||||
self.sad_mode = False
|
||||
|
||||
def sad_keep_alive(self):
|
||||
ready = select.select([self.socket, self.client], [], [], 0.5)[0]
|
||||
|
||||
if not ready:
|
||||
self.socket.send(struct.pack('>BB', 0xAF, 0))
|
||||
|
||||
if self.socket in ready:
|
||||
data = self.socket.recv(8192)
|
||||
# print "=> client", data.encode('hex')
|
||||
self.client.send(data)
|
||||
|
||||
if self.client in ready:
|
||||
data = self.client.recv(8192)
|
||||
|
||||
if not len(data):
|
||||
self.client.close()
|
||||
self.sad_mode = False
|
||||
return
|
||||
|
||||
# print "=> server", data.encode('hex')
|
||||
self.socket.send(data)
|
||||
|
||||
def run(self):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect(("localhost", 1234))
|
||||
|
||||
try:
|
||||
recvbuf = ""
|
||||
|
||||
while True:
|
||||
if self.sad_mode:
|
||||
self.sad_keep_alive()
|
||||
continue
|
||||
|
||||
data = self.socket.recv(8192)
|
||||
recvbuf += data
|
||||
|
||||
if recvbuf.endswith("SAD?"):
|
||||
print ""
|
||||
|
||||
client, server = socket.socketpair()
|
||||
|
||||
recvbuf = ""
|
||||
self.sad_mode = True
|
||||
self.client = client
|
||||
|
||||
SimpleAmigaDebuggerThread(server).start()
|
||||
|
||||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
|
||||
recvbuf = recvbuf[-4:]
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
self.socket.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client = SimpleAmigaDebuggerClient()
|
||||
client.run()
|
Loading…
Reference in New Issue