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