]>
Commit | Line | Data |
---|---|---|
12a0b67d | 1 | /* Symbol, variable and name lookup. |
fd67aa11 | 2 | Copyright (C) 2019-2024 Free Software Foundation, Inc. |
47d546f4 NA |
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> | |
1136c379 | 23 | #include <assert.h> |
47d546f4 | 24 | |
abe4ca69 NA |
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 | { | |
29 | uint32_t *new_pptrtab; | |
30 | ||
31 | if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t) | |
32 | * new_len)) == NULL) | |
33 | return (ctf_set_errno (fp, ENOMEM)); | |
34 | ||
35 | fp->ctf_pptrtab = new_pptrtab; | |
36 | ||
37 | memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0, | |
38 | sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len)); | |
39 | ||
40 | fp->ctf_pptrtab_len = new_len; | |
41 | return 0; | |
42 | } | |
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 | { | |
49 | uint32_t i; | |
50 | for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++) | |
51 | { | |
52 | ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1); | |
53 | ctf_id_t reffed_type; | |
abe4ca69 NA |
54 | |
55 | if (ctf_type_kind (fp, type) != CTF_K_POINTER) | |
56 | continue; | |
57 | ||
58 | reffed_type = ctf_type_reference (fp, type); | |
59 | ||
60 | if (LCTF_TYPE_ISPARENT (fp, reffed_type)) | |
61 | { | |
62 | 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. */ | |
abe4ca69 NA |
67 | if (idx <= pfp->ctf_typemax) |
68 | { | |
69 | if (idx >= fp->ctf_pptrtab_len | |
70 | && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0) | |
71 | return -1; /* errno is set for us. */ | |
72 | ||
73 | fp->ctf_pptrtab[idx] = i; | |
74 | } | |
75 | } | |
76 | } | |
77 | ||
78 | fp->ctf_pptrtab_typemax = fp->ctf_typemax; | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
b437bfe0 NA |
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 | { | |
101 | static const struct qual | |
102 | { | |
103 | const char *q_name; | |
104 | size_t q_len; | |
105 | } qhash[] = { | |
106 | {"static", 6}, {"", 0}, {"", 0}, {"", 0}, | |
107 | {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, | |
108 | {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0}, | |
109 | {"", 0}, {"", 0}, {"const", 5}, {"register", 8}, | |
110 | {"", 0}, {"restrict", 8}, {"_Restrict", 9} | |
111 | }; | |
112 | ||
113 | int h = s[len - 1] + (int) len - 105; | |
0bd65ce3 | 114 | const struct qual *qp; |
b437bfe0 | 115 | |
0bd65ce3 NA |
116 | if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0])) |
117 | return 0; | |
118 | ||
119 | qp = &qhash[h]; | |
120 | ||
121 | return ((size_t) len == qp->q_len && | |
b437bfe0 NA |
122 | strncmp (qp->q_name, s, qp->q_len) == 0); |
123 | } | |
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 | ||
abe4ca69 NA |
134 | static ctf_id_t |
135 | ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child, | |
136 | const char *name) | |
b437bfe0 NA |
137 | { |
138 | static const char delimiters[] = " \t\n\r\v\f*"; | |
139 | ||
140 | const ctf_lookup_t *lp; | |
141 | const char *p, *q, *end; | |
142 | ctf_id_t type = 0; | |
143 | ctf_id_t ntype, ptype; | |
144 | ||
145 | if (name == NULL) | |
998a4f58 | 146 | return (ctf_set_typed_errno (fp, EINVAL)); |
b437bfe0 NA |
147 | |
148 | for (p = name, end = name + strlen (name); *p != '\0'; p = q) | |
149 | { | |
734c8942 | 150 | while (isspace ((int) *p)) |
b437bfe0 NA |
151 | p++; /* Skip leading whitespace. */ |
152 | ||
153 | if (p == end) | |
154 | break; | |
155 | ||
156 | if ((q = strpbrk (p + 1, delimiters)) == NULL) | |
157 | q = end; /* Compare until end. */ | |
158 | ||
159 | if (*p == '*') | |
160 | { | |
abe4ca69 NA |
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 | |
e05a3e5a NA |
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.) */ | |
abe4ca69 NA |
174 | |
175 | uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type); | |
176 | int in_child = 0; | |
177 | ||
e05a3e5a | 178 | ntype = CTF_ERR; |
6ab5b6d0 | 179 | if (child && idx < child->ctf_pptrtab_len) |
abe4ca69 NA |
180 | { |
181 | ntype = child->ctf_pptrtab[idx]; | |
182 | if (ntype) | |
183 | in_child = 1; | |
e05a3e5a NA |
184 | else |
185 | ntype = CTF_ERR; | |
abe4ca69 | 186 | } |
b437bfe0 | 187 | |
e05a3e5a NA |
188 | if (ntype == CTF_ERR) |
189 | { | |
190 | ntype = fp->ctf_ptrtab[idx]; | |
191 | if (ntype == 0) | |
192 | ntype = CTF_ERR; | |
193 | } | |
b437bfe0 | 194 | |
abe4ca69 | 195 | /* Try resolving to its base type and check again. */ |
e05a3e5a | 196 | if (ntype == CTF_ERR) |
b437bfe0 | 197 | { |
abe4ca69 NA |
198 | if (child) |
199 | ntype = ctf_type_resolve_unsliced (child, type); | |
200 | else | |
201 | ntype = ctf_type_resolve_unsliced (fp, type); | |
202 | ||
203 | if (ntype == CTF_ERR) | |
204 | goto notype; | |
205 | ||
206 | idx = LCTF_TYPE_TO_INDEX (fp, ntype); | |
207 | ||
e05a3e5a | 208 | ntype = CTF_ERR; |
6ab5b6d0 | 209 | if (child && idx < child->ctf_pptrtab_len) |
b437bfe0 | 210 | { |
abe4ca69 NA |
211 | ntype = child->ctf_pptrtab[idx]; |
212 | if (ntype) | |
213 | in_child = 1; | |
e05a3e5a NA |
214 | else |
215 | ntype = CTF_ERR; | |
b437bfe0 | 216 | } |
abe4ca69 | 217 | |
e05a3e5a NA |
218 | if (ntype == CTF_ERR) |
219 | { | |
220 | ntype = fp->ctf_ptrtab[idx]; | |
221 | if (ntype == 0) | |
222 | ntype = CTF_ERR; | |
223 | } | |
abe4ca69 NA |
224 | if (ntype == CTF_ERR) |
225 | goto notype; | |
b437bfe0 NA |
226 | } |
227 | ||
abe4ca69 NA |
228 | type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD) |
229 | || 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 | if (in_child) | |
235 | { | |
236 | fp = child; | |
237 | child = NULL; | |
238 | } | |
b437bfe0 NA |
239 | |
240 | q = p + 1; | |
241 | continue; | |
242 | } | |
243 | ||
244 | if (isqualifier (p, (size_t) (q - p))) | |
245 | continue; /* Skip qualifier keyword. */ | |
246 | ||
247 | for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) | |
248 | { | |
249 | /* TODO: This is not MT-safe. */ | |
250 | if ((lp->ctl_prefix[0] == '\0' || | |
251 | strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) && | |
252 | (size_t) (q - p) >= lp->ctl_len) | |
253 | { | |
734c8942 | 254 | for (p += lp->ctl_len; isspace ((int) *p); p++) |
b437bfe0 NA |
255 | continue; /* Skip prefix and next whitespace. */ |
256 | ||
257 | if ((q = strchr (p, '*')) == NULL) | |
258 | q = end; /* Compare until end. */ | |
259 | ||
734c8942 | 260 | while (isspace ((int) q[-1])) |
b437bfe0 NA |
261 | q--; /* Exclude trailing whitespace. */ |
262 | ||
263 | /* Expand and/or allocate storage for a slice of the name, then | |
264 | copy it in. */ | |
265 | ||
266 | if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1) | |
267 | { | |
268 | memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p)); | |
269 | fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0'; | |
270 | } | |
271 | else | |
272 | { | |
273 | free (fp->ctf_tmp_typeslice); | |
942d35f7 | 274 | fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p)); |
b437bfe0 | 275 | if (fp->ctf_tmp_typeslice == NULL) |
998a4f58 | 276 | return ctf_set_typed_errno (fp, ENOMEM); |
b437bfe0 NA |
277 | } |
278 | ||
54a02191 NA |
279 | if ((type = (ctf_id_t) (uintptr_t) |
280 | ctf_dynhash_lookup (lp->ctl_hash, | |
281 | fp->ctf_tmp_typeslice)) == 0) | |
abe4ca69 | 282 | goto notype; |
b437bfe0 NA |
283 | |
284 | break; | |
285 | } | |
286 | } | |
287 | ||
288 | if (lp->ctl_prefix == NULL) | |
abe4ca69 | 289 | goto notype; |
b437bfe0 NA |
290 | } |
291 | ||
292 | if (*p != '\0' || type == 0) | |
998a4f58 | 293 | return (ctf_set_typed_errno (fp, ECTF_SYNTAX)); |
b437bfe0 NA |
294 | |
295 | return type; | |
296 | ||
abe4ca69 NA |
297 | notype: |
298 | ctf_set_errno (fp, ECTF_NOTYPE); | |
299 | if (fp->ctf_parent != NULL) | |
300 | { | |
301 | /* Need to look up in the parent, from the child's perspective. | |
302 | Make sure the pptrtab is up to date. */ | |
303 | ||
304 | if (fp->ctf_pptrtab_typemax < fp->ctf_typemax) | |
305 | { | |
306 | if (refresh_pptrtab (fp, fp->ctf_parent) < 0) | |
998a4f58 | 307 | return CTF_ERR; /* errno is set for us. */ |
abe4ca69 NA |
308 | } |
309 | ||
310 | if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp, | |
311 | name)) != CTF_ERR) | |
312 | return ptype; | |
998a4f58 | 313 | return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); |
abe4ca69 | 314 | } |
b437bfe0 NA |
315 | |
316 | return CTF_ERR; | |
317 | } | |
318 | ||
abe4ca69 NA |
319 | ctf_id_t |
320 | ctf_lookup_by_name (ctf_dict_t *fp, const char *name) | |
321 | { | |
322 | return ctf_lookup_by_name_internal (fp, NULL, name); | |
323 | } | |
324 | ||
1136c379 NA |
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) | |
b437bfe0 | 331 | { |
8a60c930 | 332 | ctf_dict_t *fp = *fpp; |
1136c379 NA |
333 | ctf_id_t idx; |
334 | ||
335 | if ((fp = ctf_get_dict (fp, type)) == NULL) | |
336 | { | |
337 | (void) ctf_set_errno (*fpp, ECTF_NOPARENT); | |
338 | return NULL; | |
339 | } | |
340 | ||
1136c379 NA |
341 | idx = LCTF_TYPE_TO_INDEX (fp, type); |
342 | if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) | |
343 | { | |
8a60c930 | 344 | *fpp = fp; /* Possibly the parent CTF dict. */ |
1136c379 NA |
345 | return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); |
346 | } | |
347 | ||
348 | (void) ctf_set_errno (*fpp, ECTF_BADID); | |
349 | return NULL; | |
350 | } | |
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; | |
b437bfe0 NA |
358 | |
359 | /* A bsearch function for variable names. */ | |
360 | ||
361 | static int | |
1136c379 | 362 | ctf_lookup_var (const void *key_, const void *lookup_) |
b437bfe0 | 363 | { |
1136c379 NA |
364 | const ctf_lookup_idx_key_t *key = key_; |
365 | const ctf_varent_t *lookup = lookup_; | |
b437bfe0 | 366 | |
1136c379 | 367 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name))); |
b437bfe0 NA |
368 | } |
369 | ||
8a60c930 NA |
370 | /* Given a variable name, return the type of the variable with that name. |
371 | Look only in this dict, not in the parent. */ | |
b437bfe0 NA |
372 | |
373 | ctf_id_t | |
8a60c930 | 374 | ctf_lookup_variable_here (ctf_dict_t *fp, const char *name) |
b437bfe0 | 375 | { |
8a60c930 | 376 | ctf_dvdef_t *dvd = ctf_dvd_lookup (fp, name); |
b437bfe0 | 377 | ctf_varent_t *ent; |
1136c379 | 378 | ctf_lookup_idx_key_t key = { fp, name, NULL }; |
b437bfe0 | 379 | |
8a60c930 NA |
380 | if (dvd != NULL) |
381 | return dvd->dvd_type; | |
382 | ||
b437bfe0 NA |
383 | /* This array is sorted, so we can bsearch for it. */ |
384 | ||
385 | ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t), | |
386 | ctf_lookup_var); | |
387 | ||
388 | if (ent == NULL) | |
8a60c930 NA |
389 | return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT)); |
390 | ||
391 | return ent->ctv_type; | |
392 | } | |
d7474051 | 393 | |
8a60c930 | 394 | /* As above, but look in the parent too. */ |
b437bfe0 | 395 | |
8a60c930 NA |
396 | ctf_id_t |
397 | ctf_lookup_variable (ctf_dict_t *fp, const char *name) | |
398 | { | |
399 | ctf_id_t type; | |
400 | ||
401 | if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR) | |
402 | { | |
403 | if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL) | |
404 | { | |
405 | if ((type = ctf_lookup_variable_here (fp->ctf_parent, name)) != CTF_ERR) | |
406 | return type; | |
407 | return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); | |
408 | } | |
409 | ||
410 | return -1; /* errno is set for us. */ | |
b437bfe0 NA |
411 | } |
412 | ||
8a60c930 | 413 | return type; |
b437bfe0 NA |
414 | } |
415 | ||
1136c379 NA |
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 | { | |
425 | const uint32_t *one = one_; | |
426 | const uint32_t *two = two_; | |
427 | ctf_symidx_sort_arg_cb_t *arg = arg_; | |
428 | ||
429 | return (strcmp (ctf_strptr (arg->fp, arg->names[*one]), | |
430 | ctf_strptr (arg->fp, arg->names[*two]))); | |
431 | } | |
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 | { | |
442 | uint32_t *sorted; | |
443 | size_t i; | |
444 | ||
445 | if ((sorted = malloc (len)) == NULL) | |
446 | { | |
447 | ctf_set_errno (fp, ENOMEM); | |
448 | return NULL; | |
449 | } | |
450 | ||
451 | *nidx = len / sizeof (uint32_t); | |
452 | for (i = 0; i < *nidx; i++) | |
453 | sorted[i] = i; | |
454 | ||
455 | if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED)) | |
456 | { | |
457 | ctf_symidx_sort_arg_cb_t arg = { fp, idx }; | |
a96a9ca9 | 458 | ctf_dprintf ("Index section unsorted: sorting.\n"); |
1136c379 NA |
459 | ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg); |
460 | fp->ctf_header->cth_flags |= CTF_F_IDXSORTED; | |
461 | } | |
462 | ||
463 | return sorted; | |
464 | } | |
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. */ | |
f4f60336 | 469 | static const char * |
139633c3 | 470 | ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx) |
b437bfe0 | 471 | { |
629acbe4 | 472 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
1136c379 NA |
473 | ctf_link_sym_t sym; |
474 | int err; | |
b437bfe0 | 475 | |
1136c379 | 476 | if (fp->ctf_dynsymidx) |
b437bfe0 | 477 | { |
1136c379 NA |
478 | err = EINVAL; |
479 | if (symidx > fp->ctf_dynsymmax) | |
480 | goto try_parent; | |
481 | ||
482 | ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx]; | |
483 | ||
484 | if (!symp) | |
485 | goto try_parent; | |
486 | ||
487 | return symp->st_name; | |
b437bfe0 NA |
488 | } |
489 | ||
1136c379 NA |
490 | err = ECTF_NOSYMTAB; |
491 | if (sp->cts_data == NULL) | |
492 | goto try_parent; | |
493 | ||
b437bfe0 | 494 | if (symidx >= fp->ctf_nsyms) |
1136c379 NA |
495 | goto try_parent; |
496 | ||
497 | switch (sp->cts_entsize) | |
b437bfe0 | 498 | { |
1136c379 NA |
499 | case sizeof (Elf64_Sym): |
500 | { | |
501 | const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx; | |
502 | ctf_elf64_to_link_sym (fp, &sym, symp, symidx); | |
503 | } | |
504 | break; | |
505 | case sizeof (Elf32_Sym): | |
506 | { | |
507 | const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx; | |
508 | ctf_elf32_to_link_sym (fp, &sym, symp, symidx); | |
509 | } | |
510 | break; | |
511 | default: | |
512 | ctf_set_errno (fp, ECTF_SYMTAB); | |
b437bfe0 NA |
513 | return _CTF_NULLSTR; |
514 | } | |
515 | ||
1136c379 | 516 | assert (!sym.st_nameidx_set); |
b437bfe0 | 517 | |
1136c379 | 518 | return sym.st_name; |
b437bfe0 | 519 | |
1136c379 NA |
520 | try_parent: |
521 | if (fp->ctf_parent) | |
f4f60336 NA |
522 | { |
523 | const char *ret; | |
524 | ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx); | |
525 | if (ret == NULL) | |
526 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); | |
527 | return ret; | |
528 | } | |
1136c379 NA |
529 | else |
530 | { | |
531 | ctf_set_errno (fp, err); | |
532 | return _CTF_NULLSTR; | |
533 | } | |
b437bfe0 NA |
534 | } |
535 | ||
f4f60336 | 536 | /* Given a symbol name, return the index of that symbol, or -1 on error or if |
8a60c930 NA |
537 | not found. If is_function is >= 0, return only function or data object |
538 | symbols, respectively. */ | |
f4f60336 | 539 | static unsigned long |
8a60c930 NA |
540 | ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent, |
541 | int is_function) | |
f4f60336 | 542 | { |
629acbe4 | 543 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
f4f60336 NA |
544 | ctf_link_sym_t sym; |
545 | void *known_idx; | |
546 | int err; | |
547 | ctf_dict_t *cache = fp; | |
548 | ||
549 | if (fp->ctf_dynsyms) | |
550 | { | |
551 | err = EINVAL; | |
552 | ||
553 | ctf_link_sym_t *symp; | |
554 | ||
8a60c930 NA |
555 | if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL) |
556 | || (symp->st_type != STT_OBJECT && is_function == 0) | |
557 | || (symp->st_type != STT_FUNC && is_function == 1)) | |
f4f60336 NA |
558 | goto try_parent; |
559 | ||
560 | return symp->st_symidx; | |
561 | } | |
562 | ||
563 | err = ECTF_NOSYMTAB; | |
564 | if (sp->cts_data == NULL) | |
565 | goto try_parent; | |
566 | ||
567 | /* First, try a hash lookup to see if we have already spotted this symbol | |
8a60c930 NA |
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 | |
f4f60336 NA |
572 | are the same across all dicts in an archive, use it. */ |
573 | ||
574 | if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache) | |
575 | cache = fp->ctf_archive->ctfi_crossdict_cache; | |
576 | ||
8a60c930 NA |
577 | if (!cache->ctf_symhash_func) |
578 | if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string, | |
579 | ctf_hash_eq_string, | |
580 | NULL, NULL)) == NULL) | |
581 | goto oom; | |
582 | ||
583 | if (!cache->ctf_symhash_objt) | |
584 | if ((cache->ctf_symhash_objt = ctf_dynhash_create (ctf_hash_string, | |
585 | ctf_hash_eq_string, | |
586 | NULL, NULL)) == NULL) | |
f4f60336 NA |
587 | goto oom; |
588 | ||
8a60c930 NA |
589 | if (is_function != 0 && |
590 | ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx)) | |
591 | return (unsigned long) (uintptr_t) known_idx; | |
592 | ||
593 | if (is_function != 1 && | |
594 | ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx)) | |
f4f60336 NA |
595 | 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 | for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize; | |
601 | cache->ctf_symhash_latest++) | |
602 | { | |
8a60c930 NA |
603 | ctf_dynhash_t *h; |
604 | ||
f4f60336 NA |
605 | switch (sp->cts_entsize) |
606 | { | |
607 | case sizeof (Elf64_Sym): | |
608 | { | |
609 | Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data; | |
8a60c930 | 610 | |
f4f60336 NA |
611 | ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], |
612 | cache->ctf_symhash_latest); | |
08794526 NA |
613 | } |
614 | break; | |
f4f60336 NA |
615 | case sizeof (Elf32_Sym): |
616 | { | |
617 | Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data; | |
618 | ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], | |
619 | cache->ctf_symhash_latest); | |
8a60c930 | 620 | break; |
08794526 | 621 | } |
f4f60336 NA |
622 | default: |
623 | ctf_set_errno (fp, ECTF_SYMTAB); | |
624 | return (unsigned long) -1; | |
625 | } | |
8a60c930 NA |
626 | |
627 | if (sym.st_type == STT_FUNC) | |
628 | h = cache->ctf_symhash_func; | |
629 | else if (sym.st_type == STT_OBJECT) | |
630 | h = cache->ctf_symhash_objt; | |
631 | else | |
632 | continue; /* Not of interest. */ | |
633 | ||
634 | if (!ctf_dynhash_lookup_kv (h, sym.st_name, | |
635 | NULL, NULL)) | |
636 | if (ctf_dynhash_cinsert (h, sym.st_name, | |
637 | (const void *) (uintptr_t) | |
638 | cache->ctf_symhash_latest) < 0) | |
639 | goto oom; | |
640 | if (strcmp (sym.st_name, symname) == 0) | |
641 | return cache->ctf_symhash_latest++; | |
f4f60336 NA |
642 | } |
643 | ||
644 | /* Searched everything, still not found. */ | |
645 | ||
646 | return (unsigned long) -1; | |
647 | ||
648 | try_parent: | |
8a60c930 | 649 | if (fp->ctf_parent && try_parent) |
d7474051 NA |
650 | { |
651 | unsigned long psym; | |
652 | ||
8a60c930 NA |
653 | if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent, |
654 | is_function)) | |
d7474051 NA |
655 | != (unsigned long) -1) |
656 | return psym; | |
657 | ||
658 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); | |
659 | return (unsigned long) -1; | |
660 | } | |
f4f60336 NA |
661 | else |
662 | { | |
663 | ctf_set_errno (fp, err); | |
664 | return (unsigned long) -1; | |
665 | } | |
666 | oom: | |
667 | ctf_set_errno (fp, ENOMEM); | |
7e1368b5 NA |
668 | ctf_err_warn (fp, 0, 0, _("cannot allocate memory for symbol " |
669 | "lookup hashtab")); | |
f4f60336 NA |
670 | return (unsigned long) -1; |
671 | ||
672 | } | |
673 | ||
8a60c930 NA |
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. */ | |
b437bfe0 NA |
685 | |
686 | ctf_id_t | |
1136c379 NA |
687 | ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, |
688 | int functions) | |
b437bfe0 | 689 | { |
cce0bb8f | 690 | ctf_id_t sym = CTF_ERR; |
1136c379 NA |
691 | ctf_next_t *i = *it; |
692 | int err; | |
b437bfe0 | 693 | |
1136c379 NA |
694 | if (!i) |
695 | { | |
696 | if ((i = ctf_next_create ()) == NULL) | |
998a4f58 | 697 | return ctf_set_typed_errno (fp, ENOMEM); |
b437bfe0 | 698 | |
1136c379 NA |
699 | i->cu.ctn_fp = fp; |
700 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; | |
701 | i->ctn_n = 0; | |
702 | *it = i; | |
703 | } | |
704 | ||
705 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) | |
998a4f58 | 706 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); |
b437bfe0 | 707 | |
1136c379 | 708 | if (fp != i->cu.ctn_fp) |
998a4f58 | 709 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); |
1136c379 | 710 | |
8a60c930 NA |
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 | |
1136c379 NA |
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 | ||
8a60c930 NA |
721 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; |
722 | void *dyn_name = NULL, *dyn_value = NULL; | |
723 | size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; | |
1136c379 | 724 | |
8a60c930 NA |
725 | if (i->ctn_n < dyn_els) |
726 | { | |
6c3a3877 | 727 | err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); |
8a60c930 | 728 | |
1136c379 NA |
729 | /* This covers errors and also end-of-iteration. */ |
730 | if (err != 0) | |
731 | { | |
732 | ctf_next_destroy (i); | |
733 | *it = NULL; | |
998a4f58 | 734 | return ctf_set_typed_errno (fp, err); |
1136c379 NA |
735 | } |
736 | ||
737 | *name = dyn_name; | |
738 | sym = (ctf_id_t) (uintptr_t) dyn_value; | |
8a60c930 NA |
739 | i->ctn_n++; |
740 | ||
741 | return sym; | |
b437bfe0 | 742 | } |
8a60c930 NA |
743 | |
744 | return ctf_symbol_next_static (fp, it, name, functions); | |
745 | } | |
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 | { | |
754 | ctf_id_t sym = CTF_ERR; | |
755 | ctf_next_t *i = *it; | |
756 | ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; | |
757 | 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 | if (!i) | |
763 | { | |
764 | if ((i = ctf_next_create ()) == NULL) | |
765 | return ctf_set_typed_errno (fp, ENOMEM); | |
766 | ||
767 | i->cu.ctn_fp = fp; | |
768 | i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; | |
769 | i->ctn_n = dyn_els; | |
770 | *it = i; | |
771 | } | |
772 | ||
773 | if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) | |
774 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); | |
775 | ||
776 | if (fp != i->cu.ctn_fp) | |
777 | return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); | |
778 | ||
779 | /* TODO-v4: Indexed after non-indexed portions? */ | |
780 | ||
781 | if ((!functions && fp->ctf_objtidx_names) || | |
782 | (functions && fp->ctf_funcidx_names)) | |
b437bfe0 | 783 | { |
1136c379 NA |
784 | ctf_header_t *hp = fp->ctf_header; |
785 | uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names; | |
786 | uint32_t *tab; | |
787 | size_t len; | |
788 | ||
789 | if (functions) | |
790 | { | |
791 | len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t); | |
792 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); | |
793 | } | |
794 | else | |
795 | { | |
796 | len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t); | |
797 | tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); | |
798 | } | |
799 | ||
800 | do | |
801 | { | |
8a60c930 | 802 | if (i->ctn_n - dyn_els >= len) |
1136c379 NA |
803 | goto end; |
804 | ||
8a60c930 NA |
805 | *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]); |
806 | sym = tab[i->ctn_n - dyn_els]; | |
807 | i->ctn_n++; | |
eefe721e NA |
808 | } |
809 | while (sym == -1u || sym == 0); | |
b437bfe0 | 810 | } |
1136c379 NA |
811 | else |
812 | { | |
8a60c930 | 813 | /* Skip over pads in ctf_sxlate, padding for typeless symbols in the |
1136c379 | 814 | symtypetab itself, and symbols in the wrong table. */ |
8a60c930 | 815 | for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++) |
1136c379 NA |
816 | { |
817 | ctf_header_t *hp = fp->ctf_header; | |
8a60c930 | 818 | size_t n = i->ctn_n - dyn_els; |
b437bfe0 | 819 | |
8a60c930 | 820 | if (fp->ctf_sxlate[n] == -1u) |
1136c379 | 821 | continue; |
b437bfe0 | 822 | |
8a60c930 | 823 | sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]); |
b437bfe0 | 824 | |
1136c379 NA |
825 | if (sym == 0) |
826 | continue; | |
827 | ||
828 | if (functions) | |
829 | { | |
8a60c930 NA |
830 | if (fp->ctf_sxlate[n] >= hp->cth_funcoff |
831 | && fp->ctf_sxlate[n] < hp->cth_objtidxoff) | |
1136c379 NA |
832 | break; |
833 | } | |
834 | else | |
835 | { | |
8a60c930 NA |
836 | if (fp->ctf_sxlate[n] >= hp->cth_objtoff |
837 | && fp->ctf_sxlate[n] < hp->cth_funcoff) | |
1136c379 NA |
838 | break; |
839 | } | |
840 | } | |
841 | ||
8a60c930 | 842 | if (i->ctn_n - dyn_els >= fp->ctf_nsyms) |
1136c379 NA |
843 | goto end; |
844 | ||
8a60c930 NA |
845 | *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els); |
846 | i->ctn_n++; | |
1136c379 NA |
847 | } |
848 | ||
849 | return sym; | |
850 | ||
851 | end: | |
852 | ctf_next_destroy (i); | |
853 | *it = NULL; | |
998a4f58 | 854 | return (ctf_set_typed_errno (fp, ECTF_NEXT_END)); |
b437bfe0 NA |
855 | } |
856 | ||
1136c379 NA |
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_) | |
688d28f6 | 861 | { |
1136c379 NA |
862 | const ctf_lookup_idx_key_t *key = key_; |
863 | const uint32_t *idx = idx_; | |
688d28f6 | 864 | |
1136c379 | 865 | return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx]))); |
688d28f6 NA |
866 | } |
867 | ||
f4f60336 NA |
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). */ | |
47d546f4 | 871 | |
1136c379 | 872 | static ctf_id_t |
f4f60336 NA |
873 | ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, |
874 | const char *symname, int is_function) | |
47d546f4 | 875 | { |
1136c379 NA |
876 | struct ctf_header *hp = fp->ctf_header; |
877 | uint32_t *symtypetab; | |
878 | uint32_t *names; | |
879 | uint32_t *sxlate; | |
880 | size_t nidx; | |
47d546f4 | 881 | |
f4f60336 NA |
882 | if (symname == NULL) |
883 | symname = ctf_lookup_symbol_name (fp, symidx); | |
884 | ||
8a60c930 NA |
885 | /* Dynamic dict with no static portion: just return. */ |
886 | if (!hp) | |
887 | { | |
888 | ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname); | |
889 | return 0; | |
890 | } | |
891 | ||
f4f60336 | 892 | ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in " |
1136c379 | 893 | "indexed symtypetab\n", symidx, symname); |
47d546f4 | 894 | |
1136c379 | 895 | if (symname[0] == '\0') |
998a4f58 | 896 | return CTF_ERR; /* errno is set for us. */ |
47d546f4 | 897 | |
1136c379 | 898 | if (is_function) |
47d546f4 | 899 | { |
1136c379 | 900 | if (!fp->ctf_funcidx_sxlate) |
47d546f4 | 901 | { |
1136c379 NA |
902 | if ((fp->ctf_funcidx_sxlate |
903 | = ctf_symidx_sort (fp, (uint32_t *) | |
904 | (fp->ctf_buf + hp->cth_funcidxoff), | |
905 | &fp->ctf_nfuncidx, | |
906 | hp->cth_varoff - hp->cth_funcidxoff)) | |
907 | == NULL) | |
908 | { | |
909 | ctf_err_warn (fp, 0, 0, _("cannot sort function symidx")); | |
998a4f58 | 910 | return CTF_ERR; /* errno is set for us. */ |
1136c379 | 911 | } |
47d546f4 | 912 | } |
1136c379 NA |
913 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); |
914 | sxlate = fp->ctf_funcidx_sxlate; | |
915 | names = fp->ctf_funcidx_names; | |
916 | nidx = fp->ctf_nfuncidx; | |
47d546f4 | 917 | } |
1136c379 NA |
918 | else |
919 | { | |
920 | if (!fp->ctf_objtidx_sxlate) | |
921 | { | |
922 | if ((fp->ctf_objtidx_sxlate | |
923 | = ctf_symidx_sort (fp, (uint32_t *) | |
924 | (fp->ctf_buf + hp->cth_objtidxoff), | |
925 | &fp->ctf_nobjtidx, | |
926 | hp->cth_funcidxoff - hp->cth_objtidxoff)) | |
927 | == NULL) | |
928 | { | |
929 | ctf_err_warn (fp, 0, 0, _("cannot sort object symidx")); | |
998a4f58 | 930 | return CTF_ERR; /* errno is set for us. */ |
1136c379 NA |
931 | } |
932 | } | |
676c3ecb | 933 | |
1136c379 NA |
934 | symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); |
935 | sxlate = fp->ctf_objtidx_sxlate; | |
936 | names = fp->ctf_objtidx_names; | |
937 | nidx = fp->ctf_nobjtidx; | |
938 | } | |
676c3ecb | 939 | |
1136c379 NA |
940 | ctf_lookup_idx_key_t key = { fp, symname, names }; |
941 | uint32_t *idx; | |
942 | ||
943 | idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name); | |
944 | ||
945 | if (!idx) | |
676c3ecb | 946 | { |
1136c379 NA |
947 | ctf_dprintf ("%s not found in idx\n", symname); |
948 | return 0; | |
676c3ecb NA |
949 | } |
950 | ||
1136c379 NA |
951 | /* Should be impossible, but be paranoid. */ |
952 | if ((idx - sxlate) > (ptrdiff_t) nidx) | |
998a4f58 | 953 | return (ctf_set_typed_errno (fp, ECTF_CORRUPT)); |
1136c379 NA |
954 | |
955 | ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname, | |
956 | symtypetab[*idx]); | |
957 | return symtypetab[*idx]; | |
47d546f4 NA |
958 | } |
959 | ||
f4f60336 NA |
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 | |
8a60c930 | 964 | names. |
b437bfe0 | 965 | |
8a60c930 NA |
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 | |
f4f60336 | 972 | ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx, |
8a60c930 NA |
973 | const char *symname, int try_parent, |
974 | int is_function) | |
b437bfe0 | 975 | { |
629acbe4 | 976 | const ctf_sect_t *sp = &fp->ctf_ext_symtab; |
1136c379 NA |
977 | ctf_id_t type = 0; |
978 | int err = 0; | |
979 | ||
8a60c930 NA |
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. */ | |
1136c379 NA |
985 | if (fp->ctf_dynsymidx) |
986 | { | |
987 | const ctf_link_sym_t *sym; | |
988 | ||
f4f60336 NA |
989 | if (symname) |
990 | ctf_dprintf ("Looking up type of object with symname %s in " | |
991 | "writable dict symtypetab\n", symname); | |
992 | else | |
993 | ctf_dprintf ("Looking up type of object with symtab idx %lx in " | |
994 | "writable dict symtypetab\n", symidx); | |
1136c379 | 995 | |
f4f60336 NA |
996 | /* No name? Need to look it up. */ |
997 | if (!symname) | |
998 | { | |
999 | err = EINVAL; | |
1000 | if (symidx > fp->ctf_dynsymmax) | |
1001 | goto try_parent; | |
1136c379 | 1002 | |
08794526 | 1003 | sym = fp->ctf_dynsymidx[symidx]; |
f4f60336 | 1004 | err = ECTF_NOTYPEDAT; |
8a60c930 NA |
1005 | if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC) |
1006 | || (sym->st_type != STT_OBJECT && is_function == 0) | |
1007 | || (sym->st_type != STT_FUNC && is_function == 1)) | |
f4f60336 | 1008 | goto try_parent; |
1136c379 | 1009 | |
f4f60336 NA |
1010 | if (!ctf_assert (fp, !sym->st_nameidx_set)) |
1011 | return CTF_ERR; | |
1012 | symname = sym->st_name; | |
1013 | } | |
1136c379 NA |
1014 | |
1015 | if (fp->ctf_objthash == NULL | |
8a60c930 NA |
1016 | || is_function == 1 |
1017 | || (type = (ctf_id_t) (uintptr_t) | |
1018 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0) | |
1136c379 NA |
1019 | { |
1020 | if (fp->ctf_funchash == NULL | |
8a60c930 NA |
1021 | || is_function == 0 |
1022 | || (type = (ctf_id_t) (uintptr_t) | |
1023 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0) | |
1136c379 NA |
1024 | goto try_parent; |
1025 | } | |
1026 | ||
1027 | return type; | |
1028 | } | |
b437bfe0 | 1029 | |
8a60c930 NA |
1030 | /* Dict not shuffled: look for a dynamic sym first, and look it up |
1031 | directly. */ | |
1032 | if (symname) | |
f4f60336 | 1033 | { |
8a60c930 NA |
1034 | if (fp->ctf_objthash != NULL |
1035 | && is_function != 1 | |
1036 | && ((type = (ctf_id_t) (uintptr_t) | |
1037 | ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0)) | |
1038 | return type; | |
1039 | ||
1040 | if (fp->ctf_funchash != NULL | |
1041 | && is_function != 0 | |
1042 | && ((type = (ctf_id_t) (uintptr_t) | |
1043 | ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0)) | |
1044 | return type; | |
f4f60336 NA |
1045 | } |
1046 | ||
1136c379 | 1047 | err = ECTF_NOSYMTAB; |
9049b960 NA |
1048 | if (sp->cts_data == NULL && symname == NULL && |
1049 | ((is_function && !fp->ctf_funcidx_names) || | |
1050 | (!is_function && !fp->ctf_objtidx_names))) | |
1136c379 | 1051 | goto try_parent; |
b437bfe0 | 1052 | |
8a60c930 NA |
1053 | /* This covers both out-of-range lookups by index and a dynamic dict which |
1054 | hasn't been shuffled yet. */ | |
1136c379 | 1055 | err = EINVAL; |
f4f60336 | 1056 | if (symname == NULL && symidx >= fp->ctf_nsyms) |
1136c379 | 1057 | goto try_parent; |
b437bfe0 | 1058 | |
8a60c930 NA |
1059 | /* Try an indexed lookup. */ |
1060 | ||
1061 | if (fp->ctf_objtidx_names && is_function != 1) | |
b437bfe0 | 1062 | { |
f4f60336 | 1063 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR) |
1136c379 | 1064 | return CTF_ERR; /* errno is set for us. */ |
b437bfe0 | 1065 | } |
8a60c930 | 1066 | if (type == 0 && fp->ctf_funcidx_names && is_function != 0) |
b437bfe0 | 1067 | { |
f4f60336 | 1068 | if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR) |
1136c379 | 1069 | return CTF_ERR; /* errno is set for us. */ |
b437bfe0 | 1070 | } |
1136c379 NA |
1071 | if (type != 0) |
1072 | return type; | |
1073 | ||
8a60c930 | 1074 | /* Indexed but no symbol found -> not present, try the parent. */ |
1136c379 NA |
1075 | err = ECTF_NOTYPEDAT; |
1076 | if (fp->ctf_objtidx_names && fp->ctf_funcidx_names) | |
1077 | goto try_parent; | |
1078 | ||
1079 | /* Table must be nonindexed. */ | |
1080 | ||
1081 | ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx); | |
b437bfe0 | 1082 | |
f4f60336 | 1083 | if (symname != NULL) |
8a60c930 NA |
1084 | if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function)) |
1085 | == (unsigned long) -1) | |
f4f60336 NA |
1086 | goto try_parent; |
1087 | ||
b437bfe0 | 1088 | if (fp->ctf_sxlate[symidx] == -1u) |
1136c379 NA |
1089 | goto try_parent; |
1090 | ||
1091 | type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]); | |
b437bfe0 | 1092 | |
1136c379 NA |
1093 | if (type == 0) |
1094 | goto try_parent; | |
b437bfe0 | 1095 | |
1136c379 | 1096 | return type; |
8a60c930 | 1097 | |
1136c379 | 1098 | try_parent: |
8a60c930 NA |
1099 | if (!try_parent) |
1100 | return ctf_set_errno (fp, err); | |
1101 | ||
1136c379 | 1102 | if (fp->ctf_parent) |
f4f60336 NA |
1103 | { |
1104 | ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx, | |
8a60c930 NA |
1105 | symname, try_parent, |
1106 | is_function); | |
f4f60336 NA |
1107 | if (ret == CTF_ERR) |
1108 | ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); | |
1109 | return ret; | |
1110 | } | |
1136c379 | 1111 | else |
998a4f58 | 1112 | return (ctf_set_typed_errno (fp, err)); |
1136c379 | 1113 | } |
b437bfe0 | 1114 | |
f4f60336 NA |
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 | { | |
8a60c930 | 1120 | return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1); |
f4f60336 NA |
1121 | } |
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 | { | |
8a60c930 | 1128 | return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1); |
f4f60336 NA |
1129 | } |
1130 | ||
1136c379 NA |
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. */ | |
b437bfe0 | 1134 | |
1136c379 NA |
1135 | int |
1136 | ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip) | |
1137 | { | |
1138 | ctf_id_t type; | |
b437bfe0 | 1139 | |
1136c379 NA |
1140 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1141 | return -1; /* errno is set for us. */ | |
b437bfe0 | 1142 | |
1136c379 NA |
1143 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1144 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); | |
b437bfe0 | 1145 | |
1136c379 | 1146 | return ctf_func_type_info (fp, type, fip); |
b437bfe0 NA |
1147 | } |
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 | |
139633c3 | 1153 | ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc, |
1136c379 | 1154 | ctf_id_t *argv) |
b437bfe0 | 1155 | { |
1136c379 | 1156 | ctf_id_t type; |
b437bfe0 | 1157 | |
1136c379 NA |
1158 | if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) |
1159 | return -1; /* errno is set for us. */ | |
b437bfe0 | 1160 | |
1136c379 NA |
1161 | if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) |
1162 | return (ctf_set_errno (fp, ECTF_NOTFUNC)); | |
b437bfe0 | 1163 | |
1136c379 | 1164 | return ctf_func_type_args (fp, type, argc, argv); |
b437bfe0 | 1165 | } |