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