library.c revision 0b55b5852b9fe2ed6cceada004db303fe6efe6ce
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 && libsym->own_name)
63		free((char *)libsym->name);
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
95enum callback_status
96library_symbol_equal_cb(struct library_symbol *libsym, void *u)
97{
98	struct library_symbol *standard = u;
99	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
100}
101
102void
103library_init(struct library *lib)
104{
105	lib->next = NULL;
106	lib->soname = NULL;
107	lib->own_soname = 0;
108	lib->pathname = NULL;
109	lib->own_pathname = 0;
110	lib->symbols = NULL;
111}
112
113int
114library_clone(struct library *retp, struct library *lib)
115{
116	const char *soname = NULL;
117	const char *pathname;
118	if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
119	     || strdup_if_owned(&pathname,
120				lib->pathname, lib->own_pathname) < 0) {
121		if (lib->own_soname)
122			free((char *)soname);
123		return -1;
124	}
125
126	library_init(retp);
127	library_set_soname(lib, soname, lib->own_soname);
128	library_set_soname(lib, pathname, lib->own_pathname);
129
130	struct library_symbol *it;
131	struct library_symbol **nsymp = &retp->symbols;
132	for (it = lib->symbols; it != NULL; it = it->next) {
133		*nsymp = malloc(sizeof(**nsymp));
134		if (*nsymp == NULL
135		    || library_symbol_clone(*nsymp, it) < 0) {
136			/* Release what we managed to allocate.  */
137			library_destroy(retp);
138			return -1;
139		}
140
141		(*nsymp)->lib = retp;
142		nsymp = &(*nsymp)->next;
143	}
144	return 0;
145}
146
147void
148library_destroy(struct library *lib)
149{
150	if (lib == NULL)
151		return;
152	library_set_soname(lib, NULL, 0);
153	library_set_pathname(lib, NULL, 0);
154
155	struct library_symbol *sym;
156	for (sym = lib->symbols; sym != NULL; ) {
157		struct library_symbol *next = sym->next;
158		library_symbol_destroy(sym);
159		free(sym);
160		sym = next;
161	}
162}
163
164void
165library_set_soname(struct library *lib, const char *new_name, int own_name)
166{
167	if (lib->own_soname)
168		free((char *)lib->soname);
169	lib->soname = new_name;
170	lib->own_soname = own_name;
171}
172
173void
174library_set_pathname(struct library *lib, const char *new_name, int own_name)
175{
176	if (lib->own_pathname)
177		free((char *)lib->pathname);
178	lib->pathname = new_name;
179	lib->own_pathname = own_name;
180}
181
182struct library_symbol *
183library_each_symbol(struct library *lib, struct library_symbol *start_after,
184		    enum callback_status (*cb)(struct library_symbol *, void *),
185		    void *data)
186{
187	struct library_symbol *it = start_after == NULL ? lib->symbols
188		: start_after->next;
189
190	while (it != NULL) {
191		struct library_symbol *next = it->next;
192
193		switch ((*cb)(it, data)) {
194		case CBS_FAIL:
195			/* XXX handle me  */
196		case CBS_STOP:
197			return it;
198		case CBS_CONT:
199			break;
200		}
201
202		it = next;
203	}
204
205	return NULL;
206}
207
208void
209library_add_symbol(struct library *lib, struct library_symbol *first)
210{
211	struct library_symbol *last;
212	for (last = first; last != NULL; ) {
213		last->lib = lib;
214		if (last->next != NULL)
215			last = last->next;
216		else
217			break;
218	}
219
220	assert(last->next == NULL);
221	last->next = lib->symbols;
222	lib->symbols = first;
223}
224
225enum callback_status
226library_named_cb(struct Process *proc, struct library *lib, void *name)
227{
228	if (name == lib->soname
229	    || strcmp(lib->soname, (char *)name) == 0)
230		return CBS_STOP;
231	else
232		return CBS_CONT;
233}
234
235enum callback_status
236library_with_base_cb(struct Process *proc, struct library *lib, void *basep)
237{
238	return lib->base == *(target_address_t *)basep ? CBS_STOP : CBS_CONT;
239}
240