//------------------------------------------------------------------------------
// Name: attach
// Desc:
//------------------------------------------------------------------------------
bool DebuggerCore::attach(edb::pid_t pid) {
	detach();
	
	// create this, so the threads created can refer to it
	process_ = new PlatformProcess(this, pid);

	bool attached;
	do {
		attached = false;
		QDir proc_directory(QString("/proc/%1/task/").arg(pid));
		for(const QString &s: proc_directory.entryList(QDir::NoDotAndDotDot | QDir::Dirs)) {
			// this can get tricky if the threads decide to spawn new threads
			// when we are attaching. I wish that linux had an atomic way to do this
			// all in one shot
			const edb::tid_t tid = s.toUInt();
			if(!threads_.contains(tid) && attach_thread(tid)) {
				attached = true;
			}
		}
	} while(attached);


	if(!threads_.empty()) {
		pid_            = pid;
		active_thread_  = pid;
		binary_info_    = edb::v1::get_binary_info(edb::v1::primary_code_region());		
		detectDebuggeeBitness();
		return true;
	} else {
		delete process_;
		process_ = nullptr;
	}

	return false;
}
Beispiel #2
0
int backtrace_ptrace(int pid, int *tids, int *index, int nr_tids)
{
#if !defined (NO_LIBUNWIND_PTRACE)
    int i, count, rc = 0;
    int *threads = NULL;

    count = get_threads(pid, &threads);
    if (!count || threads == NULL)
        return -1;

    if (tids != NULL) {
        if (adjust_threads(threads, count, tids, index, nr_tids) < 0)
            return -1;

        free(threads);
        count = nr_tids;
        threads = tids;
    }

    if (attach_process(pid) < 0)
        return -1;

    for (i = 0; i < count; ++i) {
        void *upt_info;

        printf("--------------------  thread %d (%d)  --------------------\n",
               (index != NULL ? index[i] : i+1), threads[i]);

        if (threads[i] != pid && attach_thread(threads[i]) < 0) {
            rc = -1;
            break;
        }

        upt_info = _UPT_create(threads[i]);

        if (backtrace_thread(&_UPT_accessors, upt_info) < 0)
            rc = -1;

        _UPT_destroy(upt_info);

        if (threads[i] != pid && detach_thread(threads[i]))
            rc = -1;
        if (rc < 0)
            break;
    }

    free(threads);

    if (detach_process(pid) < 0)
        return -1;

    return rc;

#else
    return -1;
#endif /* NO_LIBUNWIND_PTRACE */
}
Beispiel #3
0
static void
check_event (ptid_t ptid)
{
  struct regcache *regcache = get_thread_regcache (ptid);
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  td_event_msg_t msg;
  td_thrinfo_t ti;
  td_err_e err;
  CORE_ADDR stop_pc;
  int loop = 0;

  /* Bail out early if we're not at a thread event breakpoint.  */
  stop_pc = regcache_read_pc (regcache)
	    - gdbarch_decr_pc_after_break (gdbarch);
  if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
    return;
  loop = 1;

  do
    {
      err = td_ta_event_getmsg_p (thread_agent, &msg);
      if (err != TD_OK)
        {
	  if (err == TD_NOMSG)
	    return;
          error ("Cannot get thread event message: %s",
		 thread_db_err_str (err));
        }
      err = td_thr_get_info_p ((void *)(uintptr_t)msg.th_p, &ti);
      if (err != TD_OK)
        error ("Cannot get thread info: %s", thread_db_err_str (err));
      ptid = BUILD_THREAD (ti.ti_tid, GET_PID (ptid));
      switch (msg.event)
        {
        case TD_CREATE:
          /* We may already know about this thread, for instance when the
             user has issued the `info threads' command before the SIGTRAP
             for hitting the thread creation breakpoint was reported.  */
          attach_thread (ptid, (void *)(uintptr_t)msg.th_p, &ti, 1);
          break;
       case TD_DEATH:
         if (!in_thread_list (ptid))
           error ("Spurious thread death event.");
         detach_thread (ptid, 1);
         break;
       default:
          error ("Spurious thread event.");
       }
    }
  while (loop);
}
Beispiel #4
0
static void
get_current_thread ()
{
  td_thrhandle_t th;
  td_thrinfo_t ti;
  long lwp;
  ptid_t tmp, ptid;

  lwp = get_current_lwp (proc_handle.pid);
  tmp = BUILD_LWP (lwp, proc_handle.pid);
  ptid = thread_from_lwp (tmp, &th, &ti);
  if (!in_thread_list (ptid))
    {
      attach_thread (ptid, &th, &ti, 1);
    }
  inferior_ptid = ptid;
}
Beispiel #5
0
int pup_heap_thread_init(struct PupHeap *heap)
{
	struct PupHeapRegion *region = pup_heap_region_allocate();
	if (!region) {
		return -1;
	}
	int res = attach_thread(heap, pthread_self());
	if (res) {
		// TODO
		abort();
	}
	res = set_local_region(heap, region);
	if (res) {
		return res;
	}
	return 0;
}
/**
 * Handle activity recognition events from HAL.
 */
