Exemple #1
0
/* inserts "inst" before "where" ("inst" can be a chain of insts) */
void
instrlist_preinsert(instrlist_t *ilist, instr_t *where, instr_t *inst)
{
    instr_t *whereprev;
    instr_t *top = inst;
    instr_t *bot;

    if (where == NULL) {
        /* if where is NULL there is no inst to send for a "before" */
        instrlist_append(ilist, inst);
        return;
    }

    CLIENT_ASSERT(where != NULL, "instrlist_preinsert: where cannot be NULL");
    CLIENT_ASSERT(instr_get_prev(inst) == NULL,
                  "instrlist_preinsert: cannot add middle of list");
    whereprev = instr_get_prev(where);
    check_translation(ilist, inst);
    while (instr_get_next(inst)) {
        inst = instr_get_next(inst);
        check_translation(ilist, inst);
    }
    bot = inst;
    if (whereprev) {
        instr_set_next(whereprev, top);
        instr_set_prev(top, whereprev);
    } else {
        ilist->first = top;
    }
    instr_set_next(bot, where);
    instr_set_prev(where, bot);
}
Exemple #2
0
/* inserts "inst" after "where" ("inst" can be a chain of insts) */
void
instrlist_postinsert(instrlist_t *ilist, instr_t *where, instr_t *inst)
{
    instr_t *wherenext;
    instr_t *top = inst;
    instr_t *bot;

    if (where == NULL) {
        /* if where is NULL there is no inst to send for an "after" */
        instrlist_prepend(ilist, inst);
        return;
    }

    CLIENT_ASSERT(where != NULL, "instrlist_postinsert: where cannot be NULL");
    CLIENT_ASSERT(instr_get_prev(inst) == NULL,
                  "instrlist_postinsert: cannot add middle of list");

    wherenext = instr_get_next(where);
    check_translation(ilist, inst);
    while (instr_get_next(inst)) {
        inst = instr_get_next(inst);
        check_translation(ilist, inst);
    }
    bot = inst;
    instr_set_next(where, top);
    instr_set_prev(top, where);
    if (wherenext) {
        instr_set_next(bot, wherenext);
        instr_set_prev(wherenext, bot);
    } else {
        ilist->last = bot;
    }
}
/* 32-bit addressing forms with the ModR/M Byte (Table 2-2).  You call
 * this routine with the byte following the primary opcode byte when you
 * know that the operation's next byte is a ModR/M byte.  This routine
 * passes back the size of the Eaddr specification in bytes based on the
 * following encoding of Table 2-2.
 *
 *   Mod        R/M
 *        0 1 2 3 4 5 6 7
 *    0   1 1 1 1 * 5 1 1
 *    1   2 2 2 2 3 2 2 2
 *    2   5 5 5 5 6 5 5 5
 *    3   1 1 1 1 1 1 1 1
 *   where (*) is 6 if base==5 and 2 otherwise.
 */
