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 extern pid_t ps_getpid(struct ps_prochandle *ph); 14 15 /* 16 * This is the list of "special" symbols we care about whose addresses are 17 * cached by gdbserver from the host at init time. 18 */ 19 enum { 20 SYM_TD_CREATE, 21 SYM_THREAD_LIST, 22 NUM_SYMS 23 }; 24 25 static char const * gSymbols[] = { 26 [SYM_TD_CREATE] = "_thread_created_hook", 27 NULL 28 }; 29 30 31 char const ** 32 td_symbol_list(void) 33 { 34 return gSymbols; 35 } 36 37 38 td_err_e 39 td_ta_new(struct ps_prochandle * proc_handle, td_thragent_t ** agent_out) 40 { 41 td_thragent_t * agent; 42 43 agent = (td_thragent_t *)malloc(sizeof(td_thragent_t)); 44 if (!agent) { 45 return TD_MALLOC; 46 } 47 48 agent->pid = ps_getpid(proc_handle); 49 agent->ph = proc_handle; 50 *agent_out = agent; 51 52 return TD_OK; 53 } 54 55 56 td_err_e 57 td_ta_delete(td_thragent_t * ta) 58 { 59 free(ta); 60 // FIXME: anything else to do? 61 return TD_OK; 62 } 63 64 65 /* NOTE: not used by gdb 7.0 */ 66 67 td_err_e 68 td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events) 69 { 70 return TD_OK; 71 } 72 73 74 /* NOTE: not used by gdb 7.0 */ 75 static td_thrhandle_t gEventMsgHandle; 76 77 /* NOTE: not used by gdb 7.0 */ 78 79 static int 80 _event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr) 81 { 82 void * pc; 83 84 #ifdef __i386__ 85 /* Get the eip from offset 12*4 = 48 as defined in the struct 86 * user_regs_struct in user_32.h 87 */ 88 pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)48 /* eip */, NULL); 89 /* FIXME - pc is a non-decremented breakpoint address, hence the 90 * addition of 1 on test. This seems to work for the thread hook 91 * function in libc.so but should be properly fixed. 92 */ 93 if (pc == ((int)bkpt_addr + 1)) { 94 /* The hook function takes the id of the new thread as it's first 95 * param, so grab it from ecx at offset 4 in struct user_regs_struct 96 * (using fastcall convention for x86) 97 */ 98 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)4 /* ecx */, NULL); 99 gEventMsgHandle.tid = gEventMsgHandle.pid; 100 return 0x42; 101 } 102 #else 103 pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL); 104 105 if (pc == bkpt_addr) { 106 // The hook function takes the id of the new thread as it's first param, 107 // so grab it from r0. 108 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL); 109 gEventMsgHandle.tid = gEventMsgHandle.pid; 110 return 0x42; 111 } 112 #endif 113 return 0; 114 } 115 116 /* NOTE: not used by gdb 7.0 */ 117 118 td_err_e 119 td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event) 120 { 121 td_err_e err; 122 void * bkpt_addr; 123 124 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr); 125 if (err) { 126 return err; 127 } 128 129 err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0); 130 if (err != 0x42) { 131 return TD_NOMSG; 132 } 133 134 event->event = TD_CREATE; 135 event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way! 136 137 return TD_OK; 138 } 139 140 141 td_err_e 142 td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid, 143 td_thrhandle_t *th) 144 { 145 th->pid = ps_getpid(agent->ph); 146 th->tid = lwpid; 147 return TD_OK; 148 } 149 150 151 td_err_e 152 td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info) 153 { 154 info->ti_tid = handle->tid; 155 info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids 156 info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>. 157 This is only used to see if the thread is a zombie or not */ 158 return TD_OK; 159 } 160 161 162 /* NOTE: not used by gdb 7.0 */ 163 164 td_err_e 165 td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event) 166 { 167 // I don't think we need to do anything here... 168 return TD_OK; 169 } 170 171 172 /* NOTE: not used by gdb 7.0 */ 173 174 td_err_e 175 td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out) 176 { 177 int32_t err; 178 179 /* 180 * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up 181 * the symbol from it's cache, which is populated at start time with the 182 * symbols returned from td_symbol_list via calls back to the host. 183 */ 184 185 switch (event) { 186 case TD_CREATE: 187 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr); 188 if (err) { 189 return TD_NOEVENT; 190 } 191 return TD_OK; 192 } 193 return TD_NOEVENT; 194 } 195 196 197 td_err_e 198 td_ta_clear_event(const td_thragent_t * ta_arg, td_thr_events_t * event) 199 { 200 /* Given that gdb 7.0 doesn't use thread events, 201 there's nothing we need to do here. */ 202 return TD_OK; 203 } 204 205 206 td_err_e 207 td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie, 208 td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags) 209 { 210 td_err_e err = TD_OK; 211 char path[32]; 212 DIR * dir; 213 struct dirent * entry; 214 td_thrhandle_t handle; 215 216 snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid); 217 dir = opendir(path); 218 if (!dir) { 219 return TD_NOEVENT; 220 } 221 222 handle.pid = agent->pid; 223 while ((entry = readdir(dir)) != NULL) { 224 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 225 continue; 226 } 227 handle.tid = atoi(entry->d_name); 228 if (func(&handle, cookie) != 0) { 229 err = TD_DBERR; 230 break; 231 } 232 } 233 234 closedir(dir); 235 236 return err; 237 } 238 239 td_err_e 240 td_thr_tls_get_addr(const td_thrhandle_t * th, 241 psaddr_t map_address, size_t offset, psaddr_t * address) 242 { 243 return TD_NOAPLIC; // FIXME: TODO 244 } 245