18dffb485Schristos /* Symbol, variable and name lookup. 2*12989c96Schristos Copyright (C) 2019-2024 Free Software Foundation, Inc. 38dffb485Schristos 48dffb485Schristos This file is part of libctf. 58dffb485Schristos 68dffb485Schristos libctf is free software; you can redistribute it and/or modify it under 78dffb485Schristos the terms of the GNU General Public License as published by the Free 88dffb485Schristos Software Foundation; either version 3, or (at your option) any later 98dffb485Schristos version. 108dffb485Schristos 118dffb485Schristos This program is distributed in the hope that it will be useful, but 128dffb485Schristos WITHOUT ANY WARRANTY; without even the implied warranty of 138dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 148dffb485Schristos See the GNU General Public License for more details. 158dffb485Schristos 168dffb485Schristos You should have received a copy of the GNU General Public License 178dffb485Schristos along with this program; see the file COPYING. If not see 188dffb485Schristos <http://www.gnu.org/licenses/>. */ 198dffb485Schristos 208dffb485Schristos #include <ctf-impl.h> 218dffb485Schristos #include <elf.h> 228dffb485Schristos #include <string.h> 234b169a6bSchristos #include <assert.h> 244b169a6bSchristos 254b169a6bSchristos /* Grow the pptrtab so that it is at least NEW_LEN long. */ 264b169a6bSchristos static int 274b169a6bSchristos grow_pptrtab (ctf_dict_t *fp, size_t new_len) 284b169a6bSchristos { 294b169a6bSchristos uint32_t *new_pptrtab; 304b169a6bSchristos 314b169a6bSchristos if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t) 324b169a6bSchristos * new_len)) == NULL) 334b169a6bSchristos return (ctf_set_errno (fp, ENOMEM)); 344b169a6bSchristos 354b169a6bSchristos fp->ctf_pptrtab = new_pptrtab; 364b169a6bSchristos 374b169a6bSchristos memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0, 384b169a6bSchristos sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len)); 394b169a6bSchristos 404b169a6bSchristos fp->ctf_pptrtab_len = new_len; 414b169a6bSchristos return 0; 424b169a6bSchristos } 434b169a6bSchristos 444b169a6bSchristos /* Update entries in the pptrtab that relate to types newly added in the 454b169a6bSchristos child. */ 464b169a6bSchristos static int 474b169a6bSchristos refresh_pptrtab (ctf_dict_t *fp, ctf_dict_t *pfp) 484b169a6bSchristos { 494b169a6bSchristos uint32_t i; 504b169a6bSchristos for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++) 514b169a6bSchristos { 524b169a6bSchristos ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1); 534b169a6bSchristos ctf_id_t reffed_type; 544b169a6bSchristos 554b169a6bSchristos if (ctf_type_kind (fp, type) != CTF_K_POINTER) 564b169a6bSchristos continue; 574b169a6bSchristos 584b169a6bSchristos reffed_type = ctf_type_reference (fp, type); 594b169a6bSchristos 604b169a6bSchristos if (LCTF_TYPE_ISPARENT (fp, reffed_type)) 614b169a6bSchristos { 624b169a6bSchristos uint32_t idx = LCTF_TYPE_TO_INDEX (fp, reffed_type); 634b169a6bSchristos 644b169a6bSchristos /* Guard against references to invalid types. No need to consider 654b169a6bSchristos the CTF dict corrupt in this case: this pointer just can't be a 664b169a6bSchristos pointer to any type we know about. */ 674b169a6bSchristos if (idx <= pfp->ctf_typemax) 684b169a6bSchristos { 694b169a6bSchristos if (idx >= fp->ctf_pptrtab_len 704b169a6bSchristos && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0) 714b169a6bSchristos return -1; /* errno is set for us. */ 724b169a6bSchristos 734b169a6bSchristos fp->ctf_pptrtab[idx] = i; 744b169a6bSchristos } 754b169a6bSchristos } 764b169a6bSchristos } 774b169a6bSchristos 784b169a6bSchristos fp->ctf_pptrtab_typemax = fp->ctf_typemax; 794b169a6bSchristos 804b169a6bSchristos return 0; 814b169a6bSchristos } 828dffb485Schristos 838dffb485Schristos /* Compare the given input string and length against a table of known C storage 848dffb485Schristos qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To 858dffb485Schristos do this quickly, we use a pre-computed Perfect Hash Function similar to the 868dffb485Schristos technique originally described in the classic paper: 878dffb485Schristos 888dffb485Schristos R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple", 898dffb485Schristos Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19. 908dffb485Schristos 918dffb485Schristos For an input string S of length N, we use hash H = S[N - 1] + N - 105, which 928dffb485Schristos for the current set of qualifiers yields a unique H in the range [0 .. 20]. 938dffb485Schristos The hash can be modified when the keyword set changes as necessary. We also 948dffb485Schristos store the length of each keyword and check it prior to the final strcmp(). 958dffb485Schristos 968dffb485Schristos TODO: just use gperf. */ 978dffb485Schristos 988dffb485Schristos static int 998dffb485Schristos isqualifier (const char *s, size_t len) 1008dffb485Schristos { 1018dffb485Schristos static const struct qual 1028dffb485Schristos { 1038dffb485Schristos const char *q_name; 1048dffb485Schristos size_t q_len; 1058dffb485Schristos } qhash[] = { 1068dffb485Schristos {"static", 6}, {"", 0}, {"", 0}, {"", 0}, 1078dffb485Schristos {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, 1088dffb485Schristos {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0}, 1098dffb485Schristos {"", 0}, {"", 0}, {"const", 5}, {"register", 8}, 1108dffb485Schristos {"", 0}, {"restrict", 8}, {"_Restrict", 9} 1118dffb485Schristos }; 1128dffb485Schristos 1138dffb485Schristos int h = s[len - 1] + (int) len - 105; 1144b169a6bSchristos const struct qual *qp; 1158dffb485Schristos 1164b169a6bSchristos if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0])) 1174b169a6bSchristos return 0; 1184b169a6bSchristos 1194b169a6bSchristos qp = &qhash[h]; 1204b169a6bSchristos 1214b169a6bSchristos return ((size_t) len == qp->q_len && 1228dffb485Schristos strncmp (qp->q_name, s, qp->q_len) == 0); 1238dffb485Schristos } 1248dffb485Schristos 1258dffb485Schristos /* Attempt to convert the given C type name into the corresponding CTF type ID. 1268dffb485Schristos It is not possible to do complete and proper conversion of type names 1278dffb485Schristos without implementing a more full-fledged parser, which is necessary to 1288dffb485Schristos handle things like types that are function pointers to functions that 1298dffb485Schristos have arguments that are function pointers, and fun stuff like that. 1308dffb485Schristos Instead, this function implements a very simple conversion algorithm that 1318dffb485Schristos finds the things that we actually care about: structs, unions, enums, 1328dffb485Schristos integers, floats, typedefs, and pointers to any of these named types. */ 1338dffb485Schristos 1344b169a6bSchristos static ctf_id_t 1354b169a6bSchristos ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child, 1364b169a6bSchristos const char *name) 1378dffb485Schristos { 1388dffb485Schristos static const char delimiters[] = " \t\n\r\v\f*"; 1398dffb485Schristos 1408dffb485Schristos const ctf_lookup_t *lp; 1418dffb485Schristos const char *p, *q, *end; 1428dffb485Schristos ctf_id_t type = 0; 1438dffb485Schristos ctf_id_t ntype, ptype; 1448dffb485Schristos 1458dffb485Schristos if (name == NULL) 146*12989c96Schristos return (ctf_set_typed_errno (fp, EINVAL)); 1478dffb485Schristos 1488dffb485Schristos for (p = name, end = name + strlen (name); *p != '\0'; p = q) 1498dffb485Schristos { 1508dffb485Schristos while (isspace ((int) *p)) 1518dffb485Schristos p++; /* Skip leading whitespace. */ 1528dffb485Schristos 1538dffb485Schristos if (p == end) 1548dffb485Schristos break; 1558dffb485Schristos 1568dffb485Schristos if ((q = strpbrk (p + 1, delimiters)) == NULL) 1578dffb485Schristos q = end; /* Compare until end. */ 1588dffb485Schristos 1598dffb485Schristos if (*p == '*') 1608dffb485Schristos { 1614b169a6bSchristos /* Find a pointer to type by looking in child->ctf_pptrtab (if child 1624b169a6bSchristos is set) and fp->ctf_ptrtab. If we can't find a pointer to the 1634b169a6bSchristos given type, see if we can compute a pointer to the type resulting 1644b169a6bSchristos from resolving the type down to its base type and use that instead. 1654b169a6bSchristos This helps with cases where the CTF data includes "struct foo *" 1664b169a6bSchristos but not "foo_t *" and the user tries to access "foo_t *" in the 1674b169a6bSchristos debugger. 1688dffb485Schristos 1694b169a6bSchristos There is extra complexity here because uninitialized elements in 1704b169a6bSchristos the pptrtab and ptrtab are set to zero, but zero (as the type ID 1714b169a6bSchristos meaning the unimplemented type) is a valid return type from 1724b169a6bSchristos ctf_lookup_by_name. (Pointers to types are never of type 0, so 1734b169a6bSchristos this is unambiguous, just fiddly to deal with.) */ 1748dffb485Schristos 1754b169a6bSchristos uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type); 1764b169a6bSchristos int in_child = 0; 1774b169a6bSchristos 1784b169a6bSchristos ntype = CTF_ERR; 1794b169a6bSchristos if (child && idx < child->ctf_pptrtab_len) 1804b169a6bSchristos { 1814b169a6bSchristos ntype = child->ctf_pptrtab[idx]; 1824b169a6bSchristos if (ntype) 1834b169a6bSchristos in_child = 1; 1844b169a6bSchristos else 1854b169a6bSchristos ntype = CTF_ERR; 1864b169a6bSchristos } 1874b169a6bSchristos 1884b169a6bSchristos if (ntype == CTF_ERR) 1894b169a6bSchristos { 1904b169a6bSchristos ntype = fp->ctf_ptrtab[idx]; 1918dffb485Schristos if (ntype == 0) 1924b169a6bSchristos ntype = CTF_ERR; 1938dffb485Schristos } 1948dffb485Schristos 1954b169a6bSchristos /* Try resolving to its base type and check again. */ 1964b169a6bSchristos if (ntype == CTF_ERR) 1974b169a6bSchristos { 1984b169a6bSchristos if (child) 1994b169a6bSchristos ntype = ctf_type_resolve_unsliced (child, type); 2004b169a6bSchristos else 2014b169a6bSchristos ntype = ctf_type_resolve_unsliced (fp, type); 2024b169a6bSchristos 2034b169a6bSchristos if (ntype == CTF_ERR) 2044b169a6bSchristos goto notype; 2054b169a6bSchristos 2064b169a6bSchristos idx = LCTF_TYPE_TO_INDEX (fp, ntype); 2074b169a6bSchristos 2084b169a6bSchristos ntype = CTF_ERR; 2094b169a6bSchristos if (child && idx < child->ctf_pptrtab_len) 2104b169a6bSchristos { 2114b169a6bSchristos ntype = child->ctf_pptrtab[idx]; 2124b169a6bSchristos if (ntype) 2134b169a6bSchristos in_child = 1; 2144b169a6bSchristos else 2154b169a6bSchristos ntype = CTF_ERR; 2164b169a6bSchristos } 2174b169a6bSchristos 2184b169a6bSchristos if (ntype == CTF_ERR) 2194b169a6bSchristos { 2204b169a6bSchristos ntype = fp->ctf_ptrtab[idx]; 2214b169a6bSchristos if (ntype == 0) 2224b169a6bSchristos ntype = CTF_ERR; 2234b169a6bSchristos } 2244b169a6bSchristos if (ntype == CTF_ERR) 2254b169a6bSchristos goto notype; 2264b169a6bSchristos } 2274b169a6bSchristos 2284b169a6bSchristos type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD) 2294b169a6bSchristos || in_child); 2304b169a6bSchristos 2314b169a6bSchristos /* We are looking up a type in the parent, but the pointed-to type is 2324b169a6bSchristos in the child. Switch to looking in the child: if we need to go 2334b169a6bSchristos back into the parent, we can recurse again. */ 2344b169a6bSchristos if (in_child) 2354b169a6bSchristos { 2364b169a6bSchristos fp = child; 2374b169a6bSchristos child = NULL; 2384b169a6bSchristos } 2398dffb485Schristos 2408dffb485Schristos q = p + 1; 2418dffb485Schristos continue; 2428dffb485Schristos } 2438dffb485Schristos 2448dffb485Schristos if (isqualifier (p, (size_t) (q - p))) 2458dffb485Schristos continue; /* Skip qualifier keyword. */ 2468dffb485Schristos 2478dffb485Schristos for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) 2488dffb485Schristos { 2498dffb485Schristos /* TODO: This is not MT-safe. */ 2508dffb485Schristos if ((lp->ctl_prefix[0] == '\0' || 2518dffb485Schristos strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) && 2528dffb485Schristos (size_t) (q - p) >= lp->ctl_len) 2538dffb485Schristos { 2548dffb485Schristos for (p += lp->ctl_len; isspace ((int) *p); p++) 2558dffb485Schristos continue; /* Skip prefix and next whitespace. */ 2568dffb485Schristos 2578dffb485Schristos if ((q = strchr (p, '*')) == NULL) 2588dffb485Schristos q = end; /* Compare until end. */ 2598dffb485Schristos 2608dffb485Schristos while (isspace ((int) q[-1])) 2618dffb485Schristos q--; /* Exclude trailing whitespace. */ 2628dffb485Schristos 2638dffb485Schristos /* Expand and/or allocate storage for a slice of the name, then 2648dffb485Schristos copy it in. */ 2658dffb485Schristos 2668dffb485Schristos if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1) 2678dffb485Schristos { 2688dffb485Schristos memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p)); 2698dffb485Schristos fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0'; 2708dffb485Schristos } 2718dffb485Schristos else 2728dffb485Schristos { 2738dffb485Schristos free (fp->ctf_tmp_typeslice); 2748dffb485Schristos fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p)); 2758dffb485Schristos if (fp->ctf_tmp_typeslice == NULL) 276*12989c96Schristos return ctf_set_typed_errno (fp, ENOMEM); 2778dffb485Schristos } 2788dffb485Schristos 279*12989c96Schristos if ((type = (ctf_id_t) (uintptr_t) 280*12989c96Schristos ctf_dynhash_lookup (lp->ctl_hash, 2818dffb485Schristos fp->ctf_tmp_typeslice)) == 0) 2824b169a6bSchristos goto notype; 2838dffb485Schristos 2848dffb485Schristos break; 2858dffb485Schristos } 2868dffb485Schristos } 2878dffb485Schristos 2888dffb485Schristos if (lp->ctl_prefix == NULL) 2894b169a6bSchristos goto notype; 2908dffb485Schristos } 2918dffb485Schristos 2928dffb485Schristos if (*p != '\0' || type == 0) 293*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_SYNTAX)); 2948dffb485Schristos 2958dffb485Schristos return type; 2968dffb485Schristos 2974b169a6bSchristos notype: 2984b169a6bSchristos ctf_set_errno (fp, ECTF_NOTYPE); 2994b169a6bSchristos if (fp->ctf_parent != NULL) 3004b169a6bSchristos { 3014b169a6bSchristos /* Need to look up in the parent, from the child's perspective. 3024b169a6bSchristos Make sure the pptrtab is up to date. */ 3034b169a6bSchristos 3044b169a6bSchristos if (fp->ctf_pptrtab_typemax < fp->ctf_typemax) 3054b169a6bSchristos { 3064b169a6bSchristos if (refresh_pptrtab (fp, fp->ctf_parent) < 0) 307*12989c96Schristos return CTF_ERR; /* errno is set for us. */ 3084b169a6bSchristos } 3094b169a6bSchristos 3104b169a6bSchristos if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp, 3114b169a6bSchristos name)) != CTF_ERR) 3128dffb485Schristos return ptype; 313*12989c96Schristos return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); 3144b169a6bSchristos } 3158dffb485Schristos 3168dffb485Schristos return CTF_ERR; 3178dffb485Schristos } 3188dffb485Schristos 3198dffb485Schristos ctf_id_t 3204b169a6bSchristos ctf_lookup_by_name (ctf_dict_t *fp, const char *name) 3218dffb485Schristos { 3224b169a6bSchristos return ctf_lookup_by_name_internal (fp, NULL, name); 3238dffb485Schristos } 3248dffb485Schristos 3258dffb485Schristos /* Return the pointer to the internal CTF type data corresponding to the 3268dffb485Schristos given type ID. If the ID is invalid, the function returns NULL. 3278dffb485Schristos This function is not exported outside of the library. */ 3288dffb485Schristos 3298dffb485Schristos const ctf_type_t * 3304b169a6bSchristos ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type) 3318dffb485Schristos { 332*12989c96Schristos ctf_dict_t *fp = *fpp; 3338dffb485Schristos ctf_id_t idx; 3348dffb485Schristos 3358dffb485Schristos if ((fp = ctf_get_dict (fp, type)) == NULL) 3368dffb485Schristos { 3378dffb485Schristos (void) ctf_set_errno (*fpp, ECTF_NOPARENT); 3388dffb485Schristos return NULL; 3398dffb485Schristos } 3408dffb485Schristos 3418dffb485Schristos idx = LCTF_TYPE_TO_INDEX (fp, type); 3428dffb485Schristos if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax) 3438dffb485Schristos { 344*12989c96Schristos *fpp = fp; /* Possibly the parent CTF dict. */ 3458dffb485Schristos return (LCTF_INDEX_TO_TYPEPTR (fp, idx)); 3468dffb485Schristos } 3478dffb485Schristos 3488dffb485Schristos (void) ctf_set_errno (*fpp, ECTF_BADID); 3498dffb485Schristos return NULL; 3508dffb485Schristos } 3518dffb485Schristos 3524b169a6bSchristos typedef struct ctf_lookup_idx_key 3534b169a6bSchristos { 3544b169a6bSchristos ctf_dict_t *clik_fp; 3554b169a6bSchristos const char *clik_name; 3564b169a6bSchristos uint32_t *clik_names; 3574b169a6bSchristos } ctf_lookup_idx_key_t; 3588dffb485Schristos 3594b169a6bSchristos /* A bsearch function for variable names. */ 3604b169a6bSchristos 3614b169a6bSchristos static int 3624b169a6bSchristos ctf_lookup_var (const void *key_, const void *lookup_) 3634b169a6bSchristos { 3644b169a6bSchristos const ctf_lookup_idx_key_t *key = key_; 3654b169a6bSchristos const ctf_varent_t *lookup = lookup_; 3664b169a6bSchristos 3674b169a6bSchristos return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name))); 3684b169a6bSchristos } 3694b169a6bSchristos 370*12989c96Schristos /* Given a variable name, return the type of the variable with that name. 371*12989c96Schristos Look only in this dict, not in the parent. */ 3724b169a6bSchristos 3734b169a6bSchristos ctf_id_t 374*12989c96Schristos ctf_lookup_variable_here (ctf_dict_t *fp, const char *name) 3754b169a6bSchristos { 376*12989c96Schristos ctf_dvdef_t *dvd = ctf_dvd_lookup (fp, name); 3774b169a6bSchristos ctf_varent_t *ent; 3784b169a6bSchristos ctf_lookup_idx_key_t key = { fp, name, NULL }; 3794b169a6bSchristos 380*12989c96Schristos if (dvd != NULL) 381*12989c96Schristos return dvd->dvd_type; 382*12989c96Schristos 3834b169a6bSchristos /* This array is sorted, so we can bsearch for it. */ 3844b169a6bSchristos 3854b169a6bSchristos ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t), 3864b169a6bSchristos ctf_lookup_var); 3874b169a6bSchristos 3884b169a6bSchristos if (ent == NULL) 389*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT)); 3904b169a6bSchristos 3914b169a6bSchristos return ent->ctv_type; 3924b169a6bSchristos } 3934b169a6bSchristos 394*12989c96Schristos /* As above, but look in the parent too. */ 395*12989c96Schristos 396*12989c96Schristos ctf_id_t 397*12989c96Schristos ctf_lookup_variable (ctf_dict_t *fp, const char *name) 398*12989c96Schristos { 399*12989c96Schristos ctf_id_t type; 400*12989c96Schristos 401*12989c96Schristos if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR) 402*12989c96Schristos { 403*12989c96Schristos if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL) 404*12989c96Schristos { 405*12989c96Schristos if ((type = ctf_lookup_variable_here (fp->ctf_parent, name)) != CTF_ERR) 406*12989c96Schristos return type; 407*12989c96Schristos return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent))); 408*12989c96Schristos } 409*12989c96Schristos 410*12989c96Schristos return -1; /* errno is set for us. */ 411*12989c96Schristos } 412*12989c96Schristos 413*12989c96Schristos return type; 414*12989c96Schristos } 415*12989c96Schristos 4164b169a6bSchristos typedef struct ctf_symidx_sort_arg_cb 4174b169a6bSchristos { 4184b169a6bSchristos ctf_dict_t *fp; 4194b169a6bSchristos uint32_t *names; 4204b169a6bSchristos } ctf_symidx_sort_arg_cb_t; 4214b169a6bSchristos 4224b169a6bSchristos static int 4234b169a6bSchristos sort_symidx_by_name (const void *one_, const void *two_, void *arg_) 4244b169a6bSchristos { 4254b169a6bSchristos const uint32_t *one = one_; 4264b169a6bSchristos const uint32_t *two = two_; 4274b169a6bSchristos ctf_symidx_sort_arg_cb_t *arg = arg_; 4284b169a6bSchristos 4294b169a6bSchristos return (strcmp (ctf_strptr (arg->fp, arg->names[*one]), 4304b169a6bSchristos ctf_strptr (arg->fp, arg->names[*two]))); 4314b169a6bSchristos } 4324b169a6bSchristos 4334b169a6bSchristos /* Sort a symbol index section by name. Takes a 1:1 mapping of names to the 4344b169a6bSchristos corresponding symbol table. Returns a lexicographically sorted array of idx 4354b169a6bSchristos indexes (and thus, of indexes into the corresponding func info / data object 4364b169a6bSchristos section). */ 4374b169a6bSchristos 4384b169a6bSchristos static uint32_t * 4394b169a6bSchristos ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx, 4404b169a6bSchristos size_t len) 4414b169a6bSchristos { 4424b169a6bSchristos uint32_t *sorted; 4434b169a6bSchristos size_t i; 4444b169a6bSchristos 4454b169a6bSchristos if ((sorted = malloc (len)) == NULL) 4464b169a6bSchristos { 4474b169a6bSchristos ctf_set_errno (fp, ENOMEM); 4484b169a6bSchristos return NULL; 4494b169a6bSchristos } 4504b169a6bSchristos 4514b169a6bSchristos *nidx = len / sizeof (uint32_t); 4524b169a6bSchristos for (i = 0; i < *nidx; i++) 4534b169a6bSchristos sorted[i] = i; 4544b169a6bSchristos 4554b169a6bSchristos if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED)) 4564b169a6bSchristos { 4574b169a6bSchristos ctf_symidx_sort_arg_cb_t arg = { fp, idx }; 458*12989c96Schristos ctf_dprintf ("Index section unsorted: sorting.\n"); 4594b169a6bSchristos ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg); 4604b169a6bSchristos fp->ctf_header->cth_flags |= CTF_F_IDXSORTED; 4614b169a6bSchristos } 4624b169a6bSchristos 4634b169a6bSchristos return sorted; 4644b169a6bSchristos } 4654b169a6bSchristos 4664b169a6bSchristos /* Given a symbol index, return the name of that symbol from the table provided 4674b169a6bSchristos by ctf_link_shuffle_syms, or failing that from the secondary string table, or 4684b169a6bSchristos the null string. */ 4694b169a6bSchristos static const char * 4704b169a6bSchristos ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx) 4718dffb485Schristos { 472*12989c96Schristos const ctf_sect_t *sp = &fp->ctf_ext_symtab; 4734b169a6bSchristos ctf_link_sym_t sym; 4744b169a6bSchristos int err; 4758dffb485Schristos 4764b169a6bSchristos if (fp->ctf_dynsymidx) 4774b169a6bSchristos { 4784b169a6bSchristos err = EINVAL; 4794b169a6bSchristos if (symidx > fp->ctf_dynsymmax) 4804b169a6bSchristos goto try_parent; 4814b169a6bSchristos 4824b169a6bSchristos ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx]; 4834b169a6bSchristos 4844b169a6bSchristos if (!symp) 4854b169a6bSchristos goto try_parent; 4864b169a6bSchristos 4874b169a6bSchristos return symp->st_name; 4884b169a6bSchristos } 4894b169a6bSchristos 4904b169a6bSchristos err = ECTF_NOSYMTAB; 4918dffb485Schristos if (sp->cts_data == NULL) 4924b169a6bSchristos goto try_parent; 4938dffb485Schristos 4948dffb485Schristos if (symidx >= fp->ctf_nsyms) 4954b169a6bSchristos goto try_parent; 4968dffb485Schristos 4974b169a6bSchristos switch (sp->cts_entsize) 4984b169a6bSchristos { 4994b169a6bSchristos case sizeof (Elf64_Sym): 5004b169a6bSchristos { 5014b169a6bSchristos const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx; 5024b169a6bSchristos ctf_elf64_to_link_sym (fp, &sym, symp, symidx); 5034b169a6bSchristos } 5044b169a6bSchristos break; 5054b169a6bSchristos case sizeof (Elf32_Sym): 5068dffb485Schristos { 5078dffb485Schristos const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx; 5084b169a6bSchristos ctf_elf32_to_link_sym (fp, &sym, symp, symidx); 5094b169a6bSchristos } 5104b169a6bSchristos break; 5114b169a6bSchristos default: 5124b169a6bSchristos ctf_set_errno (fp, ECTF_SYMTAB); 5134b169a6bSchristos return _CTF_NULLSTR; 5144b169a6bSchristos } 5154b169a6bSchristos 5164b169a6bSchristos assert (!sym.st_nameidx_set); 5174b169a6bSchristos 5184b169a6bSchristos return sym.st_name; 5194b169a6bSchristos 5204b169a6bSchristos try_parent: 5214b169a6bSchristos if (fp->ctf_parent) 5224b169a6bSchristos { 5234b169a6bSchristos const char *ret; 5244b169a6bSchristos ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx); 5254b169a6bSchristos if (ret == NULL) 5264b169a6bSchristos ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); 5274b169a6bSchristos return ret; 5288dffb485Schristos } 5298dffb485Schristos else 5308dffb485Schristos { 5314b169a6bSchristos ctf_set_errno (fp, err); 5324b169a6bSchristos return _CTF_NULLSTR; 5334b169a6bSchristos } 5348dffb485Schristos } 5358dffb485Schristos 5364b169a6bSchristos /* Given a symbol name, return the index of that symbol, or -1 on error or if 537*12989c96Schristos not found. If is_function is >= 0, return only function or data object 538*12989c96Schristos symbols, respectively. */ 5394b169a6bSchristos static unsigned long 540*12989c96Schristos ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent, 541*12989c96Schristos int is_function) 5424b169a6bSchristos { 543*12989c96Schristos const ctf_sect_t *sp = &fp->ctf_ext_symtab; 5444b169a6bSchristos ctf_link_sym_t sym; 5454b169a6bSchristos void *known_idx; 5464b169a6bSchristos int err; 5474b169a6bSchristos ctf_dict_t *cache = fp; 5488dffb485Schristos 5494b169a6bSchristos if (fp->ctf_dynsyms) 5504b169a6bSchristos { 5514b169a6bSchristos err = EINVAL; 5528dffb485Schristos 5534b169a6bSchristos ctf_link_sym_t *symp; 5548dffb485Schristos 555*12989c96Schristos if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL) 556*12989c96Schristos || (symp->st_type != STT_OBJECT && is_function == 0) 557*12989c96Schristos || (symp->st_type != STT_FUNC && is_function == 1)) 5584b169a6bSchristos goto try_parent; 5598dffb485Schristos 5604b169a6bSchristos return symp->st_symidx; 5614b169a6bSchristos } 5624b169a6bSchristos 5634b169a6bSchristos err = ECTF_NOSYMTAB; 5644b169a6bSchristos if (sp->cts_data == NULL) 5654b169a6bSchristos goto try_parent; 5664b169a6bSchristos 5674b169a6bSchristos /* First, try a hash lookup to see if we have already spotted this symbol 568*12989c96Schristos during a past iteration: create the hash first if need be. The 569*12989c96Schristos lifespan of the strings is equal to the lifespan of the cts_data, so we 570*12989c96Schristos don't need to strdup them. If this dict was opened as part of an 571*12989c96Schristos archive, and this archive has a crossdict_cache to cache results that 5724b169a6bSchristos are the same across all dicts in an archive, use it. */ 5734b169a6bSchristos 5744b169a6bSchristos if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache) 5754b169a6bSchristos cache = fp->ctf_archive->ctfi_crossdict_cache; 5764b169a6bSchristos 577*12989c96Schristos if (!cache->ctf_symhash_func) 578*12989c96Schristos if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string, 5794b169a6bSchristos ctf_hash_eq_string, 5804b169a6bSchristos NULL, NULL)) == NULL) 5814b169a6bSchristos goto oom; 5824b169a6bSchristos 583*12989c96Schristos if (!cache->ctf_symhash_objt) 584*12989c96Schristos if ((cache->ctf_symhash_objt = ctf_dynhash_create (ctf_hash_string, 585*12989c96Schristos ctf_hash_eq_string, 586*12989c96Schristos NULL, NULL)) == NULL) 587*12989c96Schristos goto oom; 588*12989c96Schristos 589*12989c96Schristos if (is_function != 0 && 590*12989c96Schristos ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx)) 591*12989c96Schristos return (unsigned long) (uintptr_t) known_idx; 592*12989c96Schristos 593*12989c96Schristos if (is_function != 1 && 594*12989c96Schristos ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx)) 5954b169a6bSchristos return (unsigned long) (uintptr_t) known_idx; 5964b169a6bSchristos 5974b169a6bSchristos /* Hash lookup unsuccessful: linear search, populating the hashtab for later 5984b169a6bSchristos lookups as we go. */ 5994b169a6bSchristos 6004b169a6bSchristos for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize; 6014b169a6bSchristos cache->ctf_symhash_latest++) 6024b169a6bSchristos { 603*12989c96Schristos ctf_dynhash_t *h; 604*12989c96Schristos 6054b169a6bSchristos switch (sp->cts_entsize) 6064b169a6bSchristos { 6074b169a6bSchristos case sizeof (Elf64_Sym): 6084b169a6bSchristos { 6094b169a6bSchristos Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data; 610*12989c96Schristos 6114b169a6bSchristos ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], 6124b169a6bSchristos cache->ctf_symhash_latest); 6134b169a6bSchristos } 6144b169a6bSchristos break; 6154b169a6bSchristos case sizeof (Elf32_Sym): 6164b169a6bSchristos { 6174b169a6bSchristos Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data; 6184b169a6bSchristos ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest], 6194b169a6bSchristos cache->ctf_symhash_latest); 620*12989c96Schristos break; 621*12989c96Schristos } 622*12989c96Schristos default: 623*12989c96Schristos ctf_set_errno (fp, ECTF_SYMTAB); 624*12989c96Schristos return (unsigned long) -1; 625*12989c96Schristos } 626*12989c96Schristos 627*12989c96Schristos if (sym.st_type == STT_FUNC) 628*12989c96Schristos h = cache->ctf_symhash_func; 629*12989c96Schristos else if (sym.st_type == STT_OBJECT) 630*12989c96Schristos h = cache->ctf_symhash_objt; 631*12989c96Schristos else 632*12989c96Schristos continue; /* Not of interest. */ 633*12989c96Schristos 634*12989c96Schristos if (!ctf_dynhash_lookup_kv (h, sym.st_name, 6354b169a6bSchristos NULL, NULL)) 636*12989c96Schristos if (ctf_dynhash_cinsert (h, sym.st_name, 6374b169a6bSchristos (const void *) (uintptr_t) 6384b169a6bSchristos cache->ctf_symhash_latest) < 0) 6394b169a6bSchristos goto oom; 6404b169a6bSchristos if (strcmp (sym.st_name, symname) == 0) 6414b169a6bSchristos return cache->ctf_symhash_latest++; 6424b169a6bSchristos } 6434b169a6bSchristos 6444b169a6bSchristos /* Searched everything, still not found. */ 6454b169a6bSchristos 6464b169a6bSchristos return (unsigned long) -1; 6474b169a6bSchristos 6484b169a6bSchristos try_parent: 649*12989c96Schristos if (fp->ctf_parent && try_parent) 650*12989c96Schristos { 651*12989c96Schristos unsigned long psym; 652*12989c96Schristos 653*12989c96Schristos if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent, 654*12989c96Schristos is_function)) 655*12989c96Schristos != (unsigned long) -1) 656*12989c96Schristos return psym; 657*12989c96Schristos 658*12989c96Schristos ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); 659*12989c96Schristos return (unsigned long) -1; 660*12989c96Schristos } 6614b169a6bSchristos else 6624b169a6bSchristos { 6634b169a6bSchristos ctf_set_errno (fp, err); 6644b169a6bSchristos return (unsigned long) -1; 6654b169a6bSchristos } 6664b169a6bSchristos oom: 6674b169a6bSchristos ctf_set_errno (fp, ENOMEM); 668*12989c96Schristos ctf_err_warn (fp, 0, 0, _("cannot allocate memory for symbol " 6694b169a6bSchristos "lookup hashtab")); 6704b169a6bSchristos return (unsigned long) -1; 6714b169a6bSchristos 6724b169a6bSchristos } 6734b169a6bSchristos 674*12989c96Schristos ctf_id_t 675*12989c96Schristos ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, 676*12989c96Schristos int functions); 677*12989c96Schristos 678*12989c96Schristos /* Iterate over all symbols with types: if FUNC, function symbols, 679*12989c96Schristos otherwise, data symbols. The name argument is not optional. The return 680*12989c96Schristos order is arbitrary, though is likely to be in symbol index or name order. 681*12989c96Schristos Changing the value of 'functions' in the middle of iteration has 682*12989c96Schristos unpredictable effects (probably skipping symbols, etc) and is not 683*12989c96Schristos recommended. Adding symbols while iteration is underway may also lead 684*12989c96Schristos to other symbols being skipped. */ 6854b169a6bSchristos 6864b169a6bSchristos ctf_id_t 6874b169a6bSchristos ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, 6884b169a6bSchristos int functions) 6894b169a6bSchristos { 690*12989c96Schristos ctf_id_t sym = CTF_ERR; 6914b169a6bSchristos ctf_next_t *i = *it; 6924b169a6bSchristos int err; 6934b169a6bSchristos 6944b169a6bSchristos if (!i) 6954b169a6bSchristos { 6964b169a6bSchristos if ((i = ctf_next_create ()) == NULL) 697*12989c96Schristos return ctf_set_typed_errno (fp, ENOMEM); 6984b169a6bSchristos 6994b169a6bSchristos i->cu.ctn_fp = fp; 7004b169a6bSchristos i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; 7014b169a6bSchristos i->ctn_n = 0; 7024b169a6bSchristos *it = i; 7034b169a6bSchristos } 7044b169a6bSchristos 7054b169a6bSchristos if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) 706*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); 7074b169a6bSchristos 7084b169a6bSchristos if (fp != i->cu.ctn_fp) 709*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); 7104b169a6bSchristos 711*12989c96Schristos /* Check the dynamic set of names first, to allow previously-written names 712*12989c96Schristos to be replaced with dynamic ones (there is still no way to remove them, 713*12989c96Schristos though). 714*12989c96Schristos 715*12989c96Schristos We intentionally use raw access, not ctf_lookup_by_symbol, to avoid 7164b169a6bSchristos incurring additional sorting cost for unsorted symtypetabs coming from the 7174b169a6bSchristos compiler, to allow ctf_symbol_next to work in the absence of a symtab, and 7184b169a6bSchristos finally because it's easier to work out what the name of each symbol is if 7194b169a6bSchristos we do that. */ 7204b169a6bSchristos 7214b169a6bSchristos ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; 7224b169a6bSchristos void *dyn_name = NULL, *dyn_value = NULL; 723*12989c96Schristos size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; 7244b169a6bSchristos 725*12989c96Schristos if (i->ctn_n < dyn_els) 7264b169a6bSchristos { 7274b169a6bSchristos err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); 728*12989c96Schristos 7294b169a6bSchristos /* This covers errors and also end-of-iteration. */ 7304b169a6bSchristos if (err != 0) 7314b169a6bSchristos { 7324b169a6bSchristos ctf_next_destroy (i); 7334b169a6bSchristos *it = NULL; 734*12989c96Schristos return ctf_set_typed_errno (fp, err); 7354b169a6bSchristos } 7364b169a6bSchristos 7374b169a6bSchristos *name = dyn_name; 7384b169a6bSchristos sym = (ctf_id_t) (uintptr_t) dyn_value; 739*12989c96Schristos i->ctn_n++; 740*12989c96Schristos 741*12989c96Schristos return sym; 7424b169a6bSchristos } 743*12989c96Schristos 744*12989c96Schristos return ctf_symbol_next_static (fp, it, name, functions); 745*12989c96Schristos } 746*12989c96Schristos 747*12989c96Schristos /* ctf_symbol_next, but only for static symbols. Mostly an internal 748*12989c96Schristos implementation detail of ctf_symbol_next, but also used to simplify 749*12989c96Schristos serialization. */ 750*12989c96Schristos ctf_id_t 751*12989c96Schristos ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name, 752*12989c96Schristos int functions) 753*12989c96Schristos { 754*12989c96Schristos ctf_id_t sym = CTF_ERR; 755*12989c96Schristos ctf_next_t *i = *it; 756*12989c96Schristos ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash; 757*12989c96Schristos size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0; 758*12989c96Schristos 759*12989c96Schristos /* Only relevant for direct internal-to-library calls, not via 760*12989c96Schristos ctf_symbol_next (but important then). */ 761*12989c96Schristos 762*12989c96Schristos if (!i) 763*12989c96Schristos { 764*12989c96Schristos if ((i = ctf_next_create ()) == NULL) 765*12989c96Schristos return ctf_set_typed_errno (fp, ENOMEM); 766*12989c96Schristos 767*12989c96Schristos i->cu.ctn_fp = fp; 768*12989c96Schristos i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next; 769*12989c96Schristos i->ctn_n = dyn_els; 770*12989c96Schristos *it = i; 771*12989c96Schristos } 772*12989c96Schristos 773*12989c96Schristos if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun) 774*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); 775*12989c96Schristos 776*12989c96Schristos if (fp != i->cu.ctn_fp) 777*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); 778*12989c96Schristos 779*12989c96Schristos /* TODO-v4: Indexed after non-indexed portions? */ 780*12989c96Schristos 781*12989c96Schristos if ((!functions && fp->ctf_objtidx_names) || 7824b169a6bSchristos (functions && fp->ctf_funcidx_names)) 7834b169a6bSchristos { 7844b169a6bSchristos ctf_header_t *hp = fp->ctf_header; 7854b169a6bSchristos uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names; 7864b169a6bSchristos uint32_t *tab; 7874b169a6bSchristos size_t len; 7884b169a6bSchristos 7894b169a6bSchristos if (functions) 7904b169a6bSchristos { 7914b169a6bSchristos len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t); 7924b169a6bSchristos tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); 7934b169a6bSchristos } 7944b169a6bSchristos else 7954b169a6bSchristos { 7964b169a6bSchristos len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t); 7974b169a6bSchristos tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); 7984b169a6bSchristos } 7994b169a6bSchristos 8004b169a6bSchristos do 8014b169a6bSchristos { 802*12989c96Schristos if (i->ctn_n - dyn_els >= len) 8034b169a6bSchristos goto end; 8044b169a6bSchristos 805*12989c96Schristos *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]); 806*12989c96Schristos sym = tab[i->ctn_n - dyn_els]; 807*12989c96Schristos i->ctn_n++; 8084b169a6bSchristos } 8094b169a6bSchristos while (sym == -1u || sym == 0); 8104b169a6bSchristos } 8114b169a6bSchristos else 8124b169a6bSchristos { 813*12989c96Schristos /* Skip over pads in ctf_sxlate, padding for typeless symbols in the 8144b169a6bSchristos symtypetab itself, and symbols in the wrong table. */ 815*12989c96Schristos for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++) 8164b169a6bSchristos { 8174b169a6bSchristos ctf_header_t *hp = fp->ctf_header; 818*12989c96Schristos size_t n = i->ctn_n - dyn_els; 8194b169a6bSchristos 820*12989c96Schristos if (fp->ctf_sxlate[n] == -1u) 8214b169a6bSchristos continue; 8224b169a6bSchristos 823*12989c96Schristos sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]); 8244b169a6bSchristos 8254b169a6bSchristos if (sym == 0) 8264b169a6bSchristos continue; 8274b169a6bSchristos 8284b169a6bSchristos if (functions) 8294b169a6bSchristos { 830*12989c96Schristos if (fp->ctf_sxlate[n] >= hp->cth_funcoff 831*12989c96Schristos && fp->ctf_sxlate[n] < hp->cth_objtidxoff) 8324b169a6bSchristos break; 8334b169a6bSchristos } 8344b169a6bSchristos else 8354b169a6bSchristos { 836*12989c96Schristos if (fp->ctf_sxlate[n] >= hp->cth_objtoff 837*12989c96Schristos && fp->ctf_sxlate[n] < hp->cth_funcoff) 8384b169a6bSchristos break; 8394b169a6bSchristos } 8404b169a6bSchristos } 8414b169a6bSchristos 842*12989c96Schristos if (i->ctn_n - dyn_els >= fp->ctf_nsyms) 8434b169a6bSchristos goto end; 8444b169a6bSchristos 845*12989c96Schristos *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els); 846*12989c96Schristos i->ctn_n++; 8474b169a6bSchristos } 8484b169a6bSchristos 8494b169a6bSchristos return sym; 8504b169a6bSchristos 8514b169a6bSchristos end: 8524b169a6bSchristos ctf_next_destroy (i); 8534b169a6bSchristos *it = NULL; 854*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_NEXT_END)); 8554b169a6bSchristos } 8564b169a6bSchristos 8574b169a6bSchristos /* A bsearch function for function and object index names. */ 8584b169a6bSchristos 8594b169a6bSchristos static int 8604b169a6bSchristos ctf_lookup_idx_name (const void *key_, const void *idx_) 8614b169a6bSchristos { 8624b169a6bSchristos const ctf_lookup_idx_key_t *key = key_; 8634b169a6bSchristos const uint32_t *idx = idx_; 8644b169a6bSchristos 8654b169a6bSchristos return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx]))); 8664b169a6bSchristos } 8674b169a6bSchristos 8684b169a6bSchristos /* Given a symbol name or (failing that) number, look up that symbol in the 8694b169a6bSchristos function or object index table (which must exist). Return 0 if not found 8704b169a6bSchristos there (or pad). */ 8714b169a6bSchristos 8724b169a6bSchristos static ctf_id_t 8734b169a6bSchristos ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, 8744b169a6bSchristos const char *symname, int is_function) 8754b169a6bSchristos { 8764b169a6bSchristos struct ctf_header *hp = fp->ctf_header; 8774b169a6bSchristos uint32_t *symtypetab; 8784b169a6bSchristos uint32_t *names; 8794b169a6bSchristos uint32_t *sxlate; 8804b169a6bSchristos size_t nidx; 8814b169a6bSchristos 8824b169a6bSchristos if (symname == NULL) 8834b169a6bSchristos symname = ctf_lookup_symbol_name (fp, symidx); 8844b169a6bSchristos 885*12989c96Schristos /* Dynamic dict with no static portion: just return. */ 886*12989c96Schristos if (!hp) 887*12989c96Schristos { 888*12989c96Schristos ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname); 889*12989c96Schristos return 0; 890*12989c96Schristos } 891*12989c96Schristos 8924b169a6bSchristos ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in " 8934b169a6bSchristos "indexed symtypetab\n", symidx, symname); 8944b169a6bSchristos 8954b169a6bSchristos if (symname[0] == '\0') 896*12989c96Schristos return CTF_ERR; /* errno is set for us. */ 8974b169a6bSchristos 8984b169a6bSchristos if (is_function) 8994b169a6bSchristos { 9004b169a6bSchristos if (!fp->ctf_funcidx_sxlate) 9014b169a6bSchristos { 9024b169a6bSchristos if ((fp->ctf_funcidx_sxlate 9034b169a6bSchristos = ctf_symidx_sort (fp, (uint32_t *) 9044b169a6bSchristos (fp->ctf_buf + hp->cth_funcidxoff), 9054b169a6bSchristos &fp->ctf_nfuncidx, 9064b169a6bSchristos hp->cth_varoff - hp->cth_funcidxoff)) 9074b169a6bSchristos == NULL) 9084b169a6bSchristos { 9094b169a6bSchristos ctf_err_warn (fp, 0, 0, _("cannot sort function symidx")); 910*12989c96Schristos return CTF_ERR; /* errno is set for us. */ 9114b169a6bSchristos } 9124b169a6bSchristos } 9134b169a6bSchristos symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff); 9144b169a6bSchristos sxlate = fp->ctf_funcidx_sxlate; 9154b169a6bSchristos names = fp->ctf_funcidx_names; 9164b169a6bSchristos nidx = fp->ctf_nfuncidx; 9174b169a6bSchristos } 9184b169a6bSchristos else 9194b169a6bSchristos { 9204b169a6bSchristos if (!fp->ctf_objtidx_sxlate) 9214b169a6bSchristos { 9224b169a6bSchristos if ((fp->ctf_objtidx_sxlate 9234b169a6bSchristos = ctf_symidx_sort (fp, (uint32_t *) 9244b169a6bSchristos (fp->ctf_buf + hp->cth_objtidxoff), 9254b169a6bSchristos &fp->ctf_nobjtidx, 9264b169a6bSchristos hp->cth_funcidxoff - hp->cth_objtidxoff)) 9274b169a6bSchristos == NULL) 9284b169a6bSchristos { 9294b169a6bSchristos ctf_err_warn (fp, 0, 0, _("cannot sort object symidx")); 930*12989c96Schristos return CTF_ERR; /* errno is set for us. */ 9314b169a6bSchristos } 9324b169a6bSchristos } 9334b169a6bSchristos 9344b169a6bSchristos symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff); 9354b169a6bSchristos sxlate = fp->ctf_objtidx_sxlate; 9364b169a6bSchristos names = fp->ctf_objtidx_names; 9374b169a6bSchristos nidx = fp->ctf_nobjtidx; 9384b169a6bSchristos } 9394b169a6bSchristos 9404b169a6bSchristos ctf_lookup_idx_key_t key = { fp, symname, names }; 9414b169a6bSchristos uint32_t *idx; 9424b169a6bSchristos 9434b169a6bSchristos idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name); 9444b169a6bSchristos 9454b169a6bSchristos if (!idx) 9464b169a6bSchristos { 9474b169a6bSchristos ctf_dprintf ("%s not found in idx\n", symname); 9484b169a6bSchristos return 0; 9494b169a6bSchristos } 9504b169a6bSchristos 9514b169a6bSchristos /* Should be impossible, but be paranoid. */ 9524b169a6bSchristos if ((idx - sxlate) > (ptrdiff_t) nidx) 953*12989c96Schristos return (ctf_set_typed_errno (fp, ECTF_CORRUPT)); 9548dffb485Schristos 9554b169a6bSchristos ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname, 9564b169a6bSchristos symtypetab[*idx]); 9574b169a6bSchristos return symtypetab[*idx]; 9588dffb485Schristos } 9598dffb485Schristos 9604b169a6bSchristos /* Given a symbol name or (if NULL) symbol index, return the type of the 9614b169a6bSchristos function or data object described by the corresponding entry in the symbol 9624b169a6bSchristos table. We can only return symbols in read-only dicts and in dicts for which 9634b169a6bSchristos ctf_link_shuffle_syms has been called to assign symbol indexes to symbol 964*12989c96Schristos names. 9654b169a6bSchristos 966*12989c96Schristos If try_parent is false, do not check the parent dict too. 967*12989c96Schristos 968*12989c96Schristos If is_function is > -1, only look for data objects or functions in 969*12989c96Schristos particular. */ 970*12989c96Schristos 971*12989c96Schristos ctf_id_t 9724b169a6bSchristos ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx, 973*12989c96Schristos const char *symname, int try_parent, 974*12989c96Schristos int is_function) 9754b169a6bSchristos { 976*12989c96Schristos const ctf_sect_t *sp = &fp->ctf_ext_symtab; 9774b169a6bSchristos ctf_id_t type = 0; 9784b169a6bSchristos int err = 0; 9794b169a6bSchristos 980*12989c96Schristos /* Shuffled dynsymidx present? Use that. For now, the dynsymidx and 981*12989c96Schristos shuffled-symbol lookup only support dynamically-added symbols, because 982*12989c96Schristos this interface is meant for use by linkers, and linkers are only going 983*12989c96Schristos to report symbols against newly-created, freshly-ctf_link'ed dicts: so 984*12989c96Schristos there will be no static component in any case. */ 9854b169a6bSchristos if (fp->ctf_dynsymidx) 9864b169a6bSchristos { 9874b169a6bSchristos const ctf_link_sym_t *sym; 9884b169a6bSchristos 9894b169a6bSchristos if (symname) 9904b169a6bSchristos ctf_dprintf ("Looking up type of object with symname %s in " 9914b169a6bSchristos "writable dict symtypetab\n", symname); 9924b169a6bSchristos else 9934b169a6bSchristos ctf_dprintf ("Looking up type of object with symtab idx %lx in " 9944b169a6bSchristos "writable dict symtypetab\n", symidx); 9954b169a6bSchristos 9964b169a6bSchristos /* No name? Need to look it up. */ 9974b169a6bSchristos if (!symname) 9984b169a6bSchristos { 9994b169a6bSchristos err = EINVAL; 10004b169a6bSchristos if (symidx > fp->ctf_dynsymmax) 10014b169a6bSchristos goto try_parent; 10024b169a6bSchristos 10034b169a6bSchristos sym = fp->ctf_dynsymidx[symidx]; 10044b169a6bSchristos err = ECTF_NOTYPEDAT; 1005*12989c96Schristos if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC) 1006*12989c96Schristos || (sym->st_type != STT_OBJECT && is_function == 0) 1007*12989c96Schristos || (sym->st_type != STT_FUNC && is_function == 1)) 10084b169a6bSchristos goto try_parent; 10094b169a6bSchristos 10104b169a6bSchristos if (!ctf_assert (fp, !sym->st_nameidx_set)) 10114b169a6bSchristos return CTF_ERR; 10124b169a6bSchristos symname = sym->st_name; 10134b169a6bSchristos } 10144b169a6bSchristos 10154b169a6bSchristos if (fp->ctf_objthash == NULL 1016*12989c96Schristos || is_function == 1 1017*12989c96Schristos || (type = (ctf_id_t) (uintptr_t) 1018*12989c96Schristos ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0) 10194b169a6bSchristos { 10204b169a6bSchristos if (fp->ctf_funchash == NULL 1021*12989c96Schristos || is_function == 0 1022*12989c96Schristos || (type = (ctf_id_t) (uintptr_t) 1023*12989c96Schristos ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0) 10244b169a6bSchristos goto try_parent; 10254b169a6bSchristos } 10264b169a6bSchristos 10274b169a6bSchristos return type; 10284b169a6bSchristos } 10294b169a6bSchristos 1030*12989c96Schristos /* Dict not shuffled: look for a dynamic sym first, and look it up 1031*12989c96Schristos directly. */ 1032*12989c96Schristos if (symname) 10334b169a6bSchristos { 1034*12989c96Schristos if (fp->ctf_objthash != NULL 1035*12989c96Schristos && is_function != 1 1036*12989c96Schristos && ((type = (ctf_id_t) (uintptr_t) 1037*12989c96Schristos ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0)) 1038*12989c96Schristos return type; 1039*12989c96Schristos 1040*12989c96Schristos if (fp->ctf_funchash != NULL 1041*12989c96Schristos && is_function != 0 1042*12989c96Schristos && ((type = (ctf_id_t) (uintptr_t) 1043*12989c96Schristos ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0)) 10444b169a6bSchristos return type; 10454b169a6bSchristos } 10464b169a6bSchristos 10474b169a6bSchristos err = ECTF_NOSYMTAB; 1048*12989c96Schristos if (sp->cts_data == NULL && symname == NULL && 1049*12989c96Schristos ((is_function && !fp->ctf_funcidx_names) || 1050*12989c96Schristos (!is_function && !fp->ctf_objtidx_names))) 10514b169a6bSchristos goto try_parent; 10524b169a6bSchristos 1053*12989c96Schristos /* This covers both out-of-range lookups by index and a dynamic dict which 1054*12989c96Schristos hasn't been shuffled yet. */ 10554b169a6bSchristos err = EINVAL; 10564b169a6bSchristos if (symname == NULL && symidx >= fp->ctf_nsyms) 10574b169a6bSchristos goto try_parent; 10584b169a6bSchristos 1059*12989c96Schristos /* Try an indexed lookup. */ 1060*12989c96Schristos 1061*12989c96Schristos if (fp->ctf_objtidx_names && is_function != 1) 10624b169a6bSchristos { 10634b169a6bSchristos if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR) 10644b169a6bSchristos return CTF_ERR; /* errno is set for us. */ 10654b169a6bSchristos } 1066*12989c96Schristos if (type == 0 && fp->ctf_funcidx_names && is_function != 0) 10674b169a6bSchristos { 10684b169a6bSchristos if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR) 10694b169a6bSchristos return CTF_ERR; /* errno is set for us. */ 10704b169a6bSchristos } 10714b169a6bSchristos if (type != 0) 10724b169a6bSchristos return type; 10734b169a6bSchristos 1074*12989c96Schristos /* Indexed but no symbol found -> not present, try the parent. */ 10754b169a6bSchristos err = ECTF_NOTYPEDAT; 10764b169a6bSchristos if (fp->ctf_objtidx_names && fp->ctf_funcidx_names) 10774b169a6bSchristos goto try_parent; 10784b169a6bSchristos 10794b169a6bSchristos /* Table must be nonindexed. */ 10804b169a6bSchristos 10814b169a6bSchristos ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx); 10824b169a6bSchristos 10834b169a6bSchristos if (symname != NULL) 1084*12989c96Schristos if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function)) 1085*12989c96Schristos == (unsigned long) -1) 10864b169a6bSchristos goto try_parent; 10874b169a6bSchristos 10884b169a6bSchristos if (fp->ctf_sxlate[symidx] == -1u) 10894b169a6bSchristos goto try_parent; 10904b169a6bSchristos 10914b169a6bSchristos type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]); 10924b169a6bSchristos 10934b169a6bSchristos if (type == 0) 10944b169a6bSchristos goto try_parent; 10954b169a6bSchristos 10964b169a6bSchristos return type; 1097*12989c96Schristos 10984b169a6bSchristos try_parent: 1099*12989c96Schristos if (!try_parent) 1100*12989c96Schristos return ctf_set_errno (fp, err); 1101*12989c96Schristos 11024b169a6bSchristos if (fp->ctf_parent) 11034b169a6bSchristos { 11044b169a6bSchristos ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx, 1105*12989c96Schristos symname, try_parent, 1106*12989c96Schristos is_function); 11074b169a6bSchristos if (ret == CTF_ERR) 11084b169a6bSchristos ctf_set_errno (fp, ctf_errno (fp->ctf_parent)); 11094b169a6bSchristos return ret; 11104b169a6bSchristos } 11114b169a6bSchristos else 1112*12989c96Schristos return (ctf_set_typed_errno (fp, err)); 11134b169a6bSchristos } 11144b169a6bSchristos 11154b169a6bSchristos /* Given a symbol table index, return the type of the function or data object 11164b169a6bSchristos described by the corresponding entry in the symbol table. */ 11174b169a6bSchristos ctf_id_t 11184b169a6bSchristos ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx) 11194b169a6bSchristos { 1120*12989c96Schristos return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1); 11214b169a6bSchristos } 11224b169a6bSchristos 11234b169a6bSchristos /* Given a symbol name, return the type of the function or data object described 11244b169a6bSchristos by the corresponding entry in the symbol table. */ 11254b169a6bSchristos ctf_id_t 11264b169a6bSchristos ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname) 11274b169a6bSchristos { 1128*12989c96Schristos return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1); 11294b169a6bSchristos } 11304b169a6bSchristos 11314b169a6bSchristos /* Given a symbol table index, return the info for the function described 11324b169a6bSchristos by the corresponding entry in the symbol table, which may be a function 11334b169a6bSchristos symbol or may be a data symbol that happens to be a function pointer. */ 11344b169a6bSchristos 11354b169a6bSchristos int 11364b169a6bSchristos ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip) 11374b169a6bSchristos { 11384b169a6bSchristos ctf_id_t type; 11394b169a6bSchristos 11404b169a6bSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) 11414b169a6bSchristos return -1; /* errno is set for us. */ 11424b169a6bSchristos 11434b169a6bSchristos if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) 11444b169a6bSchristos return (ctf_set_errno (fp, ECTF_NOTFUNC)); 11454b169a6bSchristos 11464b169a6bSchristos return ctf_func_type_info (fp, type, fip); 11478dffb485Schristos } 11488dffb485Schristos 11498dffb485Schristos /* Given a symbol table index, return the arguments for the function described 11508dffb485Schristos by the corresponding entry in the symbol table. */ 11518dffb485Schristos 11528dffb485Schristos int 11534b169a6bSchristos ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc, 11548dffb485Schristos ctf_id_t *argv) 11558dffb485Schristos { 11564b169a6bSchristos ctf_id_t type; 11578dffb485Schristos 11584b169a6bSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR) 11598dffb485Schristos return -1; /* errno is set for us. */ 11608dffb485Schristos 11614b169a6bSchristos if (ctf_type_kind (fp, type) != CTF_K_FUNCTION) 11624b169a6bSchristos return (ctf_set_errno (fp, ECTF_NOTFUNC)); 11638dffb485Schristos 11644b169a6bSchristos return ctf_func_type_args (fp, type, argc, argv); 11658dffb485Schristos } 1166