library.c revision b931085e37224dd2932fb637eaba5da29c4c5eb7
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->is_weak = is_weak;
52	libsym->plt_type = type_of_plt;
53	libsym->name = name;
54	libsym->own_name = own_name;
55	libsym->enter_addr = (void *)(uintptr_t)addr;
56}
57
58void
59library_symbol_destroy(struct library_symbol *libsym)
60{
61	if (libsym != NULL && libsym->own_name)
62		free((char *)libsym->name);
63}
64
65int
66library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
67{
68	const char *name;
69	if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0)
70		return -1;
71
72	library_symbol_init(retp, libsym->lib, libsym->enter_addr,
73			    name, libsym->own_name, libsym->plt_type,
74			    libsym->is_weak);
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, const char *name, int own_name)
104{
105	lib->next = NULL;
106	lib->name = name;
107	lib->own_name = own_name;
108	lib->symbols = NULL;
109}
110
111int
112library_clone(struct library *retp, struct library *lib)
113{
114	const char *name;
115	if (strdup_if_owned(&name, lib->name, lib->own_name) < 0)
116		return -1;
117
118	library_init(retp, lib->name, lib->own_name);
119
120	struct library_symbol *it;
121	struct library_symbol **nsymp = &retp->symbols;
122	for (it = lib->symbols; it != NULL; it = it->next) {
123		*nsymp = malloc(sizeof(**nsymp));
124		if (*nsymp == NULL
125		    || library_symbol_clone(*nsymp, it) < 0) {
126			/* Release what we managed to allocate.  */
127			library_destroy(retp);
128			return -1;
129		}
130
131		(*nsymp)->lib = retp;
132		nsymp = &(*nsymp)->next;
133	}
134	return 0;
135}
136
137void
138library_destroy(struct library *lib)
139{
140	if (lib == NULL)
141		return;
142	library_set_name(lib, NULL, 0);
143
144	struct library_symbol *sym;
145	for (sym = lib->symbols; sym != NULL; ) {
146		struct library_symbol *next = sym->next;
147		library_symbol_destroy(sym);
148		free(sym);
149		sym = next;
150	}
151}
152
153void
154library_set_name(struct library *lib, const char *new_name, int own_name)
155{
156	if (lib->own_name)
157		free((char *)lib->name);
158	lib->name = new_name;
159	lib->own_name = own_name;
160}
161
162struct library_symbol *
163library_each_symbol(struct library *lib, struct library_symbol *start_after,
164		    enum callback_status (*cb)(struct library_symbol *, void *),
165		    void *data)
166{
167	struct library_symbol *it = start_after == NULL ? lib->symbols
168		: start_after->next;
169
170	while (it != NULL) {
171		struct library_symbol *next = it->next;
172
173		switch ((*cb)(it, data)) {
174		case CBS_STOP:
175			return it;
176		case CBS_CONT:
177			break;
178		}
179
180		it = next;
181	}
182
183	return NULL;
184}
185
186void
187library_add_symbol(struct library *lib, struct library_symbol *sym)
188{
189	sym->next = lib->symbols;
190	lib->symbols = sym;
191}
192
193enum callback_status
194library_named_cb(struct Process *proc, struct library *lib, void *name)
195{
196	if (name == lib->name
197	    || strcmp(lib->name, (char *)name) == 0)
198		return CBS_STOP;
199	else
200		return CBS_CONT;
201}
202
203enum callback_status
204library_with_base_cb(struct Process *proc, struct library *lib, void *basep)
205{
206	return lib->base == *(target_address_t *)basep ? CBS_STOP : CBS_CONT;
207}
208