#include <stdio.h>
#include <string.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include <mach-o/i860/reloc.h>
#include "stuff/bytesex.h"
#include "otool.h"
#include "../as/i860-opcode.h"
static void i860_dump_operands(
unsigned long opcode,
char *format,
unsigned long addr,
unsigned long sect_addr,
struct relocation_info *relocs,
unsigned long nrelocs,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose);
static void i860_dump_addr(
unsigned long addr_field,
int format,
long addr,
unsigned long sect_addr,
struct relocation_info *relocs,
unsigned long nrelocs,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose);
static enum bool i860_print_symbol(
unsigned long value,
struct relocation_info *rp,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose);
unsigned long
i860_disassemble(
char *sect,
unsigned long left,
unsigned long addr,
unsigned long sect_addr,
enum byte_sex object_byte_sex,
struct relocation_info *relocs,
unsigned long nrelocs,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose)
{
enum byte_sex host_byte_sex;
enum bool swapped;
unsigned long opcode;
int isdual;
unsigned long i;
struct i860_opcode *op;
host_byte_sex = get_host_byte_sex();
swapped = host_byte_sex != object_byte_sex;
if(left < sizeof(unsigned long)){
if(left != 0){
memcpy(&opcode, sect, left);
if(swapped)
opcode = SWAP_LONG(opcode);
printf(".long\t0x%08x\n", (unsigned int)opcode);
}
printf("(end of section)\n");
return(left);
}
memcpy(&opcode, sect, sizeof(unsigned long));
if(swapped)
opcode = SWAP_LONG(opcode);
if(opcode == 0){
printf("| Padded to i860 section boundary\n");
return(4);
}
isdual = 0;
if((opcode & OP_PREFIX_MASK) == PREFIX_FPU ||
opcode == (OP_FNOP|DUAL_INSN_MODE_BIT)){
if(opcode & DUAL_INSN_MODE_BIT){
opcode &= ~DUAL_INSN_MODE_BIT;
isdual = 1;
}
}
op = (struct i860_opcode *)i860_opcodes;
for(i = 0; i < NUMOPCODES; i++, op++){
if((opcode & op->mask) == op->match){
if(isdual)
printf("d.%-12s\t", op->name);
else
printf("%-12s\t", op->name);
i860_dump_operands(opcode, (char *)op->args, addr, sect_addr,
relocs, nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
return(sizeof(unsigned long));
}
}
printf(".long\t0x%08x\n", (unsigned int)opcode);
return(sizeof(unsigned long));
}
static char *i860_controlregs[] = {"fir", "psr", "dirbase", "db", "fsr", "epsr",
"?","?","?","?","?","?",
"?","?","?","?","?","?",
"?","?","?","?","?","?",
"?","?","?","?","?","?"};
static
void
i860_dump_operands(
unsigned long opcode,
char *format,
unsigned long addr,
unsigned long sect_addr,
struct relocation_info *relocs,
unsigned long nrelocs,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose)
{
unsigned long addr_field;
while(*format != '\0'){
switch(*format){
case '1':
printf("r%lu", GET_RS1(opcode));
break;
case '2':
printf("r%lu", GET_RS2(opcode));
break;
case 'd':
printf("r%lu", GET_RD(opcode));
break;
case 'E':
case 'e':
printf("f%lu", GET_RS1(opcode));
break;
case 'F':
case 'f':
printf("f%lu", GET_RS2(opcode));
break;
case 'H':
case 'G':
case 'g':
printf("f%lu", GET_RD(opcode));
break;
case 'I':
case 'J':
addr_field = opcode & 0xFFFF;
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'i':
addr_field = (opcode & 0xFFFF);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'j':
addr_field = (opcode & 0xFFFE);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'k':
addr_field = (opcode & 0xFFFC);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'l':
addr_field = (opcode & 0xFFF8);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'm':
addr_field = (opcode & 0xFFF0);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'n':
addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FF);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'o':
addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FE);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'p':
addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FC);
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'K':
addr_field = opcode & 0x3FFFFFF;
if(addr_field & 0x02000000)
addr_field |= 0xFC000000;
addr_field <<= 2;
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'L':
addr_field = ((opcode >> 5) & 0xF800) | (opcode & 0x7FF);
if(addr_field & 0x8000)
addr_field |= 0xFFFF0000;
addr_field <<= 2;
i860_dump_addr(addr_field, *format, addr, sect_addr, relocs,
nrelocs, symbols, nsymbols, sorted_symbols,
nsorted_symbols, strings, strings_size, verbose);
break;
case 'D':
printf("%lu", opcode & 0xFFFF);
break;
case 'B':
printf("%lu", GET_RS1(opcode));
break;
case 'C':
printf(i860_controlregs[GET_RS2(opcode)]);
break;
default:
printf("%c", *format);
break;
}
++format;
}
printf("\n");
}
static
void
i860_dump_addr(
unsigned long addr_field,
int format,
long addr,
unsigned long sect_addr,
struct relocation_info *relocs,
unsigned long nrelocs,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose)
{
unsigned long i;
struct relocation_info *rp, *pairp;
struct scattered_relocation_info *sreloc;
char *prefix;
rp = NULL;
pairp = NULL;
if(nrelocs){
for(i = 0; i < nrelocs; i++){
if(((relocs[i].r_address) & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)(relocs + i);
if(sreloc->r_type == I860_RELOC_PAIR){
fprintf(stderr, "Stray I860_RELOC_PAIR relocation "
"entry %lu\n", i);
continue;
}
if(sreloc->r_type == I860_RELOC_HIGH ||
sreloc->r_type == I860_RELOC_HIGHADJ ||
sreloc->r_type == I860_RELOC_SECTDIFF){
if(i+1 >= nrelocs ||
relocs[i+1].r_type != I860_RELOC_PAIR){
fprintf(stderr, "No I860_RELOC_PAIR relocation "
"entry after entry %lu\n", i);
}
else{
if(((relocs[i+1].r_address) & R_SCATTERED) != 0){
sreloc = (struct scattered_relocation_info *)
(relocs + i + 1);
if(sreloc->r_type != I860_RELOC_PAIR)
fprintf(stderr, "No I860_RELOC_PAIR "
"relocation entry after entry "
"%lu\n", i);
}
else if(relocs[i+1].r_type != I860_RELOC_PAIR){
fprintf(stderr, "No I860_RELOC_PAIR relocation "
"entry after entry %lu\n", i);
}
i++;
continue;
}
}
}
if(relocs[i].r_type == I860_RELOC_PAIR){
fprintf(stderr, "Stray I860_RELOC_PAIR relocation entry "
"%lu\n", i);
continue;
}
if((unsigned long)relocs[i].r_address == addr - sect_addr){
rp = &relocs[i];
if(rp->r_type == I860_RELOC_HIGH ||
rp->r_type == I860_RELOC_HIGHADJ ||
rp->r_type == I860_RELOC_SECTDIFF){
if(i+1 < nrelocs){
pairp = &rp[1];
if(pairp->r_type != I860_RELOC_PAIR){
fprintf(stderr, "No I860_RELOC_PAIR relocation "
"entry after entry %lu\n", i);
rp = NULL;
pairp = NULL;
continue;
}
}
}
break;
}
if(relocs[i].r_type == I860_RELOC_HIGH ||
relocs[i].r_type == I860_RELOC_HIGHADJ ||
relocs[i].r_type == I860_RELOC_SECTDIFF){
if(i+1 >= nrelocs ||
relocs[i+1].r_type != I860_RELOC_PAIR){
fprintf(stderr, "No I860_RELOC_PAIR relocation "
"entry after entry %lu\n", i);
}
else
i++;
}
}
}
prefix = NULL;
if((rp != NULL && rp->r_type == I860_RELOC_HIGH) || format == 'I')
prefix = "h%";
else if((rp != NULL && rp->r_type == I860_RELOC_HIGHADJ) ||
format == 'J' )
prefix = "ha%";
else if(rp != NULL && rp->r_type >= I860_RELOC_LOW0 &&
rp->r_type <= I860_RELOC_SPLIT2){
if(rp->r_pcrel == 0)
prefix = "l%";
}
if(rp != NULL && (rp->r_type == I860_RELOC_HIGH ||
rp->r_type == I860_RELOC_HIGHADJ)){
if(pairp->r_type == I860_RELOC_PAIR){
if(rp->r_type == I860_RELOC_HIGHADJ)
if(pairp->r_address & 0x8000)
addr_field = (addr_field << 16) +
(0xffff0000 | (pairp->r_address & 0xffff));
else
addr_field = (addr_field << 16) +
(pairp->r_address & 0xffff);
else
addr_field = (addr_field << 16) |
(pairp->r_address & 0xffff);
}
}
if(prefix != NULL)
printf("%s", prefix);
if(format == 'K' || format == 'L'){
if(i860_print_symbol(addr + 4 + ((long)addr_field), rp,
symbols, nsymbols, sorted_symbols, nsorted_symbols,
strings, strings_size, verbose) == TRUE)
return;
printf(".%+ld", (long)(addr_field + 4));
return;
}
if(i860_print_symbol(addr_field, rp, symbols, nsymbols,
sorted_symbols, nsorted_symbols, strings,
strings_size, verbose) == TRUE)
return;
printf("0x%x", (unsigned int)addr_field);
}
static
enum bool
i860_print_symbol(
unsigned long value,
struct relocation_info *rp,
struct nlist *symbols,
unsigned long nsymbols,
struct nlist *sorted_symbols,
unsigned long nsorted_symbols,
char *strings,
unsigned long strings_size,
enum bool verbose)
{
long high, low, mid;
if(verbose == FALSE)
return(FALSE);
if(rp != NULL){
if(rp->r_extern &&
rp->r_symbolnum < nsymbols){
if(value != 0)
printf("%s+0x%x", strings +
symbols[rp->r_symbolnum].n_un.n_strx,
(unsigned int)value);
else
printf("%s",strings + symbols[rp->r_symbolnum].n_un.n_strx);
return(TRUE);
}
}
low = 0;
high = nsorted_symbols - 1;
mid = (high - low) / 2;
while(high >= low){
if(sorted_symbols[mid].n_value == value){
printf("%s", sorted_symbols[mid].n_un.n_name);
return(TRUE);
}
if(sorted_symbols[mid].n_value > value){
high = mid - 1;
mid = (high + low) / 2;
}
else{
low = mid + 1;
mid = (high + low) / 2;
}
}
return(FALSE);
}