library.c revision 929bd57ca202fd2f2e8485ebf65d683e664f67b5
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 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 ARCH_HAVE_LIBRARY_DATA
35void
36arch_library_init(struct library *lib)
37{
38}
39
40void
41arch_library_destroy(struct library *lib)
42{
43}
44
45void
46arch_library_clone(struct library *retp, struct library *lib)
47{
48}
49#endif
50
51#ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
52int
53arch_library_symbol_init(struct library_symbol *libsym)
54{
55	return 0;
56}
57
58void
59arch_library_symbol_destroy(struct library_symbol *libsym)
60{
61}
62
63int
64arch_library_symbol_clone(struct library_symbol *retp,
65			  struct library_symbol *libsym)
66{
67	return 0;
68}
69#endif
70
71unsigned int
72target_address_hash(const void *key)
73{
74	/* XXX this assumes that key is passed by value.  */
75	union {
76		arch_addr_t addr;
77		unsigned int ints[sizeof(arch_addr_t)
78				  / sizeof(unsigned int)];
79	} u = { .addr = (arch_addr_t)key };
80
81	size_t i;
82	unsigned int h = 0;
83	for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
84		h ^= dict_key2hash_int((void *)(uintptr_t)u.ints[i]);
85	return h;
86}
87
88int
89target_address_cmp(const void *key1, const void *key2)
90{
91	/* XXX this assumes that key is passed by value.  */
92	arch_addr_t addr1 = (arch_addr_t)key1;
93	arch_addr_t addr2 = (arch_addr_t)key2;
94	return addr1 < addr2 ? 1
95	     : addr1 > addr2 ? -1 : 0;
96}
97
98/* If the other symbol owns the name, we need to make the copy, so
99 * that the life-times of the two symbols are not dependent on each
100 * other.  */
101static int
102strdup_if_owned(const char **retp, const char *str, int owned)
103{
104	if (!owned || str == NULL) {
105		*retp = str;
106		return 0;
107	} else {
108		*retp = strdup(str);
109		return *retp != NULL ? 0 : -1;
110	}
111}
112
113static void
114private_library_symbol_init(struct library_symbol *libsym,
115			    arch_addr_t addr,
116			    const char *name, int own_name,
117			    enum toplt type_of_plt,
118			    int latent, int delayed)
119{
120	libsym->next = NULL;
121	libsym->lib = NULL;
122	libsym->plt_type = type_of_plt;
123	libsym->name = name;
124	libsym->own_name = own_name;
125	libsym->latent = latent;
126	libsym->delayed = delayed;
127	libsym->enter_addr = (void *)(uintptr_t)addr;
128}
129
130static void
131private_library_symbol_destroy(struct library_symbol *libsym)
132{
133	library_symbol_set_name(libsym, NULL, 0);
134}
135
136int
137library_symbol_init(struct library_symbol *libsym,
138		    arch_addr_t addr, const char *name, int own_name,
139		    enum toplt type_of_plt)
140{
141	private_library_symbol_init(libsym, addr, name, own_name,
142				    type_of_plt, 0, 0);
143
144	/* If arch init fails, we've already set libsym->name and
145	 * own_name.  But we return failure, and the client code isn't
146	 * supposed to call library_symbol_destroy in such a case.  */
147	return arch_library_symbol_init(libsym);
148}
149
150void
151library_symbol_destroy(struct library_symbol *libsym)
152{
153	if (libsym != NULL) {
154		private_library_symbol_destroy(libsym);
155		arch_library_symbol_destroy(libsym);
156	}
157}
158
159int
160library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
161{
162	const char *name;
163	if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0)
164		return -1;
165
166	private_library_symbol_init(retp, libsym->enter_addr,
167				    name, libsym->own_name, libsym->plt_type,
168				    libsym->latent, libsym->delayed);
169
170	if (arch_library_symbol_clone(retp, libsym) < 0) {
171		private_library_symbol_destroy(retp);
172		return -1;
173	}
174
175	return 0;
176}
177
178int
179library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
180{
181	if (a->enter_addr < b->enter_addr)
182		return -1;
183	if (a->enter_addr > b->enter_addr)
184		return 1;
185	if (a->name != NULL && b->name != NULL)
186		return strcmp(a->name, b->name);
187	if (a->name == NULL) {
188		if (b->name == NULL)
189			return 0;
190		return -1;
191	}
192	return 1;
193}
194
195void
196library_symbol_set_name(struct library_symbol *libsym,
197			const char *name, int own_name)
198{
199	if (libsym->own_name)
200		free((char *)libsym->name);
201	libsym->name = name;
202	libsym->own_name = own_name;
203}
204
205enum callback_status
206library_symbol_equal_cb(struct library_symbol *libsym, void *u)
207{
208	struct library_symbol *standard = u;
209	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
210}
211
212enum callback_status
213library_symbol_named_cb(struct library_symbol *libsym, void *name)
214{
215	return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
216}
217
218enum callback_status
219library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
220{
221	return libsym->delayed ? CBS_STOP : CBS_CONT;
222}
223
224static void
225private_library_init(struct library *lib, enum library_type type)
226{
227	lib->next = NULL;
228
229	lib->key = 0;
230	lib->base = 0;
231	lib->entry = 0;
232	lib->dyn_addr = 0;
233
234	lib->soname = NULL;
235	lib->own_soname = 0;
236
237	lib->pathname = NULL;
238	lib->own_pathname = 0;
239
240	lib->symbols = NULL;
241	lib->exported_names = NULL;
242	lib->type = type;
243}
244
245void
246library_init(struct library *lib, enum library_type type)
247{
248	private_library_init(lib, type);
249	arch_library_init(lib);
250}
251
252static int
253library_exported_name_clone(struct library_exported_name *retp,
254			    struct library_exported_name *exnm)
255{
256	char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
257	if (name == NULL)
258		return -1;
259	retp->name = name;
260	retp->own_name = exnm->own_name;
261	return 0;
262}
263
264int
265library_clone(struct library *retp, struct library *lib)
266{
267	const char *soname = NULL;
268	const char *pathname;
269	if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
270	     || strdup_if_owned(&pathname,
271				lib->pathname, lib->own_pathname) < 0) {
272		if (lib->own_soname)
273			free((char *)soname);
274		return -1;
275	}
276
277	private_library_init(retp, lib->type);
278	library_set_soname(retp, soname, lib->own_soname);
279	library_set_pathname(retp, pathname, lib->own_pathname);
280	arch_library_clone(retp, lib);
281
282	retp->key = lib->key;
283
284	/* Clone symbols.  */
285	{
286		struct library_symbol *it;
287		struct library_symbol **nsymp = &retp->symbols;
288		for (it = lib->symbols; it != NULL; it = it->next) {
289			*nsymp = malloc(sizeof(**nsymp));
290			if (*nsymp == NULL
291			    || library_symbol_clone(*nsymp, it) < 0) {
292				free(*nsymp);
293			fail:
294				/* Release what we managed to allocate.  */
295				library_destroy(retp);
296				return -1;
297			}
298
299			(*nsymp)->lib = retp;
300			nsymp = &(*nsymp)->next;
301		}
302		*nsymp = NULL;
303	}
304
305	/* Clone exported names.  */
306	{
307		struct library_exported_name *it;
308		struct library_exported_name **nnamep = &retp->exported_names;
309		for (it = lib->exported_names; it != NULL; it = it->next) {
310			*nnamep = malloc(sizeof(**nnamep));
311			if (*nnamep == NULL
312			    || library_exported_name_clone(*nnamep, it) < 0) {
313				free(*nnamep);
314				goto fail;
315			}
316			nnamep = &(*nnamep)->next;
317		}
318		*nnamep = NULL;
319	}
320
321	return 0;
322}
323
324void
325library_destroy(struct library *lib)
326{
327	if (lib == NULL)
328		return;
329
330	arch_library_destroy(lib);
331	library_set_soname(lib, NULL, 0);
332	library_set_pathname(lib, NULL, 0);
333
334	struct library_symbol *sym;
335	for (sym = lib->symbols; sym != NULL; ) {
336		struct library_symbol *next = sym->next;
337		library_symbol_destroy(sym);
338		free(sym);
339		sym = next;
340	}
341
342	/* Release exported names.  */
343	struct library_exported_name *it;
344	for (it = lib->exported_names; it != NULL; ) {
345		struct library_exported_name *next = it->next;
346		if (it->own_name)
347			free((char *)it->name);
348		free(it);
349		it = next;
350	}
351}
352
353void
354library_set_soname(struct library *lib, const char *new_name, int own_name)
355{
356	if (lib->own_soname)
357		free((char *)lib->soname);
358	lib->soname = new_name;
359	lib->own_soname = own_name;
360}
361
362void
363library_set_pathname(struct library *lib, const char *new_name, int own_name)
364{
365	if (lib->own_pathname)
366		free((char *)lib->pathname);
367	lib->pathname = new_name;
368	lib->own_pathname = own_name;
369}
370
371struct library_symbol *
372library_each_symbol(struct library *lib, struct library_symbol *start_after,
373		    enum callback_status (*cb)(struct library_symbol *, void *),
374		    void *data)
375{
376	struct library_symbol *it = start_after == NULL ? lib->symbols
377		: start_after->next;
378
379	while (it != NULL) {
380		struct library_symbol *next = it->next;
381
382		switch ((*cb)(it, data)) {
383		case CBS_FAIL:
384			/* XXX handle me  */
385		case CBS_STOP:
386			return it;
387		case CBS_CONT:
388			break;
389		}
390
391		it = next;
392	}
393
394	return NULL;
395}
396
397void
398library_add_symbol(struct library *lib, struct library_symbol *first)
399{
400	struct library_symbol *last;
401	for (last = first; last != NULL; ) {
402		last->lib = lib;
403		if (last->next != NULL)
404			last = last->next;
405		else
406			break;
407	}
408
409	assert(last->next == NULL);
410	last->next = lib->symbols;
411	lib->symbols = first;
412}
413
414enum callback_status
415library_named_cb(struct process *proc, struct library *lib, void *name)
416{
417	if (name == lib->soname
418	    || strcmp(lib->soname, (char *)name) == 0)
419		return CBS_STOP;
420	else
421		return CBS_CONT;
422}
423
424enum callback_status
425library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
426{
427	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
428}
429