static int
sizeof_modrm(dcontext_t *dcontext, byte *pc, bool addr16 _IF_X64(byte **rip_rel_pc))
{
    int l = 0;          /* return value for sizeof(eAddr) */

    uint modrm = (uint)*pc;
    int r_m = modrm & 0x7;
    uint mod = modrm >> 6;
    uint sib;

#ifdef X64
    if (rip_rel_pc != NULL && X64_MODE_DC(dcontext) && mod == 0 && r_m == 5) {
        *rip_rel_pc = pc + 1; /* no sib: next 4 bytes are disp */
    }
#endif

    if (addr16 && !X64_MODE_DC(dcontext)) {
        if (mod == 1)
            return 2; /* modrm + disp8 */
        else if (mod == 2)
            return 3; /* modrm + disp16 */
        else if (mod == 3)
            return 1; /* just modrm */
        else {
            CLIENT_ASSERT(mod == 0, "internal decoding error on addr16 prefix");
            if (r_m == 6)
                return 3; /* modrm + disp16 */
            else
                return 1; /* just modrm */
        }
        CLIENT_ASSERT(false, "internal decoding error on addr16 prefix");
    }

    /* for x64, addr16 simply truncates the computed address: there is
     * no change in disp sizes */

    if (mod == 3)       /* register operand */
        return 1;

    switch (mod) {      /* memory or immediate operand */
      case 0: l = (r_m == 5) ? 5 : 1; break;
      case 1: l = 2; break;
      case 2: l = 5; break;
    }
    if (r_m == 4) {
        l += 1;         /* adjust for sib byte */
        sib = (uint)(*(pc+1));
        if ((sib & 0x7) == 5) {
            if (mod == 0)
                l += 4; /* disp32(,index,s) */
        }
    }

    return l;
}
Exemple #4
0
instrlist_t*
instrlist_clone(dcontext_t *dcontext, instrlist_t *old)
{
    instr_t *inst, *copy;
    instrlist_t *newlist = instrlist_create(dcontext);

    inst = instrlist_first(old);
    while (inst != NULL) {
        copy = instr_clone(dcontext, inst);
        /* to copy instr targets we temporarily clobber note field */
        instr_set_note(inst, (void *)copy);
        instrlist_append(newlist, copy);
        inst = instr_get_next(inst);
    }

    /* Fix up instr src if it is an instr and restore note field */
    /* Note: we do not allows instruction update code cache,
     * which is very dangerous.
     * So we do not support instr as dst opnd and won't fix up here if any.
     */
    for (inst = instrlist_first(old), copy = instrlist_first(newlist);
            inst != NULL && copy != NULL;
            inst = instr_get_next(inst), copy = instr_get_next(copy)) {
        int i;
        for (i = 0; i < inst->num_srcs; i++) {
            instr_t *tgt;
            opnd_t   op = instr_get_src(copy, i);
            if (!opnd_is_instr(op))
                continue;
            CLIENT_ASSERT(opnd_get_instr(op) != NULL,
                          "instrlist_clone: NULL instr operand");
            tgt = (instr_t *) instr_get_note(opnd_get_instr(op));
            CLIENT_ASSERT(tgt != NULL,
                          "instrlist_clone: operand instr not in instrlist");
            if (opnd_is_far_instr(op)) {
                instr_set_src(copy, i,
                              opnd_create_far_instr
                              (opnd_get_segment_selector(op), tgt));
            } else
                instr_set_src(copy, i,
                              opnd_create_instr(tgt));
        }
    }
    for (inst = instrlist_first(old), copy = instrlist_first(newlist);
            inst != NULL && copy != NULL;
            inst = instr_get_next(inst), copy = instr_get_next(copy)) {
        /* restore note field */
        instr_set_note(inst, instr_get_note(copy));
    }
#ifdef CLIENT_INTERFACE
    newlist->fall_through_bb = old->fall_through_bb;
#endif
    return newlist;
}
Exemple #5
0
/* frees the instrlist_t object */
void
instrlist_destroy(dcontext_t *dcontext, instrlist_t *ilist)
{
    CLIENT_ASSERT(ilist->first == NULL && ilist->last == NULL,
                  "instrlist_destroy: list not empty");
    heap_free(dcontext, ilist, sizeof(instrlist_t) HEAPACCT(ACCT_IR));
}
Exemple #6
0
/* return the branch type of the (branch) inst */
uint
instr_branch_type(instr_t *cti_instr)
{
    instr_get_opcode(cti_instr); /* ensure opcode is valid */
    if (instr_get_opcode(cti_instr) == OP_blx) {
        /* To handle the mode switch we go through the ibl.
         * FIXME i#1551: once we have far linking through stubs we should
         * remove this and have a faster link through the stub.
         */
        return LINK_INDIRECT|LINK_CALL;
    }
    /* We treate a predicated call as a cbr, not a call */
    else if (instr_is_cbr_arch(cti_instr) || instr_is_ubr_arch(cti_instr))
        return LINK_DIRECT|LINK_JMP;
    else if (instr_is_call_direct(cti_instr))
        return LINK_DIRECT|LINK_CALL;
    else if (instr_is_call_indirect(cti_instr))
        return LINK_INDIRECT|LINK_CALL;
    else if (instr_is_return(cti_instr))
        return LINK_INDIRECT|LINK_RETURN;
    else if (instr_is_mbr_arch(cti_instr))
        return LINK_INDIRECT|LINK_JMP;
    else
        CLIENT_ASSERT(false, "instr_branch_type: unknown opcode");
    return LINK_INDIRECT;
}
Exemple #7
0
/* If has_instr_jmp_targets is true, this routine trashes the note field
 * of each instr_t to store the offset in order to properly encode
 * the relative pc for an instr_t jump target
 */
