library.c revision 157cc4d6ee93f35e3aa65edcf57f369ae4e4677c
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
31/* If the other symbol owns the name, we need to make the copy, so
32 * that the life-times of the two symbols are not dependent on each
33 * other.  */
34static int
35strdup_if_owned(const char **retp, const char *str, int owned)
36{
37	if (!owned || str == NULL) {
38		*retp = str;
39		return 0;
40	} else {
41		*retp = strdup(str);
42		return *retp != NULL ? 0 : -1;
43	}
44}
45
46void
47library_symbol_init(struct library_symbol *libsym,
48		    target_address_t addr, const char *name, int own_name,
49		    enum toplt type_of_plt)
50{
51	libsym->next = NULL;
52	libsym->lib = NULL;
53	libsym->plt_type = type_of_plt;
54	libsym->name = name;
55	libsym->own_name = own_name;
56	libsym->enter_addr = (void *)(uintptr_t)addr;
57}
58
59void
60library_symbol_destroy(struct library_symbol *libsym)
61{
62	if (libsym != NULL)
63		library_symbol_set_name(libsym, NULL, 0);
64}
65
66int
67library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
68{
69	const char *name;
70	if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0)
71		return -1;
72
73	library_symbol_init(retp, libsym->enter_addr,
74			    name, libsym->own_name, libsym->plt_type);
75	return 0;
76}
77
78int
79library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
80{
81	if (a->enter_addr < b->enter_addr)
82		return -1;
83	if (a->enter_addr > b->enter_addr)
84		return 1;
85	if (a->name != NULL && b->name != NULL)
86		return strcmp(a->name, b->name);
87	if (a->name == NULL) {
88		if (b->name == NULL)
89			return 0;
90		return -1;
91	}
92	return 1;
93}
94
95void
96library_symbol_set_name(struct library_symbol *libsym,
97			const char *name, int own_name)
98{
99	if (libsym->own_name)
100		free((char *)libsym->name);
101	libsym->name = name;
102	libsym->own_name = own_name;
103}
104
105enum callback_status
106library_symbol_equal_cb(struct library_symbol *libsym, void *u)
107{
108	struct library_symbol *standard = u;
109	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
110}
111
112void
113library_init(struct library *lib, enum library_type type)
114{
115	lib->next = NULL;
116	lib->soname = NULL;
117	lib->own_soname = 0;
118	lib->pathname = NULL;
119	lib->own_pathname = 0;
120	lib->symbols = NULL;
121	lib->type = type;
122}
123
124int
125library_clone(struct library *retp, struct library *lib)
126{
127	const char *soname = NULL;
128	const char *pathname;
129	if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
130	     || strdup_if_owned(&pathname,
131				lib->pathname, lib->own_pathname) < 0) {
132		if (lib->own_soname)
133			free((char *)soname);
134		return -1;
135	}
136
137	library_init(retp, lib->type);
138	library_set_soname(retp, soname, lib->own_soname);
139	library_set_soname(retp, pathname, lib->own_pathname);
140
141	struct library_symbol *it;
142	struct library_symbol **nsymp = &retp->symbols;
143	for (it = lib->symbols; it != NULL; it = it->next) {
144		*nsymp = malloc(sizeof(**nsymp));
145		if (*nsymp == NULL
146		    || library_symbol_clone(*nsymp, it) < 0) {
147			/* Release what we managed to allocate.  */
148			library_destroy(retp);
149			return -1;
150		}
151
152		(*nsymp)->lib = retp;
153		nsymp = &(*nsymp)->next;
154	}
155	return 0;
156}
157
158void
159library_destroy(struct library *lib)
160{
161	if (lib == NULL)
162		return;
163	library_set_soname(lib, NULL, 0);
164	library_set_pathname(lib, NULL, 0);
165
166	struct library_symbol *sym;
167	for (sym = lib->symbols; sym != NULL; ) {
168		struct library_symbol *next = sym->next;
169		library_symbol_destroy(sym);
170		free(sym);
171		sym = next;
172	}
173}
174
175void
176library_set_soname(struct library *lib, const char *new_name, int own_name)
177{
178	if (lib->own_soname)
179		free((char *)lib->soname);
180	lib->soname = new_name;
181	lib->own_soname = own_name;
182}
183
184void
185library_set_pathname(struct library *lib, const char *new_name, int own_name)
186{
187	if (lib->own_pathname)
188		free((char *)lib->pathname);
189	lib->pathname = new_name;
190	lib->own_pathname = own_name;
191}
192
193struct library_symbol *
194library_each_symbol(struct library *lib, struct library_symbol *start_after,
195		    enum callback_status (*cb)(struct library_symbol *, void *),
196		    void *data)
197{
198	struct library_symbol *it = start_after == NULL ? lib->symbols
199		: start_after->next;
200
201	while (it != NULL) {
202		struct library_symbol *next = it->next;
203
204		switch ((*cb)(it, data)) {
205		case CBS_FAIL:
206			/* XXX handle me  */
207		case CBS_STOP:
208			return it;
209		case CBS_CONT:
210			break;
211		}
212
213		it = next;
214	}
215
216	return NULL;
217}
218
219void
220library_add_symbol(struct library *lib, struct library_symbol *first)
221{
222	struct library_symbol *last;
223	for (last = first; last != NULL; ) {
224		last->lib = lib;
225		if (last->next != NULL)
226			last = last->next;
227		else
228			break;
229	}
230
231	assert(last->next == NULL);
232	last->next = lib->symbols;
233	lib->symbols = first;
234}
235
236enum callback_status
237library_named_cb(struct Process *proc, struct library *lib, void *name)
238{
239	if (name == lib->soname
240	    || strcmp(lib->soname, (char *)name) == 0)
241		return CBS_STOP;
242	else
243		return CBS_CONT;
244}
245
246enum callback_status
247library_with_key_cb(struct Process *proc, struct library *lib, void *keyp)
248{
249	return lib->key == *(target_address_t *)keyp ? CBS_STOP : CBS_CONT;
250}
251