library.c revision 522a6ca083c8b9e964548b0e79a4bdc8095d6e2e
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 "library.h"
26#include "proc.h" // for enum callback_status
27#include "debug.h"
28
29/* If the other symbol owns the name, we need to make the copy, so
30 * that the life-times of the two symbols are not dependent on each
31 * other.  */
32static int
33strdup_if_owned(const char **retp, const char *str, int owned)
34{
35	if (!owned || str == NULL) {
36		*retp = str;
37		return 0;
38	} else {
39		*retp = strdup(str);
40		return *retp != NULL ? 0 : -1;
41	}
42}
43
44void
45library_symbol_init(struct library_symbol *libsym, struct library *lib,
46		    target_address_t addr, const char *name, int own_name,
47		    enum toplt type_of_plt, int is_weak)
48{
49	libsym->next = NULL;
50	libsym->lib = lib;
51	libsym->needs_init = 0;
52	libsym->is_weak = is_weak;
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->lib, libsym->enter_addr,
74			    name, libsym->own_name, libsym->plt_type,
75			    libsym->is_weak);
76	retp->needs_init = libsym->needs_init;
77	return 0;
78}
79
80int
81library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
82{
83	if (a->enter_addr < b->enter_addr)
84		return -1;
85	if (a->enter_addr > b->enter_addr)
86		return 1;
87	if (a->name != NULL && b->name != NULL)
88		return strcmp(a->name, b->name);
89	if (a->name == NULL) {
90		if (b->name == NULL)
91			return 0;
92		return -1;
93	}
94	return 1;
95}
96
97enum callback_status
98library_symbol_equal_cb(struct library_symbol *libsym, void *u)
99{
100	struct library_symbol *standard = u;
101	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
102}
103
104void
105library_init(struct library *lib, const char *name, int own_name)
106{
107	lib->next = NULL;
108	lib->name = name;
109	lib->own_name = own_name;
110	lib->symbols = NULL;
111}
112
113int
114library_clone(struct library *retp, struct library *lib)
115{
116	const char *name;
117	if (strdup_if_owned(&name, lib->name, lib->own_name) < 0)
118		return -1;
119
120	library_init(retp, lib->name, lib->own_name);
121
122	struct library_symbol *it;
123	struct library_symbol **nsymp = &retp->symbols;
124	for (it = lib->symbols; it != NULL; it = it->next) {
125		*nsymp = malloc(sizeof(**nsymp));
126		if (*nsymp == NULL
127		    || library_symbol_clone(*nsymp, it) < 0) {
128			/* Release what we managed to allocate.  */
129			library_destroy(retp);
130			return -1;
131		}
132
133		(*nsymp)->lib = retp;
134		nsymp = &(*nsymp)->next;
135	}
136	return 0;
137}
138
139void
140library_destroy(struct library *lib)
141{
142	if (lib == NULL)
143		return;
144	library_set_name(lib, NULL, 0);
145
146	struct library_symbol *sym;
147	for (sym = lib->symbols; sym != NULL; ) {
148		struct library_symbol *next = sym->next;
149		library_symbol_destroy(sym);
150		free(sym);
151		sym = next;
152	}
153}
154
155void
156library_set_name(struct library *lib, const char *new_name, int own_name)
157{
158	if (lib->own_name)
159		free((char *)lib->name);
160	lib->name = new_name;
161	lib->own_name = own_name;
162}
163
164struct library_symbol *
165library_each_symbol(struct library *lib, struct library_symbol *it,
166		    enum callback_status (*cb)(struct library_symbol *, void *),
167		    void *data)
168{
169	if (it == NULL)
170		it = lib->symbols;
171
172	while (it != NULL) {
173		struct library_symbol *next = it->next;
174
175		switch ((*cb)(it, data)) {
176		case CBS_STOP:
177			return it;
178		case CBS_CONT:
179			break;
180		}
181
182		it = next;
183	}
184
185	return NULL;
186}
187
188void
189library_add_symbol(struct library *lib, struct library_symbol *sym)
190{
191	sym->next = lib->symbols;
192	lib->symbols = sym;
193}
194
195enum callback_status
196library_named_cb(struct Process *proc, struct library *lib, void *name)
197{
198	if (name == lib->name
199	    || strcmp(lib->name, (char *)name) == 0)
200		return CBS_STOP;
201	else
202		return CBS_CONT;
203}
204
205enum callback_status
206library_with_base_cb(struct Process *proc, struct library *lib, void *basep)
207{
208	return lib->base == *(target_address_t *)basep ? CBS_STOP : CBS_CONT;
209}
210