Add support for disassembling VOS program modules

This commit is contained in:
Michael Pavone committed 2014-10-11 20:32:17 -07:00
1 parent bee8289f02
commit 7237def9b0
8 files changed
+573 -43

No files matched your search

+5 -2
View File
@@ -39,8 +39,8 @@ all : dis zdis stateview vgmplay blastem
blastem : blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS)
$(CC) -ggdb -o blastem blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS)
dis : dis.o 68kinst.o
$(CC) -o dis dis.o 68kinst.o
dis : dis.o 68kinst.o tern.o vos_program_module.o
$(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o
zdis : zdis.o z80inst.o
$(CC) -o zdis zdis.o z80inst.o
@@ -78,6 +78,9 @@ gen_fib : gen_fib.o gen_x86.o mem.o
offsets : offsets.c z80_to_x86.h m68k_to_x86.h
$(CC) -o offsets offsets.c
vos_prog_info : vos_prog_info.o vos_program_module.o
$(CC) -o vos_prog_info vos_prog_info.o vos_program_module.o
%.o : %.S
$(CC) -c -o $@ $<
+112 -40
View File
@@ -1,11 +1,14 @@
/*
Copyright 2013 Michael Pavone
This file is part of BlastEm.
This file is part of BlastEm.
BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
*/
#include "68kinst.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vos_program_module.h"
#include "tern.h"
uint8_t visited[(16*1024*1024)/16];
uint8_t label[(16*1024*1024)/8];
@@ -35,6 +38,36 @@ uint8_t is_label(uint32_t address)
return label[address/16] & (1 << (address % 8));
}
typedef struct {
uint32_t num_labels;
uint32_t storage;
char *labels[];
} label_names;
tern_node * add_label(tern_node * head, char * name, uint32_t address)
{
char key[MAX_INT_KEY_SIZE];
address &= 0xFFFFFF;
reference(address);
tern_int_key(address, key);
label_names * names = tern_find_ptr(head, key);
if (names)
{
if (names->num_labels == names->storage)
{
names->storage = names->storage + (names->storage >> 1);
names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *));
}
} else {
names = malloc(sizeof(label_names) + 4 * sizeof(char *));
names->num_labels = 0;
names->storage = 4;
head = tern_insert_ptr(head, key, names);
}
names->labels[names->num_labels++] = strdup(name);
return head;
}
typedef struct deferred {
uint32_t address;
struct deferred *next;
@@ -66,10 +99,6 @@ void check_reference(m68kinst * inst, m68k_op_info * op)
}
}
uint8_t labels = 0;
uint8_t addr = 0;
uint8_t only = 0;
int main(int argc, char ** argv)
{
long filesize;
@@ -77,14 +106,10 @@ int main(int argc, char ** argv)
char disbuf[1024];
m68kinst instbuf;
unsigned short * cur;
FILE * f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
filebuf = malloc(filesize);
fread(filebuf, 2, filesize/2, f);
fclose(f);
deferred *def = NULL, *tmpd;
uint8_t labels = 0, addr = 0, only = 0, vos = 0;
for(uint8_t opt = 2; opt < argc; ++opt) {
if (argv[opt][0] == '-') {
FILE * address_log;
@@ -99,6 +124,9 @@ int main(int argc, char ** argv)
case 'o':
only = 1;
break;
case 'v':
vos = 1;
break;
case 'f':
opt++;
if (opt >= argc) {
@@ -126,22 +154,70 @@ int main(int argc, char ** argv)
reference(address);
}
}
for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
FILE * f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
tern_node * named_labels = NULL;
char int_key[MAX_INT_KEY_SIZE];
uint32_t address_off, address_end;
if (vos)
{
*cur = (*cur >> 8) | (*cur << 8);
vos_program_module header;
vos_read_header(f, &header);
vos_read_alloc_module_map(f, &header);
address_off = header.user_boundary;
address_end = address_off + filesize - 0x1000;
def = defer(header.main_entry_link.code_address, def);
named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address);
for (int i = 0; i < header.n_modules; i++)
{
def = defer(header.module_map_entries[i].code_address, def);
named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address);
}
fseek(f, 0x1000, SEEK_SET);
filebuf = malloc(filesize - 0x1000);
if (fread(filebuf, 2, (filesize - 0x1000)/2, f) != (filesize - 0x1000)/2)
{
fprintf(stderr, "Failure while reading file %s\n", argv[1]);
}
fclose(f);
for(cur = filebuf; cur - filebuf < ((filesize - 0x1000)/2); ++cur)
{
*cur = (*cur >> 8) | (*cur << 8);
}
} else {
address_off = 0;
address_end = filesize;
filebuf = malloc(filesize);
if (fread(filebuf, 2, filesize/2, f) != filesize/2)
{
fprintf(stderr, "Failure while reading file %s\n", argv[1]);
}
fclose(f);
for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
{
*cur = (*cur >> 8) | (*cur << 8);
}
uint32_t start = filebuf[2] << 16 | filebuf[3];
uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2];
uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2];
uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2];
named_labels = add_label(named_labels, "start", start);
named_labels = add_label(named_labels, "int_2", int_2);
named_labels = add_label(named_labels, "int_4", int_4);
named_labels = add_label(named_labels, "int_6", int_6);
if (!def || !only) {
def = defer(start, def);
def = defer(int_2, def);
def = defer(int_4, def);
def = defer(int_6, def);
}
}
uint32_t start = filebuf[2] << 16 | filebuf[3], tmp_addr;
uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2];
uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2];
uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2];
uint16_t *encoded, *next;
uint32_t size;
if (!def || !only) {
def = defer(start, def);
def = defer(int_2, def);
def = defer(int_4, def);
def = defer(int_6, def);
}
uint32_t size, tmp_addr;
uint32_t address;
while(def) {
do {
@@ -218,25 +294,21 @@ int main(int argc, char ** argv)
}
puts("");
}
for (address = 0; address < filesize; address+=2) {
for (address = address_off; address < filesize; address+=2) {
if (is_visited(address)) {
encoded = filebuf + address/2;
encoded = filebuf + (address-address_off)/2;
m68k_decode(encoded, &instbuf, address);
if (labels) {
m68k_disasm_labels(&instbuf, disbuf);
if (address == start) {
puts("start:");
}
if(address == int_2) {
puts("int_2:");
}
if(address == int_4) {
puts("int_4:");
}
if(address == int_6) {
puts("int_6:");
}
if (is_label(instbuf.address)) {
char keybuf[MAX_INT_KEY_SIZE];
label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf));
if (names)
{
for (int i = 0; i < names->num_labels; i++)
{
printf("%s:\n", names->labels[i]);
}
} else if (is_label(instbuf.address)) {
printf("ADR_%X:\n", instbuf.address);
}
if (addr) {
+11 -1
View File
@@ -122,4 +122,14 @@ tern_node * tern_insert_ptr(tern_node * head, char * key, void * value)
return tern_insert(head, key, val);
}
char * tern_int_key(uint32_t key, char * buf)
{
char * cur = buf;
while (key)
{
*(cur++) = (key & 0x7F) + 1;
key >>= 7;
}
*cur = 0;
return buf;
}
+3
View File
@@ -8,6 +8,8 @@
#include <stdint.h>
#define MAX_INT_KEY_SIZE (sizeof(uint32_t) + 2)
typedef union {
void *ptrval;
intptr_t intval;
@@ -31,5 +33,6 @@ tern_node * tern_insert_int(tern_node * head, char * key, intptr_t value);
void * tern_find_ptr_default(tern_node * head, char * key, void * def);
void * tern_find_ptr(tern_node * head, char * key);
tern_node * tern_insert_ptr(tern_node * head, char * key, void * value);
char * tern_int_key(uint32_t key, char * buf);
#endif //TERN_H_
+100
View File
@@ -0,0 +1,100 @@
#include <stdio.h>
#include "vos_program_module.h"
int main(int argc, char ** argv)
{
vos_program_module header;
FILE * f = fopen(argv[1], "rb");
vos_read_header(f, &header);
vos_read_alloc_module_map(f, &header);
vos_read_alloc_external_vars(f, &header);
printf("Version: %d\n", header.version);
printf("Binder Version: %s\n", header.binder_version.str);
printf("Binder Options: %s\n", header.binder_options.str);
printf("System name: %s\n", header.system_name.str);
printf("User name: %s\n", header.user_name.str);
printf("Date bound: %d\n", header.date_bound);
printf("Code addresss: 0x%X, Static address: 0x%X\n",
header.main_entry_link.code_address, header.main_entry_link.static_address);
printf("User boundary: 0x%X\n", header.user_boundary);
printf("Num modules: %d\n", header.n_modules);
printf("Num extern vars: %d\n", header.n_external_vars);
printf("Num link names: %d\n", header.n_link_names);
printf("Num unsapped links: %d\n", header.n_unsnapped_links);
printf("Num VM pages: %d\n", header.n_vm_pages);
printf("Num header pages: %d\n", header.n_header_pages);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("Info %d:%d\n\tAddress: 0x%X\n\tLength: 0x%X\n",
i, j, header.info[i][j].address, header.info[i][j].len);
}
}
printf("Module map address: 0x%X\n", header.module_map_address);
printf("Module map length: 0x%X\n", header.module_map_len);
printf("External vars map address: 0x%X\n", header.external_vars_map_address);
printf("External vars map length: 0x%X\n", header.external_vars_map_len);
printf("Link names map address: 0x%X\n", header.link_names_map_address);
printf("Link names map length: 0x%X\n", header.link_names_map_len);
printf("Header address: 0x%X\n", header.header_address);
printf("Header length: 0x%X\n", header.header_len);
//printf("Access Info: 0x%X\n", header.header_address);
printf("Flags: 0x%X\n", header.flags);
printf("Num tasks: %d\n", header.n_tasks);
printf("Stack Size: 0x%X\n", header.stack_len);
printf("Num entries: %d\n", header.n_entries);
printf("Entry map address: 0x%X\n", header.entry_map_address);
printf("Entry map length: 0x%X\n", header.entry_map_len);
printf("Pop Version: %d\n", header.pop_version);
printf("Processor: %d\n", header.processor);
printf("Processor family: %d\n", header.processor_family);
printf("Release name: %s\n", header.release_name.str);
printf("Relocation info:\n\tMap Addres: 0x%X\n\tMap Length: 0x%X\n\tNum Relocations: %d\n",
header.relocation_info.map_address, header.relocation_info.map_len,
header.relocation_info.n_relocations);
printf("High water mark: 0x%X\n", header.high_water_mark);
printf("Copyright notice: %s\n", header.program_name.str);
printf("String pool address: 0x%X\n", header.string_pool_address);
printf("String pool length: 0x%X\n", header.string_pool_len);
printf("Object dir map address: 0x%X\n", header.obj_dir_map_address);
printf("Object dir map length: 0x%X\n", header.obj_dir_map_len);
puts("Global offset table addresses:");
for (int i = 0; i < 3; i++) {
printf("\t%d: 0x%X\n", i, header.global_offset_table_address[i]);
}
for (int i = 0; i < 3; i++) {
printf("Block map info %d\n\tAddress: 0x%X\n\tLength: 0x%X\n",
i, header.block_map_info[i].address, header.block_map_info[i].len);
}
printf("Secton map file address: 0x%X\n", header.section_map_file_address);
printf("Secton map address: 0x%X\n", header.section_map_address);
printf("Secton map length: 0x%X\n", header.section_map_len);
printf("Num sections: %d\n", header.n_sections);
printf("Max heap size: 0x%X\n", header.max_heap_size);
printf("Max program size: 0x%X\n", header.max_program_size);
printf("Max stack size: 0x%X\n", header.max_stack_size);
printf("Stack fence size: 0x%X\n", header.stack_fence_size);
puts("\nModules");
for (int i = 0; i < header.n_modules; i++) {
printf("\t%s:\n\t\tCode Address: 0x%X, Length: 0x%X\n",
header.module_map_entries[i].name.str,
header.module_map_entries[i].code_address,
header.module_map_entries[i].code_length);
printf("\t\tFoo Address: 0x%X, Length: 0x%X\n",
header.module_map_entries[i].foo_address,
header.module_map_entries[i].foo_length);
printf("\t\tBar Address: 0x%X, Length: 0x%X\n",
header.module_map_entries[i].bar_address,
header.module_map_entries[i].bar_length);
}
puts("\nExtrnal Vars");
for (int i = 0; i < header.n_external_vars; i++) {
printf("\t%s: 0x%X\n",
header.external_vars[i].name.str, header.external_vars[i].address);
}
vos_header_cleanup(&header);
return 0;
}
+208
View File
@@ -0,0 +1,208 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "vos_program_module.h"
static uint16_t big16(uint8_t ** src)
{
uint16_t ret = *((*src)++) << 8;
ret |= *((*src)++);
return ret;
}
static uint32_t big32(uint8_t ** src)
{
uint32_t ret = *((*src)++) << 24;
ret |= *((*src)++) << 16;
ret |= *((*src)++) << 8;
ret |= *((*src)++);
return ret;
}
static void string_(uint8_t ** src, uint16_t *len, char * str, uint32_t storage)
{
*len = big16(src);
memcpy(str, *src, storage);
*src += storage;
if (*len >= storage)
{
*len = storage;
} else {
str[*len] = 0;
}
if (storage & 1)
{
(*src)++;
}
}
#define string(src, field) string_(src, &(field).len, (field).str, sizeof((field).str))
int vos_read_header(FILE * f, vos_program_module *out)
{
uint8_t buffer[4096];
if (fread(buffer, 1, sizeof(buffer), f) != sizeof(buffer))
{
return 0;
}
uint8_t *cur = buffer;
out->version = big16(&cur);
string(&cur, out->binder_version);
string(&cur, out->binder_options);
string(&cur, out->system_name);
string(&cur, out->user_name);
out->date_bound = big32(&cur);
out->main_entry_link.code_address = big32(&cur);
out->main_entry_link.static_address = big32(&cur);
out->user_boundary = big32(&cur);
out->n_modules = big16(&cur);
out->n_external_vars = big16(&cur);
out->n_link_names = big16(&cur);
out->n_unsnapped_links = big16(&cur);
out->n_vm_pages = big16(&cur);
out->n_header_pages = big16(&cur);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
out->info[i][j].address = big32(&cur);
out->info[i][j].len = big32(&cur);
}
}
out->module_map_address = big32(&cur);
out->module_map_len = big32(&cur);
out->external_vars_map_address = big32(&cur);
out->external_vars_map_len = big32(&cur);
out->link_names_map_address = big32(&cur);
out->link_names_map_len = big32(&cur);
out->link_map_address = big32(&cur);
out->link_map_len = big32(&cur);
out->header_address = big32(&cur);
out->header_len = big32(&cur);
memcpy(out->access_info, cur, sizeof(out->access_info));
cur += sizeof(out->access_info);
out->flags = big32(&cur);
out->n_tasks = big16(&cur);
for (int i = 0; i < 3; i++)
{
out->task_static_len[i] = big32(&cur);
}
out->stack_len = big32(&cur);
out->n_entries = big16(&cur);
out->entry_map_address = big32(&cur);
out->entry_map_len = big32(&cur);
out->pop_version = big16(&cur);
out->processor = big16(&cur);
string(&cur, out->release_name);
out->relocation_info.map_address = big32(&cur);
out->relocation_info.map_len = big32(&cur);
out->relocation_info.n_relocations = big32(&cur);
out->high_water_mark = big32(&cur);
string(&cur, out->copyright_notice);
for (int i = 0; i < 14; i++)
{
out->module_origins[i] = big32(&cur);
}
out->processor_family = big16(&cur);
string(&cur, out->program_name);
out->string_pool_address = big32(&cur);
out->string_pool_len = big32(&cur);
out->obj_dir_map_address = big32(&cur);
out->obj_dir_map_len = big32(&cur);
for (int i = 0; i < 3; i++)
{
out->global_offset_table_address[i] = big32(&cur);
}
for (int i = 0; i < 3; i++)
{
out->block_map_info[i].address = big32(&cur);
out->block_map_info[i].len = big32(&cur);
}
out->section_map_file_address = big32(&cur);
out->section_map_address = big32(&cur);
out->section_map_len = big32(&cur);
out->n_sections = big16(&cur);
out->max_heap_size = big32(&cur);
out->max_program_size = big32(&cur);
out->max_stack_size = big32(&cur);
out->stack_fence_size = big32(&cur);
out->module_map_entries = NULL;
out->external_vars = NULL;
return 1;
}
#define MODULE_MAP_ENTRY_SIZE 74
int vos_read_alloc_module_map(FILE * f, vos_program_module *header)
{
if (header->module_map_len != header->n_modules * MODULE_MAP_ENTRY_SIZE)
{
return 0;
}
uint8_t * buf = malloc(header->module_map_len);
fseek(f, header->module_map_address + 0x1000 - header->user_boundary, SEEK_SET);
if (fread(buf, 1, header->module_map_len, f) != header->module_map_len)
{
free(buf);
return 0;
}
uint8_t * cur = buf;
header->module_map_entries = malloc(sizeof(vos_module_map_entry) * header->n_modules);
for (int i = 0; i < header->n_modules; i++)
{
string(&cur, header->module_map_entries[i].name);
for (int j = 0; j < 5; j++)
{
header->module_map_entries[i].unknown[j] = big16(&cur);
}
header->module_map_entries[i].code_address = big32(&cur);
header->module_map_entries[i].code_length = big32(&cur);
header->module_map_entries[i].foo_address = big32(&cur);
header->module_map_entries[i].foo_length = big32(&cur);
header->module_map_entries[i].bar_address = big32(&cur);
header->module_map_entries[i].bar_length = big32(&cur);
for (int j = 0; j < 3; j++)
{
header->module_map_entries[i].unknown2[j] = big16(&cur);
}
}
return 1;
}
#define EXTERNAL_VAR_ENTRY_SIZE 44
int vos_read_alloc_external_vars(FILE * f, vos_program_module *header)
{
if (header->external_vars_map_len != header->n_external_vars * EXTERNAL_VAR_ENTRY_SIZE)
{
return 0;
}
uint8_t * buf = malloc(header->external_vars_map_len);
fseek(f, header->external_vars_map_address + 0x1000 - header->user_boundary, SEEK_SET);
if (fread(buf, 1, header->external_vars_map_len, f) != header->external_vars_map_len)
{
free(buf);
return 0;
}
uint8_t * cur = buf;
header->external_vars = malloc(sizeof(vos_external_var_entry) * header->n_external_vars);
for (int i = 0; i < header->n_external_vars; i++)
{
string(&cur, header->external_vars[i].name);
header->external_vars[i].address = big32(&cur);
for (int j = 0; j < 3; j++)
{
header->external_vars[i].unknown[j] = big16(&cur);
}
}
return 1;
}
void vos_header_cleanup(vos_program_module *header)
{
free(header->module_map_entries);
free(header->external_vars);
}
+134
View File
@@ -0,0 +1,134 @@
#ifndef VOS_PROGRAM_MODULE_H_
#define VOS_PROGRAM_MODULE_H_
#include <stdint.h>
typedef struct
{
struct {
uint16_t len;
char str[32];
} name;
uint16_t unknown[5];
uint32_t code_address;
uint32_t code_length;
uint32_t foo_address;
uint32_t foo_length;
uint32_t bar_address;
uint32_t bar_length;
uint16_t unknown2[3];
} vos_module_map_entry;
typedef struct
{
struct {
uint16_t len;
char str[32];
} name;
uint32_t address;
uint16_t unknown[3];
} vos_external_var_entry;
typedef struct
{
uint16_t version;
struct {
uint16_t len;
char str[32];
} binder_version;
struct {
uint16_t len;
char str[32];
} binder_options;
struct {
uint16_t len;
char str[32];
} system_name;
struct {
uint16_t len;
char str[65];
} user_name;
uint32_t date_bound;
struct {
uint32_t code_address;
uint32_t static_address;
} main_entry_link;
uint32_t user_boundary;
uint16_t n_modules;
uint16_t n_external_vars;
uint16_t n_link_names;
uint16_t n_unsnapped_links;
uint16_t n_vm_pages;
uint16_t n_header_pages;
struct {
uint32_t address;
uint32_t len;
} info[3][4];
uint32_t module_map_address;
uint32_t module_map_len;
uint32_t external_vars_map_address;
uint32_t external_vars_map_len;
uint32_t link_names_map_address;
uint32_t link_names_map_len;
uint32_t link_map_address;
uint32_t link_map_len;
uint32_t header_address;
uint32_t header_len;
uint8_t access_info[2048];
uint32_t flags;
uint16_t n_tasks;
uint32_t task_static_len[3];
uint32_t stack_len;
uint16_t n_entries;
uint32_t entry_map_address;
uint32_t entry_map_len;
uint16_t pop_version;
uint16_t processor;
struct {
uint16_t len;
char str[32];
} release_name;
struct {
uint32_t map_address;
uint32_t map_len;
uint32_t n_relocations;
} relocation_info;
uint32_t high_water_mark;
struct {
uint16_t len;
char str[256];
} copyright_notice;
uint32_t module_origins[14];
uint16_t processor_family;
struct {
uint16_t len;
char str[32];
} program_name;
uint32_t string_pool_address;
uint32_t string_pool_len;
uint32_t obj_dir_map_address;
uint32_t obj_dir_map_len;
uint32_t global_offset_table_address[3];
struct {
uint32_t address;
uint32_t len;
} block_map_info[3];
uint32_t section_map_file_address;
uint32_t section_map_address;
uint32_t section_map_len;
uint16_t n_sections;
uint32_t max_heap_size;
uint32_t max_program_size;
uint32_t max_stack_size;
uint32_t stack_fence_size;
vos_module_map_entry *module_map_entries;
vos_external_var_entry *external_vars;
} vos_program_module;
int vos_read_header(FILE * f, vos_program_module *out);
int vos_read_alloc_module_map(FILE * f, vos_program_module *header);
int vos_read_alloc_external_vars(FILE * f, vos_program_module *header);
void vos_header_cleanup(vos_program_module *header);
#endif //VOS_PROGRAM_MODULE_H_
Binary file not shown.