Example #1
0
DR_EXPORT
bool
drmgr_insert_read_tls_field(void *drcontext, int idx,
                            instrlist_t *ilist, instr_t *where, reg_id_t reg)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    if (idx < 0 || idx > MAX_NUM_TLS || !tls_taken[idx] || tls == NULL)
        return false;
    if (!reg_is_gpr(reg) || !reg_is_pointer_sized(reg))
        return false;
    dr_insert_read_tls_field(drcontext, ilist, where, reg);
    instrlist_meta_preinsert(ilist, where, INSTR_CREATE_mov_ld
                             (drcontext, opnd_create_reg(reg),
                              OPND_CREATE_MEMPTR(reg, offsetof(tls_array_t, tls) +
                                                 idx*sizeof(void*))));
    return true;
}
Example #2
0
static void
insert_counter_update(void *drcontext, instrlist_t *bb, instr_t *where, int offset)
{
    /* Since the inc instruction clobbers 5 of the arithmetic eflags,
     * we have to save them around the inc. We could be more efficient
     * by not bothering to save the overflow flag and constructing our
     * own sequence of instructions to save the other 5 flags (using
     * lahf) or by doing a liveness analysis on the flags and saving
     * only if live.
     */
    dr_save_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1);
    dr_save_arith_flags_to_xax(drcontext, bb, where);

    /* Increment the global counter using the lock prefix to make it atomic
     * across threads. It would be cheaper to aggregate the thread counters
     * in the exit events, but this sample is intended to illustrate inserted
     * instrumentation.
     */
    instrlist_meta_preinsert(bb, where, LOCK(INSTR_CREATE_inc
        (drcontext, OPND_CREATE_ABSMEM(((byte *)&global_count) + offset, OPSZ_4))));

    /* Increment the thread private counter. */
    if (dr_using_all_private_caches()) {
        per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
        /* private caches - we can use an absolute address */
        instrlist_meta_preinsert(bb, where, INSTR_CREATE_inc(drcontext, 
            OPND_CREATE_ABSMEM(((byte *)&data) + offset, OPSZ_4)));
    } else {
        /* shared caches - we must indirect via thread local storage */
        /* We spill xbx to use a scratch register (we could do a liveness
         * analysis to try and find a dead register to use). Note that xax
         * is currently holding the saved eflags. */
        dr_save_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2);
        dr_insert_read_tls_field(drcontext, bb, where, DR_REG_XBX);
        instrlist_meta_preinsert(bb, where,
            INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(DR_REG_XBX, offset)));
        dr_restore_reg(drcontext, bb, where, DR_REG_XBX, SPILL_SLOT_2);
    }

    /* Restore flags and xax. */
    dr_restore_arith_flags_from_xax(drcontext, bb, where);
    dr_restore_reg(drcontext, bb, where, DR_REG_XAX, SPILL_SLOT_1);
}
Example #3
0
/** Adds instrumentation that records fragment execution. */
struct instr_info_t instrument_frag(void* ctx,
                                    instrlist_t* frag,
                                    frag_id_t id) {
  const size_t offsetof_current = offsetof(struct trace_buffer_t, current);
  ptr_int_t frag_id = id; // sign-extended for OPND_CREATE_INT32
#ifdef TRACE_DEBUG
  app_pc frag_pc;
#endif
  app_pc xl8_pc;
  instr_t* where;
  instr_t* before;
  struct instr_info_t instr_info;
  instr_t* store;
  instr_t* first;

#ifdef TRACE_DEBUG
  dr_fprintf(STDERR, "debug: instrument_frag(0x%" PRIxPTR ")\n", frag_id);
  frag_pc = instr_get_app_pc(instrlist_first(frag));
  instrlist_disassemble(ctx, frag_pc, frag, STDERR);
#endif

  where = configure_instr(&instr_info, frag);
  xl8_pc = instr_get_app_pc(where);
  before = instr_get_prev(where);

#define INSERT(instr) prexl8(frag, where, (instr), xl8_pc)

  // Add instrumentation.
  // save tls_reg
  if(instr_info.restore_tls_reg) {
    dr_save_reg(ctx, frag, where, instr_info.tls_reg, SPILL_SLOT_2);
  }
  // save current_reg
  if(instr_info.restore_current_reg) {
    dr_save_reg(ctx, frag, where, instr_info.current_reg, SPILL_SLOT_3);
  }
  // tls_reg = tb
  dr_insert_read_tls_field(ctx, frag, where, instr_info.tls_reg);
  // current_reg = tb->current
  INSERT(
      INSTR_CREATE_mov_ld(
          ctx,
          opnd_create_reg(instr_info.current_reg),
          OPND_CREATE_MEMPTR(instr_info.tls_reg, offsetof_current)));
  // *current_reg = bb_id
  store = INSERT(
      INSTR_CREATE_mov_st(
          ctx,
          OPND_CREATE_MEMPTR(instr_info.current_reg, 0),
          OPND_CREATE_INT32(frag_id)));
  // current_reg += sizeof(bb_id)
  INSERT(
      INSTR_CREATE_lea(
          ctx,
          opnd_create_reg(instr_info.current_reg),
          OPND_CREATE_MEM_lea(instr_info.current_reg,
                              DR_REG_NULL,
                              0,
                              sizeof(frag_id_t))));
  // tb->current = current_reg
  INSERT(
      INSTR_CREATE_mov_st(
          ctx,
          OPND_CREATE_MEMPTR(instr_info.tls_reg, offsetof_current),
          opnd_create_reg(instr_info.current_reg)));
  // restore current_reg
  if(instr_info.restore_current_reg) {
    dr_restore_reg(ctx, frag, where, instr_info.current_reg, SPILL_SLOT_3);
  }
  // restore tls_reg
  if(instr_info.restore_tls_reg) {
    dr_restore_reg(ctx, frag, where, instr_info.tls_reg, SPILL_SLOT_2);
  }

#undef INSERT

  // Compute instrumentation instructions offsets.
  if(before) {
    first = instr_get_next(before);
  } else {
    first = instrlist_first(frag);
  }
  instr_info.first_offset = get_offset(ctx,
                                       instrlist_first(frag),
                                       first);
  instr_info.store_offset = get_offset(ctx,
                                       instrlist_first(frag),
                                       store);

#ifdef TRACE_DUMP_BB
  instrlist_disassemble(ctx, frag_pc, frag, STDERR);
#endif
#ifdef TRACE_DEBUG
  dr_fprintf(STDERR,
             "debug: instrument_frag() done,"
             " first_offset=0x%" PRIx32
             " store_offset=0x%" PRIx32
             "\n",
             instr_info.first_offset,
             instr_info.store_offset);
#endif

  return instr_info;
}