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 0
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 **
td_symbol_list(void)44 td_symbol_list(void)
45 {
46 return gSymbols;
47 }
48
49
50 /* Extract the permitted capabilities of a given task */
51 static int
_get_task_permitted_caps(int pid,int tid,uint64_t * cap)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
td_ta_new(struct ps_prochandle * proc_handle,td_thragent_t ** agent_out)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 threads!\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
td_ta_delete(td_thragent_t * ta)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
td_ta_set_event(td_thragent_t const * agent,td_thr_events_t * events)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
_event_getmsg_helper(td_thrhandle_t const * handle,void * bkpt_addr)227 _event_getmsg_helper(td_thrhandle_t const * handle, void * bkpt_addr)
228 {
229 #if defined(__arm__)
230 void* pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)60 /* r15/pc */, NULL);
231 if (pc == bkpt_addr) {
232 // The hook function takes the id of the new thread as it's first param,
233 // so grab it from r0.
234 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)0 /* r0 */, NULL);
235 gEventMsgHandle.tid = gEventMsgHandle.pid;
236 return 0x42;
237 }
238 #elif defined(__i386__)
239 // Get the eip from offset 12*4 = 48 as defined in the struct
240 // user_regs_struct in user_32.h
241 void* pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)48 /* eip */, NULL);
242 // FIXME - pc is a non-decremented breakpoint address, hence the
243 // addition of 1 on test. This seems to work for the thread hook
244 // function in libc.so but should be properly fixed.
245 if (pc == ((int)bkpt_addr + 1)) {
246 // The hook function takes the id of the new thread as it's first
247 // param, so grab it from ecx at offset 4 in struct user_regs_struct
248 // (using fastcall convention for x86)
249 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)4 /* ecx */, NULL);
250 gEventMsgHandle.tid = gEventMsgHandle.pid;
251 return 0x42;
252 }
253 #elif defined(__mips__)
254 void* pc = (void *)ptrace(PTRACE_PEEKUSR, handle->tid, (void *)(64*4) /* pc */, NULL);
255 if (pc == bkpt_addr) {
256 // The hook function takes the id of the new thread as it's first param,
257 // so grab it from a0
258 gEventMsgHandle.pid = ptrace(PTRACE_PEEKUSR, handle->tid, (void *)(4*4) /* a0 */, NULL);
259 gEventMsgHandle.tid = gEventMsgHandle.pid;
260 return 0x42;
261 }
262 #endif
263 return 0;
264 }
265
266 /* NOTE: not used by gdb 7.0 */
267
268 td_err_e
td_ta_event_getmsg(td_thragent_t const * agent,td_event_msg_t * event)269 td_ta_event_getmsg(td_thragent_t const * agent, td_event_msg_t * event)
270 {
271 td_err_e err;
272 void * bkpt_addr;
273
274 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], &bkpt_addr);
275 if (err) {
276 return err;
277 }
278
279 err = td_ta_thr_iter(agent, _event_getmsg_helper, bkpt_addr, 0, 0, NULL, 0);
280 if (err != 0x42) {
281 return TD_NOMSG;
282 }
283
284 event->event = TD_CREATE;
285 event->th_p = &gEventMsgHandle; // Nasty hack, but it's the only way!
286
287 return TD_OK;
288 }
289
290
291 td_err_e
td_ta_map_lwp2thr(td_thragent_t const * agent,lwpid_t lwpid,td_thrhandle_t * th)292 td_ta_map_lwp2thr(td_thragent_t const * agent, lwpid_t lwpid,
293 td_thrhandle_t *th)
294 {
295 th->pid = ps_getpid(agent->ph);
296 th->tid = lwpid;
297 return TD_OK;
298 }
299
300
301 td_err_e
td_thr_get_info(td_thrhandle_t const * handle,td_thrinfo_t * info)302 td_thr_get_info(td_thrhandle_t const * handle, td_thrinfo_t * info)
303 {
304 info->ti_tid = handle->tid;
305 info->ti_lid = handle->tid; // Our pthreads uses kernel ids for tids
306 info->ti_state = TD_THR_SLEEP; /* XXX this needs to be read from /proc/<pid>/task/<tid>.
307 This is only used to see if the thread is a zombie or not */
308 return TD_OK;
309 }
310
311
312 /* NOTE: not used by gdb 7.0 */
313
314 td_err_e
td_thr_event_enable(td_thrhandle_t const * handle,td_event_e event)315 td_thr_event_enable(td_thrhandle_t const * handle, td_event_e event)
316 {
317 // I don't think we need to do anything here...
318 return TD_OK;
319 }
320
321
322 /* NOTE: not used by gdb 7.0 */
323
324 td_err_e
td_ta_event_addr(td_thragent_t const * agent,td_event_e event,td_notify_t * notify_out)325 td_ta_event_addr(td_thragent_t const * agent, td_event_e event, td_notify_t * notify_out)
326 {
327 int32_t err;
328
329 /*
330 * This is nasty, ps_pglobal_lookup is implemented in gdbserver and looks up
331 * the symbol from it's cache, which is populated at start time with the
332 * symbols returned from td_symbol_list via calls back to the host.
333 */
334
335 switch (event) {
336 case TD_CREATE:
337 err = ps_pglobal_lookup(NULL, NULL, gSymbols[SYM_TD_CREATE], ¬ify_out->u.bptaddr);
338 if (err) {
339 return TD_NOEVENT;
340 }
341 return TD_OK;
342 }
343 return TD_NOEVENT;
344 }
345
346
347 td_err_e
td_ta_clear_event(const td_thragent_t * ta_arg,td_thr_events_t * event)348 td_ta_clear_event(const td_thragent_t * ta_arg, td_thr_events_t * event)
349 {
350 /* Given that gdb 7.0 doesn't use thread events,
351 there's nothing we need to do here. */
352 return TD_OK;
353 }
354
355
356 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)357 td_ta_thr_iter(td_thragent_t const * agent, td_thr_iter_f * func, void * cookie,
358 td_thr_state_e state, int32_t prio, sigset_t * sigmask, uint32_t user_flags)
359 {
360 td_err_e err = TD_OK;
361 char path[32];
362 DIR * dir;
363 struct dirent * entry;
364 td_thrhandle_t handle;
365
366 snprintf(path, sizeof(path), "/proc/%d/task/", agent->pid);
367 dir = opendir(path);
368 if (!dir) {
369 return TD_NOEVENT;
370 }
371
372 handle.pid = agent->pid;
373 while ((entry = readdir(dir)) != NULL) {
374 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
375 continue;
376 }
377 handle.tid = atoi(entry->d_name);
378 if (func(&handle, cookie) != 0) {
379 err = TD_DBERR;
380 break;
381 }
382 }
383
384 closedir(dir);
385
386 return err;
387 }
388
389 td_err_e
td_thr_tls_get_addr(const td_thrhandle_t * th,psaddr_t map_address,size_t offset,psaddr_t * address)390 td_thr_tls_get_addr(const td_thrhandle_t * th,
391 psaddr_t map_address, size_t offset, psaddr_t * address)
392 {
393 return TD_NOAPLIC; // FIXME: TODO
394 }
395