/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-2023 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_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 | { |
277 | 0 | ctf_set_errno (fp, ENOMEM); |
278 | 0 | return CTF_ERR; |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | 0 | if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash, |
283 | 0 | fp->ctf_tmp_typeslice)) == 0) |
284 | 0 | goto notype; |
285 | | |
286 | 0 | break; |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | 0 | if (lp->ctl_prefix == NULL) |
291 | 0 | goto notype; |
292 | 0 | } |
293 | | |
294 | 0 | if (*p != '\0' || type == 0) |
295 | 0 | return (ctf_set_errno (fp, ECTF_SYNTAX)); |
296 | | |
297 | 0 | return type; |
298 | | |
299 | 0 | notype: |
300 | 0 | ctf_set_errno (fp, ECTF_NOTYPE); |
301 | 0 | if (fp->ctf_parent != NULL) |
302 | 0 | { |
303 | | /* Need to look up in the parent, from the child's perspective. |
304 | | Make sure the pptrtab is up to date. */ |
305 | |
|
306 | 0 | if (fp->ctf_pptrtab_typemax < fp->ctf_typemax) |
307 | 0 | { |
308 | 0 | if (refresh_pptrtab (fp, fp->ctf_parent) < 0) |
309 | 0 | return -1; /* errno is set for us. */ |
310 | 0 | } |
311 | | |
312 | 0 | if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp, |
313 | 0 | name)) != CTF_ERR) |
314 | 0 | return ptype; |
315 | 0 | return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent))); |
316 | 0 | } |
317 | | |
318 | 0 | return CTF_ERR; |
319 | 0 | } |
320 | | |
321 | | ctf_id_t |
322 | | ctf_lookup_by_name (ctf_dict_t *fp, const char *name) |
323 | 0 | { |
324 | 0 | return ctf_lookup_by_name_internal (fp, NULL, name); |
325 | 0 | } |
326 | | |
327 | | /* Return the pointer to the internal CTF type data corresponding to the |
328 | | given type ID. If the ID is invalid, the function returns NULL. |
329 | | This function is not exported outside of the library. */ |
330 | | |
331 | | const ctf_type_t * |
332 | | ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type) |
333 | 0 | { |
334 | 0 | ctf_dict_t *fp = *fpp; /* Caller passes in starting CTF dict. */ |
335 | 0 | ctf_id_t idx; |
336 | |
|
337 | 0 | if ((fp = ctf_get_dict (fp, type)) == NULL) |
338 | 0 | { |
339 | 0 | (void) ctf_set_errno (*fpp, ECTF_NOPARENT); |
340 | 0 | return NULL; |
341 | 0 | } |
342 | | |
343 | | /* If this dict is writable, check for a dynamic type. */ |
344 | | |
345 | 0 | if (fp->ctf_flags & LCTF_RDWR) |
346 | 0 | { |
347 | 0 | ctf_dtdef_t *dtd; |
348 | |
|
349 | 0 | if ((dtd = ctf_dynamic_type (fp, type)) != NULL) |
350 | 0 | { |
351 | 0 | *fpp = fp; |
352 | 0 | return &dtd->dtd_data; |
353 | 0 | } |
354 | 0 | (void) ctf_set_errno (*fpp, ECTF_BADID); |
355 | 0 | return NULL; |
356 | 0 | } |
357 | | |
358 | | /* Check for a type in the static portion. */ |
359 | | |
360 | 0 | idx = LCTF_TYPE_TO_INDEX (fp, type); |
361 | 0 | if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) |
362 | 0 | { |
363 | 0 | *fpp = fp; /* Function returns ending CTF dict. */ |
364 | 0 | return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); |
365 | 0 | } |
366 | | |
367 | 0 | (void) ctf_set_errno (*fpp, ECTF_BADID); |
368 | 0 | return NULL; |
369 | 0 | } |
370 | | |
371 | | typedef struct ctf_lookup_idx_key |
372 | | { |
373 | | ctf_dict_t *clik_fp; |
374 | | const char *clik_name; |
375 | | uint32_t *clik_names; |
376 | | } ctf_lookup_idx_key_t; |
377 | | |
378 | | /* A bsearch function for variable names. */ |
379 | | |
380 | | static int |
381 | | ctf_lookup_var (const void *key_, const void *lookup_) |
382 | 0 | { |
383 | 0 | const ctf_lookup_idx_key_t *key = key_; |
384 | 0 | const ctf_varent_t *lookup = lookup_; |
385 | |
|
386 | 0 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name))); |
387 | 0 | } |
388 | | |
389 | | /* Given a variable name, return the type of the variable with that name. */ |
390 | | |
391 | | ctf_id_t |
392 | | ctf_lookup_variable (ctf_dict_t *fp, const char *name) |
393 | 0 | { |
394 | 0 | ctf_varent_t *ent; |
395 | 0 | ctf_lookup_idx_key_t key = { fp, name, NULL }; |
396 | | |
397 | | /* This array is sorted, so we can bsearch for it. */ |
398 | |
|
399 | 0 | ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t), |
400 | 0 | ctf_lookup_var); |
401 | |
|
402 | 0 | if (ent == NULL) |
403 | 0 | { |
404 | 0 | if (fp->ctf_parent != NULL) |
405 | 0 | { |
406 | 0 | ctf_id_t ptype; |
407 | |
|
408 | 0 | if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR) |
409 | 0 | return ptype; |
410 | 0 | return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent))); |
411 | 0 | } |
412 | | |
413 | 0 | return (ctf_set_errno (fp, ECTF_NOTYPEDAT)); |
414 | 0 | } |
415 | | |
416 | 0 | return ent->ctv_type; |
417 | 0 | } |
418 | | |
419 | | typedef struct ctf_symidx_sort_arg_cb |
420 | | { |
421 | | ctf_dict_t *fp; |
422 | | uint32_t *names; |
423 | | } ctf_symidx_sort_arg_cb_t; |
424 | | |
425 | | static int |
426 | | sort_symidx_by_name (const void *one_, const void *two_, void *arg_) |
427 | 0 | { |
428 | 0 | const uint32_t *one = one_; |
429 | 0 | const uint32_t *two = two_; |
430 | 0 | ctf_symidx_sort_arg_cb_t *arg = arg_; |
431 | |
|
432 | 0 | return (strcmp (ctf_strptr (arg->fp, arg->names[*one]), |
433 | 0 | ctf_strptr (arg->fp, arg->names[*two]))); |
434 | 0 | } |
435 | | |
436 | | /* Sort a symbol index section by name. Takes a 1:1 mapping of names to the |
437 | | corresponding symbol table. Returns a lexicographically sorted array of idx |
438 | | indexes (and thus, of indexes into the corresponding func info / data object |
439 | | section). */ |
440 | | |
441 | | static uint32_t * |
442 | | ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx, |
443 | | size_t len) |
444 | 0 | { |
445 | 0 | uint32_t *sorted; |
446 | 0 | size_t i; |
447 | |
|
448 | 0 | if ((sorted = malloc (len)) == NULL) |
449 | 0 | { |
450 | 0 | ctf_set_errno (fp, ENOMEM); |
451 | 0 | return NULL; |
452 | 0 | } |
453 | | |
454 | 0 | *nidx = len / sizeof (uint32_t); |
455 | 0 | for (i = 0; i < *nidx; i++) |
456 | 0 | sorted[i] = i; |
457 | |
|
458 | 0 | if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED)) |
459 | 0 | { |
460 | 0 | ctf_symidx_sort_arg_cb_t arg = { fp, idx }; |
461 | 0 | ctf_dprintf ("Index section unsorted: sorting."); |
462 | 0 | ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg); |
463 | 0 | fp->ctf_header->cth_flags |= CTF_F_IDXSORTED; |
464 | 0 | } |
465 | |
|
466 | 0 | return sorted; |
467 | 0 | } |
468 | | |
469 | | /* Given a symbol index, return the name of that symbol from the table provided |
470 | | by ctf_link_shuffle_syms, or failing that from the secondary string table, or |
471 | | the null string. */ |
472 | | static const char * |
473 | | ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx) |
474 | 0 | { |
475 | 0 | const ctf_sect_t *sp = &fp->ctf_symtab; |
476 | 0 | ctf_link_sym_t sym; |
477 | 0 | int err; |
478 | |
|
479 | 0 | if (fp->ctf_dynsymidx) |
480 | 0 | { |
481 | 0 | err = EINVAL; |
482 | 0 | if (symidx > fp->ctf_dynsymmax) |
483 | 0 | goto try_parent; |
484 | | |
485 | 0 | ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx]; |
486 | |
|
487 | 0 | if (!symp) |
488 | 0 | goto try_parent; |
489 | | |
490 | 0 | return symp->st_name; |
491 | 0 | } |
492 | | |
493 | 0 | err = ECTF_NOSYMTAB; |
494 | 0 | if (sp->cts_data == NULL) |
495 | 0 | goto try_parent; |
496 | | |
497 | 0 | if (symidx >= fp->ctf_nsyms) |
498 | 0 | goto try_parent; |
499 | | |
500 | 0 | switch (sp->cts_entsize) |
501 | 0 | { |
502 | 0 | case sizeof (Elf64_Sym): |
503 | 0 | { |
504 | 0 | const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx; |
505 | 0 | ctf_elf64_to_link_sym (fp, &sym, symp, symidx); |
506 | 0 | } |
507 | 0 | break; |
508 | 0 | case sizeof (Elf32_Sym): |
509 | 0 | { |
510 | 0 | const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx; |
511 | 0 | ctf_elf32_to_link_sym (fp, &sym, symp, symidx); |
512 | 0 | } |
513 | 0 | break; |
514 | 0 | default: |
515 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
516 | 0 | return _CTF_NULLSTR; |
517 | 0 | } |
518 | | |
519 | 0 | assert (!sym.st_nameidx_set); |
520 | | |
521 | 0 | return sym.st_name; |
522 | | |
523 | 0 | try_parent: |
524 | 0 | if (fp->ctf_parent) |
525 | 0 | { |
526 | 0 | const char *ret; |
527 | 0 | ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx); |
528 | 0 | if (ret == NULL) |
529 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
530 | 0 | return ret; |
531 | 0 | } |
532 | 0 | else |
533 | 0 | { |
534 | 0 | ctf_set_errno (fp, err); |
535 | 0 | return _CTF_NULLSTR; |
536 | 0 | } |
537 | 0 | } |
538 | | |
539 | | /* Given a symbol name, return the index of that symbol, or -1 on error or if |
540 | | not found. */ |
541 | | static unsigned long |
542 | | ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname) |
543 | 0 | { |
544 | 0 | const ctf_sect_t *sp = &fp->ctf_symtab; |
545 | 0 | ctf_link_sym_t sym; |
546 | 0 | void *known_idx; |
547 | 0 | int err; |
548 | 0 | ctf_dict_t *cache = fp; |
549 | |
|
550 | 0 | if (fp->ctf_dynsyms) |
551 | 0 | { |
552 | 0 | err = EINVAL; |
553 | |
|
554 | 0 | ctf_link_sym_t *symp; |
555 | |
|
556 | 0 | if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL) |
557 | 0 | goto try_parent; |
558 | | |
559 | 0 | return symp->st_symidx; |
560 | 0 | } |
561 | | |
562 | 0 | err = ECTF_NOSYMTAB; |
563 | 0 | if (sp->cts_data == NULL) |
564 | 0 | goto try_parent; |
565 | | |
566 | | /* First, try a hash lookup to see if we have already spotted this symbol |
567 | | during a past iteration: create the hash first if need be. The lifespan |
568 | | of the strings is equal to the lifespan of the cts_data, so we don't |
569 | | need to strdup them. If this dict was opened as part of an archive, |
570 | | and this archive has designed a crossdict_cache to cache results that |
571 | | are the same across all dicts in an archive, use it. */ |
572 | | |
573 | 0 | if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache) |
574 | 0 | cache = fp->ctf_archive->ctfi_crossdict_cache; |
575 | |
|
576 | 0 | if (!cache->ctf_symhash) |
577 | 0 | if ((cache->ctf_symhash = ctf_dynhash_create (ctf_hash_string, |
578 | 0 | ctf_hash_eq_string, |
579 | 0 | NULL, NULL)) == NULL) |
580 | 0 | goto oom; |
581 | | |
582 | 0 | if (ctf_dynhash_lookup_kv (cache->ctf_symhash, symname, NULL, &known_idx)) |
583 | 0 | return (unsigned long) (uintptr_t) known_idx; |
584 | | |
585 | | /* Hash lookup unsuccessful: linear search, populating the hashtab for later |
586 | | lookups as we go. */ |
587 | | |
588 | 0 | for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize; |
589 | 0 | cache->ctf_symhash_latest++) |
590 | 0 | { |
591 | 0 | switch (sp->cts_entsize) |
592 | 0 | { |
593 | 0 | case sizeof (Elf64_Sym): |
594 | 0 | { |
595 | 0 | Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data; |
596 | 0 | ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
597 | 0 | cache->ctf_symhash_latest); |
598 | 0 | if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name, |
599 | 0 | NULL, NULL)) |
600 | 0 | if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name, |
601 | 0 | (const void *) (uintptr_t) |
602 | 0 | cache->ctf_symhash_latest) < 0) |
603 | 0 | goto oom; |
604 | 0 | if (strcmp (sym.st_name, symname) == 0) |
605 | 0 | return cache->ctf_symhash_latest++; |
606 | 0 | } |
607 | 0 | break; |
608 | 0 | case sizeof (Elf32_Sym): |
609 | 0 | { |
610 | 0 | Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data; |
611 | 0 | ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
612 | 0 | cache->ctf_symhash_latest); |
613 | 0 | if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name, |
614 | 0 | NULL, NULL)) |
615 | 0 | if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name, |
616 | 0 | (const void *) (uintptr_t) |
617 | 0 | cache->ctf_symhash_latest) < 0) |
618 | 0 | goto oom; |
619 | 0 | if (strcmp (sym.st_name, symname) == 0) |
620 | 0 | return cache->ctf_symhash_latest++; |
621 | 0 | } |
622 | 0 | break; |
623 | 0 | default: |
624 | 0 | ctf_set_errno (fp, ECTF_SYMTAB); |
625 | 0 | return (unsigned long) -1; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | | /* Searched everything, still not found. */ |
630 | | |
631 | 0 | return (unsigned long) -1; |
632 | | |
633 | 0 | try_parent: |
634 | 0 | if (fp->ctf_parent) |
635 | 0 | { |
636 | 0 | unsigned long psym; |
637 | |
|
638 | 0 | if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname)) |
639 | 0 | != (unsigned long) -1) |
640 | 0 | return psym; |
641 | | |
642 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
643 | 0 | return (unsigned long) -1; |
644 | 0 | } |
645 | 0 | else |
646 | 0 | { |
647 | 0 | ctf_set_errno (fp, err); |
648 | 0 | return (unsigned long) -1; |
649 | 0 | } |
650 | 0 | oom: |
651 | 0 | ctf_set_errno (fp, ENOMEM); |
652 | 0 | ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol " |
653 | 0 | "lookup hashtab")); |
654 | 0 | return (unsigned long) -1; |
655 | |
|
656 | 0 | } |
657 | | |
658 | | /* Iterate over all symbols with types: if FUNC, function symbols, otherwise, |
659 | | data symbols. The name argument is not optional. The return order is |
660 | | arbitrary, though is likely to be in symbol index or name order. You can |
661 | | change the value of 'functions' in the middle of iteration over non-dynamic |
662 | | dicts, but doing so on dynamic dicts will fail. (This is probably not very |
663 | | useful, but there is no reason to prohibit it.) */ |
664 | | |
665 | | ctf_id_t |
666 | | ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
667 | | int functions) |
668 | 0 | { |
669 | 0 | ctf_id_t sym = CTF_ERR; |
670 | 0 | ctf_next_t *i = *it; |
671 | 0 | int err; |
672 | |
|
673 | 0 | if (!i) |
674 | 0 | { |
675 | 0 | if ((i = ctf_next_create ()) == NULL) |
676 | 0 | return ctf_set_errno (fp, ENOMEM); |
677 | | |
678 | 0 | i->cu.ctn_fp = fp; |
679 | 0 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; |
680 | 0 | i->ctn_n = 0; |
681 | 0 | *it = i; |
682 | 0 | } |
683 | | |
684 | 0 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) |
685 | 0 | return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN)); |
686 | | |
687 | 0 | if (fp != i->cu.ctn_fp) |
688 | 0 | return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP)); |
689 | | |
690 | | /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid |
691 | | incurring additional sorting cost for unsorted symtypetabs coming from the |
692 | | compiler, to allow ctf_symbol_next to work in the absence of a symtab, and |
693 | | finally because it's easier to work out what the name of each symbol is if |
694 | | we do that. */ |
695 | | |
696 | 0 | if (fp->ctf_flags & LCTF_RDWR) |
697 | 0 | { |
698 | 0 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
699 | 0 | void *dyn_name = NULL, *dyn_value = NULL; |
700 | |
|
701 | 0 | if (!dynh) |
702 | 0 | { |
703 | 0 | ctf_next_destroy (i); |
704 | 0 | return (ctf_set_errno (fp, ECTF_NEXT_END)); |
705 | 0 | } |
706 | | |
707 | 0 | err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); |
708 | | /* This covers errors and also end-of-iteration. */ |
709 | 0 | if (err != 0) |
710 | 0 | { |
711 | 0 | ctf_next_destroy (i); |
712 | 0 | *it = NULL; |
713 | 0 | return ctf_set_errno (fp, err); |
714 | 0 | } |
715 | | |
716 | 0 | *name = dyn_name; |
717 | 0 | sym = (ctf_id_t) (uintptr_t) dyn_value; |
718 | 0 | } |
719 | 0 | else if ((!functions && fp->ctf_objtidx_names) || |
720 | 0 | (functions && fp->ctf_funcidx_names)) |
721 | 0 | { |
722 | 0 | ctf_header_t *hp = fp->ctf_header; |
723 | 0 | uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names; |
724 | 0 | uint32_t *tab; |
725 | 0 | size_t len; |
726 | |
|
727 | 0 | if (functions) |
728 | 0 | { |
729 | 0 | len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t); |
730 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
731 | 0 | } |
732 | 0 | else |
733 | 0 | { |
734 | 0 | len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t); |
735 | 0 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
736 | 0 | } |
737 | |
|
738 | 0 | do |
739 | 0 | { |
740 | 0 | if (i->ctn_n >= len) |
741 | 0 | goto end; |
742 | | |
743 | 0 | *name = ctf_strptr (fp, idx[i->ctn_n]); |
744 | 0 | sym = tab[i->ctn_n++]; |
745 | 0 | } |
746 | 0 | while (sym == -1u || sym == 0); |
747 | 0 | } |
748 | 0 | else |
749 | 0 | { |
750 | | /* Skip over pads in ctf_xslate, padding for typeless symbols in the |
751 | | symtypetab itself, and symbols in the wrong table. */ |
752 | 0 | for (; i->ctn_n < fp->ctf_nsyms; i->ctn_n++) |
753 | 0 | { |
754 | 0 | ctf_header_t *hp = fp->ctf_header; |
755 | |
|
756 | 0 | if (fp->ctf_sxlate[i->ctn_n] == -1u) |
757 | 0 | continue; |
758 | | |
759 | 0 | sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[i->ctn_n]); |
760 | |
|
761 | 0 | if (sym == 0) |
762 | 0 | continue; |
763 | | |
764 | 0 | if (functions) |
765 | 0 | { |
766 | 0 | if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_funcoff |
767 | 0 | && fp->ctf_sxlate[i->ctn_n] < hp->cth_objtidxoff) |
768 | 0 | break; |
769 | 0 | } |
770 | 0 | else |
771 | 0 | { |
772 | 0 | if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_objtoff |
773 | 0 | && fp->ctf_sxlate[i->ctn_n] < hp->cth_funcoff) |
774 | 0 | break; |
775 | 0 | } |
776 | 0 | } |
777 | |
|
778 | 0 | if (i->ctn_n >= fp->ctf_nsyms) |
779 | 0 | goto end; |
780 | | |
781 | 0 | *name = ctf_lookup_symbol_name (fp, i->ctn_n++); |
782 | 0 | } |
783 | | |
784 | 0 | return sym; |
785 | | |
786 | 0 | end: |
787 | 0 | ctf_next_destroy (i); |
788 | 0 | *it = NULL; |
789 | 0 | return (ctf_set_errno (fp, ECTF_NEXT_END)); |
790 | 0 | } |
791 | | |
792 | | /* A bsearch function for function and object index names. */ |
793 | | |
794 | | static int |
795 | | ctf_lookup_idx_name (const void *key_, const void *idx_) |
796 | 0 | { |
797 | 0 | const ctf_lookup_idx_key_t *key = key_; |
798 | 0 | const uint32_t *idx = idx_; |
799 | |
|
800 | 0 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx]))); |
801 | 0 | } |
802 | | |
803 | | /* Given a symbol name or (failing that) number, look up that symbol in the |
804 | | function or object index table (which must exist). Return 0 if not found |
805 | | there (or pad). */ |
806 | | |
807 | | static ctf_id_t |
808 | | ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, |
809 | | const char *symname, int is_function) |
810 | 0 | { |
811 | 0 | struct ctf_header *hp = fp->ctf_header; |
812 | 0 | uint32_t *symtypetab; |
813 | 0 | uint32_t *names; |
814 | 0 | uint32_t *sxlate; |
815 | 0 | size_t nidx; |
816 | |
|
817 | 0 | if (symname == NULL) |
818 | 0 | symname = ctf_lookup_symbol_name (fp, symidx); |
819 | |
|
820 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in " |
821 | 0 | "indexed symtypetab\n", symidx, symname); |
822 | |
|
823 | 0 | if (symname[0] == '\0') |
824 | 0 | return -1; /* errno is set for us. */ |
825 | | |
826 | 0 | if (is_function) |
827 | 0 | { |
828 | 0 | if (!fp->ctf_funcidx_sxlate) |
829 | 0 | { |
830 | 0 | if ((fp->ctf_funcidx_sxlate |
831 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
832 | 0 | (fp->ctf_buf + hp->cth_funcidxoff), |
833 | 0 | &fp->ctf_nfuncidx, |
834 | 0 | hp->cth_varoff - hp->cth_funcidxoff)) |
835 | 0 | == NULL) |
836 | 0 | { |
837 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort function symidx")); |
838 | 0 | return -1; /* errno is set for us. */ |
839 | 0 | } |
840 | 0 | } |
841 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
842 | 0 | sxlate = fp->ctf_funcidx_sxlate; |
843 | 0 | names = fp->ctf_funcidx_names; |
844 | 0 | nidx = fp->ctf_nfuncidx; |
845 | 0 | } |
846 | 0 | else |
847 | 0 | { |
848 | 0 | if (!fp->ctf_objtidx_sxlate) |
849 | 0 | { |
850 | 0 | if ((fp->ctf_objtidx_sxlate |
851 | 0 | = ctf_symidx_sort (fp, (uint32_t *) |
852 | 0 | (fp->ctf_buf + hp->cth_objtidxoff), |
853 | 0 | &fp->ctf_nobjtidx, |
854 | 0 | hp->cth_funcidxoff - hp->cth_objtidxoff)) |
855 | 0 | == NULL) |
856 | 0 | { |
857 | 0 | ctf_err_warn (fp, 0, 0, _("cannot sort object symidx")); |
858 | 0 | return -1; /* errno is set for us. */ |
859 | 0 | } |
860 | 0 | } |
861 | | |
862 | 0 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
863 | 0 | sxlate = fp->ctf_objtidx_sxlate; |
864 | 0 | names = fp->ctf_objtidx_names; |
865 | 0 | nidx = fp->ctf_nobjtidx; |
866 | 0 | } |
867 | | |
868 | 0 | ctf_lookup_idx_key_t key = { fp, symname, names }; |
869 | 0 | uint32_t *idx; |
870 | |
|
871 | 0 | idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name); |
872 | |
|
873 | 0 | if (!idx) |
874 | 0 | { |
875 | 0 | ctf_dprintf ("%s not found in idx\n", symname); |
876 | 0 | return 0; |
877 | 0 | } |
878 | | |
879 | | /* Should be impossible, but be paranoid. */ |
880 | 0 | if ((idx - sxlate) > (ptrdiff_t) nidx) |
881 | 0 | return (ctf_set_errno (fp, ECTF_CORRUPT)); |
882 | | |
883 | 0 | ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname, |
884 | 0 | symtypetab[*idx]); |
885 | 0 | return symtypetab[*idx]; |
886 | 0 | } |
887 | | |
888 | | /* Given a symbol name or (if NULL) symbol index, return the type of the |
889 | | function or data object described by the corresponding entry in the symbol |
890 | | table. We can only return symbols in read-only dicts and in dicts for which |
891 | | ctf_link_shuffle_syms has been called to assign symbol indexes to symbol |
892 | | names. */ |
893 | | |
894 | | static ctf_id_t |
895 | | ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx, |
896 | | const char *symname) |
897 | 0 | { |
898 | 0 | const ctf_sect_t *sp = &fp->ctf_symtab; |
899 | 0 | ctf_id_t type = 0; |
900 | 0 | int err = 0; |
901 | | |
902 | | /* Shuffled dynsymidx present? Use that. */ |
903 | 0 | if (fp->ctf_dynsymidx) |
904 | 0 | { |
905 | 0 | const ctf_link_sym_t *sym; |
906 | |
|
907 | 0 | if (symname) |
908 | 0 | ctf_dprintf ("Looking up type of object with symname %s in " |
909 | 0 | "writable dict symtypetab\n", symname); |
910 | 0 | else |
911 | 0 | ctf_dprintf ("Looking up type of object with symtab idx %lx in " |
912 | 0 | "writable dict symtypetab\n", symidx); |
913 | | |
914 | | /* The dict must be dynamic. */ |
915 | 0 | if (!ctf_assert (fp, fp->ctf_flags & LCTF_RDWR)) |
916 | 0 | return CTF_ERR; |
917 | | |
918 | | /* No name? Need to look it up. */ |
919 | 0 | if (!symname) |
920 | 0 | { |
921 | 0 | err = EINVAL; |
922 | 0 | if (symidx > fp->ctf_dynsymmax) |
923 | 0 | goto try_parent; |
924 | | |
925 | 0 | sym = fp->ctf_dynsymidx[symidx]; |
926 | 0 | err = ECTF_NOTYPEDAT; |
927 | 0 | if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC)) |
928 | 0 | goto try_parent; |
929 | | |
930 | 0 | if (!ctf_assert (fp, !sym->st_nameidx_set)) |
931 | 0 | return CTF_ERR; |
932 | 0 | symname = sym->st_name; |
933 | 0 | } |
934 | | |
935 | 0 | if (fp->ctf_objthash == NULL |
936 | 0 | || ((type = (ctf_id_t) (uintptr_t) |
937 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0)) |
938 | 0 | { |
939 | 0 | if (fp->ctf_funchash == NULL |
940 | 0 | || ((type = (ctf_id_t) (uintptr_t) |
941 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0)) |
942 | 0 | goto try_parent; |
943 | 0 | } |
944 | | |
945 | 0 | return type; |
946 | 0 | } |
947 | | |
948 | | /* Lookup by name in a dynamic dict: just do it directly. */ |
949 | 0 | if (symname && fp->ctf_flags & LCTF_RDWR) |
950 | 0 | { |
951 | 0 | if (fp->ctf_objthash == NULL |
952 | 0 | || ((type = (ctf_id_t) (uintptr_t) |
953 | 0 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0)) |
954 | 0 | { |
955 | 0 | if (fp->ctf_funchash == NULL |
956 | 0 | || ((type = (ctf_id_t) (uintptr_t) |
957 | 0 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0)) |
958 | 0 | goto try_parent; |
959 | 0 | } |
960 | 0 | return type; |
961 | 0 | } |
962 | | |
963 | 0 | err = ECTF_NOSYMTAB; |
964 | 0 | if (sp->cts_data == NULL) |
965 | 0 | goto try_parent; |
966 | | |
967 | | /* This covers both out-of-range lookups and a dynamic dict which hasn't been |
968 | | shuffled yet. */ |
969 | 0 | err = EINVAL; |
970 | 0 | if (symname == NULL && symidx >= fp->ctf_nsyms) |
971 | 0 | goto try_parent; |
972 | | |
973 | 0 | if (fp->ctf_objtidx_names) |
974 | 0 | { |
975 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR) |
976 | 0 | return CTF_ERR; /* errno is set for us. */ |
977 | 0 | } |
978 | 0 | if (type == 0 && fp->ctf_funcidx_names) |
979 | 0 | { |
980 | 0 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR) |
981 | 0 | return CTF_ERR; /* errno is set for us. */ |
982 | 0 | } |
983 | 0 | if (type != 0) |
984 | 0 | return type; |
985 | | |
986 | 0 | err = ECTF_NOTYPEDAT; |
987 | 0 | if (fp->ctf_objtidx_names && fp->ctf_funcidx_names) |
988 | 0 | goto try_parent; |
989 | | |
990 | | /* Table must be nonindexed. */ |
991 | | |
992 | 0 | ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx); |
993 | |
|
994 | 0 | if (symname != NULL) |
995 | 0 | if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1) |
996 | 0 | goto try_parent; |
997 | | |
998 | 0 | if (fp->ctf_sxlate[symidx] == -1u) |
999 | 0 | goto try_parent; |
1000 | | |
1001 | 0 | type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]); |
1002 | |
|
1003 | 0 | if (type == 0) |
1004 | 0 | goto try_parent; |
1005 | | |
1006 | 0 | return type; |
1007 | 0 | try_parent: |
1008 | 0 | if (fp->ctf_parent) |
1009 | 0 | { |
1010 | 0 | ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx, |
1011 | 0 | symname); |
1012 | 0 | if (ret == CTF_ERR) |
1013 | 0 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); |
1014 | 0 | return ret; |
1015 | 0 | } |
1016 | 0 | else |
1017 | 0 | return (ctf_set_errno (fp, err)); |
1018 | 0 | } |
1019 | | |
1020 | | /* Given a symbol table index, return the type of the function or data object |
1021 | | described by the corresponding entry in the symbol table. */ |
1022 | | ctf_id_t |
1023 | | ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx) |
1024 | 0 | { |
1025 | 0 | return ctf_lookup_by_sym_or_name (fp, symidx, NULL); |
1026 | 0 | } |
1027 | | |
1028 | | /* Given a symbol name, return the type of the function or data object described |
1029 | | by the corresponding entry in the symbol table. */ |
1030 | | ctf_id_t |
1031 | | ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname) |
1032 | 0 | { |
1033 | 0 | return ctf_lookup_by_sym_or_name (fp, 0, symname); |
1034 | 0 | } |
1035 | | |
1036 | | /* Given a symbol table index, return the info for the function described |
1037 | | by the corresponding entry in the symbol table, which may be a function |
1038 | | symbol or may be a data symbol that happens to be a function pointer. */ |
1039 | | |
1040 | | int |
1041 | | ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip) |
1042 | 0 | { |
1043 | 0 | ctf_id_t type; |
1044 | |
|
1045 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1046 | 0 | return -1; /* errno is set for us. */ |
1047 | | |
1048 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1049 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1050 | | |
1051 | 0 | return ctf_func_type_info (fp, type, fip); |
1052 | 0 | } |
1053 | | |
1054 | | /* Given a symbol table index, return the arguments for the function described |
1055 | | by the corresponding entry in the symbol table. */ |
1056 | | |
1057 | | int |
1058 | | ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc, |
1059 | | ctf_id_t *argv) |
1060 | 0 | { |
1061 | 0 | ctf_id_t type; |
1062 | |
|
1063 | 0 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1064 | 0 | return -1; /* errno is set for us. */ |
1065 | | |
1066 | 0 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1067 | 0 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); |
1068 | | |
1069 | 0 | return ctf_func_type_args (fp, type, argc, argv); |
1070 | 0 | } |