proc.c revision f0bd98b3e6753d8609a3054a61f2df6f9cdac10a
1#include "config.h"
2#include "common.h"
3
4#include <sys/types.h>
5#include <link.h>
6#include <stdio.h>
7#include <string.h>
8#include <signal.h>
9#include <unistd.h>
10
11/* /proc/pid doesn't exist just after the fork, and sometimes `ltrace'
12 * couldn't open it to find the executable.  So it may be necessary to
13 * have a bit delay
14 */
15
16#define	MAX_DELAY	100000	/* 100000 microseconds = 0.1 seconds */
17
18/*
19 * Returns a (malloc'd) file name corresponding to a running pid
20 */
21char *
22pid2name(pid_t pid) {
23	char proc_exe[1024];
24
25	if (!kill(pid, 0)) {
26		int delay = 0;
27
28		sprintf(proc_exe, "/proc/%d/exe", pid);
29
30		while (delay < MAX_DELAY) {
31			if (!access(proc_exe, F_OK)) {
32				return strdup(proc_exe);
33			}
34			delay += 1000;	/* 1 milisecond */
35		}
36	}
37	return NULL;
38}
39
40static int
41find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) {
42	int i = 0, done = 0;
43	ElfW(Dyn) entry;
44
45	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
46
47	if (addr ==	NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) {
48		return -1;
49	}
50
51	while ((!done) && (i < ELF_MAX_SEGMENTS) &&
52		(sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) &&
53		(entry.d_tag != DT_NULL)) {
54		if (entry.d_tag == d_tag) {
55			done = 1;
56			*addr = (void *)entry.d_un.d_val;
57		}
58		pvAddr += sizeof(entry);
59		i++;
60	}
61
62	if (done) {
63		debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag);
64		return 0;
65	}
66	else {
67		debug(2, "Couldn't address for dtag!\n");
68		return -1;
69	}
70}
71
72struct cb_data {
73	const char *lib_name;
74	struct ltelf *lte;
75	ElfW(Addr) addr;
76	Process *proc;
77};
78
79static void
80crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), struct cb_data *data) {
81	struct link_map rlm;
82	char lib_name[BUFSIZ];
83	struct link_map *lm = NULL;
84
85	debug (DEBUG_FUNCTION, "crawl_linkmap()");
86
87	if (!dbg || !dbg->r_map) {
88		debug(2, "Debug structure or it's linkmap are NULL!");
89		return;
90	}
91
92	lm = dbg->r_map;
93
94	while (lm) {
95		if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
96			debug(2, "Unable to read link map\n");
97			return;
98		}
99
100		lm = rlm.l_next;
101		if (rlm.l_name == NULL) {
102			debug(2, "Invalid library name referenced in dynamic linker map\n");
103			return;
104		}
105
106		umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
107
108		if (lib_name[0] == '\0') {
109			debug(2, "Library name is an empty string");
110			continue;
111		}
112
113		if (callback) {
114			debug(2, "Dispatching callback for: %s, Loaded at 0x%x\n", lib_name, rlm.l_addr);
115			data->addr = rlm.l_addr;
116			data->lib_name = lib_name;
117			callback(data);
118		}
119	}
120	return;
121}
122
123static struct r_debug *
124load_debug_struct(Process *proc) {
125	struct r_debug *rdbg = NULL;
126
127	debug(DEBUG_FUNCTION, "load_debug_struct");
128
129	rdbg = malloc(sizeof(*rdbg));
130	if (!rdbg) {
131		return NULL;
132	}
133
134	if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) {
135		debug(2, "This process does not have a debug structure!\n");
136		free(rdbg);
137		return NULL;
138	}
139
140	return rdbg;
141}
142
143static void
144linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
145	int i = 0;
146	struct cb_data *lm_add = data;
147	struct ltelf lte;
148	struct opt_x_t *xptr;
149
150	debug(DEBUG_FUNCTION, "linkmap_add_cb");
151
152	/*
153		XXX
154		iterate through library[i]'s to see if this lib is in the list.
155		if not, add it
156	 */
157	for(;i < library_num;i++) {
158		if (strcmp(library[i], lm_add->lib_name) == 0) {
159			/* found it, so its not new */
160			return;
161		}
162	}
163
164	/* new library linked! */
165	debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);
166
167	if (library_num < MAX_LIBRARIES) {
168		library[library_num++] = strdup(lm_add->lib_name);
169		memset(&lte, 0, sizeof(struct ltelf));
170		lte.base_addr = lm_add->addr;
171		do_init_elf(&lte, library[library_num-1]);
172		/* add bps */
173		for (xptr = opt_x; xptr; xptr = xptr->next) {
174			if (xptr->found)
175				continue;
176
177			GElf_Sym sym;
178			GElf_Addr addr;
179
180			if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
181				debug(2, "found symbol %s @ %lx, adding it.", xptr->name, sym.st_value);
182				addr = sym.st_value;
183				add_library_symbol(addr, xptr->name, &library_symbols, LS_TOPLT_NONE, 0);
184				xptr->found = 1;
185				insert_breakpoint(lm_add->proc, sym2addr(lm_add->proc, library_symbols), library_symbols);
186			}
187		}
188		do_close_elf(&lte);
189	}
190}
191
192void
193arch_check_dbg(Process *proc) {
194	struct r_debug *dbg = NULL;
195	struct cb_data data;
196
197	debug(DEBUG_FUNCTION, "arch_check_dbg");
198
199	if (!(dbg = load_debug_struct(proc))) {
200		debug(2, "Unable to load debug structure!");
201		return;
202	}
203
204	if (dbg->r_state == RT_CONSISTENT) {
205		debug(2, "Linkmap is now consistent");
206		if (proc->debug_state == RT_ADD) {
207			debug(2, "Adding DSO to linkmap");
208			data.proc = proc;
209			crawl_linkmap(proc, dbg, linkmap_add_cb, &data);
210		} else if (proc->debug_state == RT_DELETE) {
211			debug(2, "Removing DSO from linkmap");
212		} else {
213			debug(2, "Unexpected debug state!");
214		}
215	}
216
217	proc->debug_state = dbg->r_state;
218
219	return;
220}
221
222static void
223hook_libdl_cb(void *data) {
224	struct cb_data *hook_data = data;
225	const char *lib_name = NULL;
226	ElfW(Addr) addr;
227	struct ltelf *lte = NULL;
228
229	debug(DEBUG_FUNCTION, "add_library_cb");
230
231	if (!data) {
232		debug(2, "No callback data");
233		return;
234	}
235
236	lib_name = hook_data->lib_name;
237	addr = hook_data->addr;
238	lte = hook_data->lte;
239
240	if (library_num < MAX_LIBRARIES) {
241		library[library_num++] = strdup(lib_name);
242		lte[library_num].base_addr = addr;
243	}
244	else {
245		fprintf (stderr, "MAX LIBS REACHED\n");
246		exit(EXIT_FAILURE);
247	}
248}
249
250int
251linkmap_init(Process *proc, struct ltelf *lte) {
252	void *dbg_addr = NULL;
253	struct r_debug *rdbg = NULL;
254	struct cb_data data;
255
256	debug(DEBUG_FUNCTION, "linkmap_init()");
257
258	if (find_dynamic_entry_addr(proc, (void *)lte->dyn_addr, DT_DEBUG, &dbg_addr) == -1) {
259		debug(2, "Couldn't find debug structure!");
260		return -1;
261	}
262
263	proc->debug = dbg_addr;
264
265	if (!(rdbg = load_debug_struct(proc))) {
266		debug(2, "No debug structure or no memory to allocate one!");
267		return -1;
268	}
269
270	data.lte = lte;
271
272	add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
273	insert_breakpoint(proc, sym2addr(proc, library_symbols), library_symbols);
274
275	crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);
276
277	free(rdbg);
278	return 0;
279}
280