Move tools directory to amigaos-dev-toolkit repository.

This commit is contained in:
Krystian Bacławski 2017-08-05 11:47:17 +02:00
parent 39f0b27679
commit 524a261187
18 changed files with 0 additions and 4130 deletions

4
tools/.gitignore vendored
View File

@ -1,4 +0,0 @@
GccFindHit
hunk2aout
elf2hunk
*.pyc

View File

@ -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() */

View File

@ -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

View File

@ -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 :

View File

@ -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_ */

View File

@ -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

View File

@ -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()

View File

@ -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 ''

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -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;
}

View File

@ -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 ''

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()