/src/binutils-gdb/libctf/ctf-lookup.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Symbol, variable and name lookup. |
2 | | Copyright (C) 2019-2025 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of libctf. |
5 | | |
6 | | libctf is free software; you can redistribute it and/or modify it under |
7 | | the terms of the GNU General Public License as published by the Free |
8 | | Software Foundation; either version 3, or (at your option) any later |
9 | | version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, but |
12 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
14 | | See the GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; see the file COPYING. If not see |
18 | | <http://www.gnu.org/licenses/>. */ |
19 | | |
20 | | #include <ctf-impl.h> |
21 | | #include <elf.h> |
22 | | #include <string.h> |
23 | | #include <assert.h> |
24 | | |
25 | | /* Grow the pptrtab so that it is at least NEW_LEN long. */ |
26 | | static int |
27 | | grow_pptrtab (ctf_dict_t *fp, size_t new_len) |
28 | 0 | { |
29 | 0 | uint32_t *new_pptrtab; |
30 | |
|
31 | 0 | if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t) |
32 | 0 | * new_len)) == NULL) |
33 | 0 | return (ctf_set_errno (fp, ENOMEM)); |
34 | | |
35 | 0 | fp->ctf_pptrtab = new_pptrtab; |
36 | |
|
37 | 0 | memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0, |
38 | 0 | sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len)); |
39 | |
|
40 | 0 | fp->ctf_pptrtab_len = new_len; |
41 | 0 | return 0; |
42 | 0 | } |
43 | | |
44 | | /* Update entries in the pptrtab that relate to types newly added in the |
45 | | child. */ |
46 | | static int |
47 | | refresh_pptrtab (ctf_dict_t *fp, ctf_dict_t *pfp) |
48 | 0 | { |
49 | 0 | uint32_t i; |
50 | 0 | for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++) |
51 | 0 | { |
52 | 0 | ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1); |
53 | 0 | ctf_id_t reffed_type; |
54 | |
|
55 | 0 | if (ctf_type_kind (fp, type) != CTF_K_POINTER) |
56 | 0 | continue; |
57 | | |
58 | 0 | reffed_type = ctf_type_reference (fp, type); |
59 | |
|
60 | 0 | if (LCTF_TYPE_ISPARENT (fp, reffed_type)) |
61 | 0 | { |
62 | 0 | uint32_t idx = LCTF_TYPE_TO_INDEX (fp, reffed_type); |
63 | | |
64 | | /* Guard against references to invalid types. No need to consider |
65 | | the CTF dict corrupt in this case: this pointer just can't be a |
66 | | pointer to any type we know about. */ |
67 | 0 | if (idx <= pfp->ctf_typemax) |
68 | 0 | { |
69 | 0 | if (idx >= fp->ctf_pptrtab_len |
70 | 0 | && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0) |
71 | 0 | return -1; /* errno is set for us. */ |
72 | | |
73 | 0 | fp->ctf_pptrtab[idx] = i; |
74 | 0 | } |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | 0 | fp->ctf_pptrtab_typemax = fp->ctf_typemax; |
79 | |
|
80 | 0 | return 0; |
81 | 0 | } |
82 | | |
83 | | /* Compare the given input string and length against a table of known C storage |
84 | | qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To |
85 | | do this quickly, we use a pre-computed Perfect Hash Function similar to the |
86 | | technique originally described in the classic paper: |
87 | | |
88 | | R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple", |
89 | | Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19. |
90 | | |
91 | | For an input string S of length N, we use hash H = S[N - 1] + N - 105, which |
92 | | for the current set of qualifiers yields a unique H in the range [0 .. 20]. |
93 | | The hash can be modified when the keyword set changes as necessary. We also |
94 | | store the length of each keyword and check it prior to the final strcmp(). |
95 | | |
96 | | TODO: just use gperf. */ |
97 | | |
98 | | static int |
99 | | isqualifier (const char *s, size_t len) |
100 | 0 | { |
101 | 0 | static const struct qual |
102 | 0 | { |
103 | 0 | const char *q_name; |
104 | 0 | size_t q_len; |
105 | 0 | } qhash[] = { |
106 | 0 | {"static", 6}, {"", 0}, {"", 0}, {"", 0}, |
107 | 0 | {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, |
108 | 0 | {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0}, |
109 | 0 | {"", 0}, {"", 0}, {"const", 5}, {"register", 8}, |
110 | 0 | {"", 0}, {"restrict", 8}, {"_Restrict", 9} |
111 | 0 | }; |
112 | |
|
113 | 0 | int h = s[len - 1] + (int) len - 105; |
114 | 0 | const struct qual *qp; |
115 | |
|
116 | 0 | if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0])) |
117 | 0 | return 0; |
118 | | |
119 | 0 | qp = &qhash[h]; |
120 | |
|
121 | 0 | return ((size_t) len == qp->q_len && |
122 | 0 | strncmp (qp->q_name, s, qp->q_len) == 0); |
123 | 0 | } |
124 | | |
125 | | /* Attempt to convert the given C type name into the corresponding CTF type ID. |
126 | | It is not possible to do complete and proper conversion of type names |
127 | | without implementing a more full-fledged parser, which is necessary to |
128 | | handle things like types that are function pointers to functions that |
129 | | have arguments that are function pointers, and fun stuff like that. |
130 | | Instead, this function implements a very simple conversion algorithm that |
131 | | finds the things that we actually care about: structs, unions, enums, |
132 | | integers, floats, typedefs, and pointers to any of these named types. */ |
133 | | |
134 | | static ctf_id_t |
135 | | ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child, |
136 | | const char *name) |
137 | 0 | { |
138 | 0 | static const char delimiters[] = " \t\n\r\v\f*"; |
139 | |
|
140 | 0 | const ctf_lookup_t *lp; |
141 | 0 | const char *p, *q, *end; |
142 | 0 | ctf_id_t type = 0; |
143 | 0 | ctf_id_t ntype, ptype; |
144 | |
|
145 | 0 | if (name == NULL) |
146 | 0 | return (ctf_set_typed_errno (fp, EINVAL)); |
147 | | |
148 | 0 | for (p = name, end = name + strlen (name); *p != '\0'; p = q) |
149 | 0 | { |
150 | 0 | while (isspace ((int) *p)) |
151 | 0 | p++; /* Skip leading whitespace. */ |
152 | |
|
153 | 0 | if (p == end) |
154 | 0 | break; |
155 | | |
156 | 0 | if ((q = strpbrk (p + 1, delimiters)) == NULL) |
157 | 0 | q = end; /* Compare until end. */ |
158 | |
|
159 | 0 | if (*p == '*') |
160 | 0 | { |
161 | | /* Find a pointer to type by looking in child->ctf_pptrtab (if child |
162 | | is set) and fp->ctf_ptrtab. If we can't find a pointer to the |
163 | | given type, see if we can compute a pointer to the type resulting |
164 | | from resolving the type down to its base type and use that instead. |
165 | | This helps with cases where the CTF data includes "struct foo *" |
166 | | but not "foo_t *" and the user tries to access "foo_t *" in the |
167 | | debugger. |
168 | | |
169 | | There is extra complexity here because uninitialized elements in |
170 | | the pptrtab and ptrtab are set to zero, but zero (as the type ID |
171 | | meaning the unimplemented type) is a valid return type from |
172 | | ctf_lookup_by_name. (Pointers to types are never of type 0, so |
173 | | this is unambiguous, just fiddly to deal with.) */ |
174 | |
|
175 | 0 | uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type); |
176 | 0 | int in_child = 0; |
177 | |
|
178 | 0 | ntype = CTF_ERR; |
179 | 0 | if (child && idx < child->ctf_pptrtab_len) |
180 | 0 | { |
181 | 0 | ntype = child->ctf_pptrtab[idx]; |
182 | 0 | if (ntype) |
183 | 0 | in_child = 1; |
184 | 0 | else |
185 | 0 | ntype = CTF_ERR; |
186 | 0 | } |
187 | |
|
188 | 0 | if (ntype == CTF_ERR) |
189 | 0 | { |
190 | 0 | ntype = fp->ctf_ptrtab[idx]; |
191 | 0 | if (ntype == 0) |
192 | 0 | ntype = CTF_ERR; |
193 | 0 | } |
194 | | |
195 | | /* Try resolving to its base type and check again. */ |
196 | 0 | if (ntype == CTF_ERR) |
197 | 0 | { |
198 | 0 | if (child) |
199 | 0 | ntype = ctf_type_resolve_unsliced (child, type); |
200 | 0 | else |
201 | 0 | ntype = ctf_type_resolve_unsliced (fp, type); |
202 | |
|
203 | 0 | if (ntype == CTF_ERR) |
204 | 0 | goto notype; |
205 | | |
206 | 0 | idx = LCTF_TYPE_TO_INDEX (fp, ntype); |
207 | |
|
208 | 0 | ntype = CTF_ERR; |
209 | 0 | if (child && idx < child->ctf_pptrtab_len) |
210 | 0 | { |
211 | 0 | ntype = child->ctf_pptrtab[idx]; |
212 | 0 | if (ntype) |
213 | 0 | in_child = 1; |
214 | 0 | else |
215 | 0 | ntype = CTF_ERR; |
216 | 0 | } |
217 | |
|
218 | 0 | if (ntype == CTF_ERR) |
219 | 0 | { |
220 | 0 | ntype = fp->ctf_ptrtab[idx]; |
221 | 0 | if (ntype == 0) |
222 | 0 | ntype = CTF_ERR; |
223 | 0 | } |
224 | 0 | if (ntype == CTF_ERR) |
225 | 0 | goto notype; |
226 | 0 | } |
227 | | |
228 | 0 | type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD) |
229 | 0 | || in_child); |
230 | | |
231 | | /* We are looking up a type in the parent, but the pointed-to type is |
232 | | in the child. Switch to looking in the child: if we need to go |
233 | | back into the parent, we can recurse again. */ |
234 | 0 | if (in_child) |
235 | 0 | { |
236 | 0 | fp = child; |
237 | 0 | child = NULL; |
238 | 0 | } |
239 | |
|
240 | 0 | q = p + 1; |
241 | 0 | continue; |
242 | 0 | } |
243 | | |
244 | 0 | if (isqualifier (p, (size_t) (q - p))) |
245 | 0 | continue; /* Skip qualifier keyword. */ |
246 | | |
247 | 0 | for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) |
248 | 0 | { |
249 | | /* TODO: This is not MT-safe. */ |
250 | 0 | if ((lp->ctl_prefix[0] == '\0' || |
251 | 0 | strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) && |
252 | 0 | (size_t) (q - p) >= lp->ctl_len) |
253 | 0 | { |
254 | 0 | for (p += lp->ctl_len; isspace ((int) *p); p++) |
255 | 0 | continue; /* Skip prefix and next whitespace. */ |
256 | |
|
257 | 0 | if ((q = strchr (p, '*')) == NULL) |
258 | 0 | q = end; /* Compare until end. */ |
259 | |
|
260 | 0 | while (isspace ((int) q[-1])) |
261 | 0 | q--; /* Exclude trailing whitespace. */ |
262 | | |
263 | | /* Expand and/or allocate storage for a slice of the name, then |
264 | | copy it in. */ |
265 | |
|
266 | 0 | if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1) |
267 | 0 | { |
268 | 0 | memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p)); |
269 | 0 | fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0'; |
270 | 0 | } |
271 | 0 | else |
272 | 0 | { |
273 | 0 | free (fp->ctf_tmp_typeslice); |
274 | 0 | fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p)); |
275 | 0 | if (fp->ctf_tmp_typeslice == NULL) |
276 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
277 | 0 | } |
278 | | |
279 | 0 | if ((type = (ctf_id_t) (uintptr_t) |
280 | 0 | ctf_dynhash_lookup (lp->ctl_hash, |
281 | 0 | fp->ctf_tmp_typeslice)) == 0) |
282 | 0 | goto notype; |
283 | | |
284 | 0 | break; |
285 | 0 | } |
286 | 0 | } |
287 | | |
288 | 0 | if (lp->ctl_prefix == NULL) |
289 | 0 | goto notype; |
290 | 0 | } |
291 | | |
292 | 0 | if (*p != '\0' || type == 0) |
293 | 0 | return (ctf_set_typed_errno (fp, ECTF_SYNTAX)); |
294 | | |
295 | 0 | return type; |
296 | | |
297 | 0 | notype: |
298 | 0 | ctf_set_errno (fp, ECTF_NOTYPE); |
299 | 0 | if (fp->ctf_parent != NULL) |
300 | 0 | { |
301 | | /* Need to look up in the parent, from the child's perspective. |
302 | | Make sure the pptrtab is up to date. */ |
303 | |
|
304 | 0 | if (fp->ctf_pptrtab_typemax < fp->ctf_typemax) |
305 | 0 | { |
306 | 0 | if (refresh_pptrtab (fp, fp->ctf_parent) < 0) |
307 | 0 | return CTF_ERR; /* errno is set for us. */ |
308 | 0 | } |
309 | | |
310 | 0 | if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp, |
311 | 0 | name)) != CTF_ERR) |
312 | 0 | return ptype; |
313 | 0 | return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); |
314 | 0 | } |
315 | | |
316 | 0 | return CTF_ERR; |
317 | 0 | } |
318 | | |
319 | | ctf_id_t |
320 | | ctf_lookup_by_name (ctf_dict_t *fp, const char *name) |
321 | 0 | { |
322 | 0 | return ctf_lookup_by_name_internal (fp, NULL, name); |
323 | 0 | } |
324 | | |
325 | | /* Return the pointer to the internal CTF type data corresponding to the |
326 | | given type ID. If the ID is invalid, the function returns NULL. |
327 | | This function is not exported outside of the library. */ |
328 | | |
329 | | const ctf_type_t * |
330 | | ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type) |
331 | 0 | { |
332 | 0 | ctf_dict_t *fp = *fpp; |
333 | 0 | ctf_id_t idx; |
334 | |
|
335 | 0 | if ((fp = ctf_get_dict (fp, type)) == NULL) |
336 | 0 | { |
337 | 0 | (void) ctf_set_errno (*fpp, ECTF_NOPARENT); |
338 | 0 | return NULL; |
339 | 0 | } |
340 | | |
341 | 0 | idx = LCTF_TYPE_TO_INDEX (fp, type); |
342 | 0 | if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) |
343 | 0 | { |
344 | 0 | *fpp = fp; /* Possibly the parent CTF dict. */ |
345 | 0 | return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); |
346 | 0 | } |
347 | | |
348 | 0 | (void) ctf_set_errno (*fpp, ECTF_BADID); |
349 | 0 | return NULL; |
350 | 0 | } |
351 | | |
352 | | typedef struct ctf_lookup_idx_key |
353 | | { |
354 | | ctf_dict_t *clik_fp; |
355 | | const char *clik_name; |
356 | | uint32_t *clik_names; |
357 | | } ctf_lookup_idx_key_t; |
358 | | |
359 | | /* A bsearch function for variable names. */ |
360 | | |
361 | | static int |
362 | | ctf_lookup_var (const void *key_, const void *lookup_) |
363 | 0 | { |
364 | 0 | const ctf_lookup_idx_key_t *key = key_; |
365 | 0 | const ctf_varent_t *lookup = lookup_; |
366 | |
|
367 | 0 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name))); |
368 | 0 | } |
369 | | |
370 | | /* Given a variable name, return the type of the variable with that name. |
371 | | Look only in this dict, not in the parent. */ |
372 | | |
373 | | ctf_id_t |
374 | | ctf_lookup_variable_here (ctf_dict_t *fp, const char *name) |
375 | 0 | { |
376 | 0 | ctf_dvdef_t *dvd = ctf_dvd_lookup (fp, name); |
377 | 0 | ctf_varent_t *ent; |
378 | 0 | ctf_lookup_idx_key_t key = { fp, name, NULL }; |
379 | |
|
380 | 0 | if (dvd != NULL) |
381 | 0 | return dvd->dvd_type; |
382 | | |
383 | | /* This array is sorted, so we can bsearch for it. */ |
384 | | |
385 | 0 | ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t), |
386 | 0 | ctf_lookup_var); |
387 | |
|
388 | 0 | if (ent == NULL) |
389 | 0 | return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT)); |
390 | | |
391 | 0 | return ent->ctv_type; |
392 | 0 | } |
393 | | |
394 | | /* As above, but look in the parent too. */ |
395 | | |
396 | | ctf_id_t |
397 | | ctf_lookup_variable (ctf_dict_t *fp, const char *name) |
398 | 0 | { |
399 | 0 | ctf_id_t type; |
400 | |
|
401 | 0 | if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR) |
402 | 0 | { |
403 | 0 | if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL) |
404 | 0 | { |
405 | 0 | if ((type = ctf_lookup_variable_here (fp->ctf_parent, name)) != CTF_ERR) |
406 | 0 | return type; |
407 | 0 | return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); |
408 | 0 | } |
409 | | |
410 | 0 | return -1; /* errno is set for us. */ |
411 | 0 | } |
412 | | |
413 | 0 | return type; |
414 | 0 | } |
415 | | |
416 | | /* Look up a single enumerator by enumeration constant name. Returns the ID of |
417 | | the enum it is contained within and optionally its value. Error out with |
418 | | ECTF_DUPLICATE if multiple exist (which can happen in some older dicts). See |
419 | | ctf_lookup_enumerator_next in that case. Enumeration constants in non-root |
420 | | types are not returned, but constants in parents are, if not overridden by |
421 | | an enum in the child.. */ |
422 | | |
423 | | ctf_id_t |
424 | | ctf_lookup_enumerator (ctf_dict_t *fp, const char *name, int64_t *enum_value) |
425 | 0 | { |
426 | 0 | ctf_id_t type; |
427 | 0 | int enum_int_value; |
428 | |
|
429 | 0 | if (ctf_dynset_lookup (fp->ctf_conflicting_enums, name)) |
430 | 0 | return (ctf_set_typed_errno (fp, ECTF_DUPLICATE)); |
431 | | |
432 | | /* CTF_K_UNKNOWN suffices for things like enumeration constants that aren't |
433 | | actually types at all (ending up in the global name table). */ |
434 | 0 | type = ctf_lookup_by_rawname (fp, CTF_K_UNKNOWN, name); |
435 | | /* Nonexistent type? It may be in the parent. */ |
436 | 0 | if (type == 0 && fp->ctf_parent) |
437 | 0 | { |
438 | 0 | if ((type = ctf_lookup_enumerator (fp->ctf_parent, name, enum_value)) == 0) |
439 | 0 | return ctf_set_typed_errno (fp, ECTF_NOENUMNAM); |
440 | 0 | return type; |
441 | 0 | } |
442 | | |
443 | | /* Nothing more to do if this type didn't exist or we don't have to look up |
444 | | the enum value. */ |
445 | 0 | if (type == 0) |
446 | 0 | return ctf_set_typed_errno (fp, ECTF_NOENUMNAM); |
447 | | |
448 | 0 | if (enum_value == NULL) |
449 | 0 | return type; |
450 | | |
451 | 0 | if (ctf_enum_value (fp, type, name, &enum_int_value) < 0) |
452 | 0 | return CTF_ERR; |
453 | 0 | *enum_value = enum_int_value; |
454 | |
|
455 | 0 | return type; |
456 | 0 | } |
457 | | |
458 | | /* Return all enumeration constants with a given name in a given dict, similar |
459 | | to ctf_lookup_enumerator above but capable of returning multiple values. |
460 | | Enumerators in parent dictionaries are not returned: enumerators in |
461 | | hidden types *are* returned. */ |
462 | | |
463 | | ctf_id_t |
464 | | ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name, |
465 | | ctf_next_t **it, int64_t *val) |
466 | 0 | { |
467 | 0 | ctf_next_t *i = *it; |
468 | 0 | int found = 0; |
469 | | |
470 | | /* We use ctf_type_next() to iterate across all types, but then traverse each |
471 | | enumerator found by hand: traversing enumerators is very easy, and it would |
472 | | probably be more confusing to use two nested iterators than to do it this |
473 | | way. We use ctn_next to work over enums, then ctn_en and ctn_n to work |
474 | | over enumerators within each enum. */ |
475 | 0 | if (!i) |
476 | 0 | { |
477 | 0 | if ((i = ctf_next_create ()) == NULL) |
478 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
479 | | |
480 | 0 | i->cu.ctn_fp = fp; |
481 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_lookup_enumerator_next; |
482 | 0 | i->ctn_increment = 0; |
483 | 0 | i->ctn_tp = NULL; |
484 | 0 | i->u.ctn_en = NULL; |
485 | 0 | i->ctn_n = 0; |
486 | 0 | *it = i; |
487 | 0 | } |
488 | | |
489 | 0 | if ((void (*) (void)) ctf_lookup_enumerator_next != i->ctn_iter_fun) |
490 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
491 | | |
492 | 0 | if (fp != i->cu.ctn_fp) |
493 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
494 | | |
495 | 0 | do |
496 | 0 | { |
497 | 0 | const char *this_name; |
498 | | |
499 | | /* At end of enum? Traverse to next one, if any are left. */ |
500 | |
|
501 | 0 | if (i->u.ctn_en == NULL || i->ctn_n == 0) |
502 | 0 | { |
503 | 0 | const ctf_type_t *tp; |
504 | 0 | ctf_dtdef_t *dtd; |
505 | |
|
506 | 0 | do |
507 | 0 | i->ctn_type = ctf_type_next (i->cu.ctn_fp, &i->ctn_next, NULL, 1); |
508 | 0 | while (i->ctn_type != CTF_ERR |
509 | 0 | && ctf_type_kind_unsliced (i->cu.ctn_fp, i->ctn_type) |
510 | 0 | != CTF_K_ENUM); |
511 | |
|
512 | 0 | if (i->ctn_type == CTF_ERR) |
513 | 0 | { |
514 | | /* Conveniently, when the iterator over all types is done, so is the |
515 | | iteration as a whole: so we can just pass all errors from the |
516 | | internal iterator straight back out.. */ |
517 | 0 | ctf_next_destroy (i); |
518 | 0 | *it = NULL; |
519 | 0 | return CTF_ERR; /* errno is set for us. */ |
520 | 0 | } |
521 | | |
522 | 0 | if ((tp = ctf_lookup_by_id (&fp, i->ctn_type)) == NULL) |
523 | 0 | return CTF_ERR; /* errno is set for us. */ |
524 | 0 | i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); |
525 | |
|
526 | 0 | dtd = ctf_dynamic_type (fp, i->ctn_type); |
527 | |
|
528 | 0 | if (dtd == NULL) |
529 | 0 | { |
530 | 0 | (void) ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment); |
531 | 0 | i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp + |
532 | 0 | i->ctn_increment); |
533 | 0 | } |
534 | 0 | else |
535 | 0 | i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen; |
536 | 0 | } |
537 | | |
538 | 0 | this_name = ctf_strptr (fp, i->u.ctn_en->cte_name); |
539 | |
|
540 | 0 | i->ctn_n--; |
541 | |
|
542 | 0 | if (strcmp (name, this_name) == 0) |
543 | 0 | { |
544 | 0 | if (val) |
545 | 0 | *val = i->u.ctn_en->cte_value; |
546 | 0 | found = 1; |
547 | | |
548 | | /* Constant found in this enum: try the next one. (Constant names |
549 | | cannot be duplicated within a given enum.) */ |
550 | |
|
551 | 0 | i->ctn_n = 0; |
552 | 0 | } |
553 | |
|
554 | 0 | i->u.ctn_en++; |
555 | 0 | } |
556 | 0 | while (!found); |
557 | | |
558 | 0 | return i->ctn_type; |
559 | 0 | } |
560 | | |
561 | | typedef struct ctf_symidx_sort_arg_cb |
562 | | { |
563 | | ctf_dict_t *fp; |
564 | | uint32_t *names; |
565 | | } ctf_symidx_sort_arg_cb_t; |
566 | | |
567 | | static int |
568 | | sort_symidx_by_name (const void *one_, const void *two_, void *arg_) |
569 | 0 | { |
570 | 0 | const uint32_t *one = one_; |
571 | 0 | const uint32_t *two = two_; |
572 | 0 | ctf_symidx_sort_arg_cb_t *arg = arg_; |
573 | |
|
574 | 0 | return (strcmp (ctf_strptr (arg->fp, arg->names[*one]), |
575 | 0 | ctf_strptr (arg->fp, arg->names[*two]))); |
576 | 0 | } |
577 | | |
578 | | /* Sort a symbol index section by name. Takes a 1:1 mapping of names to the |
579 | | corresponding symbol table. Returns a lexicographically sorted array of idx |
580 | | indexes (and thus, of indexes into the corresponding func info / data object |
581 | | section). */ |
582 | | |
583 | | static uint32_t * |
584 | | ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx, |
585 | | size_t len) |
586 | 0 | { |
587 | 0 | uint32_t *sorted; |
588 | 0 | size_t i; |
589 | |
|
590 | 0 | if ((sorted = malloc (len)) == NULL) |
591 | 0 | { |
592 | 0 | ctf_set_errno (fp, ENOMEM); |
593 | 0 | return NULL; |
594 | 0 | } |
595 | | |
596 | 0 | *nidx = len / sizeof (uint32_t); |
597 | 0 | for (i = 0; i < *nidx; i++) |
598 | 0 | sorted[i] = i; |
599 | |
|
600 | 0 | if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED)) |
601 | 0 | { |
602 | 0 | ctf_symidx_sort_arg_cb_t arg = { fp, idx }; |
603 | 0 | ctf_dprintf ("Index section unsorted: sorting.\n"); |
604 | 0 | ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg); |
605 | 0 | fp->ctf_header->cth_flags |= CTF_F_IDXSORTED; |
606 | 0 | } |
607 | |
|
608 | 0 | return sorted; |
609 | 0 | } |
610 | | |
611 | | /* Given a symbol index, return the name of that symbol from the table provided |
612 | | by ctf_link_shuffle_syms, or failing that from the secondary string table, or |
613 | | the null string. */ |
614 | | static const char * |
615 | | ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx) |
616 | 0 | { |
617 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
618 | 0 | ctf_link_sym_t sym; |
619 | 0 | int err; |
620 | |
|
621 | 0 | if (fp->ctf_dynsymidx) |
622 | 0 | { |
623 | 0 | err = EINVAL; |
624 | 0 | if (symidx > fp->ctf_dynsymmax) |
625 | 0 | goto try_parent; |
626 | | |
627 | 0 | ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx]; |
628 | |
|
629 | 0 | if (!symp) |
630 | 0 | goto try_parent; |
631 | | |
632 | 0 | return symp->st_name; |
633 | 0 | } |
634 | | |
635 | 0 | err = ECTF_NOSYMTAB; |
636 | 0 | if (sp->cts_data == NULL) |
637 | 0 | goto try_parent; |
638 | | |
639 | 0 | if (symidx >= fp->ctf_nsyms) |
640 | 0 | goto try_parent; |
641 | | |
642 | 0 | switch (sp->cts_entsize) |
643 | 0 | { |
644 | 0 | case sizeof (Elf64_Sym): |
645 | 0 | { |
646 | 0 | const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx; |
647 | 0 | ctf_elf64_to_link_sym (fp, &sym, symp, symidx); |
648 | 0 | } |
649 | 0 | break; |
650 | 0 | case sizeof (Elf32_Sym): |
651 | 0 | { |
652 | 0 | const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx; |
653 | 0 | ctf_elf32_to_link_sym (fp, &sym, symp, symidx); |
654 | 0 | } |
655 | 0 | break; |
656 | 0 | default: |
657 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
658 | 0 | return _CTF_NULLSTR; |
659 | 0 | } |
660 | | |
661 | 0 | assert (!sym.st_nameidx_set); |
662 | | |
663 | 0 | return sym.st_name; |
664 | | |
665 | 0 | try_parent: |
666 | 0 | if (fp->ctf_parent) |
667 | 0 | { |
668 | 0 | const char *ret; |
669 | 0 | ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx); |
670 | 0 | if (ret == NULL) |
671 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
672 | 0 | return ret; |
673 | 0 | } |
674 | 0 | else |
675 | 0 | { |
676 | 0 | ctf_set_errno (fp, err); |
677 | 0 | return _CTF_NULLSTR; |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | /* Given a symbol name, return the index of that symbol, or -1 on error or if |
682 | | not found. If is_function is >= 0, return only function or data object |
683 | | symbols, respectively. */ |
684 | | static unsigned long |
685 | | ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent, |
686 | | int is_function) |
687 | 0 | { |
688 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
689 | 0 | ctf_link_sym_t sym; |
690 | 0 | void *known_idx; |
691 | 0 | int err; |
692 | 0 | ctf_dict_t *cache = fp; |
693 | |
|
694 | 0 | if (fp->ctf_dynsyms) |
695 | 0 | { |
696 | 0 | err = EINVAL; |
697 | |
|
698 | 0 | ctf_link_sym_t *symp; |
699 | |
|
700 | 0 | if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL) |
701 | 0 | || (symp->st_type != STT_OBJECT && is_function == 0) |
702 | 0 | || (symp->st_type != STT_FUNC && is_function == 1)) |
703 | 0 | goto try_parent; |
704 | | |
705 | 0 | return symp->st_symidx; |
706 | 0 | } |
707 | | |
708 | 0 | err = ECTF_NOSYMTAB; |
709 | 0 | if (sp->cts_data == NULL) |
710 | 0 | goto try_parent; |
711 | | |
712 | | /* First, try a hash lookup to see if we have already spotted this symbol |
713 | | during a past iteration: create the hash first if need be. The |
714 | | lifespan of the strings is equal to the lifespan of the cts_data, so we |
715 | | don't need to strdup them. If this dict was opened as part of an |
716 | | archive, and this archive has a crossdict_cache to cache results that |
717 | | are the same across all dicts in an archive, use it. */ |
718 | | |
719 | 0 | if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache) |
720 | 0 | cache = fp->ctf_archive->ctfi_crossdict_cache; |
721 | |
|
722 | 0 | if (!cache->ctf_symhash_func) |
723 | 0 | if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string, |
724 | 0 | ctf_hash_eq_string, |
725 | 0 | NULL, NULL)) == NULL) |
726 | 0 | goto oom; |
727 | | |
728 | 0 | if (!cache->ctf_symhash_objt) |
729 | 0 | if ((cache->ctf_symhash_objt = ctf_dynhash_create (ctf_hash_string, |
730 | 0 | ctf_hash_eq_string, |
731 | 0 | NULL, NULL)) == NULL) |
732 | 0 | goto oom; |
733 | | |
734 | 0 | if (is_function != 0 && |
735 | 0 | ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx)) |
736 | 0 | return (unsigned long) (uintptr_t) known_idx; |
737 | | |
738 | 0 | if (is_function != 1 && |
739 | 0 | ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx)) |
740 | 0 | return (unsigned long) (uintptr_t) known_idx; |
741 | | |
742 | | /* Hash lookup unsuccessful: linear search, populating the hashtab for later |
743 | | lookups as we go. */ |
744 | | |
745 | 0 | for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize; |
746 | 0 | cache->ctf_symhash_latest++) |
747 | 0 | { |
748 | 0 | ctf_dynhash_t *h; |
749 | |
|
750 | 0 | switch (sp->cts_entsize) |
751 | 0 | { |
752 | 0 | case sizeof (Elf64_Sym): |
753 | 0 | { |
754 | 0 | Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data; |
755 | |
|
756 | 0 | ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
757 | 0 | cache->ctf_symhash_latest); |
758 | 0 | } |
759 | 0 | break; |
760 | 0 | case sizeof (Elf32_Sym): |
761 | 0 | { |
762 | 0 | Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data; |
763 | 0 | ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
764 | 0 | cache->ctf_symhash_latest); |
765 | 0 | break; |
766 | 0 | } |
767 | 0 | default: |
768 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
769 | 0 | return (unsigned long) -1; |
770 | 0 | } |
771 | | |
772 | 0 | if (sym.st_type == STT_FUNC) |
773 | 0 | h = cache->ctf_symhash_func; |
774 | 0 | else if (sym.st_type == STT_OBJECT) |
775 | 0 | h = cache->ctf_symhash_objt; |
776 | 0 | else |
777 | 0 | continue; /* Not of interest. */ |
778 | | |
779 | 0 | if (!ctf_dynhash_lookup_kv (h, sym.st_name, |
780 | 0 | NULL, NULL)) |
781 | 0 | if (ctf_dynhash_cinsert (h, sym.st_name, |
782 | 0 | (const void *) (uintptr_t) |
783 | 0 | cache->ctf_symhash_latest) < 0) |
784 | 0 | goto oom; |
785 | 0 | if (strcmp (sym.st_name, symname) == 0) |
786 | 0 | return cache->ctf_symhash_latest++; |
787 | 0 | } |
788 | | |
789 | | /* Searched everything, still not found. */ |
790 | | |
791 | 0 | return (unsigned long) -1; |
792 | | |
793 | 0 | try_parent: |
794 | 0 | if (fp->ctf_parent && try_parent) |
795 | 0 | { |
796 | 0 | unsigned long psym; |
797 | |
|
798 | 0 | if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent, |
799 | 0 | is_function)) |
800 | 0 | != (unsigned long) -1) |
801 | 0 | return psym; |
802 | | |
803 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
804 | 0 | return (unsigned long) -1; |
805 | 0 | } |
806 | 0 | else |
807 | 0 | { |
808 | 0 | ctf_set_errno (fp, err); |
809 | 0 | return (unsigned long) -1; |
810 | 0 | } |
811 | 0 | oom: |
812 | 0 | ctf_set_errno (fp, ENOMEM); |
813 | 0 | ctf_err_warn (fp, 0, 0, _("cannot allocate memory for symbol " |
814 | 0 | "lookup hashtab")); |
815 | 0 | return (unsigned long) -1; |
816 | |
|
817 | 0 | } |
818 | | |
819 | | ctf_id_t |
820 | | ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
821 | | int functions); |
822 | | |
823 | | /* Iterate over all symbols with types: if FUNC, function symbols, |
824 | | otherwise, data symbols. The name argument is not optional. The return |
825 | | order is arbitrary, though is likely to be in symbol index or name order. |
826 | | Changing the value of 'functions' in the middle of iteration has |
827 | | unpredictable effects (probably skipping symbols, etc) and is not |
828 | | recommended. Adding symbols while iteration is underway may also lead |
829 | | to other symbols being skipped. */ |
830 | | |
831 | | ctf_id_t |
832 | | ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
833 | | int functions) |
834 | 0 | { |
835 | 0 | ctf_id_t sym = CTF_ERR; |
836 | 0 | ctf_next_t *i = *it; |
837 | 0 | int err; |
838 | |
|
839 | 0 | if (!i) |
840 | 0 | { |
841 | 0 | if ((i = ctf_next_create ()) == NULL) |
842 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
843 | | |
844 | 0 | i->cu.ctn_fp = fp; |
845 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; |
846 | 0 | i->ctn_n = 0; |
847 | 0 | *it = i; |
848 | 0 | } |
849 | | |
850 | 0 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) |
851 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
852 | | |
853 | 0 | if (fp != i->cu.ctn_fp) |
854 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
855 | | |
856 | | /* Check the dynamic set of names first, to allow previously-written names |
857 | | to be replaced with dynamic ones (there is still no way to remove them, |
858 | | though). |
859 | | |
860 | | We intentionally use raw access, not ctf_lookup_by_symbol, to avoid |
861 | | incurring additional sorting cost for unsorted symtypetabs coming from the |
862 | | compiler, to allow ctf_symbol_next to work in the absence of a symtab, and |
863 | | finally because it's easier to work out what the name of each symbol is if |
864 | | we do that. */ |
865 | | |
866 | 0 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
867 | 0 | void *dyn_name = NULL, *dyn_value = NULL; |
868 | 0 | size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; |
869 | |
|
870 | 0 | if (i->ctn_n < dyn_els) |
871 | 0 | { |
872 | 0 | err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); |
873 | | |
874 | | /* This covers errors and also end-of-iteration. */ |
875 | 0 | if (err != 0) |
876 | 0 | { |
877 | 0 | ctf_next_destroy (i); |
878 | 0 | *it = NULL; |
879 | 0 | return ctf_set_typed_errno (fp, err); |
880 | 0 | } |
881 | | |
882 | 0 | *name = dyn_name; |
883 | 0 | sym = (ctf_id_t) (uintptr_t) dyn_value; |
884 | 0 | i->ctn_n++; |
885 | |
|
886 | 0 | return sym; |
887 | 0 | } |
888 | | |
889 | 0 | return ctf_symbol_next_static (fp, it, name, functions); |
890 | 0 | } |
891 | | |
892 | | /* ctf_symbol_next, but only for static symbols. Mostly an internal |
893 | | implementation detail of ctf_symbol_next, but also used to simplify |
894 | | serialization. */ |
895 | | ctf_id_t |
896 | | ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
897 | | int functions) |
898 | 0 | { |
899 | 0 | ctf_id_t sym = CTF_ERR; |
900 | 0 | ctf_next_t *i = *it; |
901 | 0 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
902 | 0 | size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; |
903 | | |
904 | | /* Only relevant for direct internal-to-library calls, not via |
905 | | ctf_symbol_next (but important then). */ |
906 | |
|
907 | 0 | if (!i) |
908 | 0 | { |
909 | 0 | if ((i = ctf_next_create ()) == NULL) |
910 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
911 | | |
912 | 0 | i->cu.ctn_fp = fp; |
913 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; |
914 | 0 | i->ctn_n = dyn_els; |
915 | 0 | *it = i; |
916 | 0 | } |
917 | | |
918 | 0 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) |
919 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
920 | | |
921 | 0 | if (fp != i->cu.ctn_fp) |
922 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
923 | | |
924 | | /* TODO-v4: Indexed after non-indexed portions? */ |
925 | | |
926 | 0 | if ((!functions && fp->ctf_objtidx_names) || |
927 | 0 | (functions && fp->ctf_funcidx_names)) |
928 | 0 | { |
929 | 0 | ctf_header_t *hp = fp->ctf_header; |
930 | 0 | uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names; |
931 | 0 | uint32_t *tab; |
932 | 0 | size_t len; |
933 | |
|
934 | 0 | if (functions) |
935 | 0 | { |
936 | 0 | len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t); |
937 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
938 | 0 | } |
939 | 0 | else |
940 | 0 | { |
941 | 0 | len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t); |
942 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
943 | 0 | } |
944 | |
|
945 | 0 | do |
946 | 0 | { |
947 | 0 | if (i->ctn_n - dyn_els >= len) |
948 | 0 | goto end; |
949 | | |
950 | 0 | *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]); |
951 | 0 | sym = tab[i->ctn_n - dyn_els]; |
952 | 0 | i->ctn_n++; |
953 | 0 | } |
954 | 0 | while (sym == -1u || sym == 0); |
955 | 0 | } |
956 | 0 | else |
957 | 0 | { |
958 | | /* Skip over pads in ctf_sxlate, padding for typeless symbols in the |
959 | | symtypetab itself, and symbols in the wrong table. */ |
960 | 0 | for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++) |
961 | 0 | { |
962 | 0 | ctf_header_t *hp = fp->ctf_header; |
963 | 0 | size_t n = i->ctn_n - dyn_els; |
964 | |
|
965 | 0 | if (fp->ctf_sxlate[n] == -1u) |
966 | 0 | continue; |
967 | | |
968 | 0 | sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]); |
969 | |
|
970 | 0 | if (sym == 0) |
971 | 0 | continue; |
972 | | |
973 | 0 | if (functions) |
974 | 0 | { |
975 | 0 | if (fp->ctf_sxlate[n] >= hp->cth_funcoff |
976 | 0 | && fp->ctf_sxlate[n] < hp->cth_objtidxoff) |
977 | 0 | break; |
978 | 0 | } |
979 | 0 | else |
980 | 0 | { |
981 | 0 | if (fp->ctf_sxlate[n] >= hp->cth_objtoff |
982 | 0 | && fp->ctf_sxlate[n] < hp->cth_funcoff) |
983 | 0 | break; |
984 | 0 | } |
985 | 0 | } |
986 | |
|
987 | 0 | if (i->ctn_n - dyn_els >= fp->ctf_nsyms) |
988 | 0 | goto end; |
989 | | |
990 | 0 | *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els); |
991 | 0 | i->ctn_n++; |
992 | 0 | } |
993 | | |
994 | 0 | return sym; |
995 | | |
996 | 0 | end: |
997 | 0 | ctf_next_destroy (i); |
998 | 0 | *it = NULL; |
999 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_END)); |
1000 | 0 | } |
1001 | | |
1002 | | /* A bsearch function for function and object index names. */ |
1003 | | |
1004 | | static int |
1005 | | ctf_lookup_idx_name (const void *key_, const void *idx_) |
1006 | 0 | { |
1007 | 0 | const ctf_lookup_idx_key_t *key = key_; |
1008 | 0 | const uint32_t *idx = idx_; |
1009 | |
|
1010 | 0 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx]))); |
1011 | 0 | } |
1012 | | |
1013 | | /* Given a symbol name or (failing that) number, look up that symbol in the |
1014 | | function or object index table (which must exist). Return 0 if not found |
1015 | | there (or pad). */ |
1016 | | |
1017 | | static ctf_id_t |
1018 | | ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, |
1019 | | const char *symname, int is_function) |
1020 | 0 | { |
1021 | 0 | struct ctf_header *hp = fp->ctf_header; |
1022 | 0 | uint32_t *symtypetab; |
1023 | 0 | uint32_t *names; |
1024 | 0 | uint32_t *sxlate; |
1025 | 0 | size_t nidx; |
1026 | |
|
1027 | 0 | if (symname == NULL) |
1028 | 0 | symname = ctf_lookup_symbol_name (fp, symidx); |
1029 | | |
1030 | | /* Dynamic dict with no static portion: just return. */ |
1031 | 0 | if (!hp) |
1032 | 0 | { |
1033 | 0 | ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname); |
1034 | 0 | return 0; |
1035 | 0 | } |
1036 | | |
1037 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in " |
1038 | 0 | "indexed symtypetab\n", symidx, symname); |
1039 | |
|
1040 | 0 | if (symname[0] == '\0') |
1041 | 0 | return CTF_ERR; /* errno is set for us. */ |
1042 | | |
1043 | 0 | if (is_function) |
1044 | 0 | { |
1045 | 0 | if (!fp->ctf_funcidx_sxlate) |
1046 | 0 | { |
1047 | 0 | if ((fp->ctf_funcidx_sxlate |
1048 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
1049 | 0 | (fp->ctf_buf + hp->cth_funcidxoff), |
1050 | 0 | &fp->ctf_nfuncidx, |
1051 | 0 | hp->cth_varoff - hp->cth_funcidxoff)) |
1052 | 0 | == NULL) |
1053 | 0 | { |
1054 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort function symidx")); |
1055 | 0 | return CTF_ERR; /* errno is set for us. */ |
1056 | 0 | } |
1057 | 0 | } |
1058 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
1059 | 0 | sxlate = fp->ctf_funcidx_sxlate; |
1060 | 0 | names = fp->ctf_funcidx_names; |
1061 | 0 | nidx = fp->ctf_nfuncidx; |
1062 | 0 | } |
1063 | 0 | else |
1064 | 0 | { |
1065 | 0 | if (!fp->ctf_objtidx_sxlate) |
1066 | 0 | { |
1067 | 0 | if ((fp->ctf_objtidx_sxlate |
1068 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
1069 | 0 | (fp->ctf_buf + hp->cth_objtidxoff), |
1070 | 0 | &fp->ctf_nobjtidx, |
1071 | 0 | hp->cth_funcidxoff - hp->cth_objtidxoff)) |
1072 | 0 | == NULL) |
1073 | 0 | { |
1074 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort object symidx")); |
1075 | 0 | return CTF_ERR; /* errno is set for us. */ |
1076 | 0 | } |
1077 | 0 | } |
1078 | | |
1079 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
1080 | 0 | sxlate = fp->ctf_objtidx_sxlate; |
1081 | 0 | names = fp->ctf_objtidx_names; |
1082 | 0 | nidx = fp->ctf_nobjtidx; |
1083 | 0 | } |
1084 | | |
1085 | 0 | ctf_lookup_idx_key_t key = { fp, symname, names }; |
1086 | 0 | uint32_t *idx; |
1087 | |
|
1088 | 0 | idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name); |
1089 | |
|
1090 | 0 | if (!idx) |
1091 | 0 | { |
1092 | 0 | ctf_dprintf ("%s not found in idx\n", symname); |
1093 | 0 | return 0; |
1094 | 0 | } |
1095 | | |
1096 | | /* Should be impossible, but be paranoid. */ |
1097 | 0 | if ((idx - sxlate) > (ptrdiff_t) nidx) |
1098 | 0 | return (ctf_set_typed_errno (fp, ECTF_CORRUPT)); |
1099 | | |
1100 | 0 | ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname, |
1101 | 0 | symtypetab[*idx]); |
1102 | 0 | return symtypetab[*idx]; |
1103 | 0 | } |
1104 | | |
1105 | | /* Given a symbol name or (if NULL) symbol index, return the type of the |
1106 | | function or data object described by the corresponding entry in the symbol |
1107 | | table. We can only return symbols in read-only dicts and in dicts for which |
1108 | | ctf_link_shuffle_syms has been called to assign symbol indexes to symbol |
1109 | | names. |
1110 | | |
1111 | | If try_parent is false, do not check the parent dict too. |
1112 | | |
1113 | | If is_function is > -1, only look for data objects or functions in |
1114 | | particular. */ |
1115 | | |
1116 | | ctf_id_t |
1117 | | ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx, |
1118 | | const char *symname, int try_parent, |
1119 | | int is_function) |
1120 | 0 | { |
1121 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
1122 | 0 | ctf_id_t type = 0; |
1123 | 0 | int err = 0; |
1124 | | |
1125 | | /* Shuffled dynsymidx present? Use that. For now, the dynsymidx and |
1126 | | shuffled-symbol lookup only support dynamically-added symbols, because |
1127 | | this interface is meant for use by linkers, and linkers are only going |
1128 | | to report symbols against newly-created, freshly-ctf_link'ed dicts: so |
1129 | | there will be no static component in any case. */ |
1130 | 0 | if (fp->ctf_dynsymidx) |
1131 | 0 | { |
1132 | 0 | const ctf_link_sym_t *sym; |
1133 | |
|
1134 | 0 | if (symname) |
1135 | 0 | ctf_dprintf ("Looking up type of object with symname %s in " |
1136 | 0 | "writable dict symtypetab\n", symname); |
1137 | 0 | else |
1138 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx in " |
1139 | 0 | "writable dict symtypetab\n", symidx); |
1140 | | |
1141 | | /* No name? Need to look it up. */ |
1142 | 0 | if (!symname) |
1143 | 0 | { |
1144 | 0 | err = EINVAL; |
1145 | 0 | if (symidx > fp->ctf_dynsymmax) |
1146 | 0 | goto try_parent; |
1147 | | |
1148 | 0 | sym = fp->ctf_dynsymidx[symidx]; |
1149 | 0 | err = ECTF_NOTYPEDAT; |
1150 | 0 | if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC) |
1151 | 0 | || (sym->st_type != STT_OBJECT && is_function == 0) |
1152 | 0 | || (sym->st_type != STT_FUNC && is_function == 1)) |
1153 | 0 | goto try_parent; |
1154 | | |
1155 | 0 | if (!ctf_assert (fp, !sym->st_nameidx_set)) |
1156 | 0 | return CTF_ERR; |
1157 | 0 | symname = sym->st_name; |
1158 | 0 | } |
1159 | | |
1160 | 0 | if (fp->ctf_objthash == NULL |
1161 | 0 | || is_function == 1 |
1162 | 0 | || (type = (ctf_id_t) (uintptr_t) |
1163 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0) |
1164 | 0 | { |
1165 | 0 | if (fp->ctf_funchash == NULL |
1166 | 0 | || is_function == 0 |
1167 | 0 | || (type = (ctf_id_t) (uintptr_t) |
1168 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0) |
1169 | 0 | goto try_parent; |
1170 | 0 | } |
1171 | | |
1172 | 0 | return type; |
1173 | 0 | } |
1174 | | |
1175 | | /* Dict not shuffled: look for a dynamic sym first, and look it up |
1176 | | directly. */ |
1177 | 0 | if (symname) |
1178 | 0 | { |
1179 | 0 | if (fp->ctf_objthash != NULL |
1180 | 0 | && is_function != 1 |
1181 | 0 | && ((type = (ctf_id_t) (uintptr_t) |
1182 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0)) |
1183 | 0 | return type; |
1184 | | |
1185 | 0 | if (fp->ctf_funchash != NULL |
1186 | 0 | && is_function != 0 |
1187 | 0 | && ((type = (ctf_id_t) (uintptr_t) |
1188 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0)) |
1189 | 0 | return type; |
1190 | 0 | } |
1191 | | |
1192 | 0 | err = ECTF_NOSYMTAB; |
1193 | 0 | if (sp->cts_data == NULL && symname == NULL && |
1194 | 0 | ((is_function && !fp->ctf_funcidx_names) || |
1195 | 0 | (!is_function && !fp->ctf_objtidx_names))) |
1196 | 0 | goto try_parent; |
1197 | | |
1198 | | /* This covers both out-of-range lookups by index and a dynamic dict which |
1199 | | hasn't been shuffled yet. */ |
1200 | 0 | err = EINVAL; |
1201 | 0 | if (symname == NULL && symidx >= fp->ctf_nsyms) |
1202 | 0 | goto try_parent; |
1203 | | |
1204 | | /* Try an indexed lookup. */ |
1205 | | |
1206 | 0 | if (fp->ctf_objtidx_names && is_function != 1) |
1207 | 0 | { |
1208 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR) |
1209 | 0 | return CTF_ERR; /* errno is set for us. */ |
1210 | 0 | } |
1211 | 0 | if (type == 0 && fp->ctf_funcidx_names && is_function != 0) |
1212 | 0 | { |
1213 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR) |
1214 | 0 | return CTF_ERR; /* errno is set for us. */ |
1215 | 0 | } |
1216 | 0 | if (type != 0) |
1217 | 0 | return type; |
1218 | | |
1219 | | /* Indexed but no symbol found -> not present, try the parent. */ |
1220 | 0 | err = ECTF_NOTYPEDAT; |
1221 | 0 | if (fp->ctf_objtidx_names && fp->ctf_funcidx_names) |
1222 | 0 | goto try_parent; |
1223 | | |
1224 | | /* Table must be nonindexed. */ |
1225 | | |
1226 | 0 | ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx); |
1227 | |
|
1228 | 0 | if (symname != NULL) |
1229 | 0 | if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function)) |
1230 | 0 | == (unsigned long) -1) |
1231 | 0 | goto try_parent; |
1232 | | |
1233 | 0 | if (fp->ctf_sxlate[symidx] == -1u) |
1234 | 0 | goto try_parent; |
1235 | | |
1236 | 0 | type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]); |
1237 | |
|
1238 | 0 | if (type == 0) |
1239 | 0 | goto try_parent; |
1240 | | |
1241 | 0 | return type; |
1242 | | |
1243 | 0 | try_parent: |
1244 | 0 | if (!try_parent) |
1245 | 0 | return ctf_set_errno (fp, err); |
1246 | | |
1247 | 0 | if (fp->ctf_parent) |
1248 | 0 | { |
1249 | 0 | ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx, |
1250 | 0 | symname, try_parent, |
1251 | 0 | is_function); |
1252 | 0 | if (ret == CTF_ERR) |
1253 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
1254 | 0 | return ret; |
1255 | 0 | } |
1256 | 0 | else |
1257 | 0 | return (ctf_set_typed_errno (fp, err)); |
1258 | 0 | } |
1259 | | |
1260 | | /* Given a symbol table index, return the type of the function or data object |
1261 | | described by the corresponding entry in the symbol table. */ |
1262 | | ctf_id_t |
1263 | | ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx) |
1264 | 0 | { |
1265 | 0 | return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1); |
1266 | 0 | } |
1267 | | |
1268 | | /* Given a symbol name, return the type of the function or data object described |
1269 | | by the corresponding entry in the symbol table. */ |
1270 | | ctf_id_t |
1271 | | ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname) |
1272 | 0 | { |
1273 | 0 | return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1); |
1274 | 0 | } |
1275 | | |
1276 | | /* Given a symbol table index, return the info for the function described |
1277 | | by the corresponding entry in the symbol table, which may be a function |
1278 | | symbol or may be a data symbol that happens to be a function pointer. */ |
1279 | | |
1280 | | int |
1281 | | ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip) |
1282 | 0 | { |
1283 | 0 | ctf_id_t type; |
1284 | |
|
1285 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1286 | 0 | return -1; /* errno is set for us. */ |
1287 | | |
1288 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1289 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1290 | | |
1291 | 0 | return ctf_func_type_info (fp, type, fip); |
1292 | 0 | } |
1293 | | |
1294 | | /* Given a symbol table index, return the arguments for the function described |
1295 | | by the corresponding entry in the symbol table. */ |
1296 | | |
1297 | | int |
1298 | | ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc, |
1299 | | ctf_id_t *argv) |
1300 | 0 | { |
1301 | 0 | ctf_id_t type; |
1302 | |
|
1303 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1304 | 0 | return -1; /* errno is set for us. */ |
1305 | | |
1306 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1307 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1308 | | |
1309 | 0 | return ctf_func_type_args (fp, type, argc, argv); |
1310 | 0 | } |