diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:35 -0800 |
commit | 1dc9e472e19acfe6dc7f41e429236e7eef7ceda1 (patch) | |
tree | 3be0c520fae17689bbf5584e1136fb820caef26f /libthread_db | |
parent | 1767f908af327fa388b1c66883760ad851267013 (diff) | |
download | bionic-1dc9e472e19acfe6dc7f41e429236e7eef7ceda1.zip bionic-1dc9e472e19acfe6dc7f41e429236e7eef7ceda1.tar.gz bionic-1dc9e472e19acfe6dc7f41e429236e7eef7ceda1.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libthread_db')
-rw-r--r-- | libthread_db/Android.mk | 33 | ||||
-rw-r--r-- | libthread_db/MODULE_LICENSE_BSD | 0 | ||||
-rw-r--r-- | libthread_db/NOTICE | 26 | ||||
-rw-r--r-- | libthread_db/include/thread_db.h | 143 | ||||
-rw-r--r-- | libthread_db/libthread_db.c | 183 |
5 files changed, 385 insertions, 0 deletions
diff --git a/libthread_db/Android.mk b/libthread_db/Android.mk new file mode 100644 index 0000000..3091bbc --- /dev/null +++ b/libthread_db/Android.mk @@ -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) diff --git a/libthread_db/MODULE_LICENSE_BSD b/libthread_db/MODULE_LICENSE_BSD new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libthread_db/MODULE_LICENSE_BSD diff --git a/libthread_db/NOTICE b/libthread_db/NOTICE new file mode 100644 index 0000000..3831b34 --- /dev/null +++ b/libthread_db/NOTICE @@ -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. diff --git a/libthread_db/include/thread_db.h b/libthread_db/include/thread_db.h new file mode 100644 index 0000000..9c76d40 --- /dev/null +++ b/libthread_db/include/thread_db.h @@ -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 diff --git a/libthread_db/libthread_db.c b/libthread_db/libthread_db.c new file mode 100644 index 0000000..f1a78ac --- /dev/null +++ b/libthread_db/libthread_db.c @@ -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], ¬ify_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; +} + |