1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
/*
* This file is part of ltrace.
* Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2006 Paul Gilliam, IBM Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef LIBRARY_H
#define LIBRARY_H
#include <stdint.h>
#include <stdbool.h>
#if defined(HAVE_LIBDW)
# include <elfutils/libdwfl.h>
#endif
#include "dict.h"
#include "callback.h"
#include "forward.h"
#include "sysdep.h"
enum toplt {
LS_TOPLT_NONE = 0, /* PLT not used for this symbol. */
LS_TOPLT_EXEC, /* PLT for this symbol is executable. */
};
/* Dict interface. */
size_t arch_addr_hash(const arch_addr_t *addr);
int arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2);
/* For handling -l and for handling library export aliases (different symbol
* name, same address)
*
* This structure needs to
* - store (addr, name) tuples
* - be searchable by addr (when populating)
* - be searchable by name (when looking for aliases)
* - be enumeratable (by activate_latent_in())
*/
struct library_exported_names {
// I store the data in several structures to facilitate different types
// of access
struct dict names; // maps a name to an address
struct dict addrs; // maps an address to a vect of names
};
struct library_symbol {
struct library_symbol *next;
struct library *lib;
const char *name;
arch_addr_t enter_addr;
enum toplt plt_type;
/* If this is non-NULL, this prototype is used instead of
* looking up one in LIB->protolib. */
struct prototype *proto;
int own_name : 1;
/* This is relevant for PLT symbols. Latent PLT symbols are
* those that don't match any of the -e rules, but that might
* potentially become active if a library implementing them
* appears that matches a -l rule. Ltrace core is responsible
* for clearing latent flag. */
int latent : 1;
/* Delayed symbols are those for which a breakpoint shouldn't
* be enabled yet. They are similar to latent symbols, but
* backend is responsible for clearing the delayed flag. See
* proc_activate_delayed_symbol. */
int delayed : 1;
struct arch_library_symbol_data arch;
struct os_library_symbol_data os;
};
/* Init LIBSYM. NAME will be freed when LIBSYM is destroyed if
* OWN_NAME. ARCH has to be initialized by a separate call. */
int library_symbol_init(struct library_symbol *libsym,
arch_addr_t addr, const char *name, int own_name,
enum toplt type_of_plt);
/* Copy library symbol SYM into the area pointed-to by RETP. Return 0
* on success or a negative value on failure. */
int library_symbol_clone(struct library_symbol *retp,
struct library_symbol *sym);
/* Destroy library symbol. This essentially just frees name if it's
* owned. It doesn't free the memory associated with SYM pointer
* itself. Returns 0 on success or a negative value in case of an
* error (which would be an out of memory condition). */
void library_symbol_destroy(struct library_symbol *sym);
/* Compare two library symbols. Returns a negative value, 0, or a
* positive value, much like strcmp. The function compares symbol
* addresses, and if those are equal, it compares symbol names. If
* those are equal, too, the symbols are considered equal. */
int library_symbol_cmp(struct library_symbol *a, struct library_symbol *b);
/* Set a name for library symbol. This frees the old name, if
* that is owned. */
void library_symbol_set_name(struct library_symbol *libsym,
const char *name, int own_name);
/* A function that can be used as library_each_symbol callback. Looks
* for a symbol SYM for which library_symbol_cmp(SYM, STANDARD)
* returns 0. */
enum callback_status library_symbol_equal_cb(struct library_symbol *libsym,
void *standard);
/* A function that can be used as library_each_symbol callback. Looks
* for a symbol SYM for which strcmp(SYM->name, NAME) == 0. */
enum callback_status library_symbol_named_cb(struct library_symbol *libsym,
void *name);
/* A function that can be used as library_each_symbol callback. Looks
* for a delayed symbol. */
enum callback_status library_symbol_delayed_cb(struct library_symbol *libsym,
void *unused);
enum library_type {
LT_LIBTYPE_MAIN,
LT_LIBTYPE_DSO,
LT_LIBTYPE_SYSCALL,
};
/* XXX we might consider sharing libraries across processes. Things
* like libc will be opened by every single process, no point cloning
* these everywhere. But for now, keep the ownership structure
* simple. */
struct library {
struct library *next;
/* Unique key. Two library objects are considered equal, if
* they have the same key. */
arch_addr_t key;
/* Address where the library is mapped. */
arch_addr_t base;
/* Absolute address of the entry point. Useful for main
* binary, though I suppose the value might be useful for the
* dynamic linker, too (in case we ever want to do early
* process tracing). */
arch_addr_t entry;
/* Address of PT_DYNAMIC segment. */
arch_addr_t dyn_addr;
/* Symbols associated with the library. This includes a
* symbols that don't have a breakpoint attached (yet). */
struct library_symbol *symbols;
/* List of names that this library implements, and that match
* -l filter. Each time a new library is mapped, its list of
* exports is examined, and corresponding PLT slots are
* enabled. This data structure also keeps track of export
* addresses to find symbols with different names, but same
* addresses */
struct library_exported_names exported_names;
/* Prototype library associated with this library. */
struct protolib *protolib;
const char *soname;
const char *pathname;
enum library_type type;
char own_soname : 1;
char own_pathname : 1;
bool should_activate_latent : 1;
struct arch_library_data arch;
struct os_library_data os;
#if defined(HAVE_LIBDW)
Dwfl_Module *dwfl_module;
#endif
};
/* Init LIB. */
int library_init(struct library *lib, enum library_type type);
/* Initialize RETP to a library identical to LIB. Symbols are not
* shared, but copied over. Returns 0 on success and a negative value
* in case of failure. */
int library_clone(struct library *retp, struct library *lib);
/* Destroy library. Doesn't free LIB itself. Symbols are destroyed
* and freed. */
void library_destroy(struct library *lib);
/* Set library soname. Frees the old name if necessary. */
void library_set_soname(struct library *lib,
const char *new_name, int own_name);
/* Set library pathname. Frees the old name if necessary. */
void library_set_pathname(struct library *lib,
const char *new_name, int own_name);
/* Iterate through list of symbols of library LIB. See callback.h for
* notes on this interface. */
struct library_symbol *library_each_symbol
(struct library *lib, struct library_symbol *start_after,
enum callback_status (*cb)(struct library_symbol *, void *),
void *data);
/* Add a new symbol SYM to LIB. SYM is assumed owned, we need to
* overwrite SYM->next. */
void library_add_symbol(struct library *lib, struct library_symbol *sym);
/* A function that can be used as proc_each_library callback. Looks
* for a library with the name passed in DATA. PROC is ignored. */
enum callback_status library_named_cb(struct process *proc,
struct library *lib, void *name);
/* A function that can be used as proc_each_library callback. Looks
* for a library with given base.
*
* NOTE: The key is passed as a POINTER to arch_addr_t (that
* because in general, arch_addr_t doesn't fit in void*). */
enum callback_status library_with_key_cb(struct process *proc,
struct library *lib, void *keyp);
/* XXX this should really be in backend.h (as on pmachata/revamp
* branch), or, on this branch, in common.h. But we need
* arch_addr_t (which should also be in backend.h, I reckon), so
* stuff it here for the time being. */
/* This function is implemented in the back end. It is called for all
* raw addresses as read from symbol tables etc. If necessary on
* given architecture, this function should translate the address
* according to .opd or other indirection mechanism. Returns 0 on
* success and a negative value on failure. */
struct ltelf;
int arch_translate_address(struct ltelf *lte,
arch_addr_t addr, arch_addr_t *ret);
/* This is the same function as arch_translate_address, except it's
* used at the point that we don't have ELF available anymore. */
int arch_translate_address_dyn(struct process *proc,
arch_addr_t addr, arch_addr_t *ret);
/* Pushes a name/address tuple to the list of a library's exports. Returns 0 on
* success
*/
int library_exported_names_push(struct library_exported_names *names,
uint64_t addr, char *name,
int own_name );
/* Iterates through the a library's export list, reporting each symbol that is
* an alias of the given 'aliasname' symbol. This 'aliasname' symbol itself is
* NOT reported, so if this symbol is unique, the callback is not called at all.
*
* If we want to iterate through the whole alias list, set
* name_start_after=NULL. If we want to start iterating immediately past a
* particular symbol name, pass a pointer to this symbol name in
* name_start_after. This must be a pointer in the internal dict, preferably
* returned by an earlier call to this function
*
* If the callback fails at any point, a pointer to the failing key is returned.
* On success, returns NULL. The returned pointer can be passed back to this
* function in name_start_after to resume skipping this element
*/
const char** library_exported_names_each_alias(
struct library_exported_names *names,
const char *aliasname,
const char **name_start_after,
enum callback_status (*cb)(const char *,
void *),
void *data);
/* Returns 0 if the exported names list does not contain a given name, or 1 if
* it does */
int library_exported_names_contains(struct library_exported_names *names,
const char *queryname);
#endif /* LIBRARY_H */
|