static void activity_callback(
        const activity_recognition_callback_procs_t* procs,
        const activity_event_t* events,
        int count) {
    if (sOnActivityChanged == NULL) {
        ALOGE("Dropping activity_callback because onActivityChanged handler is null.");
        return;
    }

    if (events == NULL || count <= 0) {
        ALOGE("Invalid activity_callback. Count: %d, Events: %p", count, events);
        return;
    }

    JNIEnv* env = NULL;
    int result = attach_thread(&env);
    if (result != JNI_OK) {
        ALOGE("Unable to attach thread with JNI.");
        return;
    }

    jclass event_class =
            env->FindClass("android/hardware/location/ActivityRecognitionHardware$Event");
    jmethodID event_ctor = env->GetMethodID(event_class, "<init>", "()V");
    jfieldID activity_field = env->GetFieldID(event_class, "activity", "I");
    jfieldID type_field = env->GetFieldID(event_class, "type", "I");
    jfieldID timestamp_field = env->GetFieldID(event_class, "timestamp", "J");

    jobjectArray events_array = env->NewObjectArray(count, event_class, NULL);
    for (int i = 0; i < count; ++i) {
        const activity_event_t* event = &events[i];
        jobject event_object = env->NewObject(event_class, event_ctor);
        env->SetIntField(event_object, activity_field, event->activity);
        env->SetIntField(event_object, type_field, event->event_type);
        env->SetLongField(event_object, timestamp_field, event->timestamp);
        env->SetObjectArrayElement(events_array, i, event_object);
        env->DeleteLocalRef(event_object);
    }

    env->CallVoidMethod(sCallbacksObject, sOnActivityChanged, events_array);
    check_and_clear_exceptions(env, __FUNCTION__);

    // TODO: ideally we'd let the HAL register the callback thread only once
    detach_thread();
}
Beispiel #7
0
static int
maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p,
		     int *counter)
{
  struct lwp_info *lwp;

  lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
  if (lwp != NULL)
    return 1;

  if (!attach_thread (th_p, ti_p))
    return 0;

  if (counter != NULL)
    *counter += 1;

  return 1;
}
Beispiel #8
0
static ptid_t
fbsd_thread_wait (struct target_ops *ops,
		  ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
  struct target_ops *beneath = find_target_beneath (ops);
  ptid_t ret;
  long lwp;
  CORE_ADDR stop_pc;
  td_thrhandle_t th;
  td_thrinfo_t ti;

  ret = beneath->to_wait (beneath, ptid, ourstatus, options);
  if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED)
    {
      lwp = get_current_lwp (GET_PID(ret));
      ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)),
         &th, &ti);
      if (!in_thread_list(ret)) {
        /*
         * We have to enable event reporting for initial thread
         * which was not mapped before.
	 */
        attach_thread(ret, &th, &ti, 1);
      }
      if (ourstatus->value.sig == TARGET_SIGNAL_TRAP)
        check_event(ret);
      /* this is a hack, if an event won't cause gdb to stop, for example,
         SIGALRM, gdb resumes the process immediatly without setting
         inferior_ptid to the new thread returned here, this is a bug
         because inferior_ptid may already not exist there, and passing
         a non-existing thread to fbsd_thread_resume causes error. However,
         if the exiting thread is the currently selected thread,
         then that is handled later in handle_inferior_event(), and we must
         not delete the currently selected thread. 
      */
      if (!fbsd_thread_alive (ops, inferior_ptid) && !ptid_equal(inferior_ptid, ret))
        {
          delete_thread (inferior_ptid);
          inferior_ptid = ret;
        }
    }

  return (ret);
}
Beispiel #9
0
static int
find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
{
  td_thrinfo_t ti;
  td_err_e err;
  ptid_t ptid;

  err = td_thr_get_info_p (th_p, &ti);
  if (err != TD_OK)
    error ("Cannot get thread info: %s", thread_db_err_str (err));

  /* Ignore zombie */
  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
    return 0;

  ptid = BUILD_THREAD (ti.ti_tid, proc_handle.pid);
  attach_thread (ptid, th_p, &ti, 1);
  return 0;
}
Beispiel #10
0
/* Attach to lwp PTID, doing whatever else is required to have this
   LWP under the debugger's control --- e.g., enabling event
   reporting.  Returns true on success.  */
