示例#1
0
static int
dis_i386_instrlen(dis_handle_t *dhp, uint64_t pc)
{
	if (dis_disassemble(dhp, pc, NULL, 0) != 0)
		return (-1);

	return (dhp->dh_addr - pc);
}
示例#2
0
/*
 * Return the previous instruction.  On x86, we have no choice except to
 * disassemble everything from the start of the symbol, and stop when we have
 * reached our instruction address.  If we're not in the middle of a known
 * symbol, then we return the same address to indicate failure.
 */
static uint64_t
dis_i386_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
{
	uint64_t *hist, addr, start;
	int cur, nseen;
	uint64_t res = pc;

	if (n <= 0)
		return (pc);

	if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
	    start == pc)
		return (res);

	hist = dis_zalloc(sizeof (uint64_t) * n);

	for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
		hist[cur] = addr;
		cur = (cur + 1) % n;
		nseen++;

		/* if we cannot make forward progress, give up */
		if (dis_disassemble(dhp, addr, NULL, 0) != 0)
			goto done;
	}

	if (addr != pc) {
		/*
		 * We scanned past %pc, but didn't find an instruction that
		 * started at %pc.  This means that either the caller specified
		 * an invalid address, or we ran into something other than code
		 * during our scan.  Virtually any combination of bytes can be
		 * construed as a valid Intel instruction, so any non-code bytes
		 * we encounter will have thrown off the scan.
		 */
		goto done;
	}

	res = hist[(cur + n - MIN(n, nseen)) % n];

done:
	dis_free(hist, sizeof (uint64_t) * n);
	return (res);
}
示例#3
0
/*
 * The main disassembly routine.  Given a fixed-sized buffer and starting
 * address, disassemble the data using the supplied target and libdisasm handle.
 */
void
dis_data(dis_tgt_t *tgt, dis_handle_t *dhp, uint64_t addr, void *data,
    size_t datalen)
{
	dis_buffer_t db = { 0 };
	char buf[BUFSIZE];
	char symbuf[BUFSIZE];
	const char *symbol;
	const char *last_symbol;
	off_t symoffset;
	int i;
	int bytesperline;
	size_t symsize;
	int isfunc;
	size_t symwidth = 0;
	int ret;
	int insz = insn_size(dhp);

	db.db_tgt = tgt;
	db.db_data = data;
	db.db_addr = addr;
	db.db_size = datalen;

	dis_set_data(dhp, &db);

	if ((bytesperline = dis_max_instrlen(dhp)) > 6)
		bytesperline = 6;

	symbol = NULL;

	while (addr < db.db_addr + db.db_size) {

		ret = dis_disassemble(dhp, addr, buf, BUFSIZE);
		if (ret != 0 && insz > 0) {
			/*
			 * Since we know instructions are fixed size, we
			 * always know the address of the next instruction
			 */
			(void) snprintf(buf, sizeof (buf),
			    "*** invalid opcode ***");
			db.db_nextaddr = addr + insz;

		} else if (ret != 0) {
			off_t next;

			(void) snprintf(buf, sizeof (buf),
			    "*** invalid opcode ***");

			/*
			 * On architectures with variable sized instructions
			 * we have no way to figure out where the next
			 * instruction starts if we encounter an invalid
			 * instruction.  Instead we print the rest of the
			 * instruction stream as hex until we reach the
			 * next valid symbol in the section.
			 */
			if ((next = dis_tgt_next_symbol(tgt, addr)) == 0) {
				db.db_nextaddr = db.db_addr + db.db_size;
			} else {
				if (next > db.db_size)
					db.db_nextaddr = db.db_addr +
					    db.db_size;
				else
					db.db_nextaddr = addr + next;
			}
		}

		/*
		 * Print out the line as:
		 *
		 * 	address:	bytes	text
		 *
		 * If there are more than 6 bytes in any given instruction,
		 * spread the bytes across two lines.  We try to get symbolic
		 * information for the address, but if that fails we print out
		 * the numeric address instead.
		 *
		 * We try to keep the address portion of the text aligned at
		 * MINSYMWIDTH characters.  If we are disassembling a function
		 * with a long name, this can be annoying.  So we pick a width
		 * based on the maximum width that the current symbol can be.
		 * This at least produces text aligned within each function.
		 */
		last_symbol = symbol;
		symbol = dis_tgt_lookup(tgt, addr, &symoffset, 1, &symsize,
		    &isfunc);
		if (symbol == NULL) {
			symbol = dis_find_section(tgt, addr, &symoffset);
			symsize = symoffset;
		}

		if (symbol != last_symbol)
			getsymname(addr, symbol, symsize, symbuf,
			    sizeof (symbuf));

		symwidth = MAX(symwidth, strlen(symbuf));
		getsymname(addr, symbol, symoffset, symbuf, sizeof (symbuf));

		/*
		 * If we've crossed a new function boundary, print out the
		 * function name on a blank line.
		 */
		if (!g_quiet && symoffset == 0 && symbol != NULL && isfunc)
			(void) printf("%s()\n", symbol);

		(void) printf("    %s:%*s ", symbuf,
		    symwidth - strlen(symbuf), "");

		/* print bytes */
		for (i = 0; i < MIN(bytesperline, (db.db_nextaddr - addr));
		    i++) {
			int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
			if (g_flags & DIS_OCTAL)
				(void) printf("%03o ", byte);
			else
				(void) printf("%02x ", byte);
		}

		/* trailing spaces for missing bytes */
		for (; i < bytesperline; i++) {
			if (g_flags & DIS_OCTAL)
				(void) printf("    ");
			else
				(void) printf("   ");
		}

		/* contents of disassembly */
		(void) printf(" %s", buf);

		/* excess bytes that spill over onto subsequent lines */
		for (; i < db.db_nextaddr - addr; i++) {
			int byte = *((uchar_t *)data + (addr - db.db_addr) + i);
			if (i % bytesperline == 0)
				(void) printf("\n    %*s  ", symwidth, "");
			if (g_flags & DIS_OCTAL)
				(void) printf("%03o ", byte);
			else
				(void) printf("%02x ", byte);
		}

		(void) printf("\n");

		addr = db.db_nextaddr;
	}
}