do not edit — generated by btf.
git.druid.rocksindexdruid520jurysrc/disasm.c

src/disasm.c


#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "isa.h"
 
#define VAR_ROW 4  /* bytes per data line, same width as the longest op */
 
typedef struct {
	char name[32];
	unsigned long at;
	unsigned long len;
} var;
 
var vars[VARS_MAX];
int nvars = 0;
 
void loadvars(const char* binfile, unsigned long binlen);
void printvar(const unsigned char* prog, const var* v);
int main(int argc, char** argv);
 
/* reads binfile + ".vars" if its there, keeps vars sorted by address.
 * no file just means no variables, everything gets decoded like
 * before. a line that doesnt make sense gets skipped with a warning. */
void
loadvars(const char* binfile, unsigned long binlen)
{
	char* name;
	char line[128];
	FILE* f;
	var v;
	int lineno = 0;
	int i;
	char extra;
 
	name = malloc(strlen(binfile) + strlen(VARS_EXT) + 1);
	if(name == NULL)
	{
		return;
	}
	strcpy(name, binfile);
	strcat(name, VARS_EXT);
	f = fopen(name, "rb");
	if(f == NULL)
	{
		free(name);
		return;
	}
 
	while(fgets(line, sizeof(line), f) != NULL)
	{
		lineno = lineno + 1;
		if(sscanf(line, "%31s %lx %lx %c", v.name, &v.at, &v.len, &extra) != 3 ||
		   v.len == 0 || v.at >= binlen || v.len > binlen - v.at)
		{
			fprintf(stderr, "warn: %s line %d: bad variable, ignored.\n", name, lineno);
			continue;
		}
		if(nvars == VARS_MAX)
		{
			fprintf(stderr, "warn: %s: too many variables, rest ignored.\n", name);
			break;
		}
		/* insert sorted, drop anything that overlaps a neighbour */
		for(i = nvars; i > 0 && vars[i - 1].at > v.at; i = i - 1)
		{
		}
		if((i > 0 && vars[i - 1].at + vars[i - 1].len > v.at) ||
		   (i < nvars && v.at + v.len > vars[i].at))
		{
			fprintf(stderr, "warn: %s line %d: '%s' overlaps another variable, ignored.\n", name, lineno, v.name);
			continue;
		}
		memmove(&vars[i + 1], &vars[i], (nvars - i) * sizeof(var));
		vars[i] = v;
		nvars = nvars + 1;
	}
	fclose(f);
	free(name);
}
 
/* "name;" then VAR_ROW bytes a line as "; 0x.. 0x..", which is valid
 * asm that carries on the variable, so this still reassembles. the
 * comment shows the bytes as characters, od -c style, lined up under
 * the hex column's width. */
void
printvar(const unsigned char* prog, const var* v)
{
	char hex[VAR_ROW * 3 + 1];
	char src[VAR_ROW * 5 + 3];
	unsigned long a;
	int k;
	int c;
 
	printf("%04lx:  %-12s %s;  # %lu byte(s)\n", v->at, "", v->name, v->len);
	for(a = v->at; a < v->at + v->len; a = a + VAR_ROW)
	{
		strcpy(src, ";");
		for(k = 0; k < VAR_ROW && a + k < v->at + v->len; k = k + 1)
		{
			sprintf(hex + k * 3, "%02x ", prog[a + k]);
			sprintf(src + strlen(src), " 0x%02x", prog[a + k]);
		}
		printf("%04lx:  %-12s %-22s #", a, hex, src);
		for(k = 0; k < VAR_ROW && a + k < v->at + v->len; k = k + 1)
		{
			c = prog[a + k];
			switch(c)
			{
				case '\0': printf(" \\0"); break;
				case '\t': printf(" \\t"); break;
				case '\n': printf(" \\n"); break;
				case '\r': printf(" \\r"); break;
				default:   printf("  %c", isprint(c) ? c : '.'); break;
			}
		}
		printf("\n");
	}
}
 
/* prints "addr:  bytes         asm". the asm column is valid asm source,
 * a byte that doesnt start a valid instruction comes out as a raw byte
 * with a comment saying why, so disasm output always assembles back to
 * the exact same binary. variables from prog.bin.vars come out as data,
 * and no instruction is decoded across the start of one. */
int
main(int argc, char** argv)
{
	const char* infile = "prog.bin";
	FILE* in;
	static unsigned char prog[RAM_SIZE + 1];
	unsigned long len;
	unsigned long pc;
	unsigned long end;
	char hex[INS_MAX * 3 + 1];
	char txt[INS_TXT];
	ins i;
	int st;
	int k;
	int vi = 0;
 
	if(argc > 2)
	{
		fprintf(stderr, "err: bad usage.\n");
		fprintf(stderr, "usage: %s [in.bin|-]\n", argv[0]);
		return 1;
	}
	if(argc == 2)
	{
		infile = argv[1];
	}
 
	if(strcmp(infile, "-") == 0)
	{
		in = stdin;
	}
	else
	{
		in = fopen(infile, "rb");
		if(in == NULL)
		{
			fprintf(stderr, "err: cant open %s.\n", infile);
			return 1;
		}
	}
 
	len = fread(prog, 1, RAM_SIZE + 1, in);
 
	if(in != stdin)
	{
		fclose(in);
	}
	if(len > RAM_SIZE)
	{
		fprintf(stderr, "err: %s is bigger than ram (%d bytes).\n", infile, RAM_SIZE);
		return 1;
	}
	if(in != stdin)
	{
		loadvars(infile, len);
	}
 
	pc = 0;
	while(pc < len)
	{
		if(vi < nvars && vars[vi].at == pc)
		{
			printvar(prog, &vars[vi]);
			pc = pc + vars[vi].len;
			vi = vi + 1;
			continue;
		}
		end = vi < nvars ? vars[vi].at : len;
		st = isadecode(prog, end, pc, &i);
		if(st != DEC_OK)
		{
			printf("%04lx:  %02x           %02x  # %s\n", pc, prog[pc], prog[pc],
			       st == DEC_SHORT ? "cut off." : DECMSG[st]);
			pc = pc + 1;
			continue;
		}
		hex[0] = '\0';
		for(k = 0; k < i.len; k = k + 1)
		{
			sprintf(hex + k * 3, "%02x ", prog[pc + k]);
		}
		isafmt(&i, txt);
		printf("%04lx:  %-12s %s\n", pc, hex, txt);
		pc = pc + i.len;
	}
 
	fprintf(stderr, "ok: disassembled %lu bytes.\n", len);
 
	return 0;
}
powered by btf.