1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 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 OS_HAVE_LIBRARY_DATA
35int
36os_library_init(struct library *lib)
37{
38	return 0;
39}
40
41void
42os_library_destroy(struct library *lib)
43{
44}
45
46int
47os_library_clone(struct library *retp, struct library *lib)
48{
49	return 0;
50}
51#endif
52
53#ifndef ARCH_HAVE_LIBRARY_DATA
54int
55arch_library_init(struct library *lib)
56{
57	return 0;
58}
59
60void
61arch_library_destroy(struct library *lib)
62{
63}
64
65int
66arch_library_clone(struct library *retp, struct library *lib)
67{
68	return 0;
69}
70#endif
71
72#ifndef OS_HAVE_LIBRARY_SYMBOL_DATA
73int
74os_library_symbol_init(struct library_symbol *libsym)
75{
76	return 0;
77}
78
79void
80os_library_symbol_destroy(struct library_symbol *libsym)
81{
82}
83
84int
85os_library_symbol_clone(struct library_symbol *retp,
86			struct library_symbol *libsym)
87{
88	return 0;
89}
90#endif
91
92#ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
93int
94arch_library_symbol_init(struct library_symbol *libsym)
95{
96	return 0;
97}
98
99void
100arch_library_symbol_destroy(struct library_symbol *libsym)
101{
102}
103
104int
105arch_library_symbol_clone(struct library_symbol *retp,
106			  struct library_symbol *libsym)
107{
108	return 0;
109}
110#endif
111
112size_t
113arch_addr_hash(const arch_addr_t *addr)
114{
115	union {
116		arch_addr_t addr;
117		int ints[sizeof(arch_addr_t)
118			 / sizeof(unsigned int)];
119	} u = { .addr = *addr };
120
121	size_t i;
122	size_t h = 0;
123	for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
124		h ^= dict_hash_int(&u.ints[i]);
125	return h;
126}
127
128int
129arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
130{
131	return *addr1 == *addr2;
132}
133
134int
135strdup_if(const char **retp, const char *str, int whether)
136{
137	if (whether && str != NULL) {
138		str = strdup(str);
139		if (str == NULL)
140			return -1;
141	}
142
143	*retp = str;
144	return 0;
145}
146
147static void
148private_library_symbol_init(struct library_symbol *libsym,
149			    arch_addr_t addr,
150			    const char *name, int own_name,
151			    enum toplt type_of_plt,
152			    int latent, int delayed)
153{
154	libsym->next = NULL;
155	libsym->lib = NULL;
156	libsym->plt_type = type_of_plt;
157	libsym->name = name;
158	libsym->own_name = own_name;
159	libsym->latent = latent;
160	libsym->delayed = delayed;
161	libsym->enter_addr = (void *)(uintptr_t)addr;
162	libsym->proto = NULL;
163}
164
165static void
166private_library_symbol_destroy(struct library_symbol *libsym)
167{
168	library_symbol_set_name(libsym, NULL, 0);
169}
170
171int
172library_symbol_init(struct library_symbol *libsym,
173		    arch_addr_t addr, const char *name, int own_name,
174		    enum toplt type_of_plt)
175{
176	private_library_symbol_init(libsym, addr, name, own_name,
177				    type_of_plt, 0, 0);
178
179	if (os_library_symbol_init(libsym) < 0)
180		/* We've already set libsym->name and own_name.  But
181		 * we return failure, and the client code isn't
182		 * supposed to call library_symbol_destroy in such
183		 * case.  */
184		return -1;
185
186	if (arch_library_symbol_init(libsym) < 0) {
187		os_library_symbol_destroy(libsym);
188		return -1;
189	}
190
191	return 0;
192}
193
194void
195library_symbol_destroy(struct library_symbol *libsym)
196{
197	if (libsym != NULL) {
198		arch_library_symbol_destroy(libsym);
199		os_library_symbol_destroy(libsym);
200		private_library_symbol_destroy(libsym);
201	}
202}
203
204int
205library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
206{
207	/* Make lifetimes of name stored at original independent of
208	 * the one at the clone.  */
209	const char *name;
210	if (strdup_if(&name, libsym->name, libsym->own_name) < 0)
211		return -1;
212
213	private_library_symbol_init(retp, libsym->enter_addr,
214				    name, libsym->own_name, libsym->plt_type,
215				    libsym->latent, libsym->delayed);
216
217	if (os_library_symbol_clone(retp, libsym) < 0) {
218	fail:
219		private_library_symbol_destroy(retp);
220		return -1;
221	}
222
223	if (arch_library_symbol_clone(retp, libsym) < 0) {
224		os_library_symbol_destroy(retp);
225		goto fail;
226	}
227
228	return 0;
229}
230
231int
232library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
233{
234	if (a->enter_addr < b->enter_addr)
235		return -1;
236	if (a->enter_addr > b->enter_addr)
237		return 1;
238	if (a->name != NULL && b->name != NULL)
239		return strcmp(a->name, b->name);
240	if (a->name == NULL) {
241		if (b->name == NULL)
242			return 0;
243		return -1;
244	}
245	return 1;
246}
247
248void
249library_symbol_set_name(struct library_symbol *libsym,
250			const char *name, int own_name)
251{
252	if (libsym->own_name)
253		free((char *)libsym->name);
254	libsym->name = name;
255	libsym->own_name = own_name;
256}
257
258enum callback_status
259library_symbol_equal_cb(struct library_symbol *libsym, void *u)
260{
261	struct library_symbol *standard = u;
262	return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
263}
264
265enum callback_status
266library_symbol_named_cb(struct library_symbol *libsym, void *name)
267{
268	return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
269}
270
271enum callback_status
272library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
273{
274	return libsym->delayed ? CBS_STOP : CBS_CONT;
275}
276
277static void
278private_library_init(struct library *lib, enum library_type type)
279{
280	lib->next = NULL;
281
282	lib->key = 0;
283	lib->base = 0;
284	lib->entry = 0;
285	lib->dyn_addr = 0;
286	lib->protolib = NULL;
287
288	lib->soname = NULL;
289	lib->own_soname = 0;
290
291	lib->pathname = NULL;
292	lib->own_pathname = 0;
293
294	lib->symbols = NULL;
295	lib->exported_names = NULL;
296	lib->type = type;
297}
298
299int
300library_init(struct library *lib, enum library_type type)
301{
302	private_library_init(lib, type);
303
304	if (os_library_init(lib) < 0)
305		return -1;
306
307	if (arch_library_init(lib) < 0) {
308		os_library_destroy(lib);
309		return -1;
310	}
311
312	return 0;
313}
314
315static int
316library_exported_name_clone(struct library_exported_name *retp,
317			    struct library_exported_name *exnm)
318{
319	char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
320	if (name == NULL)
321		return -1;
322	retp->name = name;
323	retp->own_name = exnm->own_name;
324	return 0;
325}
326
327int
328library_clone(struct library *retp, struct library *lib)
329{
330	const char *soname = NULL;
331	const char *pathname;
332
333	/* Make lifetimes of strings stored at original independent of
334	 * those at the clone.  */
335	if (strdup_if(&soname, lib->soname, lib->own_soname) < 0
336	    || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) {
337		if (lib->own_soname)
338			free((char *)soname);
339		return -1;
340	}
341
342	private_library_init(retp, lib->type);
343	library_set_soname(retp, soname, lib->own_soname);
344	library_set_pathname(retp, pathname, lib->own_pathname);
345
346	retp->key = lib->key;
347
348	/* Clone symbols.  */
349	{
350		struct library_symbol *it;
351		struct library_symbol **nsymp = &retp->symbols;
352		for (it = lib->symbols; it != NULL; it = it->next) {
353			*nsymp = malloc(sizeof(**nsymp));
354			if (*nsymp == NULL
355			    || library_symbol_clone(*nsymp, it) < 0) {
356				free(*nsymp);
357				*nsymp = NULL;
358			fail:
359				/* Release what we managed to allocate.  */
360				library_destroy(retp);
361				return -1;
362			}
363
364			(*nsymp)->lib = retp;
365			nsymp = &(*nsymp)->next;
366		}
367		*nsymp = NULL;
368	}
369
370	/* Clone exported names.  */
371	{
372		struct library_exported_name *it;
373		struct library_exported_name **nnamep = &retp->exported_names;
374		for (it = lib->exported_names; it != NULL; it = it->next) {
375			*nnamep = malloc(sizeof(**nnamep));
376			if (*nnamep == NULL
377			    || library_exported_name_clone(*nnamep, it) < 0) {
378				free(*nnamep);
379				goto fail;
380			}
381			nnamep = &(*nnamep)->next;
382		}
383		*nnamep = NULL;
384	}
385
386	if (os_library_clone(retp, lib) < 0)
387		goto fail;
388
389	if (arch_library_clone(retp, lib) < 0) {
390		os_library_destroy(retp);
391		goto fail;
392	}
393
394	return 0;
395}
396
397void
398library_destroy(struct library *lib)
399{
400	if (lib == NULL)
401		return;
402
403	arch_library_destroy(lib);
404	os_library_destroy(lib);
405
406	library_set_soname(lib, NULL, 0);
407	library_set_pathname(lib, NULL, 0);
408
409	struct library_symbol *sym;
410	for (sym = lib->symbols; sym != NULL; ) {
411		struct library_symbol *next = sym->next;
412		library_symbol_destroy(sym);
413		free(sym);
414		sym = next;
415	}
416
417	/* Release exported names.  */
418	struct library_exported_name *it;
419	for (it = lib->exported_names; it != NULL; ) {
420		struct library_exported_name *next = it->next;
421		if (it->own_name)
422			free((char *)it->name);
423		free(it);
424		it = next;
425	}
426}
427
428void
429library_set_soname(struct library *lib, const char *new_name, int own_name)
430{
431	if (lib->own_soname)
432		free((char *)lib->soname);
433	lib->soname = new_name;
434	lib->own_soname = own_name;
435}
436
437void
438library_set_pathname(struct library *lib, const char *new_name, int own_name)
439{
440	if (lib->own_pathname)
441		free((char *)lib->pathname);
442	lib->pathname = new_name;
443	lib->own_pathname = own_name;
444}
445
446struct library_symbol *
447library_each_symbol(struct library *lib, struct library_symbol *start_after,
448		    enum callback_status (*cb)(struct library_symbol *, void *),
449		    void *data)
450{
451	struct library_symbol *it = start_after == NULL ? lib->symbols
452		: start_after->next;
453
454	while (it != NULL) {
455		struct library_symbol *next = it->next;
456
457		switch ((*cb)(it, data)) {
458		case CBS_FAIL:
459			/* XXX handle me  */
460		case CBS_STOP:
461			return it;
462		case CBS_CONT:
463			break;
464		}
465
466		it = next;
467	}
468
469	return NULL;
470}
471
472void
473library_add_symbol(struct library *lib, struct library_symbol *first)
474{
475	struct library_symbol *last;
476	for (last = first; last != NULL; ) {
477		last->lib = lib;
478		if (last->next != NULL)
479			last = last->next;
480		else
481			break;
482	}
483
484	assert(last->next == NULL);
485	last->next = lib->symbols;
486	lib->symbols = first;
487}
488
489enum callback_status
490library_named_cb(struct process *proc, struct library *lib, void *name)
491{
492	if (name == lib->soname
493	    || strcmp(lib->soname, (char *)name) == 0)
494		return CBS_STOP;
495	else
496		return CBS_CONT;
497}
498
499enum callback_status
500library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
501{
502	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
503}
504