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 #include <unistd.h> 12 #include <fcntl.h> 13 #include <errno.h> 14 15 #define DEBUG 1 16 #if DEBUG 17 # include <string.h> /* for strerror() */ 18 # define D(...) fprintf(stderr, "libthread_db:%s: ", __FUNCTION__), fprintf(stderr, __VA_ARGS__) 19 #else 20 # define D(...) do{}while(0) 21 #endif 22 23 24 extern int ps_pglobal_lookup (void *, const char *obj, const char *name, void **sym_addr); 25 extern pid_t ps_getpid(struct ps_prochandle *ph); 26 27 /* 28 * This is the list of "special" symbols we care about whose addresses are 29 * cached by gdbserver from the host at init time. 30 */ 31 enum { 32 SYM_TD_CREATE, 33 SYM_THREAD_LIST, 34 NUM_SYMS 35 }; 36 37 static char const * gSymbols[] = { 38 [SYM_TD_CREATE] = "_thread_created_hook", 39 NULL 40 }; 41 42 43 char const ** 44 td_symbol_list(void) 45 { 46 return gSymbols; 47 } 48 49 50 /* Extract the permitted capabilities of a given task */ 51 static int 52 _get_task_permitted_caps(int pid, int tid, uint64_t *cap) 53 { 54 char path[64]; 55 char buff[1024]; 56 int len; 57 int fd; 58 int result = -1; 59 char* perm; 60 char* end; 61 62 /* Open task status file */ 63 snprintf(path, sizeof path, "/proc/%d/task/%d/status", pid, tid); 64 fd = open(path, O_RDONLY); 65 if (fd < 0) { 66 D("Could not open %s: %s\n", path, strerror(errno)); 67 return -1; 68 } 69 70 /* Read its content, up to sizeof buff-1, then zero-terminate */ 71 do { 72 len = read(fd, buff, sizeof buff-1); 73 } while (len < 0 && errno == EINTR); 74 75 if (len < 0) { 76 D("Could not read %s: %s\n", path, strerror(errno)); 77 goto EXIT; 78 } 79 80 buff[len] = 0; 81 82 /* Look for "CapPrm: " in it */ 83 perm = strstr(buff, "CapPrm:"); 84 if (perm == NULL) { 85 D("Could not find CapPrm in %s!\n---- cut here ----\n%.*s\n----- cut here -----\n", 86 path, len, buff); 87 errno = EINVAL; 88 goto EXIT; 89 } 90 91 /* Now read the hexadecimal value after 'CapPrm: ' */ 92 errno = 0; 93 *cap = (uint64_t) strtoull(perm+8, &end, 16); 94 if (errno == 0) { 95 D("Found CapPerm of %lld in %s\n", *cap, path); 96 result = 0; 97 } else { 98 D("Cannot read CapPerm from %s: '%.*s'\n", path, 24, perm); 99 } 100 EXIT: 101 close(fd); 102 return result; 103 } 104 105 106 td_err_e 107 td_ta_new(struct ps_prochandle * proc_handle, td_thragent_t ** agent_out) 108 { 109 td_thragent_t * agent; 110 111 /* Platforms before Android 2.3 contain a system bug that prevents 112 * gdbserver to attach to all threads in a target process when 113 * it is run as the same userID than the target (works fine if 114 * run as root). 115 * 116 * Due to the way gdbserver is coded, this makes gdbserver exit() 117 * immediately (see linux_attach_lwp in linux-low.c). Even if we 118 * modify the source code to not exit(), then signals will not 119 * be properly rerouted to gdbserver, preventing breakpoints from 120 * working correctly. 121 * 122 * The following code is here to test for this problematic condition. 123 * If it is detected, we return TD_NOLIBTHREAD to indicate that there 124 * are no threads to attach to (gdbserver will attach to the main thread 125 * though). 126 */ 127 do { 128 char path[64]; 129 DIR* dir; 130 struct dirent *entry; 131 pid_t my_pid = getpid(); 132 int target_pid = ps_getpid(proc_handle); 133 uint64_t my_caps, tid_caps; 134 135 D("Probing system for platform bug.\n"); 136 137 /* nothing to do if we run as root */ 138 if (geteuid() == 0) { 139 D("Running as root, nothing to do.\n"); 140 break; 141 } 142 143 /* First, get our own permitted capabilities */ 144 if (_get_task_permitted_caps(my_pid, my_pid, &my_caps) < 0) { 145 /* something is really fishy here */ 146 D("Could not get gdbserver permitted caps!\n"); 147 return TD_NOLIBTHREAD; 148 } 149 150 /* Now, for each thread in the target process, compare the 151 * permitted capabilities set to our own. If they differ, 152 * the thread attach will fail. Booo... 153 */ 154 snprintf(path, sizeof path, "/proc/%d/task", target_pid); 155 dir = opendir(path); 156 if (!dir) { 157 D("Could not open %s: %s\n", path, strerror(errno)); 158 break; 159 } 160 while ((entry = readdir(dir)) != NULL) { 161 int tid; 162 163 if (entry->d_name[0] == '.') /* skip . and .. */ 164 continue; 165 166 tid = atoi(entry->d_name); 167 if (tid == 0) /* should not happen - be safe */ 168 continue; 169 170 if (_get_task_permitted_caps(target_pid, tid, &tid_caps) < 0) { 171 /* again, something is fishy */ 172 D("Could not get permitted caps for thread %d\n", tid); 173 closedir(dir); 174 return TD_NOLIBTHREAD; 175 } 176 177 if (tid_caps != my_caps) { 178 /* AAAARGH !! The permitted capabilities set differ. */ 179 D("AAAAAH, Can't debug threads!\n"); 180 closedir(dir); 181 return TD_NOLIBTHREAD; 182 } 183 } 184 closedir(dir); 185 D("Victory: We can debug theads!\n"); 186 } while (0); 187 188 /* We now return to our regularly scheduled program */ 189 190 agent = (td_thragent_t *)malloc(sizeof(td_thragent_t)); 191 if (!agent) { 192 return TD_MALLOC; 193 } 194 195 agent->pid = ps_getpid(proc_handle); 196 agent->ph = proc_handle; 197 *agent_out = agent; 198 199 return TD_OK; 200 } 201 202 203 td_err_e 204 td_ta_delete(td_thragent_t * ta) 205 { 206 free(ta); 207 // FIXME: anything else to do? 208 return TD_OK; 209 } 210 211 212 /* NOTE: not used by gdb 7.0 */ 213 214 td_err_e 215 td_ta_set_event(td_thragent_t const * agent, td_thr_events_t * events) 216 { 217 return TD_OK; 218 } 219 220 221 /* NOTE: not used by gdb 7.0 */ 222 static td_thrhandle_t gEventMsgHandle; 223 224 /* NOTE: not used by gdb 7.0 */ 225 226 static int 227 _event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr) 228 { 229 void * pc; 230 231 pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL); 232 233 if (pc == bkpt_addr) { 234 // The hook function takes the id of the new thread as it's first param, 235 // so grab it from r0. 236 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL); 237 gEventMsgHandle.tid = gEventMsgHandle.pid; 238 return 0x42; 239 } 240 return 0; 241 } 242 243 /* NOTE: not used by gdb 7.0 */ 244 245 td_err_e 246 td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event) 247 { 248 td_err_e err; 249 void * bkpt_addr; 250 251 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr); 252 if (err) { 253 return err; 254 } 255 256 err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0); 257 if (err != 0x42) { 258 return TD_NOMSG; 259 } 260 261 event->event = TD_CREATE; 262 event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way! 263 264 return TD_OK; 265 } 266 267 268 td_err_e 269 td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid, 270 td_thrhandle_t *th) 271 { 272 th->pid = ps_getpid(agent->ph); 273 th->tid = lwpid; 274 return TD_OK; 275 } 276 277 278 td_err_e 279 td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info) 280 { 281 info->ti_tid = handle->tid; 282 info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids 283 info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>. 284 This is only used to see if the thread is a zombie or not */ 285 return TD_OK; 286 } 287 288 289 /* NOTE: not used by gdb 7.0 */ 290 291 td_err_e 292 td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event) 293 { 294 // I don't think we need to do anything here... 295 return TD_OK; 296 } 297 298 299 /* NOTE: not used by gdb 7.0 */ 300 301 td_err_e 302 td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out) 303 { 304 int32_t err; 305 306 /* 307 * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up 308 * the symbol from it's cache, which is populated at start time with the 309 * symbols returned from td_symbol_list via calls back to the host. 310 */ 311 312 switch (event) { 313 case TD_CREATE: 314 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr); 315 if (err) { 316 return TD_NOEVENT; 317 } 318 return TD_OK; 319 } 320 return TD_NOEVENT; 321 } 322 323 324 td_err_e 325 td_ta_clear_event(const td_thragent_t * ta_arg, td_thr_events_t * event) 326 { 327 /* Given that gdb 7.0 doesn't use thread events, 328 there's nothing we need to do here. */ 329 return TD_OK; 330 } 331 332 333 td_err_e 334 td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie, 335 td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags) 336 { 337 td_err_e err = TD_OK; 338 char path[32]; 339 DIR * dir; 340 struct dirent * entry; 341 td_thrhandle_t handle; 342 343 snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid); 344 dir = opendir(path); 345 if (!dir) { 346 return TD_NOEVENT; 347 } 348 349 handle.pid = agent->pid; 350 while ((entry = readdir(dir)) != NULL) { 351 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 352 continue; 353 } 354 handle.tid = atoi(entry->d_name); 355 if (func(&handle, cookie) != 0) { 356 err = TD_DBERR; 357 break; 358 } 359 } 360 361 closedir(dir); 362 363 return err; 364 } 365 366 td_err_e 367 td_thr_tls_get_addr(const td_thrhandle_t * th, 368 psaddr_t map_address, size_t offset, psaddr_t * address) 369 { 370 return TD_NOAPLIC; // FIXME: TODO 371 } 372