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 pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL); 85 86 if (pc == bkpt_addr) { 87 // The hook function takes the id of the new thread as it's first param, 88 // so grab it from r0. 89 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL); 90 gEventMsgHandle.tid = gEventMsgHandle.pid; 91 return 0x42; 92 } 93 return 0; 94 } 95 96 /* NOTE: not used by gdb 7.0 */ 97 98 td_err_e 99 td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event) 100 { 101 td_err_e err; 102 void * bkpt_addr; 103 104 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr); 105 if (err) { 106 return err; 107 } 108 109 err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0); 110 if (err != 0x42) { 111 return TD_NOMSG; 112 } 113 114 event->event = TD_CREATE; 115 event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way! 116 117 return TD_OK; 118 } 119 120 121 td_err_e 122 td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid, 123 td_thrhandle_t *th) 124 { 125 th->pid = ps_getpid(agent->ph); 126 th->tid = lwpid; 127 return TD_OK; 128 } 129 130 131 td_err_e 132 td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info) 133 { 134 info->ti_tid = handle->tid; 135 info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids 136 info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>. 137 This is only used to see if the thread is a zombie or not */ 138 return TD_OK; 139 } 140 141 142 /* NOTE: not used by gdb 7.0 */ 143 144 td_err_e 145 td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event) 146 { 147 // I don't think we need to do anything here... 148 return TD_OK; 149 } 150 151 152 /* NOTE: not used by gdb 7.0 */ 153 154 td_err_e 155 td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out) 156 { 157 int32_t err; 158 159 /* 160 * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up 161 * the symbol from it's cache, which is populated at start time with the 162 * symbols returned from td_symbol_list via calls back to the host. 163 */ 164 165 switch (event) { 166 case TD_CREATE: 167 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr); 168 if (err) { 169 return TD_NOEVENT; 170 } 171 return TD_OK; 172 } 173 return TD_NOEVENT; 174 } 175 176 177 td_err_e 178 td_ta_clear_event(const td_thragent_t * ta_arg, td_thr_events_t * event) 179 { 180 /* Given that gdb 7.0 doesn't use thread events, 181 there's nothing we need to do here. */ 182 return TD_OK; 183 } 184 185 186 td_err_e 187 td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie, 188 td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags) 189 { 190 td_err_e err = TD_OK; 191 char path[32]; 192 DIR * dir; 193 struct dirent * entry; 194 td_thrhandle_t handle; 195 196 snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid); 197 dir = opendir(path); 198 if (!dir) { 199 return TD_NOEVENT; 200 } 201 202 handle.pid = agent->pid; 203 while ((entry = readdir(dir)) != NULL) { 204 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 205 continue; 206 } 207 handle.tid = atoi(entry->d_name); 208 if (func(&handle, cookie) != 0) { 209 err = TD_DBERR; 210 break; 211 } 212 } 213 214 closedir(dir); 215 216 return err; 217 } 218 219 td_err_e 220 td_thr_tls_get_addr(const td_thrhandle_t * th, 221 psaddr_t map_address, size_t offset, psaddr_t * address) 222 { 223 return TD_NOAPLIC; // FIXME: TODO 224 } 225