Ejemplo n.º 1
0
static bool
drmgr_cls_stack_pop(void)
{
    /* Our callback enter is AFTER DR's, but our callback exit is BEFORE. */
    void *drcontext = dr_get_current_drcontext();
    tls_array_t *tls_child = (tls_array_t *) dr_get_tls_field(drcontext);
    tls_array_t *tls_parent;
    generic_event_entry_t *e;
    if (tls_child == NULL) {
        ASSERT(false, "internal error");
        return false;
    }

    tls_parent = tls_child->prev;
    if (tls_parent == NULL) {
        /* DR took over in the middle of a callback: ignore */
        return true;
    }

    /* let client know, though normally no action is needed */
    dr_rwlock_read_lock(cls_event_lock);
    for (e = cblist_cls_exit; e != NULL; e = e->next)
        (*e->cb.cls_cb)(drcontext, false/*!thread_exit*/);
    dr_rwlock_read_unlock(cls_event_lock);

    /* update tls w/ any changes while in child context */
    memcpy(tls_parent->tls, tls_child->tls, sizeof(*tls_child->tls)*MAX_NUM_TLS);
    /* swap in as the current structure */
    dr_set_tls_field(drcontext, (void *)tls_parent);

    return true;
}
Ejemplo n.º 2
0
static bool
drmgr_cls_stack_push(void)
{
    void *drcontext = dr_get_current_drcontext();
    tls_array_t *tls_parent = (tls_array_t *) dr_get_tls_field(drcontext);
    tls_array_t *tls_child;
    bool new_depth = false;
    if (tls_parent == NULL) {
        ASSERT(false, "internal error");
        return false;
    }

    tls_child = tls_parent->next;
    /* we re-use to avoid churn */
    if (tls_child == NULL) {
        tls_child = dr_thread_alloc(drcontext, sizeof(*tls_child));
        memset(tls_child, 0, sizeof(*tls_child));
        tls_parent->next = tls_child;
        tls_child->prev = tls_parent;
        tls_child->next = NULL;
        new_depth = true;
    } else
        ASSERT(tls_child->prev == tls_parent, "cls stack corrupted");

    /* share the tls slots */
    memcpy(tls_child->tls, tls_parent->tls, sizeof(*tls_child->tls)*MAX_NUM_TLS);
    /* swap in as the current structure */
    dr_set_tls_field(drcontext, (void *)tls_child);

    return drmgr_cls_stack_push_event(drcontext, new_depth);
}
Ejemplo n.º 3
0
static void
event_thread_exit(void *drcontext)
{
    per_thread_t *data = dr_get_tls_field(drcontext);
    dr_raw_mem_free(data->buf_base, TLS_BUF_SIZE);
    dr_thread_free(drcontext, data, sizeof(*data));
}
Ejemplo n.º 4
0
/** Records given fragment. */
void record_frag(void* ctx, instrlist_t* frag, frag_id_t id) {
  bool flushed;
  struct trace_buffer_t* tb;

  tb = dr_get_tls_field(ctx);
  tb_tlv_complete(tb);
  for(flushed = false; ; tb_flush(tb), flushed = true) {
    struct frag_t* frag_data;
    void* current;

    tb_tlv(tb, TYPE_FRAG);
    frag_data = tb->current;
    current = record_frag_instrs(ctx, frag, &frag_data->chunks, tb_end(tb));
    if(current) {
      frag_data->id = id;
      tb->current = current;
      tb_tlv_complete(tb);
      tb_tlv(tb, TYPE_TRACE);
      break;
    } else {
      if(flushed) {
        dr_fprintf(STDERR, "fatal: not enough buffer space after flush\n");
        dr_exit_process(1);
      }
      tb_tlv_cancel(tb);
    }
  }
}
Ejemplo n.º 5
0
DR_EXPORT
void *
drmgr_get_cls_field(void *drcontext, int idx)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    if (idx < 0 || idx > MAX_NUM_TLS || !cls_taken[idx] || tls == NULL)
        return NULL;
    return tls->cls[idx];
}
Ejemplo n.º 6
0
/* Clean call for the cbr */
static void
at_cbr(app_pc inst_addr, app_pc targ_addr, app_pc fall_addr, int taken, void *bb_addr)
{
    void *drcontext = dr_get_current_drcontext();
    file_t log = (file_t)(ptr_uint_t)dr_get_tls_field(drcontext);
    dr_fprintf(log, ""PFX" ["PFX", "PFX", "PFX"] => "PFX"\n",
               bb_addr, inst_addr, fall_addr, targ_addr,
               taken == 0 ? fall_addr : targ_addr);
}
Ejemplo n.º 7
0
DR_EXPORT
void *
drmgr_get_tls_field(void *drcontext, int idx)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    /* no need to check for tls_taken since would return NULL anyway (i#484) */
    if (idx < 0 || idx > MAX_NUM_TLS || tls == NULL)
        return NULL;
    return tls->tls[idx];
}
Ejemplo n.º 8
0
DR_EXPORT
bool 
drmgr_set_cls_field(void *drcontext, int idx, void *value)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    if (idx < 0 || idx > MAX_NUM_TLS || !cls_taken[idx] || tls == NULL)
        return false;
    tls->cls[idx] = value;
    return true;
}
Ejemplo n.º 9
0
static void
at_return(app_pc instr_addr, app_pc target_addr)
{
    file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
#ifdef SHOW_SYMBOLS
    print_address(f, instr_addr, "RETURN @ ");
    print_address(f, target_addr, "\t to ");
#else
    dr_fprintf(f, "RETURN @ "PFX" to "PFX"\n", instr_addr, target_addr);
#endif
}
Ejemplo n.º 10
0
void handle_thread_exit(void* ctx) {
  thread_id_t thread_id;
  struct trace_buffer_t* tb;

  check_ctx(ctx, "handle_thread_exit");
  thread_id = dr_get_thread_id(ctx);
  dr_fprintf(STDERR,
             "info: cleaning up thread 0x%" PRIx64 "..\n",
             (uint64_t)thread_id);
  tb = dr_get_tls_field(ctx);
  tb_delete(tb);
  dr_set_tls_field(ctx, NULL);
}
Ejemplo n.º 11
0
DR_EXPORT
bool
drmgr_set_tls_field(void *drcontext, int idx, void *value)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    if (idx < 0 || idx > MAX_NUM_TLS || tls == NULL)
        return false;
    /* going DR's traditional route of efficiency over safety: making this
     * a debug-only check to avoid cost in release build
     */
    ASSERT(tls_taken[idx], "usage error: setting tls index that is not reserved");
    tls->tls[idx] = value;
    return true;
}
Ejemplo n.º 12
0
static void
at_call(app_pc instr_addr, app_pc target_addr)
{
    file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
    dr_mcontext_t mc = {sizeof(mc),DR_MC_CONTROL/*only need xsp*/};
    dr_get_mcontext(dr_get_current_drcontext(), &mc);
#ifdef SHOW_SYMBOLS
    print_address(f, instr_addr, "CALL @ ");
    print_address(f, target_addr, "\t to ");
    dr_fprintf(f, "\tTOS is "PFX"\n", mc.xsp);
#else
    dr_fprintf(f, "CALL @ "PFX" to "PFX", TOS is "PFX"\n",
               instr_addr, target_addr, mc.xsp);
#endif
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
static void 
event_thread_exit(void *drcontext)
{
    per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
    char msg[512];
    int len;

    len = dr_snprintf(msg, sizeof(msg)/sizeof(msg[0]),
                      "Thread %d exited - ", dr_get_thread_id(drcontext));
    DR_ASSERT(len > 0);
    NULL_TERMINATE(msg);

    /* display thread private counts data */
    display_results(data, msg);

    /* clean up memory */
    dr_thread_free(drcontext, data, sizeof(per_thread_t));
}
Ejemplo n.º 15
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);
}
Ejemplo n.º 16
0
/** Common handler for basic blocks and traces. */
void handle_frag(void* ctx,
                 void* tag,
                 instrlist_t* frag,
                 bool new_frag,
                 bool instrument,
                 frag_id_t id_mask) {
  struct trace_buffer_t* tb;
  frag_id_t deleted_id;
  struct tag_info_t* tag_info;

  tb = dr_get_tls_field(ctx);

  deleted_id = 0;
  dr_mutex_lock(tags_lock);
  tag_info = hashtable_lookup(&tags, tag);
  if(tag_info == NULL) {
    tag_info = tag_info_new(tag);
  }
  if(new_frag) {
    deleted_id = tag_info_reset(tag_info);
    tag_info->id |= id_mask;
  } else {
    tag_info_reference(tag_info);
  }
  dr_mutex_unlock(tags_lock);

  if(deleted_id) {
    record_deletion(tb, deleted_id);
  }

  if(new_frag) {
    record_frag(ctx, frag, tag_info->id);
  }

  if(instrument) {
    struct instr_info_t instr_info;

    instr_info = instrument_frag(ctx, frag, tag_info->id);
    if(new_frag) {
      tag_info->instr_info = instr_info;
    }
  }
}
Ejemplo n.º 17
0
// XXX: use exceptions on Windows
dr_signal_action_t handle_signal(void* ctx, dr_siginfo_t* siginfo) {
  dr_fprintf(STDERR, "info: caught signal %u\n", (unsigned int)siginfo->sig);
  if(siginfo->sig == SIGSEGV) {
    struct trace_buffer_t* tb;
    struct tag_info_t* tag_info;

#ifdef TRACE_DEBUG
    dr_fprintf(STDERR,
               "debug: this is SIGSEGV and faulting address is " PFX "\n",
               siginfo->access_address);
#endif
    if(siginfo->raw_mcontext == NULL) {
      dr_fprintf(STDERR, "fatal: raw_mcontext missing\n");
      dr_exit_process(1);
    }
#ifdef TRACE_DEBUG
    dr_fprintf(STDERR, "debug: offending instruction is\n");
    disassemble(ctx, siginfo->raw_mcontext->xip, STDERR);
#endif

    tag_info = find_tag_or_die(siginfo->fault_fragment_info.tag);
    if(is_guard_page_access(siginfo->raw_mcontext,
                            tag_info,
                            siginfo->fault_fragment_info.cache_start_pc)) {
#ifdef TRACE_DEBUG
      dr_fprintf(STDERR, "debug: this is guard page access\n");
#endif

      // Flush.
      tb = dr_get_tls_field(siginfo->drcontext);
      tb_flush(tb);
      tb_tlv(tb, TYPE_TRACE);

      // Restart instrumentation.
      siginfo->raw_mcontext->xip = siginfo->fault_fragment_info.cache_start_pc +
                                   tag_info->instr_info.first_offset;
      restore_state(ctx, siginfo->raw_mcontext, tag_info);
      return DR_SIGNAL_SUPPRESS;
    }
  }
  return DR_SIGNAL_DELIVER;
}
Ejemplo n.º 18
0
void handle_delete(void* ctx, void* tag) {
  struct tag_info_t* tag_info;
  frag_id_t id;
  struct trace_buffer_t* tb;

#ifdef TRACE_DEBUG
  dr_fprintf(STDERR, "debug: handle_delete(tag=%p)\n", tag);
#endif

  dr_mutex_lock(tags_lock);
  tag_info = hashtable_lookup(&tags, tag);
  if(tag_info == NULL) {
    // Ignore -- this must be trace tag.
    dr_mutex_unlock(tags_lock);
    return;
  }
  if(--tag_info->counter != 0) {
    // Ignore -- this deletion was already reported.
    dr_mutex_unlock(tags_lock);
    return;
  }
  id = tag_info->id;
  hashtable_remove(&tags, tag);
  dr_mutex_unlock(tags_lock);

  if(ctx == NULL) {
    dr_mutex_lock(trace_buffer_lock);
    tb = trace_buffer;
  } else {
    tb = dr_get_tls_field(ctx);
  }
  record_deletion(tb, id);
  if(tb == trace_buffer) {
    dr_mutex_unlock(trace_buffer_lock);
  }
}
Ejemplo n.º 19
0
static bool
drmgr_cls_stack_exit(void *drcontext)
{
    tls_array_t *tls = (tls_array_t *) dr_get_tls_field(drcontext);
    tls_array_t *nxt, *tmp;
    generic_event_entry_t *e;
    if (tls == NULL)
        return false;
    for (nxt = tls; nxt->prev != NULL; nxt = nxt->prev)
        ; /* nothing */
    dr_rwlock_read_lock(cls_event_lock);
    while (nxt != NULL) {
        tmp = nxt;
        nxt = nxt->next;
        /* set the field in case client queries */
        dr_set_tls_field(drcontext, (void *)tmp);
        for (e = cblist_cls_exit; e != NULL; e = e->next)
            (*e->cb.cls_cb)(drcontext, true/*thread_exit*/);
        dr_thread_free(drcontext, tmp, sizeof(*tmp));
    }
    dr_rwlock_read_unlock(cls_event_lock);
    dr_set_tls_field(drcontext, NULL);
    return true;
}
Ejemplo n.º 20
0
static void
event_thread_exit(void *drcontext)
{
    log_file_close((file_t)(ptr_uint_t)dr_get_tls_field(drcontext));
}