1 /* 2 * Copyright 2006 The Android Open Source Project 3 */ 4 5 #include <dirent.h> 6 #include <sys/ptrace.h> 7 #include <stdint.h> 8 #include <thread_db.h> 9 #include <stdlib.h> 10 #include <stdio.h> 11 12 extern int ps_pglobal_lookup (void *, const char *obj, const char *name, void **sym_addr); 13 14 struct ps_prochandle 15 { 16 pid_t pid; 17 }; 18 19 20 /* 21 * This is the list of "special" symbols we care about whose addresses are 22 * cached by gdbserver from the host at init time. 23 */ 24 enum { 25 SYM_TD_CREATE, 26 SYM_THREAD_LIST, 27 NUM_SYMS 28 }; 29 30 static char const * gSymbols[] = { 31 [SYM_TD_CREATE] = "_thread_created_hook", 32 NULL 33 }; 34 35 36 char const ** 37 td_symbol_list(void) 38 { 39 return gSymbols; 40 } 41 42 43 td_err_e 44 td_ta_new(struct ps_prochandle const * proc_handle, td_thragent_t ** agent_out) 45 { 46 td_thragent_t * agent; 47 48 agent = (td_thragent_t *)malloc(sizeof(td_thragent_t)); 49 if (!agent) { 50 return TD_MALLOC; 51 } 52 53 agent->pid = proc_handle->pid; 54 *agent_out = agent; 55 56 return TD_OK; 57 } 58 59 60 td_err_e 61 td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events) 62 { 63 return TD_OK; 64 } 65 66 67 static td_thrhandle_t gEventMsgHandle; 68 69 static int 70 _event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr) 71 { 72 void * pc; 73 74 pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL); 75 76 if (pc == bkpt_addr) { 77 // The hook function takes the id of the new thread as it's first param, 78 // so grab it from r0. 79 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL); 80 gEventMsgHandle.tid = gEventMsgHandle.pid; 81 return 0x42; 82 } 83 return 0; 84 } 85 86 td_err_e 87 td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event) 88 { 89 td_err_e err; 90 void * bkpt_addr; 91 92 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr); 93 if (err) { 94 return err; 95 } 96 97 err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0); 98 if (err != 0x42) { 99 return TD_NOMSG; 100 } 101 102 event->event = TD_CREATE; 103 event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way! 104 105 return TD_OK; 106 } 107 108 109 td_err_e 110 td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info) 111 { 112 info->ti_tid = handle->tid; 113 info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids 114 info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>. 115 This is only used to see if the thread is a zombie or not */ 116 return TD_OK; 117 } 118 119 120 td_err_e 121 td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event) 122 { 123 // I don't think we need to do anything here... 124 return TD_OK; 125 } 126 127 128 td_err_e 129 td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out) 130 { 131 int32_t err; 132 133 /* 134 * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up 135 * the symbol from it's cache, which is populated at start time with the 136 * symbols returned from td_symbol_list via calls back to the host. 137 */ 138 139 switch (event) { 140 case TD_CREATE: 141 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr); 142 if (err) { 143 return TD_NOEVENT; 144 } 145 return TD_OK; 146 } 147 return TD_NOEVENT; 148 } 149 150 151 td_err_e 152 td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie, 153 td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags) 154 { 155 td_err_e err = TD_OK; 156 char path[32]; 157 DIR * dir; 158 struct dirent * entry; 159 td_thrhandle_t handle; 160 161 snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid); 162 dir = opendir(path); 163 if (!dir) { 164 return TD_NOEVENT; 165 } 166 167 handle.pid = agent->pid; 168 while ((entry = readdir(dir)) != NULL) { 169 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 170 continue; 171 } 172 handle.tid = atoi(entry->d_name); 173 err = func(&handle, cookie); 174 if (err) { 175 break; 176 } 177 } 178 179 closedir(dir); 180 181 return err; 182 } 183 184