int
thread_db_attach_lwp (ptid_t ptid)
{
  td_thrhandle_t th;
  td_thrinfo_t ti;
  td_err_e err;
  struct thread_db_info *info;

  info = get_thread_db_info (GET_PID (ptid));

  if (info == NULL)
    return 0;

  /* This ptid comes from linux-nat.c, which should always fill in the
     LWP.  */
  gdb_assert (GET_LWP (ptid) != 0);

  /* Access an lwp we know is stopped.  */
  info->proc_handle.ptid = ptid;

  /* If we have only looked at the first thread before libpthread was
     initialized, we may not know its thread ID yet.  Make sure we do
     before we add another thread to the list.  */
  if (!have_threads (ptid))
    thread_db_find_new_threads_1 (ptid);

  err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th);
  if (err != TD_OK)
    /* Cannot find user-level thread.  */
    return 0;

  err = info->td_thr_get_info_p (&th, &ti);
  if (err != TD_OK)
    {
      warning (_("Cannot get thread info: %s"), thread_db_err_str (err));
      return 0;
    }

  attach_thread (ptid, &th, &ti);
  return 1;
}
Beispiel #11
0
static int
thread_get_info_callback (const td_thrhandle_t *thp, void *argp)
{
  td_thrinfo_t ti;
  td_err_e err;
  ptid_t thread_ptid;
  struct thread_get_info_inout *inout;
  struct thread_db_info *info;

  inout = argp;
  info = inout->thread_db_info;

  err = info->td_thr_get_info_p (thp, &ti);
  if (err != TD_OK)
    error (_("thread_get_info_callback: cannot get thread info: %s"),
	   thread_db_err_str (err));

  /* Fill the cache.  */
  thread_ptid = ptid_build (info->pid, ti.ti_lid, 0);
  inout->thread_info = find_thread_ptid (thread_ptid);

  /* In the case of a zombie thread, don't continue.  We don't want to
     attach to it thinking it is a new thread.  */
  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
    return TD_THR_ZOMBIE;

  if (inout->thread_info == NULL)
    {
      /* New thread.  Attach to it now (why wait?).  */
      if (!have_threads (thread_ptid))
 	thread_db_find_new_threads_1 (thread_ptid);
      else
	attach_thread (thread_ptid, thp, &ti);
      inout->thread_info = find_thread_ptid (thread_ptid);
      gdb_assert (inout->thread_info != NULL);
    }

  return 0;
}
Beispiel #12
0
static ptid_t
fbsd_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
  ptid_t ret;
  long lwp;
  CORE_ADDR stop_pc;
  td_thrhandle_t th;
  td_thrinfo_t ti;

  ret = child_ops.to_wait (ptid, ourstatus);
  if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED)
    {
      lwp = get_current_lwp (GET_PID(ret));
      ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)),
         &th, &ti);
      if (!in_thread_list(ret)) {
        /*
         * We have to enable event reporting for initial thread
         * which was not mapped before.
	 */
        attach_thread(ret, &th, &ti, 1);
      }
      if (ourstatus->value.sig == TARGET_SIGNAL_TRAP)
        check_event(ret);
      /* this is a hack, if an event won't cause gdb to stop, for example,
         SIGARLM, gdb resumes the process immediatly without setting
         inferior_ptid to the new thread returned here, this is a bug
         because inferior_ptid may already not exist there, and passing
         a none existing thread to fbsd_thread_resume causes error. */
      if (!fbsd_thread_alive (inferior_ptid))
        {
          delete_thread (inferior_ptid);
          inferior_ptid = ret;
        }
    }

  return (ret);
}
Beispiel #13
0
/*
 * save process' memory maps, stack contents, thread identifiers and registers
 */