byte *
instrlist_encode_to_copy(dcontext_t *dcontext, instrlist_t *ilist, byte *copy_pc,
                         byte *final_pc, byte *max_pc, bool has_instr_jmp_targets)
{
    instr_t *inst;
    int len = 0;
#ifdef ARM
    /* XXX i#1734: reset encode state to avoid any stale encode state
     * or dangling pointer.
     */
    if (instr_get_isa_mode(instrlist_first(ilist)) == DR_ISA_ARM_THUMB)
        encode_reset_it_block(dcontext);
#endif
    /* Do an extra pass over the instrlist so we can determine if an instr opnd
     * was erroneously used with has_instr_jmp_targets = false.
     */
    DOCHECK(2, {
        if (!has_instr_jmp_targets) {
            for (inst = instrlist_first(ilist); inst; inst = instr_get_next(inst)) {
                if (TEST(INSTR_OPERANDS_VALID, (inst)->flags)) {
                    int i;
                    for (i = 0; i < instr_num_srcs(inst); ++i) {
                        CLIENT_ASSERT(!opnd_is_instr(instr_get_src(inst, i)),
                                      "has_instr_jmp_targets was unset "
                                      "but an instr opnd was found");
                    }
                }
            }
        }
    });
/* Two-byte opcode map (Tables A-4 and A-5).  You use this routine
 * when you have identified the primary opcode as 0x0f.  You pass this
 * routine the next byte to determine the number of extra bytes in the
 * entire instruction.
 * May return 0 size for certain invalid instructions.
 */
static int
sizeof_escape(dcontext_t *dcontext, byte *pc, bool addr16 _IF_X64(byte **rip_rel_pc))
{
    uint opc = (uint)*pc;
    int sz = escape_fixed_length[opc];
    ushort varlen = escape_variable_length[opc];

    /* for a valid instr, sz must be > 0 here, but we don't want to assert
     * since we need graceful failure
     */

    if (varlen == VARLEN_MODRM)
        return sz + sizeof_modrm(dcontext, pc+1, addr16 _IF_X64(rip_rel_pc));
    else if (varlen == VARLEN_3BYTE_38_ESCAPE) {
        opc = *(++pc);
        /* so far all 3-byte instrs have modrm bytes */
        /* to be robust for future additions we don't actually
         * use the threebyte_38_fixed_length[opc] entry and assume 1 */
        return sz + 1 + sizeof_modrm(dcontext, pc+1, addr16 _IF_X64(rip_rel_pc));
    }
    else if (varlen == VARLEN_3BYTE_3A_ESCAPE) {
        opc = *(++pc);
        /* so far all 0f 3a 3-byte instrs have modrm bytes and 1-byte immeds */
        /* to be robust for future additions we don't actually
         * use the threebyte_3a_fixed_length[opc] entry and assume 1 */
        return sz + 1 + sizeof_modrm(dcontext, pc+1, addr16 _IF_X64(rip_rel_pc)) + 1;
    }
    else
        CLIENT_ASSERT(varlen == VARLEN_NONE, "internal decoding error");

    return sz;
}
Exemple #9
0
uint
opnd_immed_float_arch(uint opcode)
{
    /* FIXME i#1551: NYI */
    CLIENT_ASSERT(false, "NYI");
    return 0;
}
Exemple #10
0
bool
instr_is_mov(instr_t *instr)
{
    /* FIXME i#1551: NYI */
    CLIENT_ASSERT(false, "NYI");
    return false;
}
Exemple #11
0
/* replace oldinst with newinst, remove oldinst from ilist, and return oldinst
   (newinst can be a chain of insts) */
instr_t *
instrlist_replace(instrlist_t *ilist, instr_t *oldinst, instr_t *newinst)
{
    instr_t *where;

    CLIENT_ASSERT(oldinst != NULL, "instrlist_replace: oldinst cannot be NULL");
    CLIENT_ASSERT(instr_get_prev(newinst) == NULL,
                  "instrlist_replace: cannot add middle of list");
    where = instr_get_prev(oldinst);
    instrlist_remove(ilist, oldinst);
    if (where)
        instrlist_postinsert(ilist, where, newinst);
    else
        instrlist_prepend(ilist, newinst);

    return oldinst;
}
Exemple #12
0
/* returns an empty instrlist_t object */
instrlist_t *
instrlist_create(dcontext_t *dcontext)
{
    instrlist_t *ilist =
        (instrlist_t *)heap_alloc(dcontext, sizeof(instrlist_t) HEAPACCT(ACCT_IR));
    CLIENT_ASSERT(ilist != NULL, "instrlist_create: allocation error");
    instrlist_init(ilist);
    return ilist;
}
Exemple #13
0
/* initializes an instrlist_t object */
void
instrlist_init(instrlist_t *ilist)
{
    CLIENT_ASSERT(ilist != NULL, "instrlist_create: NULL parameter");
    ilist->first = ilist->last = NULL;
    ilist->flags = 0;   /* no flags set */
    ilist->translation_target = NULL;
#ifdef CLIENT_INTERFACE
    ilist->fall_through_bb = NULL;
#endif
}
Exemple #14
0
static inline void
check_translation(instrlist_t *ilist, instr_t *inst)
{
    if (ilist->translation_target != NULL && instr_get_translation(inst) == NULL) {
        instr_set_translation(inst, ilist->translation_target);
    }
    if (instrlist_get_our_mangling(ilist))
        instr_set_our_mangling(inst, true);
#if defined(CLIENT_INTERFACE) && defined(ARM)
    if (instr_is_meta(inst)) {
        dr_pred_type_t auto_pred = ilist->auto_pred;
        if (instr_predicate_is_cond(auto_pred)) {
            CLIENT_ASSERT(!instr_is_cti(inst), "auto-predication does not support cti's");
            CLIENT_ASSERT(
                !TESTANY(EFLAGS_WRITE_NZCV,
                         instr_get_arith_flags(inst, DR_QUERY_INCLUDE_COND_SRCS)),
                "cannot auto predicate a meta-inst that writes to NZCV");
            if (!instr_is_predicated(inst))
                instr_set_predicate(inst, auto_pred);
        }
    }
#endif
}
Exemple #15
0
void
loader_init(void)
{
    uint i;
    privmod_t *mod;

    acquire_recursive_lock(&privload_lock);
    VMVECTOR_ALLOC_VECTOR(modlist_areas, GLOBAL_DCONTEXT,
                          VECTOR_SHARED | VECTOR_NEVER_MERGE
                          /* protected by privload_lock */
                          | VECTOR_NO_LOCK,
                          modlist_areas);
    /* os specific loader initialization prologue before finalize the load */
    os_loader_init_prologue();

    /* Process client libs we loaded early but did not finalize */
    for (i = 0; i < privmod_static_idx; i++) {
        /* Transfer to real list so we can do normal processing */
        char name_copy[MAXIMUM_PATH];
        mod = privload_insert(NULL,
                              privmod_static[i].base,
                              privmod_static[i].size,
                              privmod_static[i].name,
                              privmod_static[i].path);
        LOG(GLOBAL, LOG_LOADER, 1, "%s: processing imports for %s\n",
            __FUNCTION__, mod->name);
        /* save a copy for error msg, b/c mod will be unloaded (i#643) */
        snprintf(name_copy, BUFFER_SIZE_ELEMENTS(name_copy), "%s", mod->name);
        NULL_TERMINATE_BUFFER(name_copy);
        if (!privload_load_finalize(mod)) {
            mod = NULL; /* it's been unloaded! */
#ifdef CLIENT_INTERFACE
            SYSLOG(SYSLOG_ERROR, CLIENT_LIBRARY_UNLOADABLE, 4,
                   get_application_name(), get_application_pid(), name_copy,
                   ".\n\tUnable to process imports of client library");
#endif
            CLIENT_ASSERT(false, "failure to process imports of client library");
        }
    }
    /* os specific loader initialization epilogue after finalize the load */
    os_loader_init_epilogue();
    /* FIXME i#338: call loader_thread_init here once get
     * loader_init called after dynamo_thread_init but in a way that
     * works with Windows
     */
    release_recursive_lock(&privload_lock);
}
Exemple #16
0
static void
set_cache_size(uint val, uint *dst)
{
	// COOMPLETEDD #254 set_cache_size
    CLIENT_ASSERT(dst != NULL, "invalid internal param");
    switch (val) {
        case 8:    *dst = CACHE_SIZE_8_KB;   break;
        case 16:   *dst = CACHE_SIZE_16_KB;  break;
        case 32:   *dst = CACHE_SIZE_32_KB;  break;
        case 64:   *dst = CACHE_SIZE_64_KB;  break;
        case 128:  *dst = CACHE_SIZE_128_KB; break;
        case 256:  *dst = CACHE_SIZE_256_KB; break;
        case 512:  *dst = CACHE_SIZE_512_KB; break;
        case 1024: *dst = CACHE_SIZE_1_MB;   break;
        case 2048: *dst = CACHE_SIZE_2_MB;   break;
        default: SYSLOG_INTERNAL_ERROR("Unknown processor cache size"); break;
    }
}
Exemple #17
0
const char *
proc_get_cache_size_str(cache_size_t size)
{
	// COMPLETEDD #255 proc_get_cache_size_str
	printf("Starting proc_get_cache_size_str\n");
    static const char *strings[] = {
        "8 KB",
        "16 KB",
        "32 KB",
        "64 KB",
        "128 KB",
        "256 KB",
        "512 KB",
        "1 MB",
        "2 MB",
        "unknown"
    };
    CLIENT_ASSERT(size <= CACHE_SIZE_UNKNOWN, "proc_get_cache_size_str: invalid size");
    return strings[size];
}
Exemple #18
0
/* prepends inst to the list ("inst" can be a chain of insts) */
void
instrlist_prepend(instrlist_t *ilist, instr_t *inst)
{
    instr_t *top = inst;
    instr_t *bot;

    CLIENT_ASSERT(instr_get_prev(inst) == NULL,
                  "instrlist_prepend: cannot add middle of list");
    check_translation(ilist, inst);
    while (instr_get_next(inst)) {
        inst = instr_get_next(inst);
        check_translation(ilist, inst);
    }
    bot = inst;
    if (ilist->first) {
        instr_set_next(bot, ilist->first);
        instr_set_prev(ilist->first, bot);
        ilist->first = top;
    } else {
        ilist->first = top;
        ilist->last = bot;
    }
}
Exemple #19
0
int
opnd_get_reg_dcontext_offs(reg_id_t reg)
{
    switch (reg) {
    case DR_REG_R0:  return  R0_OFFSET;
    case DR_REG_R1:  return  R1_OFFSET;
    case DR_REG_R2:  return  R2_OFFSET;
    case DR_REG_R3:  return  R3_OFFSET;
    case DR_REG_R4:  return  R4_OFFSET;
    case DR_REG_R5:  return  R5_OFFSET;
    case DR_REG_R6:  return  R6_OFFSET;
    case DR_REG_R7:  return  R7_OFFSET;
    case DR_REG_R8:  return  R8_OFFSET;
    case DR_REG_R9:  return  R9_OFFSET;
    case DR_REG_R10: return R10_OFFSET;
    case DR_REG_R11: return R11_OFFSET;
    case DR_REG_R12: return R12_OFFSET;
    case DR_REG_R13: return R13_OFFSET;
    case DR_REG_R14: return R14_OFFSET;
    case DR_REG_R15: return PC_OFFSET;
    default: CLIENT_ASSERT(false, "opnd_get_reg_dcontext_offs: invalid reg");
        return -1;
    }
}