• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of ltrace.
3  * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
4  * Copyright (C) 2001,2009 Juan Cespedes
5  * Copyright (C) 2006 Ian Wienand
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  */
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <stdio.h>
27 
28 #include "library.h"
29 #include "callback.h"
30 #include "debug.h"
31 #include "dict.h"
32 #include "backend.h" // for arch_library_symbol_init, arch_library_init
33 
34 #ifndef OS_HAVE_LIBRARY_DATA
35 int
os_library_init(struct library * lib)36 os_library_init(struct library *lib)
37 {
38 	return 0;
39 }
40 
41 void
os_library_destroy(struct library * lib)42 os_library_destroy(struct library *lib)
43 {
44 }
45 
46 int
os_library_clone(struct library * retp,struct library * lib)47 os_library_clone(struct library *retp, struct library *lib)
48 {
49 	return 0;
50 }
51 #endif
52 
53 #ifndef ARCH_HAVE_LIBRARY_DATA
54 int
arch_library_init(struct library * lib)55 arch_library_init(struct library *lib)
56 {
57 	return 0;
58 }
59 
60 void
arch_library_destroy(struct library * lib)61 arch_library_destroy(struct library *lib)
62 {
63 }
64 
65 int
arch_library_clone(struct library * retp,struct library * lib)66 arch_library_clone(struct library *retp, struct library *lib)
67 {
68 	return 0;
69 }
70 #endif
71 
72 #ifndef OS_HAVE_LIBRARY_SYMBOL_DATA
73 int
os_library_symbol_init(struct library_symbol * libsym)74 os_library_symbol_init(struct library_symbol *libsym)
75 {
76 	return 0;
77 }
78 
79 void
os_library_symbol_destroy(struct library_symbol * libsym)80 os_library_symbol_destroy(struct library_symbol *libsym)
81 {
82 }
83 
84 int
os_library_symbol_clone(struct library_symbol * retp,struct library_symbol * libsym)85 os_library_symbol_clone(struct library_symbol *retp,
86 			struct library_symbol *libsym)
87 {
88 	return 0;
89 }
90 #endif
91 
92 #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
93 int
arch_library_symbol_init(struct library_symbol * libsym)94 arch_library_symbol_init(struct library_symbol *libsym)
95 {
96 	return 0;
97 }
98 
99 void
arch_library_symbol_destroy(struct library_symbol * libsym)100 arch_library_symbol_destroy(struct library_symbol *libsym)
101 {
102 }
103 
104 int
arch_library_symbol_clone(struct library_symbol * retp,struct library_symbol * libsym)105 arch_library_symbol_clone(struct library_symbol *retp,
106 			  struct library_symbol *libsym)
107 {
108 	return 0;
109 }
110 #endif
111 
112 size_t
arch_addr_hash(const arch_addr_t * addr)113 arch_addr_hash(const arch_addr_t *addr)
114 {
115 	union {
116 		arch_addr_t addr;
117 		int ints[sizeof(arch_addr_t)
118 			 / sizeof(unsigned int)];
119 	} u = { .addr = *addr };
120 
121 	size_t i;
122 	size_t h = 0;
123 	for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
124 		h ^= dict_hash_int(&u.ints[i]);
125 	return h;
126 }
127 
128 int
arch_addr_eq(const arch_addr_t * addr1,const arch_addr_t * addr2)129 arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
130 {
131 	return *addr1 == *addr2;
132 }
133 
134 int
strdup_if(const char ** retp,const char * str,int whether)135 strdup_if(const char **retp, const char *str, int whether)
136 {
137 	if (whether && str != NULL) {
138 		str = strdup(str);
139 		if (str == NULL)
140 			return -1;
141 	}
142 
143 	*retp = str;
144 	return 0;
145 }
146 
147 static void
private_library_symbol_init(struct library_symbol * libsym,arch_addr_t addr,const char * name,int own_name,enum toplt type_of_plt,int latent,int delayed)148 private_library_symbol_init(struct library_symbol *libsym,
149 			    arch_addr_t addr,
150 			    const char *name, int own_name,
151 			    enum toplt type_of_plt,
152 			    int latent, int delayed)
153 {
154 	libsym->next = NULL;
155 	libsym->lib = NULL;
156 	libsym->plt_type = type_of_plt;
157 	libsym->name = name;
158 	libsym->own_name = own_name;
159 	libsym->latent = latent;
160 	libsym->delayed = delayed;
161 	libsym->enter_addr = (void *)(uintptr_t)addr;
162 	libsym->proto = NULL;
163 }
164 
165 static void
private_library_symbol_destroy(struct library_symbol * libsym)166 private_library_symbol_destroy(struct library_symbol *libsym)
167 {
168 	library_symbol_set_name(libsym, NULL, 0);
169 }
170 
171 int
library_symbol_init(struct library_symbol * libsym,arch_addr_t addr,const char * name,int own_name,enum toplt type_of_plt)172 library_symbol_init(struct library_symbol *libsym,
173 		    arch_addr_t addr, const char *name, int own_name,
174 		    enum toplt type_of_plt)
175 {
176 	private_library_symbol_init(libsym, addr, name, own_name,
177 				    type_of_plt, 0, 0);
178 
179 	if (os_library_symbol_init(libsym) < 0)
180 		/* We've already set libsym->name and own_name.  But
181 		 * we return failure, and the client code isn't
182 		 * supposed to call library_symbol_destroy in such
183 		 * case.  */
184 		return -1;
185 
186 	if (arch_library_symbol_init(libsym) < 0) {
187 		os_library_symbol_destroy(libsym);
188 		return -1;
189 	}
190 
191 	return 0;
192 }
193 
194 void
library_symbol_destroy(struct library_symbol * libsym)195 library_symbol_destroy(struct library_symbol *libsym)
196 {
197 	if (libsym != NULL) {
198 		arch_library_symbol_destroy(libsym);
199 		os_library_symbol_destroy(libsym);
200 		private_library_symbol_destroy(libsym);
201 	}
202 }
203 
204 int
library_symbol_clone(struct library_symbol * retp,struct library_symbol * libsym)205 library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
206 {
207 	/* Make lifetimes of name stored at original independent of
208 	 * the one at the clone.  */
209 	const char *name;
210 	if (strdup_if(&name, libsym->name, libsym->own_name) < 0)
211 		return -1;
212 
213 	private_library_symbol_init(retp, libsym->enter_addr,
214 				    name, libsym->own_name, libsym->plt_type,
215 				    libsym->latent, libsym->delayed);
216 
217 	if (os_library_symbol_clone(retp, libsym) < 0) {
218 	fail:
219 		private_library_symbol_destroy(retp);
220 		return -1;
221 	}
222 
223 	if (arch_library_symbol_clone(retp, libsym) < 0) {
224 		os_library_symbol_destroy(retp);
225 		goto fail;
226 	}
227 
228 	return 0;
229 }
230 
231 int
library_symbol_cmp(struct library_symbol * a,struct library_symbol * b)232 library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
233 {
234 	if (a->enter_addr < b->enter_addr)
235 		return -1;
236 	if (a->enter_addr > b->enter_addr)
237 		return 1;
238 	if (a->name != NULL && b->name != NULL)
239 		return strcmp(a->name, b->name);
240 	if (a->name == NULL) {
241 		if (b->name == NULL)
242 			return 0;
243 		return -1;
244 	}
245 	return 1;
246 }
247 
248 void
library_symbol_set_name(struct library_symbol * libsym,const char * name,int own_name)249 library_symbol_set_name(struct library_symbol *libsym,
250 			const char *name, int own_name)
251 {
252 	if (libsym->own_name)
253 		free((char *)libsym->name);
254 	libsym->name = name;
255 	libsym->own_name = own_name;
256 }
257 
258 enum callback_status
library_symbol_equal_cb(struct library_symbol * libsym,void * u)259 library_symbol_equal_cb(struct library_symbol *libsym, void *u)
260 {
261 	struct library_symbol *standard = u;
262 	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
263 }
264 
265 enum callback_status
library_symbol_named_cb(struct library_symbol * libsym,void * name)266 library_symbol_named_cb(struct library_symbol *libsym, void *name)
267 {
268 	return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
269 }
270 
271 enum callback_status
library_symbol_delayed_cb(struct library_symbol * libsym,void * unused)272 library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
273 {
274 	return libsym->delayed ? CBS_STOP : CBS_CONT;
275 }
276 
277 static void
private_library_init(struct library * lib,enum library_type type)278 private_library_init(struct library *lib, enum library_type type)
279 {
280 	lib->next = NULL;
281 
282 	lib->key = 0;
283 	lib->base = 0;
284 	lib->entry = 0;
285 	lib->dyn_addr = 0;
286 	lib->protolib = NULL;
287 
288 	lib->soname = NULL;
289 	lib->own_soname = 0;
290 
291 	lib->pathname = NULL;
292 	lib->own_pathname = 0;
293 
294 	lib->symbols = NULL;
295 	lib->exported_names = NULL;
296 	lib->type = type;
297 }
298 
299 int
library_init(struct library * lib,enum library_type type)300 library_init(struct library *lib, enum library_type type)
301 {
302 	private_library_init(lib, type);
303 
304 	if (os_library_init(lib) < 0)
305 		return -1;
306 
307 	if (arch_library_init(lib) < 0) {
308 		os_library_destroy(lib);
309 		return -1;
310 	}
311 
312 	return 0;
313 }
314 
315 static int
library_exported_name_clone(struct library_exported_name * retp,struct library_exported_name * exnm)316 library_exported_name_clone(struct library_exported_name *retp,
317 			    struct library_exported_name *exnm)
318 {
319 	char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
320 	if (name == NULL)
321 		return -1;
322 	retp->name = name;
323 	retp->own_name = exnm->own_name;
324 	return 0;
325 }
326 
327 int
library_clone(struct library * retp,struct library * lib)328 library_clone(struct library *retp, struct library *lib)
329 {
330 	const char *soname = NULL;
331 	const char *pathname;
332 
333 	/* Make lifetimes of strings stored at original independent of
334 	 * those at the clone.  */
335 	if (strdup_if(&soname, lib->soname, lib->own_soname) < 0
336 	    || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) {
337 		if (lib->own_soname)
338 			free((char *)soname);
339 		return -1;
340 	}
341 
342 	private_library_init(retp, lib->type);
343 	library_set_soname(retp, soname, lib->own_soname);
344 	library_set_pathname(retp, pathname, lib->own_pathname);
345 
346 	retp->key = lib->key;
347 
348 	/* Clone symbols.  */
349 	{
350 		struct library_symbol *it;
351 		struct library_symbol **nsymp = &retp->symbols;
352 		for (it = lib->symbols; it != NULL; it = it->next) {
353 			*nsymp = malloc(sizeof(**nsymp));
354 			if (*nsymp == NULL
355 			    || library_symbol_clone(*nsymp, it) < 0) {
356 				free(*nsymp);
357 				*nsymp = NULL;
358 			fail:
359 				/* Release what we managed to allocate.  */
360 				library_destroy(retp);
361 				return -1;
362 			}
363 
364 			(*nsymp)->lib = retp;
365 			nsymp = &(*nsymp)->next;
366 		}
367 		*nsymp = NULL;
368 	}
369 
370 	/* Clone exported names.  */
371 	{
372 		struct library_exported_name *it;
373 		struct library_exported_name **nnamep = &retp->exported_names;
374 		for (it = lib->exported_names; it != NULL; it = it->next) {
375 			*nnamep = malloc(sizeof(**nnamep));
376 			if (*nnamep == NULL
377 			    || library_exported_name_clone(*nnamep, it) < 0) {
378 				free(*nnamep);
379 				goto fail;
380 			}
381 			nnamep = &(*nnamep)->next;
382 		}
383 		*nnamep = NULL;
384 	}
385 
386 	if (os_library_clone(retp, lib) < 0)
387 		goto fail;
388 
389 	if (arch_library_clone(retp, lib) < 0) {
390 		os_library_destroy(retp);
391 		goto fail;
392 	}
393 
394 	return 0;
395 }
396 
397 void
library_destroy(struct library * lib)398 library_destroy(struct library *lib)
399 {
400 	if (lib == NULL)
401 		return;
402 
403 	arch_library_destroy(lib);
404 	os_library_destroy(lib);
405 
406 	library_set_soname(lib, NULL, 0);
407 	library_set_pathname(lib, NULL, 0);
408 
409 	struct library_symbol *sym;
410 	for (sym = lib->symbols; sym != NULL; ) {
411 		struct library_symbol *next = sym->next;
412 		library_symbol_destroy(sym);
413 		free(sym);
414 		sym = next;
415 	}
416 
417 	/* Release exported names.  */
418 	struct library_exported_name *it;
419 	for (it = lib->exported_names; it != NULL; ) {
420 		struct library_exported_name *next = it->next;
421 		if (it->own_name)
422 			free((char *)it->name);
423 		free(it);
424 		it = next;
425 	}
426 }
427 
428 void
library_set_soname(struct library * lib,const char * new_name,int own_name)429 library_set_soname(struct library *lib, const char *new_name, int own_name)
430 {
431 	if (lib->own_soname)
432 		free((char *)lib->soname);
433 	lib->soname = new_name;
434 	lib->own_soname = own_name;
435 }
436 
437 void
library_set_pathname(struct library * lib,const char * new_name,int own_name)438 library_set_pathname(struct library *lib, const char *new_name, int own_name)
439 {
440 	if (lib->own_pathname)
441 		free((char *)lib->pathname);
442 	lib->pathname = new_name;
443 	lib->own_pathname = own_name;
444 }
445 
446 struct library_symbol *
library_each_symbol(struct library * lib,struct library_symbol * start_after,enum callback_status (* cb)(struct library_symbol *,void *),void * data)447 library_each_symbol(struct library *lib, struct library_symbol *start_after,
448 		    enum callback_status (*cb)(struct library_symbol *, void *),
449 		    void *data)
450 {
451 	struct library_symbol *it = start_after == NULL ? lib->symbols
452 		: start_after->next;
453 
454 	while (it != NULL) {
455 		struct library_symbol *next = it->next;
456 
457 		switch ((*cb)(it, data)) {
458 		case CBS_FAIL:
459 			/* XXX handle me  */
460 		case CBS_STOP:
461 			return it;
462 		case CBS_CONT:
463 			break;
464 		}
465 
466 		it = next;
467 	}
468 
469 	return NULL;
470 }
471 
472 void
library_add_symbol(struct library * lib,struct library_symbol * first)473 library_add_symbol(struct library *lib, struct library_symbol *first)
474 {
475 	struct library_symbol *last;
476 	for (last = first; last != NULL; ) {
477 		last->lib = lib;
478 		if (last->next != NULL)
479 			last = last->next;
480 		else
481 			break;
482 	}
483 
484 	assert(last->next == NULL);
485 	last->next = lib->symbols;
486 	lib->symbols = first;
487 }
488 
489 enum callback_status
library_named_cb(struct process * proc,struct library * lib,void * name)490 library_named_cb(struct process *proc, struct library *lib, void *name)
491 {
492 	if (name == lib->soname
493 	    || strcmp(lib->soname, (char *)name) == 0)
494 		return CBS_STOP;
495 	else
496 		return CBS_CONT;
497 }
498 
499 enum callback_status
library_with_key_cb(struct process * proc,struct library * lib,void * keyp)500 library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
501 {
502 	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
503 }
504