library.c revision f70074cd77f82182cb234b673cad3e9618a52843
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
71size_t
72arch_addr_hash(const arch_addr_t *addr)
73{
74	union {
75		arch_addr_t addr;
76		int ints[sizeof(arch_addr_t)
77			 / sizeof(unsigned int)];
78	} u = { .addr = *addr };
79
80	size_t i;
81	size_t h = 0;
82	for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
83		h ^= dict_hash_int(&u.ints[i]);
84	return h;
85}
86
87int
88arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
89{
90	return *addr1 == *addr2;
91}
92
93/* If the other symbol owns the name, we need to make the copy, so
94 * that the life-times of the two symbols are not dependent on each
95 * other.  */
96static int
97strdup_if_owned(const char **retp, const char *str, int owned)
98{
99	if (!owned || str == NULL) {
100		*retp = str;
101		return 0;
102	} else {
103		*retp = strdup(str);
104		return *retp != NULL ? 0 : -1;
105	}
106}
107
108static void
109private_library_symbol_init(struct library_symbol *libsym,
110			    arch_addr_t addr,
111			    const char *name, int own_name,
112			    enum toplt type_of_plt,
113			    int latent, int delayed)
114{
115	libsym->next = NULL;
116	libsym->lib = NULL;
117	libsym->plt_type = type_of_plt;
118	libsym->name = name;
119	libsym->own_name = own_name;
120	libsym->latent = latent;
121	libsym->delayed = delayed;
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,
137				    type_of_plt, 0, 0);
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				    libsym->latent, libsym->delayed);
164
165	if (arch_library_symbol_clone(retp, libsym) < 0) {
166		private_library_symbol_destroy(retp);
167		return -1;
168	}
169
170	return 0;
171}
172
173int
174library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
175{
176	if (a->enter_addr < b->enter_addr)
177		return -1;
178	if (a->enter_addr > b->enter_addr)
179		return 1;
180	if (a->name != NULL && b->name != NULL)
181		return strcmp(a->name, b->name);
182	if (a->name == NULL) {
183		if (b->name == NULL)
184			return 0;
185		return -1;
186	}
187	return 1;
188}
189
190void
191library_symbol_set_name(struct library_symbol *libsym,
192			const char *name, int own_name)
193{
194	if (libsym->own_name)
195		free((char *)libsym->name);
196	libsym->name = name;
197	libsym->own_name = own_name;
198}
199
200enum callback_status
201library_symbol_equal_cb(struct library_symbol *libsym, void *u)
202{
203	struct library_symbol *standard = u;
204	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
205}
206
207enum callback_status
208library_symbol_named_cb(struct library_symbol *libsym, void *name)
209{
210	return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
211}
212
213enum callback_status
214library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
215{
216	return libsym->delayed ? CBS_STOP : CBS_CONT;
217}
218
219static void
220private_library_init(struct library *lib, enum library_type type)
221{
222	lib->next = NULL;
223
224	lib->key = 0;
225	lib->base = 0;
226	lib->entry = 0;
227	lib->dyn_addr = 0;
228	lib->protolib = NULL;
229
230	lib->soname = NULL;
231	lib->own_soname = 0;
232
233	lib->pathname = NULL;
234	lib->own_pathname = 0;
235
236	lib->symbols = NULL;
237	lib->exported_names = NULL;
238	lib->type = type;
239}
240
241void
242library_init(struct library *lib, enum library_type type)
243{
244	private_library_init(lib, type);
245	arch_library_init(lib);
246}
247
248static int
249library_exported_name_clone(struct library_exported_name *retp,
250			    struct library_exported_name *exnm)
251{
252	char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
253	if (name == NULL)
254		return -1;
255	retp->name = name;
256	retp->own_name = exnm->own_name;
257	return 0;
258}
259
260int
261library_clone(struct library *retp, struct library *lib)
262{
263	const char *soname = NULL;
264	const char *pathname;
265	if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
266	     || strdup_if_owned(&pathname,
267				lib->pathname, lib->own_pathname) < 0) {
268		if (lib->own_soname)
269			free((char *)soname);
270		return -1;
271	}
272
273	private_library_init(retp, lib->type);
274	library_set_soname(retp, soname, lib->own_soname);
275	library_set_pathname(retp, pathname, lib->own_pathname);
276	arch_library_clone(retp, lib);
277
278	retp->key = lib->key;
279
280	/* Clone symbols.  */
281	{
282		struct library_symbol *it;
283		struct library_symbol **nsymp = &retp->symbols;
284		for (it = lib->symbols; it != NULL; it = it->next) {
285			*nsymp = malloc(sizeof(**nsymp));
286			if (*nsymp == NULL
287			    || library_symbol_clone(*nsymp, it) < 0) {
288				free(*nsymp);
289			fail:
290				/* Release what we managed to allocate.  */
291				library_destroy(retp);
292				return -1;
293			}
294
295			(*nsymp)->lib = retp;
296			nsymp = &(*nsymp)->next;
297		}
298		*nsymp = NULL;
299	}
300
301	/* Clone exported names.  */
302	{
303		struct library_exported_name *it;
304		struct library_exported_name **nnamep = &retp->exported_names;
305		for (it = lib->exported_names; it != NULL; it = it->next) {
306			*nnamep = malloc(sizeof(**nnamep));
307			if (*nnamep == NULL
308			    || library_exported_name_clone(*nnamep, it) < 0) {
309				free(*nnamep);
310				goto fail;
311			}
312			nnamep = &(*nnamep)->next;
313		}
314		*nnamep = NULL;
315	}
316
317	return 0;
318}
319
320void
321library_destroy(struct library *lib)
322{
323	if (lib == NULL)
324		return;
325
326	arch_library_destroy(lib);
327	library_set_soname(lib, NULL, 0);
328	library_set_pathname(lib, NULL, 0);
329
330	struct library_symbol *sym;
331	for (sym = lib->symbols; sym != NULL; ) {
332		struct library_symbol *next = sym->next;
333		library_symbol_destroy(sym);
334		free(sym);
335		sym = next;
336	}
337
338	/* Release exported names.  */
339	struct library_exported_name *it;
340	for (it = lib->exported_names; it != NULL; ) {
341		struct library_exported_name *next = it->next;
342		if (it->own_name)
343			free((char *)it->name);
344		free(it);
345		it = next;
346	}
347}
348
349void
350library_set_soname(struct library *lib, const char *new_name, int own_name)
351{
352	if (lib->own_soname)
353		free((char *)lib->soname);
354	lib->soname = new_name;
355	lib->own_soname = own_name;
356}
357
358void
359library_set_pathname(struct library *lib, const char *new_name, int own_name)
360{
361	if (lib->own_pathname)
362		free((char *)lib->pathname);
363	lib->pathname = new_name;
364	lib->own_pathname = own_name;
365}
366
367struct library_symbol *
368library_each_symbol(struct library *lib, struct library_symbol *start_after,
369		    enum callback_status (*cb)(struct library_symbol *, void *),
370		    void *data)
371{
372	struct library_symbol *it = start_after == NULL ? lib->symbols
373		: start_after->next;
374
375	while (it != NULL) {
376		struct library_symbol *next = it->next;
377
378		switch ((*cb)(it, data)) {
379		case CBS_FAIL:
380			/* XXX handle me  */
381		case CBS_STOP:
382			return it;
383		case CBS_CONT:
384			break;
385		}
386
387		it = next;
388	}
389
390	return NULL;
391}
392
393void
394library_add_symbol(struct library *lib, struct library_symbol *first)
395{
396	struct library_symbol *last;
397	for (last = first; last != NULL; ) {
398		last->lib = lib;
399		if (last->next != NULL)
400			last = last->next;
401		else
402			break;
403	}
404
405	assert(last->next == NULL);
406	last->next = lib->symbols;
407	lib->symbols = first;
408}
409
410enum callback_status
411library_named_cb(struct process *proc, struct library *lib, void *name)
412{
413	if (name == lib->soname
414	    || strcmp(lib->soname, (char *)name) == 0)
415		return CBS_STOP;
416	else
417		return CBS_CONT;
418}
419
420enum callback_status
421library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
422{
423	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
424}
425