blob: d8dfae08fb51d482141571592fcf192c885bee5a [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- ---*/
/*--- This file (guest-generic/bb_to_IR.c) is ---*/
/*--- Copyright (c) OpenWorks LLP. All rights reserved. ---*/
/*--- ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of LibVEX, a library for dynamic binary
instrumentation and translation.
Copyright (C) 2004-2005 OpenWorks LLP.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; Version 2 dated June 1991 of the
license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
for damages. See the GNU General Public License for more details.
Neither the names of the U.S. Department of Energy nor the
University of California nor the names of its contributors may be
used to endorse or promote products derived from this software
without prior written permission.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
*/
#include "libvex_basictypes.h"
#include "libvex_ir.h"
#include "libvex.h"
#include "main/vex_util.h"
#include "main/vex_globals.h"
#include "guest-generic/bb_to_IR.h"
/* Disassemble a complete basic block, starting at guest_IP_start,
returning a new IRBB. The disassembler may chase across basic
block boundaries if it wishes and if chase_into_ok allows it.
The precise guest address ranges from which code has been taken
are written into vge. guest_IP_start is taken to be the IP in
the guest's address space corresponding to the instruction at
&guest_code[0].
dis_instr_fn is the arch-specific fn to disassemble on function; it
is this that does the real work.
*/
static Bool const_False ( Addr64 a ) { return False; }
IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
/*IN*/ DisOneInstrFn dis_instr_fn,
/*IN*/ UChar* guest_code,
/*IN*/ Addr64 guest_IP_bbstart,
/*IN*/ Bool (*chase_into_ok)(Addr64),
/*IN*/ Bool host_bigendian,
/*IN*/ VexArchInfo* archinfo_guest,
/*IN*/ IRType guest_word_type )
{
Long delta;
Int i, n_instrs, first_stmt_idx;
Bool resteerOK, need_to_put_IP, debug_print;
DisResult dres;
IRStmt* imark;
static Int n_resteers = 0;
Int d_resteers = 0;
IRBB* irbb;
Addr64 guest_IP_curr_instr;
Bool (*resteerOKfn)(Addr64) = NULL;
debug_print = toBool(vex_traceflags & VEX_TRACE_FE);
/* check sanity .. */
vassert(vex_control.guest_max_insns >= 1);
vassert(vex_control.guest_max_insns < 500);
vassert(vex_control.guest_chase_thresh >= 0);
vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
vassert(guest_word_type == Ity_I32 || guest_word_type == Ity_I64);
/* Start a new, empty extent. */
vge->n_used = 1;
vge->base[0] = guest_IP_bbstart;
vge->len[0] = 0;
/* And a new IR BB to dump the result into. */
irbb = emptyIRBB();
/* Delta keeps track of how far along the guest_code array we have
so far gone. */
delta = 0;
n_instrs = 0;
while (True) {
vassert(n_instrs < vex_control.guest_max_insns);
/* Regardless of what chase_into_ok says, is chasing permissible
at all right now? Set resteerOKfn accordingly. */
resteerOK
= toBool(
n_instrs < vex_control.guest_chase_thresh
/* we can't afford to have a resteer once we're on the
last extent slot. */
&& vge->n_used < 3
);
resteerOKfn
= resteerOK ? chase_into_ok : const_False;
/* This is the IP of the instruction we're just about to deal
with. */
guest_IP_curr_instr = guest_IP_bbstart + delta;
/* This is the irbb statement array index of the first stmt in
this insn. That will always be the instruction-mark
descriptor. */
first_stmt_idx = irbb->stmts_used;
/* Add an instruction-mark statement. We won't know until after
disassembling the instruction how long it instruction is, so
just put in a zero length and we'll fix it up later. */
addStmtToIRBB( irbb, IRStmt_IMark( guest_IP_curr_instr, 0 ));
/* for the first insn, the dispatch loop will have set
%IP, but for all the others we have to do it ourselves. */
need_to_put_IP = toBool(n_instrs > 0);
/* Finally, actually disassemble an instruction. */
dres = dis_instr_fn ( irbb,
need_to_put_IP,
resteerOKfn,
guest_code,
delta,
guest_IP_curr_instr,
archinfo_guest,
host_bigendian );
/* stay sane ... */
vassert(dres.whatNext == Dis_StopHere
|| dres.whatNext == Dis_Continue
|| dres.whatNext == Dis_Resteer);
vassert(dres.len >= 0 && dres.len <= 18);
if (dres.whatNext != Dis_Resteer)
vassert(dres.continueAt == 0);
/* Fill in the insn-mark length field. */
vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
imark = irbb->stmts[first_stmt_idx];
vassert(imark);
vassert(imark->tag == Ist_IMark);
vassert(imark->Ist.IMark.len == 0);
imark->Ist.IMark.len = toUInt(dres.len);
/* Print the resulting IR, if needed. */
if (vex_traceflags & VEX_TRACE_FE) {
for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
vex_printf(" ");
ppIRStmt(irbb->stmts[i]);
vex_printf("\n");
}
}
/* If dis_instr_fn terminated the BB at this point, check it
also filled in the irbb->next field. */
if (dres.whatNext == Dis_StopHere) {
vassert(irbb->next != NULL);
if (debug_print) {
vex_printf(" ");
vex_printf( "goto {");
ppIRJumpKind(irbb->jumpkind);
vex_printf( "} ");
ppIRExpr( irbb->next );
vex_printf( "\n");
}
}
/* Update the VexGuestExtents we are constructing. */
/* If vex_control.guest_max_insns is required to be < 500 and
each insn is at max 15 bytes long, this limit of 10000 then
seems reasonable since the max possible extent length will be
500 * 15 == 7500. */
vassert(vge->len[vge->n_used-1] < 10000);
vge->len[vge->n_used-1]
= toUShort(toUInt( vge->len[vge->n_used-1] + dres.len ));
n_instrs++;
if (debug_print)
vex_printf("\n");
/* Advance delta (inconspicuous but very important :-) */
delta += (Long)dres.len;
switch (dres.whatNext) {
case Dis_Continue:
vassert(irbb->next == NULL);
if (n_instrs < vex_control.guest_max_insns) {
/* keep going */
} else {
/* We have to stop. */
irbb->next
= IRExpr_Const(
guest_word_type == Ity_I32
? IRConst_U32(toUInt(guest_IP_bbstart+delta))
: IRConst_U64(guest_IP_bbstart+delta)
);
return irbb;
}
break;
case Dis_StopHere:
vassert(irbb->next != NULL);
return irbb;
case Dis_Resteer:
/* Check that we actually allowed a resteer .. */
vassert(resteerOK);
vassert(irbb->next == NULL);
/* figure out a new delta to continue at. */
vassert(resteerOKfn(dres.continueAt));
delta = dres.continueAt - guest_IP_bbstart;
/* we now have to start a new extent slot. */
vge->n_used++;
vassert(vge->n_used <= 3);
vge->base[vge->n_used-1] = dres.continueAt;
vge->len[vge->n_used-1] = 0;
n_resteers++;
d_resteers++;
if (0 && (n_resteers & 0xFF) == 0)
vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
n_resteers, d_resteers,
dres.continueAt, delta);
break;
default:
vpanic("bb_to_IR");
}
}
}
/*--------------------------------------------------------------------*/
/*--- end guest-generic/bb_to_IR.c ---*/
/*--------------------------------------------------------------------*/