blob: 9b05ce2c2fcaeee340835e9e5031482d2c0daca6 [file] [log] [blame]
Petr Machata750ca8c2011-10-06 14:29:34 +02001#define _GNU_SOURCE /* For getline. */
Juan Cespedesd44c6b81998-09-25 14:48:42 +02002#include "config.h"
Joe Damato47cae1e2010-11-08 15:47:39 -08003#include "common.h"
Juan Cespedesd44c6b81998-09-25 14:48:42 +02004
Juan Cespedes1fe93d51998-03-13 00:29:21 +01005#include <sys/types.h>
Petr Machata9a5420c2011-07-09 11:21:23 +02006#include <sys/stat.h>
7#include <fcntl.h>
Zachary T Welchbfb26c72010-12-06 23:21:00 -08008#include <inttypes.h>
Joe Damato47cae1e2010-11-08 15:47:39 -08009#include <link.h>
Juan Cespedes1fe93d51998-03-13 00:29:21 +010010#include <stdio.h>
11#include <string.h>
12#include <signal.h>
Juan Cespedes273ea6d1998-03-14 23:02:40 +010013#include <unistd.h>
Petr Machata9a5420c2011-07-09 11:21:23 +020014#include <dirent.h>
15#include <ctype.h>
16#include <errno.h>
17#include <sys/syscall.h>
Petr Machata750ca8c2011-10-06 14:29:34 +020018#include <error.h>
Petr Machata9a5420c2011-07-09 11:21:23 +020019
Juan Cespedes273ea6d1998-03-14 23:02:40 +010020
21/* /proc/pid doesn't exist just after the fork, and sometimes `ltrace'
22 * couldn't open it to find the executable. So it may be necessary to
23 * have a bit delay
24 */
25
Ian Wienand2d45b1a2006-02-20 22:48:07 +010026#define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */
Juan Cespedes1fe93d51998-03-13 00:29:21 +010027
Petr Machata9a5420c2011-07-09 11:21:23 +020028#define PROC_PID_FILE(VAR, FORMAT, PID) \
29 char VAR[strlen(FORMAT) + 6]; \
30 sprintf(VAR, FORMAT, PID)
31
Juan Cespedes1fe93d51998-03-13 00:29:21 +010032/*
Juan Cespedese0660df2009-05-21 18:14:39 +020033 * Returns a (malloc'd) file name corresponding to a running pid
Juan Cespedes1fe93d51998-03-13 00:29:21 +010034 */
Juan Cespedesf1350522008-12-16 18:19:58 +010035char *
36pid2name(pid_t pid) {
Juan Cespedes1fe93d51998-03-13 00:29:21 +010037 if (!kill(pid, 0)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010038 int delay = 0;
Juan Cespedes273ea6d1998-03-14 23:02:40 +010039
Petr Machata9a5420c2011-07-09 11:21:23 +020040 PROC_PID_FILE(proc_exe, "/proc/%d/exe", pid);
Juan Cespedes273ea6d1998-03-14 23:02:40 +010041
Ian Wienand2d45b1a2006-02-20 22:48:07 +010042 while (delay < MAX_DELAY) {
Juan Cespedes273ea6d1998-03-14 23:02:40 +010043 if (!access(proc_exe, F_OK)) {
44 return strdup(proc_exe);
45 }
46 delay += 1000; /* 1 milisecond */
47 }
Juan Cespedes1fe93d51998-03-13 00:29:21 +010048 }
Juan Cespedes273ea6d1998-03-14 23:02:40 +010049 return NULL;
Juan Cespedes1fe93d51998-03-13 00:29:21 +010050}
Joe Damato47cae1e2010-11-08 15:47:39 -080051
Petr Machata9a5420c2011-07-09 11:21:23 +020052static FILE *
53open_status_file(pid_t pid)
54{
55 PROC_PID_FILE(fn, "/proc/%d/status", pid);
56 /* Don't complain if we fail. This would typically happen
57 when the process is about to terminate, and these files are
58 not available anymore. This function is called from the
59 event loop, and we don't want to clutter the output just
60 because the process terminates. */
61 return fopen(fn, "r");
62}
63
64static char *
65find_line_starting(FILE * file, const char * prefix, size_t len)
66{
67 char * line = NULL;
68 size_t line_len = 0;
69 while (!feof(file)) {
70 if (getline(&line, &line_len, file) < 0)
71 return NULL;
72 if (strncmp(line, prefix, len) == 0)
73 return line;
74 }
75 return NULL;
76}
77
78static void
79each_line_starting(FILE * file, const char *prefix,
80 enum pcb_status (*cb)(const char * line, const char * prefix,
81 void * data),
82 void * data)
83{
84 size_t len = strlen(prefix);
85 char * line;
86 while ((line = find_line_starting(file, prefix, len)) != NULL) {
87 enum pcb_status st = (*cb)(line, prefix, data);
88 free (line);
89 if (st == pcb_stop)
90 return;
91 }
92}
93
94static enum pcb_status
95process_leader_cb(const char * line, const char * prefix, void * data)
96{
97 pid_t * pidp = data;
98 *pidp = atoi(line + strlen(prefix));
99 return pcb_stop;
100}
101
102pid_t
103process_leader(pid_t pid)
104{
105 pid_t tgid = pid;
106 FILE * file = open_status_file(pid);
107 if (file != NULL) {
108 each_line_starting(file, "Tgid:\t", &process_leader_cb, &tgid);
109 fclose(file);
110 }
111
112 return tgid;
113}
114
115static enum pcb_status
116process_stopped_cb(const char * line, const char * prefix, void * data)
117{
118 char c = line[strlen(prefix)];
119 // t:tracing stop, T:job control stop
120 *(int *)data = (c == 't' || c == 'T');
121 return pcb_stop;
122}
123
124int
125process_stopped(pid_t pid)
126{
127 int is_stopped = -1;
128 FILE * file = open_status_file(pid);
129 if (file != NULL) {
130 each_line_starting(file, "State:\t", &process_stopped_cb,
131 &is_stopped);
132 fclose(file);
133 }
134 return is_stopped;
135}
136
137static enum pcb_status
138process_status_cb(const char * line, const char * prefix, void * data)
139{
Petr Machata617ff0b2011-10-06 14:23:24 +0200140 const char * status = line + strlen(prefix);
141 const char c = *status;
142
143#define RETURN(C) do { \
144 *(enum process_status *)data = C; \
145 return pcb_stop; \
146 } while (0)
147
148 switch (c) {
149 case 'Z': RETURN(ps_zombie);
150 case 't': RETURN(ps_tracing_stop);
151 case 'T': {
152 /* This can be either "T (stopped)" or, for older
153 * kernels, "T (tracing stop)". */
154 if (!strcmp(status, "T (stopped)\n"))
155 RETURN(ps_stop);
156 else if (!strcmp(status, "T (tracing stop)\n"))
157 RETURN(ps_tracing_stop);
158 else {
159 fprintf(stderr, "Unknown process status: %s",
160 status);
161 RETURN(ps_stop); /* Some sort of stop
162 * anyway. */
163 }
164 }
165 }
166
167 RETURN(ps_other);
168#undef RETURN
Petr Machata9a5420c2011-07-09 11:21:23 +0200169}
170
Petr Machata617ff0b2011-10-06 14:23:24 +0200171enum process_status
Petr Machata9a5420c2011-07-09 11:21:23 +0200172process_status(pid_t pid)
173{
Petr Machata617ff0b2011-10-06 14:23:24 +0200174 enum process_status ret = ps_invalid;
Petr Machata9a5420c2011-07-09 11:21:23 +0200175 FILE * file = open_status_file(pid);
176 if (file != NULL) {
177 each_line_starting(file, "State:\t", &process_status_cb, &ret);
178 fclose(file);
Petr Machata750ca8c2011-10-06 14:29:34 +0200179 if (ret == ps_invalid)
180 error(0, errno, "process_status %d", pid);
181 } else
182 /* If the file is not present, the process presumably
183 * exited already. */
184 ret = ps_zombie;
185
Petr Machata9a5420c2011-07-09 11:21:23 +0200186 return ret;
187}
188
189static int
190all_digits(const char *str)
191{
192 while (isdigit(*str))
193 str++;
194 return !*str;
195}
196
197int
198process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n)
199{
200 PROC_PID_FILE(fn, "/proc/%d/task", pid);
201 DIR * d = opendir(fn);
202 if (d == NULL)
203 return -1;
204
205 /* XXX This is racy. We need to stop the tasks that we
206 discover this way and re-scan the directory to eventually
207 reach a full set of tasks. */
208 pid_t *tasks = NULL;
209 size_t n = 0;
210 size_t alloc = 0;
211
212 while (1) {
213 struct dirent entry;
214 struct dirent *result;
215 if (readdir_r(d, &entry, &result) != 0) {
216 free(tasks);
217 return -1;
218 }
219 if (result == NULL)
220 break;
221 if (result->d_type == DT_DIR && all_digits(result->d_name)) {
222 pid_t npid = atoi(result->d_name);
223 if (n >= alloc) {
224 alloc = alloc > 0 ? (2 * alloc) : 8;
225 pid_t *ntasks = realloc(tasks,
226 sizeof(*tasks) * alloc);
227 if (ntasks == NULL) {
228 free(tasks);
229 return -1;
230 }
231 tasks = ntasks;
232 }
233 if (n >= alloc)
234 abort();
235 tasks[n++] = npid;
236 }
237 }
238
239 closedir(d);
240
241 *ret_tasks = tasks;
242 *ret_n = n;
243 return 0;
244}
245
Joe Damato47cae1e2010-11-08 15:47:39 -0800246static int
247find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
248 int i = 0, done = 0;
249 ElfW(Dyn) entry;
250
251 debug(DEBUG_FUNCTION, "find_dynamic_entry()");
252
253 if (addr == NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
254 return -1;
255 }
256
257 while ((!done) && (i < ELF_MAX_SEGMENTS) &&
258 (sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
259 (entry.d_tag != DT_NULL)) {
260 if (entry.d_tag == d_tag) {
261 done = 1;
262 *addr = (void *)entry.d_un.d_val;
263 }
264 pvAddr += sizeof(entry);
265 i++;
266 }
267
268 if (done) {
269 debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
270 return 0;
271 }
272 else {
273 debug(2, "Couldn't address for dtag!\n");
274 return -1;
275 }
276}
Joe Damatof0bd98b2010-11-08 15:47:42 -0800277
278struct cb_data {
279 const char *lib_name;
280 struct ltelf *lte;
281 ElfW(Addr) addr;
282 Process *proc;
283};
284
285static void
286crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), struct cb_data *data) {
287 struct link_map rlm;
288 char lib_name[BUFSIZ];
289 struct link_map *lm = NULL;
290
291 debug (DEBUG_FUNCTION, "crawl_linkmap()");
292
293 if (!dbg || !dbg->r_map) {
294 debug(2, "Debug structure or it's linkmap are NULL!");
295 return;
296 }
297
298 lm = dbg->r_map;
299
300 while (lm) {
301 if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
302 debug(2, "Unable to read link map\n");
303 return;
304 }
305
306 lm = rlm.l_next;
307 if (rlm.l_name == NULL) {
308 debug(2, "Invalid library name referenced in dynamic linker map\n");
309 return;
310 }
311
312 umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
313
314 if (lib_name[0] == '\0') {
315 debug(2, "Library name is an empty string");
316 continue;
317 }
318
319 if (callback) {
Zachary T Welch3ba522f2010-12-14 15:12:47 -0800320 debug(2, "Dispatching callback for: %s, "
321 "Loaded at 0x%" PRI_ELF_ADDR "\n",
322 lib_name, rlm.l_addr);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800323 data->addr = rlm.l_addr;
324 data->lib_name = lib_name;
325 callback(data);
326 }
327 }
328 return;
329}
330
331static struct r_debug *
332load_debug_struct(Process *proc) {
333 struct r_debug *rdbg = NULL;
334
335 debug(DEBUG_FUNCTION, "load_debug_struct");
336
337 rdbg = malloc(sizeof(*rdbg));
338 if (!rdbg) {
339 return NULL;
340 }
341
342 if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) {
343 debug(2, "This process does not have a debug structure!\n");
344 free(rdbg);
345 return NULL;
346 }
347
348 return rdbg;
349}
350
351static void
352linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
Zachary T Welchba6aca22010-12-08 18:55:09 -0800353 size_t i = 0;
Joe Damatof0bd98b2010-11-08 15:47:42 -0800354 struct cb_data *lm_add = data;
355 struct ltelf lte;
356 struct opt_x_t *xptr;
357
358 debug(DEBUG_FUNCTION, "linkmap_add_cb");
359
360 /*
361 XXX
362 iterate through library[i]'s to see if this lib is in the list.
363 if not, add it
364 */
365 for(;i < library_num;i++) {
366 if (strcmp(library[i], lm_add->lib_name) == 0) {
367 /* found it, so its not new */
368 return;
369 }
370 }
371
372 /* new library linked! */
373 debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);
374
375 if (library_num < MAX_LIBRARIES) {
376 library[library_num++] = strdup(lm_add->lib_name);
377 memset(&lte, 0, sizeof(struct ltelf));
378 lte.base_addr = lm_add->addr;
379 do_init_elf(&lte, library[library_num-1]);
380 /* add bps */
381 for (xptr = opt_x; xptr; xptr = xptr->next) {
382 if (xptr->found)
383 continue;
384
385 GElf_Sym sym;
386 GElf_Addr addr;
387
388 if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
Zachary T Welchbfb26c72010-12-06 23:21:00 -0800389 debug(2, "found symbol %s @ %#" PRIx64
390 ", adding it.",
391 xptr->name, sym.st_value);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800392 addr = sym.st_value;
393 add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
394 xptr->found = 1;
Petr Machata26627682011-07-08 18:15:32 +0200395 insert_breakpoint(lm_add->proc,
396 sym2addr(lm_add->proc,
397 library_symbols),
Petr Machatac7585b62011-07-08 22:58:12 +0200398 library_symbols, 1);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800399 }
400 }
401 do_close_elf(&lte);
402 }
403}
404
405void
406arch_check_dbg(Process *proc) {
407 struct r_debug *dbg = NULL;
408 struct cb_data data;
409
410 debug(DEBUG_FUNCTION, "arch_check_dbg");
411
412 if (!(dbg = load_debug_struct(proc))) {
413 debug(2, "Unable to load debug structure!");
414 return;
415 }
416
417 if (dbg->r_state == RT_CONSISTENT) {
418 debug(2, "Linkmap is now consistent");
419 if (proc->debug_state == RT_ADD) {
420 debug(2, "Adding DSO to linkmap");
421 data.proc = proc;
422 crawl_linkmap(proc, dbg, linkmap_add_cb, &data);
423 } else if (proc->debug_state == RT_DELETE) {
424 debug(2, "Removing DSO from linkmap");
425 } else {
426 debug(2, "Unexpected debug state!");
427 }
428 }
429
430 proc->debug_state = dbg->r_state;
431
432 return;
433}
434
435static void
436hook_libdl_cb(void *data) {
437 struct cb_data *hook_data = data;
438 const char *lib_name = NULL;
439 ElfW(Addr) addr;
440 struct ltelf *lte = NULL;
441
442 debug(DEBUG_FUNCTION, "add_library_cb");
443
444 if (!data) {
445 debug(2, "No callback data");
446 return;
447 }
448
449 lib_name = hook_data->lib_name;
450 addr = hook_data->addr;
451 lte = hook_data->lte;
452
453 if (library_num < MAX_LIBRARIES) {
Joe Damatof0bd98b2010-11-08 15:47:42 -0800454 lte[library_num].base_addr = addr;
Petr Machata08677d02011-05-19 16:09:17 +0200455 library[library_num++] = strdup(lib_name);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800456 }
457 else {
458 fprintf (stderr, "MAX LIBS REACHED\n");
459 exit(EXIT_FAILURE);
460 }
461}
462
463int
464linkmap_init(Process *proc, struct ltelf *lte) {
Zachary T Welch3ba522f2010-12-14 15:12:47 -0800465 void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800466 struct r_debug *rdbg = NULL;
467 struct cb_data data;
468
469 debug(DEBUG_FUNCTION, "linkmap_init()");
470
Zachary T Welchba6aca22010-12-08 18:55:09 -0800471 if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
Joe Damatof0bd98b2010-11-08 15:47:42 -0800472 debug(2, "Couldn't find debug structure!");
473 return -1;
474 }
475
476 proc->debug = dbg_addr;
477
478 if (!(rdbg = load_debug_struct(proc))) {
479 debug(2, "No debug structure or no memory to allocate one!");
480 return -1;
481 }
482
483 data.lte = lte;
484
485 add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
Petr Machata26627682011-07-08 18:15:32 +0200486 insert_breakpoint(proc, sym2addr(proc, library_symbols),
Petr Machatac7585b62011-07-08 22:58:12 +0200487 library_symbols, 1);
Joe Damatof0bd98b2010-11-08 15:47:42 -0800488
489 crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);
490
491 free(rdbg);
492 return 0;
493}
Petr Machata9a5420c2011-07-09 11:21:23 +0200494
495int
496task_kill (pid_t pid, int sig)
497{
498 // Taken from GDB
499 int ret;
500
501 errno = 0;
502 ret = syscall (__NR_tkill, pid, sig);
503 return ret;
504}