proc.c revision 17476b7bfac0e1cb68f9a1dbdb65dab2ac2160c6
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	ElfW(Dyn) entry;
253
254	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
255
256	if (addr ==	NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
257		return -1;
258	}
259
260	while ((sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
261	       (entry.d_tag != DT_NULL)) {
262		fprintf(stderr, " entry %ld %#lx\n", entry.d_tag, entry.d_un.d_val);
263		if (entry.d_tag == d_tag) {
264			fprintf(stderr, "   hit\n");
265			*addr = (void *)entry.d_un.d_val;
266			debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
267			return 0;
268		}
269		pvAddr += sizeof(entry);
270	}
271
272	debug(2, "Couldn't address for dtag!\n");
273	return -1;
274}
275
276enum callback_status
277find_library_addr(struct Process *proc, struct library *lib, void *data)
278{
279	target_address_t addr = (target_address_t)*(GElf_Addr *)data;
280	return lib->base == addr ? CBS_STOP : CBS_CONT;
281}
282
283static void
284crawl_linkmap(Process *proc, struct r_debug *dbg)
285{
286	struct link_map rlm;
287	char lib_name[BUFSIZ];
288	struct link_map *lm = NULL;
289
290	debug (DEBUG_FUNCTION, "crawl_linkmap()");
291
292	if (!dbg || !dbg->r_map) {
293		debug(2, "Debug structure or it's linkmap are NULL!");
294		return;
295	}
296
297	lm = dbg->r_map;
298
299	while (lm) {
300		if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
301			debug(2, "Unable to read link map\n");
302			return;
303		}
304
305		lm = rlm.l_next;
306		if (rlm.l_name == NULL) {
307			debug(2, "Invalid library name referenced in dynamic linker map\n");
308			return;
309		}
310
311		umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
312
313		debug(2, "Dispatching callback for: %s, "
314		      "Loaded at 0x%" PRI_ELF_ADDR "\n",
315		      lib_name, rlm.l_addr);
316		fprintf(stderr, "DSO addr=%#lx, name='%s'\n", rlm.l_addr, lib_name);
317
318		/* Do we have that library already?  */
319		struct library *lib
320			= proc_each_library(proc, NULL, find_library_addr,
321					    &rlm.l_addr);
322		if (lib != NULL)
323			continue;
324
325		if (*lib_name == '\0') {
326			/* VDSO.  No associated file, XXX but we might
327			 * load it from the address space of the
328			 * process.  */
329			continue;
330		}
331
332		lib = ltelf_read_library(proc, lib_name, rlm.l_addr);
333		if (lib == NULL) {
334			error(0, errno, "Couldn't load ELF object %s\n",
335			      lib_name);
336			continue;
337		}
338
339		proc_add_library(proc, lib);
340	}
341	return;
342}
343
344static struct r_debug *
345load_debug_struct(Process *proc) {
346	struct r_debug *rdbg = NULL;
347
348	debug(DEBUG_FUNCTION, "load_debug_struct");
349
350	rdbg = malloc(sizeof(*rdbg));
351	if (!rdbg) {
352		return NULL;
353	}
354
355	if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) {
356		debug(2, "This process does not have a debug structure!\n");
357		free(rdbg);
358		return NULL;
359	}
360
361	return rdbg;
362}
363
364static void
365rdebug_callback_hit(struct breakpoint *bp, struct Process *proc)
366{
367	fprintf(stderr, "======= HIT\n");
368	struct r_debug *dbg = NULL;
369	//struct cb_data data;
370
371	debug(DEBUG_FUNCTION, "arch_check_dbg");
372
373	if (!(dbg = load_debug_struct(proc))) {
374		debug(2, "Unable to load debug structure!");
375		return;
376	}
377
378	if (dbg->r_state == RT_CONSISTENT) {
379		debug(2, "Linkmap is now consistent");
380		if (proc->debug_state == RT_ADD) {
381			debug(2, "Adding DSO to linkmap");
382			//data.proc = proc;
383			crawl_linkmap(proc, dbg);
384			//&data);
385		} else if (proc->debug_state == RT_DELETE) {
386			debug(2, "Removing DSO from linkmap");
387		} else {
388			debug(2, "Unexpected debug state!");
389		}
390	}
391
392	proc->debug_state = dbg->r_state;
393	return;
394}
395
396void *dyn_addr;
397int
398linkmap_init(struct Process *proc)
399{
400  return 0;
401	void *dbg_addr = NULL;
402	struct r_debug *rdbg = NULL;
403	//struct cb_data data;
404
405	debug(DEBUG_FUNCTION, "linkmap_init()");
406	fprintf(stderr, "linkmap_init dyn_addr=%p\n", dyn_addr);
407
408	if (find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
409		debug(2, "Couldn't find debug structure!");
410		return -1;
411	}
412
413	proc->debug = dbg_addr;
414
415	if (!(rdbg = load_debug_struct(proc))) {
416		debug(2, "No debug structure or no memory to allocate one!");
417		return -1;
418	}
419
420	//data.lte = lte;
421
422	void *addr;
423	{
424		struct library_symbol libsym;
425		library_symbol_init(&libsym, (target_address_t)rdbg->r_brk,
426				    NULL, 0, LS_TOPLT_NONE);
427		addr = sym2addr(proc, &libsym);
428		library_symbol_destroy(&libsym);
429	}
430	struct breakpoint *rdebug_bp = insert_breakpoint(proc, addr, NULL);
431	static struct bp_callbacks rdebug_callbacks = {
432		.on_hit = rdebug_callback_hit,
433	};
434	rdebug_bp->cbs = &rdebug_callbacks;
435
436	crawl_linkmap(proc, rdbg);
437
438	free(rdbg);
439	return 0;
440}
441
442int
443task_kill (pid_t pid, int sig)
444{
445	// Taken from GDB
446        int ret;
447
448        errno = 0;
449        ret = syscall (__NR_tkill, pid, sig);
450	return ret;
451}
452