struct snapshot *get_snapshot(int pid, int *tids, int *index, int nr_tids)
{
    struct snapshot *res;
    int attached_tid = 0;
    int i, n_frames;
    long page, label, rc;
    struct mem_data_chunk **stacks_cover = NULL;

    if ((page = sysconf(_SC_PAGESIZE)) < 0) {
        perror("get pagesize");
        return NULL;
    }
    --page;

    res = calloc(1, sizeof(struct snapshot));

    /*
     * create memory_map structure corresponding to process' maps
     */
    res->map = create_maps(pid);
    if (res->map == NULL)
        goto get_snapshot_fail;

    /*
     * get process' threads
     */
    res->num_threads = get_threads(pid, &res->tids);
    if (res->num_threads < 0 || res->tids == NULL)
        goto get_snapshot_fail;

    /*
     * user-provided list of threads
     */
    if (tids != NULL) {
        if (adjust_threads(res->tids, res->num_threads, tids, index, nr_tids) < 0)
            goto get_snapshot_fail;

        free(res->tids);
        res->num_threads = nr_tids;
        res->tids = tids;
    }

    res->cur_thr = 0;

    res->regs = malloc(sizeof(res->regs[0])*res->num_threads);
    if (res->regs == NULL) {
        perror("malloc");
        goto get_snapshot_fail;
    }

    /* FREEZE PROCESS */
    if (attach_process(pid) < 0)
        goto get_snapshot_fail;

    for (i = 0; i < res->num_threads; ++i) {
        struct iovec iov;

        /*
         * we have already attached to main thread. call attach_thread()
         * for other ones
         */
        attached_tid = res->tids[i];
        if (res->tids[i] != pid && attach_thread(res->tids[i]) < 0)
            goto get_snapshot_fail_attached;

        /*
         * save thread's registers
         */
        iov.iov_len = sizeof(res->regs[0]);
        iov.iov_base = &res->regs[i];
        rc = ptrace(PTRACE_GETREGSET, res->tids[i], NT_PRSTATUS, &iov);
        if (rc < 0) {
            perror("PTRACE_GETREGSET");
            goto get_snapshot_fail_attached;
        }

        /*
         * save label on memory region. it will indicate that memory contents
         * upper than this point (%rsp) will needed to unwind stacks
         */
        label = SP_REG(&res->regs[i]) & ~page;
        rc = mem_map_add_label(res->map, (void *)label, res->num_threads);

        if (rc < 0) {
            fprintf(stderr, "failed to add label 0x%lx [rsp 0x%llx thread %d]\n",
                    label, (long long unsigned int)SP_REG(&res->regs[i]), res->tids[i]);
            goto get_snapshot_fail_attached;
        }

        /*
         * detach from thread. it will still be frozen due to SIGSTOP
         */
        if (res->tids[i] != pid && detach_thread(res->tids[i]) < 0)
            goto get_snapshot_fail_attached;
    }

    /*
     * arrange data chunks to copy memory contents. in most cases the chunks
     * will start from %rsp pointing somewhere in thread's stack
     * to the end of the stack region
     */
    stacks_cover = malloc(sizeof(struct mem_data_chunk*) * res->num_threads);

