Initial Contribution

This commit is contained in:
The Android Open Source Project
2008-10-21 07:00:00 -07:00
commit a27d2baa0c
1777 changed files with 163452 additions and 0 deletions

33
libthread_db/Android.mk Normal file
View File

@@ -0,0 +1,33 @@
LOCAL_PATH:= $(call my-dir)
#
# static
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
libthread_db.c
LOCAL_MODULE:= libthread_db
include $(BUILD_STATIC_LIBRARY)
#
# shared
#
include $(CLEAR_VARS)
LOCAL_WHOLE_STATIC_LIBRARIES := libthread_db
LOCAL_MODULE:=libthread_db
LOCAL_SHARED_LIBRARIES := libdl
# NOTE: Using --no-undefined results in a missing symbol that is defined inside
# gdbserver and is resolved at runtime. Since there is no library containing
# this symbol that we can link against, set LOCAL_ALLOW_UNDEFINED_SYMBOLS so
# that --no-undefined is removed from the linker flags.
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_SYSTEM_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)

View File

26
libthread_db/NOTICE Normal file
View File

@@ -0,0 +1,26 @@
Copyright (C) 2007 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2006 The Android Open Source Project
*/
#ifndef _LIBTHREAD_DB__THREAD_DB_H
#define _LIBTHREAD_DB__THREAD_DB_H
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <sys/types.h>
#define TD_THR_ANY_USER_FLAGS 0xffffffff
#define TD_THR_LOWEST_PRIORITY -20
#define TD_SIGNO_MASK NULL
/* td_err_e values */
enum {
TD_OK,
TD_ERR,
TD_NOTHR,
TD_NOSV,
TD_NOLWP,
TD_BADPH,
TD_BADTH,
TD_BADSH,
TD_BADTA,
TD_BADKEY,
TD_NOMSG,
TD_NOFPREGS,
TD_NOLIBTHREAD,
TD_NOEVENT,
TD_NOCAPAB,
TD_DBERR,
TD_NOAPLIC,
TD_NOTSD,
TD_MALLOC,
TD_PARTIALREG,
TD_NOXREGS,
TD_VERSION
};
/*
* td_event_e values
* NOTE: There is a max of 32 events
*/
enum {
TD_CREATE,
TD_DEATH
};
/* td_thr_state_e values */
enum {
TD_THR_ANY_STATE,
TD_THR_UNKNOWN,
TD_THR_SLEEP,
TD_THR_ZOMBIE
};
typedef int32_t td_err_e;
typedef uint32_t td_event_e;
typedef uint32_t td_notify_e;
typedef uint32_t td_thr_state_e;
typedef pthread_t thread_t;
typedef struct
{
pid_t pid;
} td_thragent_t;
typedef struct
{
pid_t pid;
pid_t tid;
} td_thrhandle_t;
typedef struct
{
td_event_e event;
td_thrhandle_t const * th_p;
union {
void * data;
} msg;
} td_event_msg_t;
typedef struct
{
uint32_t events;
} td_thr_events_t;
typedef struct
{
union {
void * bptaddr;
} u;
} td_notify_t;
typedef struct
{
td_thr_state_e ti_state;
thread_t ti_tid; // pthread's id for the thread
int32_t ti_lid; // the kernel's id for the thread
} td_thrinfo_t;
#define td_event_emptyset(set) \
(set)->events = 0
#define td_event_fillset(set) \
(set)->events = 0xffffffff
#define td_event_addset(set, n) \
(set)->events |= (1 << n)
typedef int td_thr_iter_f(td_thrhandle_t const *, void *);
struct ps_prochandle;
#ifdef __cplusplus
extern "C"{
#endif
extern td_err_e td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** thread_agent);
extern td_err_e td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * event);
extern td_err_e td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify);
extern td_err_e td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event);
extern td_err_e td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags);
extern char const ** td_symbol_list(void);
#ifdef __cplusplus
}
#endif
#endif

183
libthread_db/libthread_db.c Normal file
View File

@@ -0,0 +1,183 @@
/*
* Copyright 2006 The Android Open Source Project
*/
#include <dirent.h>
#include <sys/ptrace.h>
#include <stdint.h>
#include <thread_db.h>
#include <stdlib.h>
#include <stdio.h>
extern int ps_pglobal_lookup (void *, const char *obj, const char *name, void **sym_addr);
struct ps_prochandle
{
pid_t pid;
};
/*
* This is the list of "special" symbols we care about whose addresses are
* cached by gdbserver from the host at init time.
*/
enum {
SYM_TD_CREATE,
SYM_THREAD_LIST,
NUM_SYMS
};
static char const * gSymbols[] = {
[SYM_TD_CREATE] = "_thread_created_hook",
NULL
};
char const **
td_symbol_list(void)
{
return gSymbols;
}
td_err_e
td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** agent_out)
{
td_thragent_t * agent;
agent = (td_thragent_t *)malloc(sizeof(td_thragent_t));
if (!agent) {
return TD_MALLOC;
}
agent->pid = proc_handle->pid;
*agent_out = agent;
return TD_OK;
}
td_err_e
td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events)
{
return TD_OK;
}
static td_thrhandle_t gEventMsgHandle;
static int
_event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr)
{
void * pc;
pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL);
if (pc == bkpt_addr) {
// The hook function takes the id of the new thread as it's first param,
// so grab it from r0.
gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL);
gEventMsgHandle.tid = gEventMsgHandle.pid;
return 0x42;
}
return 0;
}
td_err_e
td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event)
{
td_err_e err;
void * bkpt_addr;
err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr);
if (err) {
return err;
}
err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0);
if (err != 0x42) {
return TD_NOMSG;
}
event->event = TD_CREATE;
event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way!
return TD_OK;
}
td_err_e
td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info)
{
info->ti_tid = handle->tid;
info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids
info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>.
This is only used to see if the thread is a zombie or not */
return TD_OK;
}
td_err_e
td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event)
{
// I don't think we need to do anything here...
return TD_OK;
}
td_err_e
td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out)
{
int32_t err;
/*
* This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up
* the symbol from it's cache, which is populated at start time with the
* symbols returned from td_symbol_list via calls back to the host.
*/
switch (event) {
case TD_CREATE:
err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &notify_out->u.bptaddr);
if (err) {
return TD_NOEVENT;
}
return TD_OK;
}
return TD_NOEVENT;
}
td_err_e
td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags)
{
td_err_e err = TD_OK;
char path[32];
DIR * dir;
struct dirent * entry;
td_thrhandle_t handle;
snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
dir = opendir(path);
if (!dir) {
return TD_NOEVENT;
}
handle.pid = agent->pid;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
handle.tid = atoi(entry->d_name);
err = func(&handle, cookie);
if (err) {
break;
}
}
closedir(dir);
return err;
}