proc.c revision 750ca8c13f402a40b01802dcb5c88e092ff68125
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	/* 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
246static 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}
277
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) {
320			debug(2, "Dispatching callback for: %s, "
321					"Loaded at 0x%" PRI_ELF_ADDR "\n",
322					lib_name, rlm.l_addr);
323			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) {
353	size_t i = 0;
354	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)) {
389				debug(2, "found symbol %s @ %#" PRIx64
390						", adding it.",
391						xptr->name, sym.st_value);
392				addr = sym.st_value;
393				add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
394				xptr->found = 1;
395				insert_breakpoint(lm_add->proc,
396						  sym2addr(lm_add->proc,
397							   library_symbols),
398						  library_symbols, 1);
399			}
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) {
454		lte[library_num].base_addr = addr;
455		library[library_num++] = strdup(lib_name);
456	}
457	else {
458		fprintf (stderr, "MAX LIBS REACHED\n");
459		exit(EXIT_FAILURE);
460	}
461}
462
463int
464linkmap_init(Process *proc, struct ltelf *lte) {
465	void *dbg_addr = NULL, *dyn_addr = GELF_ADDR_CAST(lte->dyn_addr);
466	struct r_debug *rdbg = NULL;
467	struct cb_data data;
468
469	debug(DEBUG_FUNCTION, "linkmap_init()");
470
471	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
472		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);
486	insert_breakpoint(proc, sym2addr(proc, library_symbols),
487			  library_symbols, 1);
488
489	crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);
490
491	free(rdbg);
492	return 0;
493}
494
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}
505