    n_frames = mem_map_build_label_cover(res->map, stack_size,
            stacks_cover, page + 1);

    if (stacks_cover == NULL) {
        fprintf(stderr, "error: stacks cover == NULL, n_frames=%d\n", n_frames);
        goto get_snapshot_fail_attached;
    }

    /*
     * copy memory contents
     */
    rc = copy_memory(pid, stacks_cover, n_frames);

    if (rc < 0)
        goto get_snapshot_fail_attached;

    /* UNFREEZE PROCESS */
    if (detach_process(pid) < 0)
        goto get_snapshot_fail;

    if (opt_verbose) {
        for (i = 0; i < n_frames; ++i) {
            struct mem_data_chunk *chunk = stacks_cover[i];
            printf("chunk #%d: 0x%lx-0x%lx length: %ldK\n",
                    i, (size_t)chunk->start,
                    (size_t)chunk->start + chunk->length,
                    chunk->length >> 10);
        }
    }

    free(stacks_cover);

    return res;

get_snapshot_fail_attached:
    if (attached_tid)
        detach_thread(attached_tid);

    detach_process(pid);

get_snapshot_fail:
    if (opt_verbose) {
        fprintf(stderr, "maps of %d:\n", pid);
        print_proc_maps(pid);
    }

    free(stacks_cover);
    snapshot_destroy(res);
    return NULL;
}
Beispiel #14
0
int backtrace_ptrace(int pid, int *tids, int *index, int nr_tids)
{
#if !defined (NO_LIBUNWIND_PTRACE)
    int i, count, rc = 0;
    int *threads = NULL;

    count = get_threads(pid, &threads);
    if (!count || threads == NULL)
        return -1;

    if (tids != NULL) {
        if (adjust_threads(threads, count, tids, index, nr_tids) < 0)
            return -1;

        free(threads);
        count = nr_tids;
        threads = tids;
    }

    if (attach_process(pid) < 0)
        return -1;

    for (i = 0; i < count; ++i) {
        void *upt_info;
        int x;
        char comm[16];
        char end_pad[25] = "------------------------";

        x = get_thread_comm(threads[i], comm, sizeof(comm));

        if (x > 0 && x <= sizeof(end_pad))
        {
            end_pad[sizeof(end_pad) - x] = '\0';
            printf("-------------- thread %d (%d) (%s) %s\n", (index != NULL ? index[i] : i + 1), threads[i], comm, end_pad);
        }

        if (threads[i] != pid && attach_thread(threads[i]) < 0) {
            rc = -1;
            break;
        }

        upt_info = _UPT_create(threads[i]);

        if (backtrace_thread(&_UPT_accessors, upt_info) < 0)
            rc = -1;

        _UPT_destroy(upt_info);

        if (threads[i] != pid && detach_thread(threads[i]))
            rc = -1;
        if (rc < 0)
            break;
    }

    free(threads);

    if (detach_process(pid) < 0)
        return -1;

    return rc;

#else
    return -1;
#endif /* NO_LIBUNWIND_PTRACE */
}
Beispiel #15
0
/*
 * save process' memory maps, stack contents, thread identifiers and registers
 */
struct snapshot *get_snapshot(int pid, int *tids, int *index, int nr_tids)
{
    struct snapshot *res;
    int i, attached_tid, n_frames;
    long page, label, rc;
    struct mem_data_chunk **stacks_cover = NULL;
    int v_major, v_minor;
    int use_process_vm_readv = 0;

    if ((page = sysconf(_SC_PAGESIZE)) < 0) {
        perror("get pagesize");
        return NULL;
    }
    --page;

    res = calloc(1, sizeof(struct snapshot));

    /*
     * create memory_map structure corresponding to process' maps
     */
    res->map = create_maps(pid);
    if (res->map == NULL)
        goto get_snapshot_fail;

    /*
     * get process' threads
     */
    res->num_threads = get_threads(pid, &res->tids);
    if (res->num_threads < 0 || res->tids == NULL)
        goto get_snapshot_fail;

