/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-2024 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 | | typedef struct ctf_symidx_sort_arg_cb |
417 | | { |
418 | | ctf_dict_t *fp; |
419 | | uint32_t *names; |
420 | | } ctf_symidx_sort_arg_cb_t; |
421 | | |
422 | | static int |
423 | | sort_symidx_by_name (const void *one_, const void *two_, void *arg_) |
424 | 0 | { |
425 | 0 | const uint32_t *one = one_; |
426 | 0 | const uint32_t *two = two_; |
427 | 0 | ctf_symidx_sort_arg_cb_t *arg = arg_; |
428 | |
|
429 | 0 | return (strcmp (ctf_strptr (arg->fp, arg->names[*one]), |
430 | 0 | ctf_strptr (arg->fp, arg->names[*two]))); |
431 | 0 | } |
432 | | |
433 | | /* Sort a symbol index section by name. Takes a 1:1 mapping of names to the |
434 | | corresponding symbol table. Returns a lexicographically sorted array of idx |
435 | | indexes (and thus, of indexes into the corresponding func info / data object |
436 | | section). */ |
437 | | |
438 | | static uint32_t * |
439 | | ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx, |
440 | | size_t len) |
441 | 0 | { |
442 | 0 | uint32_t *sorted; |
443 | 0 | size_t i; |
444 | |
|
445 | 0 | if ((sorted = malloc (len)) == NULL) |
446 | 0 | { |
447 | 0 | ctf_set_errno (fp, ENOMEM); |
448 | 0 | return NULL; |
449 | 0 | } |
450 | | |
451 | 0 | *nidx = len / sizeof (uint32_t); |
452 | 0 | for (i = 0; i < *nidx; i++) |
453 | 0 | sorted[i] = i; |
454 | |
|
455 | 0 | if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED)) |
456 | 0 | { |
457 | 0 | ctf_symidx_sort_arg_cb_t arg = { fp, idx }; |
458 | 0 | ctf_dprintf ("Index section unsorted: sorting.\n"); |
459 | 0 | ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg); |
460 | 0 | fp->ctf_header->cth_flags |= CTF_F_IDXSORTED; |
461 | 0 | } |
462 | |
|
463 | 0 | return sorted; |
464 | 0 | } |
465 | | |
466 | | /* Given a symbol index, return the name of that symbol from the table provided |
467 | | by ctf_link_shuffle_syms, or failing that from the secondary string table, or |
468 | | the null string. */ |
469 | | static const char * |
470 | | ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx) |
471 | 0 | { |
472 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
473 | 0 | ctf_link_sym_t sym; |
474 | 0 | int err; |
475 | |
|
476 | 0 | if (fp->ctf_dynsymidx) |
477 | 0 | { |
478 | 0 | err = EINVAL; |
479 | 0 | if (symidx > fp->ctf_dynsymmax) |
480 | 0 | goto try_parent; |
481 | | |
482 | 0 | ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx]; |
483 | |
|
484 | 0 | if (!symp) |
485 | 0 | goto try_parent; |
486 | | |
487 | 0 | return symp->st_name; |
488 | 0 | } |
489 | | |
490 | 0 | err = ECTF_NOSYMTAB; |
491 | 0 | if (sp->cts_data == NULL) |
492 | 0 | goto try_parent; |
493 | | |
494 | 0 | if (symidx >= fp->ctf_nsyms) |
495 | 0 | goto try_parent; |
496 | | |
497 | 0 | switch (sp->cts_entsize) |
498 | 0 | { |
499 | 0 | case sizeof (Elf64_Sym): |
500 | 0 | { |
501 | 0 | const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx; |
502 | 0 | ctf_elf64_to_link_sym (fp, &sym, symp, symidx); |
503 | 0 | } |
504 | 0 | break; |
505 | 0 | case sizeof (Elf32_Sym): |
506 | 0 | { |
507 | 0 | const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx; |
508 | 0 | ctf_elf32_to_link_sym (fp, &sym, symp, symidx); |
509 | 0 | } |
510 | 0 | break; |
511 | 0 | default: |
512 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
513 | 0 | return _CTF_NULLSTR; |
514 | 0 | } |
515 | | |
516 | 0 | assert (!sym.st_nameidx_set); |
517 | | |
518 | 0 | return sym.st_name; |
519 | | |
520 | 0 | try_parent: |
521 | 0 | if (fp->ctf_parent) |
522 | 0 | { |
523 | 0 | const char *ret; |
524 | 0 | ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx); |
525 | 0 | if (ret == NULL) |
526 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
527 | 0 | return ret; |
528 | 0 | } |
529 | 0 | else |
530 | 0 | { |
531 | 0 | ctf_set_errno (fp, err); |
532 | 0 | return _CTF_NULLSTR; |
533 | 0 | } |
534 | 0 | } |
535 | | |
536 | | /* Given a symbol name, return the index of that symbol, or -1 on error or if |
537 | | not found. If is_function is >= 0, return only function or data object |
538 | | symbols, respectively. */ |
539 | | static unsigned long |
540 | | ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent, |
541 | | int is_function) |
542 | 0 | { |
543 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
544 | 0 | ctf_link_sym_t sym; |
545 | 0 | void *known_idx; |
546 | 0 | int err; |
547 | 0 | ctf_dict_t *cache = fp; |
548 | |
|
549 | 0 | if (fp->ctf_dynsyms) |
550 | 0 | { |
551 | 0 | err = EINVAL; |
552 | |
|
553 | 0 | ctf_link_sym_t *symp; |
554 | |
|
555 | 0 | if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL) |
556 | 0 | || (symp->st_type != STT_OBJECT && is_function == 0) |
557 | 0 | || (symp->st_type != STT_FUNC && is_function == 1)) |
558 | 0 | goto try_parent; |
559 | | |
560 | 0 | return symp->st_symidx; |
561 | 0 | } |
562 | | |
563 | 0 | err = ECTF_NOSYMTAB; |
564 | 0 | if (sp->cts_data == NULL) |
565 | 0 | goto try_parent; |
566 | | |
567 | | /* First, try a hash lookup to see if we have already spotted this symbol |
568 | | during a past iteration: create the hash first if need be. The |
569 | | lifespan of the strings is equal to the lifespan of the cts_data, so we |
570 | | don't need to strdup them. If this dict was opened as part of an |
571 | | archive, and this archive has a crossdict_cache to cache results that |
572 | | are the same across all dicts in an archive, use it. */ |
573 | | |
574 | 0 | if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache) |
575 | 0 | cache = fp->ctf_archive->ctfi_crossdict_cache; |
576 | |
|
577 | 0 | if (!cache->ctf_symhash_func) |
578 | 0 | if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string, |
579 | 0 | ctf_hash_eq_string, |
580 | 0 | NULL, NULL)) == NULL) |
581 | 0 | goto oom; |
582 | | |
583 | 0 | if (!cache->ctf_symhash_objt) |
584 | 0 | if ((cache->ctf_symhash_objt = ctf_dynhash_create (ctf_hash_string, |
585 | 0 | ctf_hash_eq_string, |
586 | 0 | NULL, NULL)) == NULL) |
587 | 0 | goto oom; |
588 | | |
589 | 0 | if (is_function != 0 && |
590 | 0 | ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx)) |
591 | 0 | return (unsigned long) (uintptr_t) known_idx; |
592 | | |
593 | 0 | if (is_function != 1 && |
594 | 0 | ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx)) |
595 | 0 | return (unsigned long) (uintptr_t) known_idx; |
596 | | |
597 | | /* Hash lookup unsuccessful: linear search, populating the hashtab for later |
598 | | lookups as we go. */ |
599 | | |
600 | 0 | for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize; |
601 | 0 | cache->ctf_symhash_latest++) |
602 | 0 | { |
603 | 0 | ctf_dynhash_t *h; |
604 | |
|
605 | 0 | switch (sp->cts_entsize) |
606 | 0 | { |
607 | 0 | case sizeof (Elf64_Sym): |
608 | 0 | { |
609 | 0 | Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data; |
610 | |
|
611 | 0 | ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
612 | 0 | cache->ctf_symhash_latest); |
613 | 0 | } |
614 | 0 | break; |
615 | 0 | case sizeof (Elf32_Sym): |
616 | 0 | { |
617 | 0 | Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data; |
618 | 0 | ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
619 | 0 | cache->ctf_symhash_latest); |
620 | 0 | break; |
621 | 0 | } |
622 | 0 | default: |
623 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
624 | 0 | return (unsigned long) -1; |
625 | 0 | } |
626 | | |
627 | 0 | if (sym.st_type == STT_FUNC) |
628 | 0 | h = cache->ctf_symhash_func; |
629 | 0 | else if (sym.st_type == STT_OBJECT) |
630 | 0 | h = cache->ctf_symhash_objt; |
631 | 0 | else |
632 | 0 | continue; /* Not of interest. */ |
633 | | |
634 | 0 | if (!ctf_dynhash_lookup_kv (h, sym.st_name, |
635 | 0 | NULL, NULL)) |
636 | 0 | if (ctf_dynhash_cinsert (h, sym.st_name, |
637 | 0 | (const void *) (uintptr_t) |
638 | 0 | cache->ctf_symhash_latest) < 0) |
639 | 0 | goto oom; |
640 | 0 | if (strcmp (sym.st_name, symname) == 0) |
641 | 0 | return cache->ctf_symhash_latest++; |
642 | 0 | } |
643 | | |
644 | | /* Searched everything, still not found. */ |
645 | | |
646 | 0 | return (unsigned long) -1; |
647 | | |
648 | 0 | try_parent: |
649 | 0 | if (fp->ctf_parent && try_parent) |
650 | 0 | { |
651 | 0 | unsigned long psym; |
652 | |
|
653 | 0 | if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent, |
654 | 0 | is_function)) |
655 | 0 | != (unsigned long) -1) |
656 | 0 | return psym; |
657 | | |
658 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
659 | 0 | return (unsigned long) -1; |
660 | 0 | } |
661 | 0 | else |
662 | 0 | { |
663 | 0 | ctf_set_errno (fp, err); |
664 | 0 | return (unsigned long) -1; |
665 | 0 | } |
666 | 0 | oom: |
667 | 0 | ctf_set_errno (fp, ENOMEM); |
668 | 0 | ctf_err_warn (fp, 0, 0, _("cannot allocate memory for symbol " |
669 | 0 | "lookup hashtab")); |
670 | 0 | return (unsigned long) -1; |
671 | |
|
672 | 0 | } |
673 | | |
674 | | ctf_id_t |
675 | | ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
676 | | int functions); |
677 | | |
678 | | /* Iterate over all symbols with types: if FUNC, function symbols, |
679 | | otherwise, data symbols. The name argument is not optional. The return |
680 | | order is arbitrary, though is likely to be in symbol index or name order. |
681 | | Changing the value of 'functions' in the middle of iteration has |
682 | | unpredictable effects (probably skipping symbols, etc) and is not |
683 | | recommended. Adding symbols while iteration is underway may also lead |
684 | | to other symbols being skipped. */ |
685 | | |
686 | | ctf_id_t |
687 | | ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
688 | | int functions) |
689 | 0 | { |
690 | 0 | ctf_id_t sym = CTF_ERR; |
691 | 0 | ctf_next_t *i = *it; |
692 | 0 | int err; |
693 | |
|
694 | 0 | if (!i) |
695 | 0 | { |
696 | 0 | if ((i = ctf_next_create ()) == NULL) |
697 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
698 | | |
699 | 0 | i->cu.ctn_fp = fp; |
700 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; |
701 | 0 | i->ctn_n = 0; |
702 | 0 | *it = i; |
703 | 0 | } |
704 | | |
705 | 0 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) |
706 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
707 | | |
708 | 0 | if (fp != i->cu.ctn_fp) |
709 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
710 | | |
711 | | /* Check the dynamic set of names first, to allow previously-written names |
712 | | to be replaced with dynamic ones (there is still no way to remove them, |
713 | | though). |
714 | | |
715 | | We intentionally use raw access, not ctf_lookup_by_symbol, to avoid |
716 | | incurring additional sorting cost for unsorted symtypetabs coming from the |
717 | | compiler, to allow ctf_symbol_next to work in the absence of a symtab, and |
718 | | finally because it's easier to work out what the name of each symbol is if |
719 | | we do that. */ |
720 | | |
721 | 0 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
722 | 0 | void *dyn_name = NULL, *dyn_value = NULL; |
723 | 0 | size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; |
724 | |
|
725 | 0 | if (i->ctn_n < dyn_els) |
726 | 0 | { |
727 | 0 | err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); |
728 | | |
729 | | /* This covers errors and also end-of-iteration. */ |
730 | 0 | if (err != 0) |
731 | 0 | { |
732 | 0 | ctf_next_destroy (i); |
733 | 0 | *it = NULL; |
734 | 0 | return ctf_set_typed_errno (fp, err); |
735 | 0 | } |
736 | | |
737 | 0 | *name = dyn_name; |
738 | 0 | sym = (ctf_id_t) (uintptr_t) dyn_value; |
739 | 0 | i->ctn_n++; |
740 | |
|
741 | 0 | return sym; |
742 | 0 | } |
743 | | |
744 | 0 | return ctf_symbol_next_static (fp, it, name, functions); |
745 | 0 | } |
746 | | |
747 | | /* ctf_symbol_next, but only for static symbols. Mostly an internal |
748 | | implementation detail of ctf_symbol_next, but also used to simplify |
749 | | serialization. */ |
750 | | ctf_id_t |
751 | | ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
752 | | int functions) |
753 | 0 | { |
754 | 0 | ctf_id_t sym = CTF_ERR; |
755 | 0 | ctf_next_t *i = *it; |
756 | 0 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
757 | 0 | size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; |
758 | | |
759 | | /* Only relevant for direct internal-to-library calls, not via |
760 | | ctf_symbol_next (but important then). */ |
761 | |
|
762 | 0 | if (!i) |
763 | 0 | { |
764 | 0 | if ((i = ctf_next_create ()) == NULL) |
765 | 0 | return ctf_set_typed_errno (fp, ENOMEM); |
766 | | |
767 | 0 | i->cu.ctn_fp = fp; |
768 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; |
769 | 0 | i->ctn_n = dyn_els; |
770 | 0 | *it = i; |
771 | 0 | } |
772 | | |
773 | 0 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) |
774 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
775 | | |
776 | 0 | if (fp != i->cu.ctn_fp) |
777 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
778 | | |
779 | | /* TODO-v4: Indexed after non-indexed portions? */ |
780 | | |
781 | 0 | if ((!functions && fp->ctf_objtidx_names) || |
782 | 0 | (functions && fp->ctf_funcidx_names)) |
783 | 0 | { |
784 | 0 | ctf_header_t *hp = fp->ctf_header; |
785 | 0 | uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names; |
786 | 0 | uint32_t *tab; |
787 | 0 | size_t len; |
788 | |
|
789 | 0 | if (functions) |
790 | 0 | { |
791 | 0 | len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t); |
792 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
793 | 0 | } |
794 | 0 | else |
795 | 0 | { |
796 | 0 | len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t); |
797 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
798 | 0 | } |
799 | |
|
800 | 0 | do |
801 | 0 | { |
802 | 0 | if (i->ctn_n - dyn_els >= len) |
803 | 0 | goto end; |
804 | | |
805 | 0 | *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]); |
806 | 0 | sym = tab[i->ctn_n - dyn_els]; |
807 | 0 | i->ctn_n++; |
808 | 0 | } |
809 | 0 | while (sym == -1u || sym == 0); |
810 | 0 | } |
811 | 0 | else |
812 | 0 | { |
813 | | /* Skip over pads in ctf_sxlate, padding for typeless symbols in the |
814 | | symtypetab itself, and symbols in the wrong table. */ |
815 | 0 | for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++) |
816 | 0 | { |
817 | 0 | ctf_header_t *hp = fp->ctf_header; |
818 | 0 | size_t n = i->ctn_n - dyn_els; |
819 | |
|
820 | 0 | if (fp->ctf_sxlate[n] == -1u) |
821 | 0 | continue; |
822 | | |
823 | 0 | sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]); |
824 | |
|
825 | 0 | if (sym == 0) |
826 | 0 | continue; |
827 | | |
828 | 0 | if (functions) |
829 | 0 | { |
830 | 0 | if (fp->ctf_sxlate[n] >= hp->cth_funcoff |
831 | 0 | && fp->ctf_sxlate[n] < hp->cth_objtidxoff) |
832 | 0 | break; |
833 | 0 | } |
834 | 0 | else |
835 | 0 | { |
836 | 0 | if (fp->ctf_sxlate[n] >= hp->cth_objtoff |
837 | 0 | && fp->ctf_sxlate[n] < hp->cth_funcoff) |
838 | 0 | break; |
839 | 0 | } |
840 | 0 | } |
841 | |
|
842 | 0 | if (i->ctn_n - dyn_els >= fp->ctf_nsyms) |
843 | 0 | goto end; |
844 | | |
845 | 0 | *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els); |
846 | 0 | i->ctn_n++; |
847 | 0 | } |
848 | | |
849 | 0 | return sym; |
850 | | |
851 | 0 | end: |
852 | 0 | ctf_next_destroy (i); |
853 | 0 | *it = NULL; |
854 | 0 | return (ctf_set_typed_errno (fp, ECTF_NEXT_END)); |
855 | 0 | } |
856 | | |
857 | | /* A bsearch function for function and object index names. */ |
858 | | |
859 | | static int |
860 | | ctf_lookup_idx_name (const void *key_, const void *idx_) |
861 | 0 | { |
862 | 0 | const ctf_lookup_idx_key_t *key = key_; |
863 | 0 | const uint32_t *idx = idx_; |
864 | |
|
865 | 0 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx]))); |
866 | 0 | } |
867 | | |
868 | | /* Given a symbol name or (failing that) number, look up that symbol in the |
869 | | function or object index table (which must exist). Return 0 if not found |
870 | | there (or pad). */ |
871 | | |
872 | | static ctf_id_t |
873 | | ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, |
874 | | const char *symname, int is_function) |
875 | 0 | { |
876 | 0 | struct ctf_header *hp = fp->ctf_header; |
877 | 0 | uint32_t *symtypetab; |
878 | 0 | uint32_t *names; |
879 | 0 | uint32_t *sxlate; |
880 | 0 | size_t nidx; |
881 | |
|
882 | 0 | if (symname == NULL) |
883 | 0 | symname = ctf_lookup_symbol_name (fp, symidx); |
884 | | |
885 | | /* Dynamic dict with no static portion: just return. */ |
886 | 0 | if (!hp) |
887 | 0 | { |
888 | 0 | ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname); |
889 | 0 | return 0; |
890 | 0 | } |
891 | | |
892 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in " |
893 | 0 | "indexed symtypetab\n", symidx, symname); |
894 | |
|
895 | 0 | if (symname[0] == '\0') |
896 | 0 | return CTF_ERR; /* errno is set for us. */ |
897 | | |
898 | 0 | if (is_function) |
899 | 0 | { |
900 | 0 | if (!fp->ctf_funcidx_sxlate) |
901 | 0 | { |
902 | 0 | if ((fp->ctf_funcidx_sxlate |
903 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
904 | 0 | (fp->ctf_buf + hp->cth_funcidxoff), |
905 | 0 | &fp->ctf_nfuncidx, |
906 | 0 | hp->cth_varoff - hp->cth_funcidxoff)) |
907 | 0 | == NULL) |
908 | 0 | { |
909 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort function symidx")); |
910 | 0 | return CTF_ERR; /* errno is set for us. */ |
911 | 0 | } |
912 | 0 | } |
913 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
914 | 0 | sxlate = fp->ctf_funcidx_sxlate; |
915 | 0 | names = fp->ctf_funcidx_names; |
916 | 0 | nidx = fp->ctf_nfuncidx; |
917 | 0 | } |
918 | 0 | else |
919 | 0 | { |
920 | 0 | if (!fp->ctf_objtidx_sxlate) |
921 | 0 | { |
922 | 0 | if ((fp->ctf_objtidx_sxlate |
923 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
924 | 0 | (fp->ctf_buf + hp->cth_objtidxoff), |
925 | 0 | &fp->ctf_nobjtidx, |
926 | 0 | hp->cth_funcidxoff - hp->cth_objtidxoff)) |
927 | 0 | == NULL) |
928 | 0 | { |
929 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort object symidx")); |
930 | 0 | return CTF_ERR; /* errno is set for us. */ |
931 | 0 | } |
932 | 0 | } |
933 | | |
934 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
935 | 0 | sxlate = fp->ctf_objtidx_sxlate; |
936 | 0 | names = fp->ctf_objtidx_names; |
937 | 0 | nidx = fp->ctf_nobjtidx; |
938 | 0 | } |
939 | | |
940 | 0 | ctf_lookup_idx_key_t key = { fp, symname, names }; |
941 | 0 | uint32_t *idx; |
942 | |
|
943 | 0 | idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name); |
944 | |
|
945 | 0 | if (!idx) |
946 | 0 | { |
947 | 0 | ctf_dprintf ("%s not found in idx\n", symname); |
948 | 0 | return 0; |
949 | 0 | } |
950 | | |
951 | | /* Should be impossible, but be paranoid. */ |
952 | 0 | if ((idx - sxlate) > (ptrdiff_t) nidx) |
953 | 0 | return (ctf_set_typed_errno (fp, ECTF_CORRUPT)); |
954 | | |
955 | 0 | ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname, |
956 | 0 | symtypetab[*idx]); |
957 | 0 | return symtypetab[*idx]; |
958 | 0 | } |
959 | | |
960 | | /* Given a symbol name or (if NULL) symbol index, return the type of the |
961 | | function or data object described by the corresponding entry in the symbol |
962 | | table. We can only return symbols in read-only dicts and in dicts for which |
963 | | ctf_link_shuffle_syms has been called to assign symbol indexes to symbol |
964 | | names. |
965 | | |
966 | | If try_parent is false, do not check the parent dict too. |
967 | | |
968 | | If is_function is > -1, only look for data objects or functions in |
969 | | particular. */ |
970 | | |
971 | | ctf_id_t |
972 | | ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx, |
973 | | const char *symname, int try_parent, |
974 | | int is_function) |
975 | 0 | { |
976 | 0 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
977 | 0 | ctf_id_t type = 0; |
978 | 0 | int err = 0; |
979 | | |
980 | | /* Shuffled dynsymidx present? Use that. For now, the dynsymidx and |
981 | | shuffled-symbol lookup only support dynamically-added symbols, because |
982 | | this interface is meant for use by linkers, and linkers are only going |
983 | | to report symbols against newly-created, freshly-ctf_link'ed dicts: so |
984 | | there will be no static component in any case. */ |
985 | 0 | if (fp->ctf_dynsymidx) |
986 | 0 | { |
987 | 0 | const ctf_link_sym_t *sym; |
988 | |
|
989 | 0 | if (symname) |
990 | 0 | ctf_dprintf ("Looking up type of object with symname %s in " |
991 | 0 | "writable dict symtypetab\n", symname); |
992 | 0 | else |
993 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx in " |
994 | 0 | "writable dict symtypetab\n", symidx); |
995 | | |
996 | | /* No name? Need to look it up. */ |
997 | 0 | if (!symname) |
998 | 0 | { |
999 | 0 | err = EINVAL; |
1000 | 0 | if (symidx > fp->ctf_dynsymmax) |
1001 | 0 | goto try_parent; |
1002 | | |
1003 | 0 | sym = fp->ctf_dynsymidx[symidx]; |
1004 | 0 | err = ECTF_NOTYPEDAT; |
1005 | 0 | if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC) |
1006 | 0 | || (sym->st_type != STT_OBJECT && is_function == 0) |
1007 | 0 | || (sym->st_type != STT_FUNC && is_function == 1)) |
1008 | 0 | goto try_parent; |
1009 | | |
1010 | 0 | if (!ctf_assert (fp, !sym->st_nameidx_set)) |
1011 | 0 | return CTF_ERR; |
1012 | 0 | symname = sym->st_name; |
1013 | 0 | } |
1014 | | |
1015 | 0 | if (fp->ctf_objthash == NULL |
1016 | 0 | || is_function == 1 |
1017 | 0 | || (type = (ctf_id_t) (uintptr_t) |
1018 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0) |
1019 | 0 | { |
1020 | 0 | if (fp->ctf_funchash == NULL |
1021 | 0 | || is_function == 0 |
1022 | 0 | || (type = (ctf_id_t) (uintptr_t) |
1023 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0) |
1024 | 0 | goto try_parent; |
1025 | 0 | } |
1026 | | |
1027 | 0 | return type; |
1028 | 0 | } |
1029 | | |
1030 | | /* Dict not shuffled: look for a dynamic sym first, and look it up |
1031 | | directly. */ |
1032 | 0 | if (symname) |
1033 | 0 | { |
1034 | 0 | if (fp->ctf_objthash != NULL |
1035 | 0 | && is_function != 1 |
1036 | 0 | && ((type = (ctf_id_t) (uintptr_t) |
1037 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0)) |
1038 | 0 | return type; |
1039 | | |
1040 | 0 | if (fp->ctf_funchash != NULL |
1041 | 0 | && is_function != 0 |
1042 | 0 | && ((type = (ctf_id_t) (uintptr_t) |
1043 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0)) |
1044 | 0 | return type; |
1045 | 0 | } |
1046 | | |
1047 | 0 | err = ECTF_NOSYMTAB; |
1048 | 0 | if (sp->cts_data == NULL && symname == NULL && |
1049 | 0 | ((is_function && !fp->ctf_funcidx_names) || |
1050 | 0 | (!is_function && !fp->ctf_objtidx_names))) |
1051 | 0 | goto try_parent; |
1052 | | |
1053 | | /* This covers both out-of-range lookups by index and a dynamic dict which |
1054 | | hasn't been shuffled yet. */ |
1055 | 0 | err = EINVAL; |
1056 | 0 | if (symname == NULL && symidx >= fp->ctf_nsyms) |
1057 | 0 | goto try_parent; |
1058 | | |
1059 | | /* Try an indexed lookup. */ |
1060 | | |
1061 | 0 | if (fp->ctf_objtidx_names && is_function != 1) |
1062 | 0 | { |
1063 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR) |
1064 | 0 | return CTF_ERR; /* errno is set for us. */ |
1065 | 0 | } |
1066 | 0 | if (type == 0 && fp->ctf_funcidx_names && is_function != 0) |
1067 | 0 | { |
1068 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR) |
1069 | 0 | return CTF_ERR; /* errno is set for us. */ |
1070 | 0 | } |
1071 | 0 | if (type != 0) |
1072 | 0 | return type; |
1073 | | |
1074 | | /* Indexed but no symbol found -> not present, try the parent. */ |
1075 | 0 | err = ECTF_NOTYPEDAT; |
1076 | 0 | if (fp->ctf_objtidx_names && fp->ctf_funcidx_names) |
1077 | 0 | goto try_parent; |
1078 | | |
1079 | | /* Table must be nonindexed. */ |
1080 | | |
1081 | 0 | ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx); |
1082 | |
|
1083 | 0 | if (symname != NULL) |
1084 | 0 | if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function)) |
1085 | 0 | == (unsigned long) -1) |
1086 | 0 | goto try_parent; |
1087 | | |
1088 | 0 | if (fp->ctf_sxlate[symidx] == -1u) |
1089 | 0 | goto try_parent; |
1090 | | |
1091 | 0 | type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]); |
1092 | |
|
1093 | 0 | if (type == 0) |
1094 | 0 | goto try_parent; |
1095 | | |
1096 | 0 | return type; |
1097 | | |
1098 | 0 | try_parent: |
1099 | 0 | if (!try_parent) |
1100 | 0 | return ctf_set_errno (fp, err); |
1101 | | |
1102 | 0 | if (fp->ctf_parent) |
1103 | 0 | { |
1104 | 0 | ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx, |
1105 | 0 | symname, try_parent, |
1106 | 0 | is_function); |
1107 | 0 | if (ret == CTF_ERR) |
1108 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
1109 | 0 | return ret; |
1110 | 0 | } |
1111 | 0 | else |
1112 | 0 | return (ctf_set_typed_errno (fp, err)); |
1113 | 0 | } |
1114 | | |
1115 | | /* Given a symbol table index, return the type of the function or data object |
1116 | | described by the corresponding entry in the symbol table. */ |
1117 | | ctf_id_t |
1118 | | ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx) |
1119 | 0 | { |
1120 | 0 | return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1); |
1121 | 0 | } |
1122 | | |
1123 | | /* Given a symbol name, return the type of the function or data object described |
1124 | | by the corresponding entry in the symbol table. */ |
1125 | | ctf_id_t |
1126 | | ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname) |
1127 | 0 | { |
1128 | 0 | return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1); |
1129 | 0 | } |
1130 | | |
1131 | | /* Given a symbol table index, return the info for the function described |
1132 | | by the corresponding entry in the symbol table, which may be a function |
1133 | | symbol or may be a data symbol that happens to be a function pointer. */ |
1134 | | |
1135 | | int |
1136 | | ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip) |
1137 | 0 | { |
1138 | 0 | ctf_id_t type; |
1139 | |
|
1140 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1141 | 0 | return -1; /* errno is set for us. */ |
1142 | | |
1143 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1144 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1145 | | |
1146 | 0 | return ctf_func_type_info (fp, type, fip); |
1147 | 0 | } |
1148 | | |
1149 | | /* Given a symbol table index, return the arguments for the function described |
1150 | | by the corresponding entry in the symbol table. */ |
1151 | | |
1152 | | int |
1153 | | ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc, |
1154 | | ctf_id_t *argv) |
1155 | 0 | { |
1156 | 0 | ctf_id_t type; |
1157 | |
|
1158 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1159 | 0 | return -1; /* errno is set for us. */ |
1160 | | |
1161 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1162 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1163 | | |
1164 | 0 | return ctf_func_type_args (fp, type, argc, argv); |
1165 | 0 | } |