proc.c revision 522a6ca083c8b9e964548b0e79a4bdc8095d6e2e
1#define _GNU_SOURCE /* For getline.  */
2#include "config.h"
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <inttypes.h>
8#include <link.h>
9#include <stdio.h>
10#include <string.h>
11#include <signal.h>
12#include <unistd.h>
13#include <dirent.h>
14#include <ctype.h>
15#include <errno.h>
16#include <sys/syscall.h>
17#include <error.h>
18
19#include "common.h"
20#include "breakpoint.h"
21#include "proc.h"
22#include "library.h"
23
24/* /proc/pid doesn't exist just after the fork, and sometimes `ltrace'
25 * couldn't open it to find the executable.  So it may be necessary to
26 * have a bit delay
27 */
28
29#define	MAX_DELAY	100000	/* 100000 microseconds = 0.1 seconds */
30
31#define PROC_PID_FILE(VAR, FORMAT, PID)		\
32	char VAR[strlen(FORMAT) + 6];		\
33	sprintf(VAR, FORMAT, PID)
34
35/*
36 * Returns a (malloc'd) file name corresponding to a running pid
37 */
38char *
39pid2name(pid_t pid) {
40	if (!kill(pid, 0)) {
41		int delay = 0;
42
43		PROC_PID_FILE(proc_exe, "/proc/%d/exe", pid);
44
45		while (delay < MAX_DELAY) {
46			if (!access(proc_exe, F_OK)) {
47				return strdup(proc_exe);
48			}
49			delay += 1000;	/* 1 milisecond */
50		}
51	}
52	return NULL;
53}
54
55static FILE *
56open_status_file(pid_t pid)
57{
58	PROC_PID_FILE(fn, "/proc/%d/status", pid);
59	/* Don't complain if we fail.  This would typically happen
60	   when the process is about to terminate, and these files are
61	   not available anymore.  This function is called from the
62	   event loop, and we don't want to clutter the output just
63	   because the process terminates.  */
64	return fopen(fn, "r");
65}
66
67static char *
68find_line_starting(FILE * file, const char * prefix, size_t len)
69{
70	char * line = NULL;
71	size_t line_len = 0;
72	while (!feof(file)) {
73		if (getline(&line, &line_len, file) < 0)
74			return NULL;
75		if (strncmp(line, prefix, len) == 0)
76			return line;
77	}
78	return NULL;
79}
80
81static void
82each_line_starting(FILE *file, const char *prefix,
83		   enum callback_status (*cb)(const char *line,
84					      const char *prefix,
85					      void *data),
86		   void *data)
87{
88	size_t len = strlen(prefix);
89	char * line;
90	while ((line = find_line_starting(file, prefix, len)) != NULL) {
91		enum callback_status st = (*cb)(line, prefix, data);
92		free (line);
93		if (st == CBS_STOP)
94			return;
95	}
96}
97
98static enum callback_status
99process_leader_cb(const char *line, const char *prefix, void *data)
100{
101	pid_t * pidp = data;
102	*pidp = atoi(line + strlen(prefix));
103	return CBS_STOP;
104}
105
106pid_t
107process_leader(pid_t pid)
108{
109	pid_t tgid = 0;
110	FILE * file = open_status_file(pid);
111	if (file != NULL) {
112		each_line_starting(file, "Tgid:\t", &process_leader_cb, &tgid);
113		fclose(file);
114	}
115
116	return tgid;
117}
118
119static enum callback_status
120process_stopped_cb(const char *line, const char *prefix, void *data)
121{
122	char c = line[strlen(prefix)];
123	// t:tracing stop, T:job control stop
124	*(int *)data = (c == 't' || c == 'T');
125	return CBS_STOP;
126}
127
128int
129process_stopped(pid_t pid)
130{
131	int is_stopped = -1;
132	FILE * file = open_status_file(pid);
133	if (file != NULL) {
134		each_line_starting(file, "State:\t", &process_stopped_cb,
135				   &is_stopped);
136		fclose(file);
137	}
138	return is_stopped;
139}
140
141static enum callback_status
142process_status_cb(const char *line, const char *prefix, void *data)
143{
144	const char * status = line + strlen(prefix);
145	const char c = *status;
146
147#define RETURN(C) do {					\
148		*(enum process_status *)data = C;	\
149		return CBS_STOP;			\
150	} while (0)
151
152	switch (c) {
153	case 'Z': RETURN(ps_zombie);
154	case 't': RETURN(ps_tracing_stop);
155	case 'T':
156		/* This can be either "T (stopped)" or, for older
157		 * kernels, "T (tracing stop)".  */
158		if (!strcmp(status, "T (stopped)\n"))
159			RETURN(ps_stop);
160		else if (!strcmp(status, "T (tracing stop)\n"))
161			RETURN(ps_tracing_stop);
162		else {
163			fprintf(stderr, "Unknown process status: %s",
164				status);
165			RETURN(ps_stop); /* Some sort of stop
166					  * anyway.  */
167		}
168	case 'D':
169	case 'S': RETURN(ps_sleeping);
170	}
171
172	RETURN(ps_other);
173#undef RETURN
174}
175
176enum process_status
177process_status(pid_t pid)
178{
179	enum process_status ret = ps_invalid;
180	FILE * file = open_status_file(pid);
181	if (file != NULL) {
182		each_line_starting(file, "State:\t", &process_status_cb, &ret);
183		fclose(file);
184		if (ret == ps_invalid)
185			error(0, errno, "process_status %d", pid);
186	} else
187		/* If the file is not present, the process presumably
188		 * exited already.  */
189		ret = ps_zombie;
190
191	return ret;
192}
193
194static int
195all_digits(const char *str)
196{
197	while (isdigit(*str))
198		str++;
199	return !*str;
200}
201
202int
203process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n)
204{
205	PROC_PID_FILE(fn, "/proc/%d/task", pid);
206	DIR * d = opendir(fn);
207	if (d == NULL)
208		return -1;
209
210	pid_t *tasks = NULL;
211	size_t n = 0;
212	size_t alloc = 0;
213
214	while (1) {
215		struct dirent entry;
216		struct dirent *result;
217		if (readdir_r(d, &entry, &result) != 0) {
218			free(tasks);
219			return -1;
220		}
221		if (result == NULL)
222			break;
223		if (result->d_type == DT_DIR && all_digits(result->d_name)) {
224			pid_t npid = atoi(result->d_name);
225			if (n >= alloc) {
226				alloc = alloc > 0 ? (2 * alloc) : 8;
227				pid_t *ntasks = realloc(tasks,
228							sizeof(*tasks) * alloc);
229				if (ntasks == NULL) {
230					free(tasks);
231					return -1;
232				}
233				tasks = ntasks;
234			}
235			if (n >= alloc)
236				abort();
237			tasks[n++] = npid;
238		}
239	}
240
241	closedir(d);
242
243	*ret_tasks = tasks;
244	*ret_n = n;
245	return 0;
246}
247
248static int
249find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
250	fprintf(stderr, "find_dynamic_entry_addr %d %p %d\n",
251		proc->pid, pvAddr, d_tag);
252	int i = 0, done = 0;
253	ElfW(Dyn) entry;
254
255	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
256
257	if (addr ==	NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
258		return -1;
259	}
260
261	while ((!done) && (i < ELF_MAX_SEGMENTS) &&
262		(sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
263		(entry.d_tag != DT_NULL)) {
264		fprintf(stderr, " entry %ld %#lx\n", entry.d_tag, entry.d_un.d_val);
265		if (entry.d_tag == d_tag) {
266			fprintf(stderr, "   hit\n");
267			done = 1;
268			*addr = (void *)entry.d_un.d_val;
269		}
270		pvAddr += sizeof(entry);
271		i++;
272	}
273
274	if (done) {
275		debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
276		return 0;
277	}
278	else {
279		debug(2, "Couldn't address for dtag!\n");
280		return -1;
281	}
282}
283
284enum callback_status
285find_library_addr(struct Process *proc, struct library *lib, void *data)
286{
287	target_address_t addr = (target_address_t)*(GElf_Addr *)data;
288	return lib->base == addr ? CBS_STOP : CBS_CONT;
289}
290
291static void
292crawl_linkmap(Process *proc, struct r_debug *dbg)
293{
294	struct link_map rlm;
295	char lib_name[BUFSIZ];
296	struct link_map *lm = NULL;
297
298	debug (DEBUG_FUNCTION, "crawl_linkmap()");
299
300	if (!dbg || !dbg->r_map) {
301		debug(2, "Debug structure or it's linkmap are NULL!");
302		return;
303	}
304
305	lm = dbg->r_map;
306
307	while (lm) {
308		if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
309			debug(2, "Unable to read link map\n");
310			return;
311		}
312
313		lm = rlm.l_next;
314		if (rlm.l_name == NULL) {
315			debug(2, "Invalid library name referenced in dynamic linker map\n");
316			return;
317		}
318
319		umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
320
321		debug(2, "Dispatching callback for: %s, "
322		      "Loaded at 0x%" PRI_ELF_ADDR "\n",
323		      lib_name, rlm.l_addr);
324		fprintf(stderr, "DSO addr=%#lx, name='%s'\n", rlm.l_addr, lib_name);
325
326		/* Do we have that library already?  */
327		struct library *lib
328			= proc_each_library(proc, NULL, find_library_addr,
329					    &rlm.l_addr);
330		if (lib != NULL)
331			continue;
332
333		if (*lib_name == '\0') {
334			/* VDSO.  No associated file, XXX but we might
335			 * load it from the address space of the
336			 * process.  */
337			continue;
338		}
339
340		lib = ltelf_read_library(lib_name, rlm.l_addr);
341		if (lib == NULL) {
342			error(0, errno, "Couldn't load ELF object %s\n",
343			      lib_name);
344			continue;
345		}
346
347		proc_add_library(proc, lib);
348	}
349	return;
350}
351
352static struct r_debug *
353load_debug_struct(Process *proc) {
354	struct r_debug *rdbg = NULL;
355
356	debug(DEBUG_FUNCTION, "load_debug_struct");
357
358	rdbg = malloc(sizeof(*rdbg));
359	if (!rdbg) {
360		return NULL;
361	}
362
363	if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) {
364		debug(2, "This process does not have a debug structure!\n");
365		free(rdbg);
366		return NULL;
367	}
368
369	return rdbg;
370}
371
372static void
373rdebug_callback_hit(struct breakpoint *bp, struct Process *proc)
374{
375	fprintf(stderr, "======= HIT\n");
376	struct r_debug *dbg = NULL;
377	//struct cb_data data;
378
379	debug(DEBUG_FUNCTION, "arch_check_dbg");
380
381	if (!(dbg = load_debug_struct(proc))) {
382		debug(2, "Unable to load debug structure!");
383		return;
384	}
385
386	if (dbg->r_state == RT_CONSISTENT) {
387		debug(2, "Linkmap is now consistent");
388		if (proc->debug_state == RT_ADD) {
389			debug(2, "Adding DSO to linkmap");
390			//data.proc = proc;
391			crawl_linkmap(proc, dbg);
392			//&data);
393		} else if (proc->debug_state == RT_DELETE) {
394			debug(2, "Removing DSO from linkmap");
395		} else {
396			debug(2, "Unexpected debug state!");
397		}
398	}
399
400	proc->debug_state = dbg->r_state;
401	return;
402}
403
404void *dyn_addr;
405int
406linkmap_init(struct Process *proc)
407{
408	void *dbg_addr = NULL;
409	struct r_debug *rdbg = NULL;
410	//struct cb_data data;
411
412	debug(DEBUG_FUNCTION, "linkmap_init()");
413	fprintf(stderr, "linkmap_init dyn_addr=%p\n", dyn_addr);
414
415	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
416		debug(2, "Couldn't find debug structure!");
417		return -1;
418	}
419
420	proc->debug = dbg_addr;
421
422	if (!(rdbg = load_debug_struct(proc))) {
423		debug(2, "No debug structure or no memory to allocate one!");
424		return -1;
425	}
426
427	//data.lte = lte;
428
429	void *addr;
430	{
431		struct library_symbol libsym;
432		library_symbol_init(&libsym, NULL,
433				    (target_address_t)rdbg->r_brk, NULL, 0,
434				    LS_TOPLT_NONE, 0);
435		addr = sym2addr(proc, &libsym);
436		library_symbol_destroy(&libsym);
437	}
438	struct breakpoint *rdebug_bp = insert_breakpoint(proc, addr, NULL, 1);
439	static struct bp_callbacks rdebug_callbacks = {
440		.on_hit = rdebug_callback_hit,
441	};
442	rdebug_bp->cbs = &rdebug_callbacks;
443
444	crawl_linkmap(proc, rdbg);
445
446	free(rdbg);
447	return 0;
448}
449
450int
451task_kill (pid_t pid, int sig)
452{
453	// Taken from GDB
454        int ret;
455
456        errno = 0;
457        ret = syscall (__NR_tkill, pid, sig);
458	return ret;
459}
460