    /*
     * user-provided list of threads
     */
    if (tids != NULL) {
        if (adjust_threads(res->tids, res->num_threads, tids, index, nr_tids) < 0)
            goto get_snapshot_fail;

        free(res->tids);
        res->num_threads = nr_tids;
        res->tids = tids;
    }

    res->cur_thr = 0;

    res->regs = malloc(sizeof(struct user_regs_struct)*res->num_threads);
    if (res->regs == NULL) {
        perror("malloc");
        goto get_snapshot_fail;
    }

    /*
     * decide how to copy memory contents of the process. on newer kernels
     * proc_vm_readv() is used by default. on older kernels or when the option
     * --proc-mem is specified read the file /proc/<pid>/mem
     */
    if (!opt_proc_mem) {
        if (get_kernel_version(&v_major, &v_minor) < 0)
            goto get_snapshot_fail;
        if (((v_major << 16) | v_minor) >= 0x30002)
            use_process_vm_readv = 1;
    } else {
        use_process_vm_readv = 0;
    }

    /* FREEZE PROCESS */
    if (attach_process(pid) < 0)
        goto get_snapshot_fail;

    for (i = 0; i < res->num_threads; ++i) {
        /*
         * we have already attached to main thread. call attach_thread()
         * for other ones
         */
        attached_tid = res->tids[i];
        if (res->tids[i] != pid && attach_thread(res->tids[i]) < 0)
            goto get_snapshot_fail_attached;

        /*
         * save thread's registers
         */
        rc = ptrace(PTRACE_GETREGS, res->tids[i], NULL, &res->regs[i]);
        if (rc < 0) {
            perror("PTRACE_GETREGS");
            goto get_snapshot_fail_attached;
        }

        /*
         * save label on memory region. it will indicate that memory contents
         * upper than this point (%rsp) will needed to unwind stacks
         */
        label = res->regs[i].rsp & ~page;
        rc = mem_map_add_label(res->map, (void *)label, res->num_threads);

        if (rc < 0) {
            fprintf(stderr, "failed to add label 0x%lx [rsp 0x%lx thread %d]\n",
                    label, res->regs[i].rsp, res->tids[i]);
            goto get_snapshot_fail_attached;
        }

        /*
         * detach from thread. it will still be frozen due to SIGSTOP
         */
        if (res->tids[i] != pid && detach_thread(res->tids[i]) < 0)
            goto get_snapshot_fail_attached;
    }

    /*
     * arrange data chunks to copy memory contents. in most cases the chunks
     * will start from %rsp pointing somewhere in thread's stack
     * to the end of the stack region
     */
    stacks_cover = malloc(sizeof(struct mem_data_chunk*) * res->num_threads);

    n_frames = mem_map_build_label_cover(res->map, stack_size,
            stacks_cover, page + 1);

    if (stacks_cover == NULL) {
        fprintf(stderr, "error: stacks cover == NULL, n_frames=%d\n", n_frames);
        goto get_snapshot_fail_attached;
    }

    /*
     * copy memory contents
     */
    rc = use_process_vm_readv ?
        copy_memory_process_vm_readv(pid, stacks_cover, n_frames) :
        copy_memory_proc_mem(pid, stacks_cover, n_frames);

    if (rc < 0)
        goto get_snapshot_fail_attached;

    /* UNFREEZE PROCESS */
    if (detach_process(pid) < 0)
        goto get_snapshot_fail;

    if (opt_verbose) {
        for (i = 0; i < n_frames; ++i) {
            struct mem_data_chunk *chunk = stacks_cover[i];
            printf("chunk #%d: 0x%lx-0x%lx length: %ldK\n",
                    i, (size_t)chunk->start,
                    (size_t)chunk->start + chunk->length,
                    chunk->length >> 10);
        }
    }

    free(stacks_cover);

    return res;

get_snapshot_fail_attached:
    if (attached_tid)
        detach_thread(attached_tid);

    detach_process(pid);

get_snapshot_fail:
    if (opt_verbose) {
        fprintf(stderr, "maps of %d:\n", pid);
        print_proc_maps(pid);
    }

    free(stacks_cover);
    snapshot_destroy(res);
    return NULL;
}