library.c revision 4b4dff4c810ebaccb1e36e1b3e9d69cd793ebde1
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			    int latent, int delayed)
118{
119	libsym->next = NULL;
120	libsym->lib = NULL;
121	libsym->plt_type = type_of_plt;
122	libsym->name = name;
123	libsym->own_name = own_name;
124	libsym->latent = latent;
125	libsym->delayed = delayed;
126	libsym->enter_addr = (void *)(uintptr_t)addr;
127}
128
129static void
130private_library_symbol_destroy(struct library_symbol *libsym)
131{
132	library_symbol_set_name(libsym, NULL, 0);
133}
134
135int
136library_symbol_init(struct library_symbol *libsym,
137		    arch_addr_t addr, const char *name, int own_name,
138		    enum toplt type_of_plt)
139{
140	private_library_symbol_init(libsym, addr, name, own_name,
141				    type_of_plt, 0, 0);
142
143	/* If arch init fails, we've already set libsym->name and
144	 * own_name.  But we return failure, and the client code isn't
145	 * supposed to call library_symbol_destroy in such a case.  */
146	return arch_library_symbol_init(libsym);
147}
148
149void
150library_symbol_destroy(struct library_symbol *libsym)
151{
152	if (libsym != NULL) {
153		private_library_symbol_destroy(libsym);
154		arch_library_symbol_destroy(libsym);
155	}
156}
157
158int
159library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
160{
161	const char *name;
162	if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0)
163		return -1;
164
165	private_library_symbol_init(retp, libsym->enter_addr,
166				    name, libsym->own_name, libsym->plt_type,
167				    libsym->latent, libsym->delayed);
168
169	if (arch_library_symbol_clone(retp, libsym) < 0) {
170		private_library_symbol_destroy(retp);
171		return -1;
172	}
173
174	return 0;
175}
176
177int
178library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
179{
180	if (a->enter_addr < b->enter_addr)
181		return -1;
182	if (a->enter_addr > b->enter_addr)
183		return 1;
184	if (a->name != NULL && b->name != NULL)
185		return strcmp(a->name, b->name);
186	if (a->name == NULL) {
187		if (b->name == NULL)
188			return 0;
189		return -1;
190	}
191	return 1;
192}
193
194void
195library_symbol_set_name(struct library_symbol *libsym,
196			const char *name, int own_name)
197{
198	if (libsym->own_name)
199		free((char *)libsym->name);
200	libsym->name = name;
201	libsym->own_name = own_name;
202}
203
204enum callback_status
205library_symbol_equal_cb(struct library_symbol *libsym, void *u)
206{
207	struct library_symbol *standard = u;
208	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
209}
210
211enum callback_status
212library_symbol_named_cb(struct library_symbol *libsym, void *name)
213{
214	return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
215}
216
217static void
218private_library_init(struct library *lib, enum library_type type)
219{
220	lib->next = NULL;
221
222	lib->key = 0;
223	lib->base = 0;
224	lib->entry = 0;
225	lib->dyn_addr = 0;
226
227	lib->soname = NULL;
228	lib->own_soname = 0;
229
230	lib->pathname = NULL;
231	lib->own_pathname = 0;
232
233	lib->symbols = NULL;
234	lib->exported_names = NULL;
235	lib->type = type;
236}
237
238void
239library_init(struct library *lib, enum library_type type)
240{
241	private_library_init(lib, type);
242	arch_library_init(lib);
243}
244
245static int
246library_exported_name_clone(struct library_exported_name *retp,
247			    struct library_exported_name *exnm)
248{
249	char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
250	if (name == NULL)
251		return -1;
252	retp->name = name;
253	retp->own_name = exnm->own_name;
254	return 0;
255}
256
257int
258library_clone(struct library *retp, struct library *lib)
259{
260	const char *soname = NULL;
261	const char *pathname;
262	if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
263	     || strdup_if_owned(&pathname,
264				lib->pathname, lib->own_pathname) < 0) {
265		if (lib->own_soname)
266			free((char *)soname);
267		return -1;
268	}
269
270	private_library_init(retp, lib->type);
271	library_set_soname(retp, soname, lib->own_soname);
272	library_set_soname(retp, pathname, lib->own_pathname);
273	arch_library_clone(retp, lib);
274
275	/* Clone symbols.  */
276	{
277		struct library_symbol *it;
278		struct library_symbol **nsymp = &retp->symbols;
279		for (it = lib->symbols; it != NULL; it = it->next) {
280			*nsymp = malloc(sizeof(**nsymp));
281			if (*nsymp == NULL
282			    || library_symbol_clone(*nsymp, it) < 0) {
283				free(*nsymp);
284			fail:
285				/* Release what we managed to allocate.  */
286				library_destroy(retp);
287				return -1;
288			}
289
290			(*nsymp)->lib = retp;
291			nsymp = &(*nsymp)->next;
292		}
293	}
294
295	/* Clone exported names.  */
296	{
297		struct library_exported_name *it;
298		struct library_exported_name **nnamep = &retp->exported_names;
299		for (it = lib->exported_names; it != NULL; it = it->next) {
300			*nnamep = malloc(sizeof(**nnamep));
301			if (*nnamep == NULL
302			    || library_exported_name_clone(*nnamep, it) < 0) {
303				free(*nnamep);
304				goto fail;
305			}
306			nnamep = &(*nnamep)->next;
307		}
308	}
309
310	return 0;
311}
312
313void
314library_destroy(struct library *lib)
315{
316	if (lib == NULL)
317		return;
318
319	arch_library_destroy(lib);
320	library_set_soname(lib, NULL, 0);
321	library_set_pathname(lib, NULL, 0);
322
323	struct library_symbol *sym;
324	for (sym = lib->symbols; sym != NULL; ) {
325		struct library_symbol *next = sym->next;
326		library_symbol_destroy(sym);
327		free(sym);
328		sym = next;
329	}
330}
331
332void
333library_set_soname(struct library *lib, const char *new_name, int own_name)
334{
335	if (lib->own_soname)
336		free((char *)lib->soname);
337	lib->soname = new_name;
338	lib->own_soname = own_name;
339}
340
341void
342library_set_pathname(struct library *lib, const char *new_name, int own_name)
343{
344	if (lib->own_pathname)
345		free((char *)lib->pathname);
346	lib->pathname = new_name;
347	lib->own_pathname = own_name;
348}
349
350struct library_symbol *
351library_each_symbol(struct library *lib, struct library_symbol *start_after,
352		    enum callback_status (*cb)(struct library_symbol *, void *),
353		    void *data)
354{
355	struct library_symbol *it = start_after == NULL ? lib->symbols
356		: start_after->next;
357
358	while (it != NULL) {
359		struct library_symbol *next = it->next;
360
361		switch ((*cb)(it, data)) {
362		case CBS_FAIL:
363			/* XXX handle me  */
364		case CBS_STOP:
365			return it;
366		case CBS_CONT:
367			break;
368		}
369
370		it = next;
371	}
372
373	return NULL;
374}
375
376void
377library_add_symbol(struct library *lib, struct library_symbol *first)
378{
379	struct library_symbol *last;
380	for (last = first; last != NULL; ) {
381		last->lib = lib;
382		if (last->next != NULL)
383			last = last->next;
384		else
385			break;
386	}
387
388	assert(last->next == NULL);
389	last->next = lib->symbols;
390	lib->symbols = first;
391}
392
393enum callback_status
394library_named_cb(struct Process *proc, struct library *lib, void *name)
395{
396	if (name == lib->soname
397	    || strcmp(lib->soname, (char *)name) == 0)
398		return CBS_STOP;
399	else
400		return CBS_CONT;
401}
402
403enum callback_status
404library_with_key_cb(struct Process *proc, struct library *lib, void *keyp)
405{
406	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
407}
408