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