proc.c revision 3c516d5ced53508d8df7d82914a3190a3235b62d
1#define _GNU_SOURCE /* For getline.  */
2#include "config.h"
3#include "common.h"
4
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <inttypes.h>
9#include <link.h>
10#include <stdio.h>
11#include <string.h>
12#include <signal.h>
13#include <unistd.h>
14#include <dirent.h>
15#include <ctype.h>
16#include <errno.h>
17#include <sys/syscall.h>
18#include <error.h>
19
20
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
26#define	MAX_DELAY	100000	/* 100000 microseconds = 0.1 seconds */
27
28#define PROC_PID_FILE(VAR, FORMAT, PID)		\
29	char VAR[strlen(FORMAT) + 6];		\
30	sprintf(VAR, FORMAT, PID)
31
32/*
33 * Returns a (malloc'd) file name corresponding to a running pid
34 */
35char *
36pid2name(pid_t pid) {
37	if (!kill(pid, 0)) {
38		int delay = 0;
39
40		PROC_PID_FILE(proc_exe, "/proc/%d/exe", pid);
41
42		while (delay < MAX_DELAY) {
43			if (!access(proc_exe, F_OK)) {
44				return strdup(proc_exe);
45			}
46			delay += 1000;	/* 1 milisecond */
47		}
48	}
49	return NULL;
50}
51
52static 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{
140	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
169}
170
171enum process_status
172process_status(pid_t pid)
173{
174	enum process_status ret = ps_invalid;
175	FILE * file = open_status_file(pid);
176	if (file != NULL) {
177		each_line_starting(file, "State:\t", &process_status_cb, &ret);
178		fclose(file);
179		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
186	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	pid_t *tasks = NULL;
206	size_t n = 0;
207	size_t alloc = 0;
208
209	while (1) {
210		struct dirent entry;
211		struct dirent *result;
212		if (readdir_r(d, &entry, &result) != 0) {
213			free(tasks);
214			return -1;
215		}
216		if (result == NULL)
217			break;
218		if (result->d_type == DT_DIR && all_digits(result->d_name)) {
219			pid_t npid = atoi(result->d_name);
220			if (n >= alloc) {
221				alloc = alloc > 0 ? (2 * alloc) : 8;
222				pid_t *ntasks = realloc(tasks,
223							sizeof(*tasks) * alloc);
224				if (ntasks == NULL) {
225					free(tasks);
226					return -1;
227				}
228				tasks = ntasks;
229			}
230			if (n >= alloc)
231				abort();
232			tasks[n++] = npid;
233		}
234	}
235
236	closedir(d);
237
238	*ret_tasks = tasks;
239	*ret_n = n;
240	return 0;
241}
242
243static int
244find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
245	int i = 0, done = 0;
246	ElfW(Dyn) entry;
247
248	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
249
250	if (addr ==	NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
251		return -1;
252	}
253
254	while ((!done) && (i < ELF_MAX_SEGMENTS) &&
255		(sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
256		(entry.d_tag != DT_NULL)) {
257		if (entry.d_tag == d_tag) {
258			done = 1;
259			*addr = (void *)entry.d_un.d_val;
260		}
261		pvAddr += sizeof(entry);
262		i++;
263	}
264
265	if (done) {
266		debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
267		return 0;
268	}
269	else {
270		debug(2, "Couldn't address for dtag!\n");
271		return -1;
272	}
273}
274
275struct cb_data {
276	const char *lib_name;
277	struct ltelf *lte;
278	ElfW(Addr) addr;
279	Process *proc;
280};
281
282static void
283crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), struct cb_data *data) {
284	struct link_map rlm;
285	char lib_name[BUFSIZ];
286	struct link_map *lm = NULL;
287
288	debug (DEBUG_FUNCTION, "crawl_linkmap()");
289
290	if (!dbg || !dbg->r_map) {
291		debug(2, "Debug structure or it's linkmap are NULL!");
292		return;
293	}
294
295	lm = dbg->r_map;
296
297	while (lm) {
298		if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
299			debug(2, "Unable to read link map\n");
300			return;
301		}
302
303		lm = rlm.l_next;
304		if (rlm.l_name == NULL) {
305			debug(2, "Invalid library name referenced in dynamic linker map\n");
306			return;
307		}
308
309		umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
310
311		if (lib_name[0] == '\0') {
312			debug(2, "Library name is an empty string");
313			continue;
314		}
315
316		if (callback) {
317			debug(2, "Dispatching callback for: %s, "
318					"Loaded at 0x%" PRI_ELF_ADDR "\n",
319					lib_name, rlm.l_addr);
320			data->addr = rlm.l_addr;
321			data->lib_name = lib_name;
322			callback(data);
323		}
324	}
325	return;
326}
327
328static struct r_debug *
329load_debug_struct(Process *proc) {
330	struct r_debug *rdbg = NULL;
331
332	debug(DEBUG_FUNCTION, "load_debug_struct");
333
334	rdbg = malloc(sizeof(*rdbg));
335	if (!rdbg) {
336		return NULL;
337	}
338
339	if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) {
340		debug(2, "This process does not have a debug structure!\n");
341		free(rdbg);
342		return NULL;
343	}
344
345	return rdbg;
346}
347
348static void
349linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
350	size_t i = 0;
351	struct cb_data *lm_add = data;
352	struct ltelf lte;
353	struct opt_x_t *xptr;
354
355	debug(DEBUG_FUNCTION, "linkmap_add_cb");
356
357	/*
358		XXX
359		iterate through library[i]'s to see if this lib is in the list.
360		if not, add it
361	 */
362	for(;i < library_num;i++) {
363		if (strcmp(library[i], lm_add->lib_name) == 0) {
364			/* found it, so its not new */
365			return;
366		}
367	}
368
369	/* new library linked! */
370	debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);
371
372	if (library_num < MAX_LIBRARIES) {
373		library[library_num++] = strdup(lm_add->lib_name);
374		memset(&lte, 0, sizeof(struct ltelf));
375		lte.base_addr = lm_add->addr;
376		do_init_elf(&lte, library[library_num-1]);
377		/* add bps */
378		for (xptr = opt_x; xptr; xptr = xptr->next) {
379			if (xptr->found)
380				continue;
381
382			GElf_Sym sym;
383			GElf_Addr addr;
384
385			if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
386				debug(2, "found symbol %s @ %#" PRIx64
387						", adding it.",
388						xptr->name, sym.st_value);
389				addr = sym.st_value;
390				add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
391				xptr->found = 1;
392				insert_breakpoint(lm_add->proc,
393						  sym2addr(lm_add->proc,
394							   library_symbols),
395						  library_symbols, 1);
396			}
397		}
398		do_close_elf(&lte);
399	}
400}
401
402void
403arch_check_dbg(Process *proc) {
404	struct r_debug *dbg = NULL;
405	struct cb_data data;
406
407	debug(DEBUG_FUNCTION, "arch_check_dbg");
408
409	if (!(dbg = load_debug_struct(proc))) {
410		debug(2, "Unable to load debug structure!");
411		return;
412	}
413
414	if (dbg->r_state == RT_CONSISTENT) {
415		debug(2, "Linkmap is now consistent");
416		if (proc->debug_state == RT_ADD) {
417			debug(2, "Adding DSO to linkmap");
418			data.proc = proc;
419			crawl_linkmap(proc, dbg, linkmap_add_cb, &data);
420		} else if (proc->debug_state == RT_DELETE) {
421			debug(2, "Removing DSO from linkmap");
422		} else {
423			debug(2, "Unexpected debug state!");
424		}
425	}
426
427	proc->debug_state = dbg->r_state;
428
429	return;
430}
431
432static void
433hook_libdl_cb(void *data) {
434	struct cb_data *hook_data = data;
435	const char *lib_name = NULL;
436	ElfW(Addr) addr;
437	struct ltelf *lte = NULL;
438
439	debug(DEBUG_FUNCTION, "add_library_cb");
440
441	if (!data) {
442		debug(2, "No callback data");
443		return;
444	}
445
446	lib_name = hook_data->lib_name;
447	addr = hook_data->addr;
448	lte = hook_data->lte;
449
450	if (library_num < MAX_LIBRARIES) {
451		lte[library_num].base_addr = addr;
452		library[library_num++] = strdup(lib_name);
453	}
454	else {
455		fprintf (stderr, "MAX LIBS REACHED\n");
456		exit(EXIT_FAILURE);
457	}
458}
459
460int
461linkmap_init(Process *proc, struct ltelf *lte) {
462	void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr);
463	struct r_debug *rdbg = NULL;
464	struct cb_data data;
465
466	debug(DEBUG_FUNCTION, "linkmap_init()");
467
468	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
469		debug(2, "Couldn't find debug structure!");
470		return -1;
471	}
472
473	proc->debug = dbg_addr;
474
475	if (!(rdbg = load_debug_struct(proc))) {
476		debug(2, "No debug structure or no memory to allocate one!");
477		return -1;
478	}
479
480	data.lte = lte;
481
482	add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
483	insert_breakpoint(proc, sym2addr(proc, library_symbols),
484			  library_symbols, 1);
485
486	crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);
487
488	free(rdbg);
489	return 0;
490}
491
492int
493task_kill (pid_t pid, int sig)
494{
495	// Taken from GDB
496        int ret;
497
498        errno = 0;
499        ret = syscall (__NR_tkill, pid, sig);
500	return ret;
501}
502