1867d70fcSchristos /* Symbol, variable and name lookup.
2*c42dbd0eSchristos Copyright (C) 2019-2022 Free Software Foundation, Inc.
3867d70fcSchristos
4867d70fcSchristos This file is part of libctf.
5867d70fcSchristos
6867d70fcSchristos libctf is free software; you can redistribute it and/or modify it under
7867d70fcSchristos the terms of the GNU General Public License as published by the Free
8867d70fcSchristos Software Foundation; either version 3, or (at your option) any later
9867d70fcSchristos version.
10867d70fcSchristos
11867d70fcSchristos This program is distributed in the hope that it will be useful, but
12867d70fcSchristos WITHOUT ANY WARRANTY; without even the implied warranty of
13867d70fcSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14867d70fcSchristos See the GNU General Public License for more details.
15867d70fcSchristos
16867d70fcSchristos You should have received a copy of the GNU General Public License
17867d70fcSchristos along with this program; see the file COPYING. If not see
18867d70fcSchristos <http://www.gnu.org/licenses/>. */
19867d70fcSchristos
20867d70fcSchristos #include <ctf-impl.h>
21867d70fcSchristos #include <elf.h>
22867d70fcSchristos #include <string.h>
23*c42dbd0eSchristos #include <assert.h>
24*c42dbd0eSchristos
25*c42dbd0eSchristos /* Grow the pptrtab so that it is at least NEW_LEN long. */
26*c42dbd0eSchristos static int
grow_pptrtab(ctf_dict_t * fp,size_t new_len)27*c42dbd0eSchristos grow_pptrtab (ctf_dict_t *fp, size_t new_len)
28*c42dbd0eSchristos {
29*c42dbd0eSchristos uint32_t *new_pptrtab;
30*c42dbd0eSchristos
31*c42dbd0eSchristos if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
32*c42dbd0eSchristos * new_len)) == NULL)
33*c42dbd0eSchristos return (ctf_set_errno (fp, ENOMEM));
34*c42dbd0eSchristos
35*c42dbd0eSchristos fp->ctf_pptrtab = new_pptrtab;
36*c42dbd0eSchristos
37*c42dbd0eSchristos memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0,
38*c42dbd0eSchristos sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len));
39*c42dbd0eSchristos
40*c42dbd0eSchristos fp->ctf_pptrtab_len = new_len;
41*c42dbd0eSchristos return 0;
42*c42dbd0eSchristos }
43*c42dbd0eSchristos
44*c42dbd0eSchristos /* Update entries in the pptrtab that relate to types newly added in the
45*c42dbd0eSchristos child. */
46*c42dbd0eSchristos static int
refresh_pptrtab(ctf_dict_t * fp,ctf_dict_t * pfp)47*c42dbd0eSchristos refresh_pptrtab (ctf_dict_t *fp, ctf_dict_t *pfp)
48*c42dbd0eSchristos {
49*c42dbd0eSchristos uint32_t i;
50*c42dbd0eSchristos for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++)
51*c42dbd0eSchristos {
52*c42dbd0eSchristos ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1);
53*c42dbd0eSchristos ctf_id_t reffed_type;
54*c42dbd0eSchristos
55*c42dbd0eSchristos if (ctf_type_kind (fp, type) != CTF_K_POINTER)
56*c42dbd0eSchristos continue;
57*c42dbd0eSchristos
58*c42dbd0eSchristos reffed_type = ctf_type_reference (fp, type);
59*c42dbd0eSchristos
60*c42dbd0eSchristos if (LCTF_TYPE_ISPARENT (fp, reffed_type))
61*c42dbd0eSchristos {
62*c42dbd0eSchristos uint32_t idx = LCTF_TYPE_TO_INDEX (fp, reffed_type);
63*c42dbd0eSchristos
64*c42dbd0eSchristos /* Guard against references to invalid types. No need to consider
65*c42dbd0eSchristos the CTF dict corrupt in this case: this pointer just can't be a
66*c42dbd0eSchristos pointer to any type we know about. */
67*c42dbd0eSchristos if (idx <= pfp->ctf_typemax)
68*c42dbd0eSchristos {
69*c42dbd0eSchristos if (idx >= fp->ctf_pptrtab_len
70*c42dbd0eSchristos && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0)
71*c42dbd0eSchristos return -1; /* errno is set for us. */
72*c42dbd0eSchristos
73*c42dbd0eSchristos fp->ctf_pptrtab[idx] = i;
74*c42dbd0eSchristos }
75*c42dbd0eSchristos }
76*c42dbd0eSchristos }
77*c42dbd0eSchristos
78*c42dbd0eSchristos fp->ctf_pptrtab_typemax = fp->ctf_typemax;
79*c42dbd0eSchristos
80*c42dbd0eSchristos return 0;
81*c42dbd0eSchristos }
82867d70fcSchristos
83867d70fcSchristos /* Compare the given input string and length against a table of known C storage
84867d70fcSchristos qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To
85867d70fcSchristos do this quickly, we use a pre-computed Perfect Hash Function similar to the
86867d70fcSchristos technique originally described in the classic paper:
87867d70fcSchristos
88867d70fcSchristos R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple",
89867d70fcSchristos Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19.
90867d70fcSchristos
91867d70fcSchristos For an input string S of length N, we use hash H = S[N - 1] + N - 105, which
92867d70fcSchristos for the current set of qualifiers yields a unique H in the range [0 .. 20].
93867d70fcSchristos The hash can be modified when the keyword set changes as necessary. We also
94867d70fcSchristos store the length of each keyword and check it prior to the final strcmp().
95867d70fcSchristos
96867d70fcSchristos TODO: just use gperf. */
97867d70fcSchristos
98867d70fcSchristos static int
isqualifier(const char * s,size_t len)99867d70fcSchristos isqualifier (const char *s, size_t len)
100867d70fcSchristos {
101867d70fcSchristos static const struct qual
102867d70fcSchristos {
103867d70fcSchristos const char *q_name;
104867d70fcSchristos size_t q_len;
105867d70fcSchristos } qhash[] = {
106867d70fcSchristos {"static", 6}, {"", 0}, {"", 0}, {"", 0},
107867d70fcSchristos {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0},
108867d70fcSchristos {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0},
109867d70fcSchristos {"", 0}, {"", 0}, {"const", 5}, {"register", 8},
110867d70fcSchristos {"", 0}, {"restrict", 8}, {"_Restrict", 9}
111867d70fcSchristos };
112867d70fcSchristos
113867d70fcSchristos int h = s[len - 1] + (int) len - 105;
114*c42dbd0eSchristos const struct qual *qp;
115867d70fcSchristos
116*c42dbd0eSchristos if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0]))
117*c42dbd0eSchristos return 0;
118*c42dbd0eSchristos
119*c42dbd0eSchristos qp = &qhash[h];
120*c42dbd0eSchristos
121*c42dbd0eSchristos return ((size_t) len == qp->q_len &&
122867d70fcSchristos strncmp (qp->q_name, s, qp->q_len) == 0);
123867d70fcSchristos }
124867d70fcSchristos
125867d70fcSchristos /* Attempt to convert the given C type name into the corresponding CTF type ID.
126867d70fcSchristos It is not possible to do complete and proper conversion of type names
127867d70fcSchristos without implementing a more full-fledged parser, which is necessary to
128867d70fcSchristos handle things like types that are function pointers to functions that
129867d70fcSchristos have arguments that are function pointers, and fun stuff like that.
130867d70fcSchristos Instead, this function implements a very simple conversion algorithm that
131867d70fcSchristos finds the things that we actually care about: structs, unions, enums,
132867d70fcSchristos integers, floats, typedefs, and pointers to any of these named types. */
133867d70fcSchristos
134*c42dbd0eSchristos static ctf_id_t
ctf_lookup_by_name_internal(ctf_dict_t * fp,ctf_dict_t * child,const char * name)135*c42dbd0eSchristos ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
136*c42dbd0eSchristos const char *name)
137867d70fcSchristos {
138867d70fcSchristos static const char delimiters[] = " \t\n\r\v\f*";
139867d70fcSchristos
140867d70fcSchristos const ctf_lookup_t *lp;
141867d70fcSchristos const char *p, *q, *end;
142867d70fcSchristos ctf_id_t type = 0;
143867d70fcSchristos ctf_id_t ntype, ptype;
144867d70fcSchristos
145867d70fcSchristos if (name == NULL)
146867d70fcSchristos return (ctf_set_errno (fp, EINVAL));
147867d70fcSchristos
148867d70fcSchristos for (p = name, end = name + strlen (name); *p != '\0'; p = q)
149867d70fcSchristos {
150*c42dbd0eSchristos while (isspace ((int) *p))
151867d70fcSchristos p++; /* Skip leading whitespace. */
152867d70fcSchristos
153867d70fcSchristos if (p == end)
154867d70fcSchristos break;
155867d70fcSchristos
156867d70fcSchristos if ((q = strpbrk (p + 1, delimiters)) == NULL)
157867d70fcSchristos q = end; /* Compare until end. */
158867d70fcSchristos
159867d70fcSchristos if (*p == '*')
160867d70fcSchristos {
161*c42dbd0eSchristos /* Find a pointer to type by looking in child->ctf_pptrtab (if child
162*c42dbd0eSchristos is set) and fp->ctf_ptrtab. If we can't find a pointer to the
163*c42dbd0eSchristos given type, see if we can compute a pointer to the type resulting
164*c42dbd0eSchristos from resolving the type down to its base type and use that instead.
165*c42dbd0eSchristos This helps with cases where the CTF data includes "struct foo *"
166*c42dbd0eSchristos but not "foo_t *" and the user tries to access "foo_t *" in the
167*c42dbd0eSchristos debugger.
168867d70fcSchristos
169*c42dbd0eSchristos There is extra complexity here because uninitialized elements in
170*c42dbd0eSchristos the pptrtab and ptrtab are set to zero, but zero (as the type ID
171*c42dbd0eSchristos meaning the unimplemented type) is a valid return type from
172*c42dbd0eSchristos ctf_lookup_by_name. (Pointers to types are never of type 0, so
173*c42dbd0eSchristos this is unambiguous, just fiddly to deal with.) */
174867d70fcSchristos
175*c42dbd0eSchristos uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type);
176*c42dbd0eSchristos int in_child = 0;
177*c42dbd0eSchristos
178*c42dbd0eSchristos ntype = CTF_ERR;
179*c42dbd0eSchristos if (child && idx < child->ctf_pptrtab_len)
180*c42dbd0eSchristos {
181*c42dbd0eSchristos ntype = child->ctf_pptrtab[idx];
182*c42dbd0eSchristos if (ntype)
183*c42dbd0eSchristos in_child = 1;
184*c42dbd0eSchristos else
185*c42dbd0eSchristos ntype = CTF_ERR;
186*c42dbd0eSchristos }
187*c42dbd0eSchristos
188*c42dbd0eSchristos if (ntype == CTF_ERR)
189*c42dbd0eSchristos {
190*c42dbd0eSchristos ntype = fp->ctf_ptrtab[idx];
191867d70fcSchristos if (ntype == 0)
192*c42dbd0eSchristos ntype = CTF_ERR;
193867d70fcSchristos }
194867d70fcSchristos
195*c42dbd0eSchristos /* Try resolving to its base type and check again. */
196*c42dbd0eSchristos if (ntype == CTF_ERR)
197*c42dbd0eSchristos {
198*c42dbd0eSchristos if (child)
199*c42dbd0eSchristos ntype = ctf_type_resolve_unsliced (child, type);
200*c42dbd0eSchristos else
201*c42dbd0eSchristos ntype = ctf_type_resolve_unsliced (fp, type);
202*c42dbd0eSchristos
203*c42dbd0eSchristos if (ntype == CTF_ERR)
204*c42dbd0eSchristos goto notype;
205*c42dbd0eSchristos
206*c42dbd0eSchristos idx = LCTF_TYPE_TO_INDEX (fp, ntype);
207*c42dbd0eSchristos
208*c42dbd0eSchristos ntype = CTF_ERR;
209*c42dbd0eSchristos if (child && idx < child->ctf_pptrtab_len)
210*c42dbd0eSchristos {
211*c42dbd0eSchristos ntype = child->ctf_pptrtab[idx];
212*c42dbd0eSchristos if (ntype)
213*c42dbd0eSchristos in_child = 1;
214*c42dbd0eSchristos else
215*c42dbd0eSchristos ntype = CTF_ERR;
216*c42dbd0eSchristos }
217*c42dbd0eSchristos
218*c42dbd0eSchristos if (ntype == CTF_ERR)
219*c42dbd0eSchristos {
220*c42dbd0eSchristos ntype = fp->ctf_ptrtab[idx];
221*c42dbd0eSchristos if (ntype == 0)
222*c42dbd0eSchristos ntype = CTF_ERR;
223*c42dbd0eSchristos }
224*c42dbd0eSchristos if (ntype == CTF_ERR)
225*c42dbd0eSchristos goto notype;
226*c42dbd0eSchristos }
227*c42dbd0eSchristos
228*c42dbd0eSchristos type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)
229*c42dbd0eSchristos || in_child);
230*c42dbd0eSchristos
231*c42dbd0eSchristos /* We are looking up a type in the parent, but the pointed-to type is
232*c42dbd0eSchristos in the child. Switch to looking in the child: if we need to go
233*c42dbd0eSchristos back into the parent, we can recurse again. */
234*c42dbd0eSchristos if (in_child)
235*c42dbd0eSchristos {
236*c42dbd0eSchristos fp = child;
237*c42dbd0eSchristos child = NULL;
238*c42dbd0eSchristos }
239867d70fcSchristos
240867d70fcSchristos q = p + 1;
241867d70fcSchristos continue;
242867d70fcSchristos }
243867d70fcSchristos
244867d70fcSchristos if (isqualifier (p, (size_t) (q - p)))
245867d70fcSchristos continue; /* Skip qualifier keyword. */
246867d70fcSchristos
247867d70fcSchristos for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++)
248867d70fcSchristos {
249867d70fcSchristos /* TODO: This is not MT-safe. */
250867d70fcSchristos if ((lp->ctl_prefix[0] == '\0' ||
251867d70fcSchristos strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) &&
252867d70fcSchristos (size_t) (q - p) >= lp->ctl_len)
253867d70fcSchristos {
254*c42dbd0eSchristos for (p += lp->ctl_len; isspace ((int) *p); p++)
255867d70fcSchristos continue; /* Skip prefix and next whitespace. */
256867d70fcSchristos
257867d70fcSchristos if ((q = strchr (p, '*')) == NULL)
258867d70fcSchristos q = end; /* Compare until end. */
259867d70fcSchristos
260*c42dbd0eSchristos while (isspace ((int) q[-1]))
261867d70fcSchristos q--; /* Exclude trailing whitespace. */
262867d70fcSchristos
263867d70fcSchristos /* Expand and/or allocate storage for a slice of the name, then
264867d70fcSchristos copy it in. */
265867d70fcSchristos
266867d70fcSchristos if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1)
267867d70fcSchristos {
268867d70fcSchristos memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p));
269867d70fcSchristos fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0';
270867d70fcSchristos }
271867d70fcSchristos else
272867d70fcSchristos {
273867d70fcSchristos free (fp->ctf_tmp_typeslice);
274867d70fcSchristos fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
275867d70fcSchristos if (fp->ctf_tmp_typeslice == NULL)
276867d70fcSchristos {
277*c42dbd0eSchristos ctf_set_errno (fp, ENOMEM);
278867d70fcSchristos return CTF_ERR;
279867d70fcSchristos }
280867d70fcSchristos }
281867d70fcSchristos
282867d70fcSchristos if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash,
283867d70fcSchristos fp->ctf_tmp_typeslice)) == 0)
284*c42dbd0eSchristos goto notype;
285867d70fcSchristos
286867d70fcSchristos break;
287867d70fcSchristos }
288867d70fcSchristos }
289867d70fcSchristos
290867d70fcSchristos if (lp->ctl_prefix == NULL)
291*c42dbd0eSchristos goto notype;
292867d70fcSchristos }
293867d70fcSchristos
294867d70fcSchristos if (*p != '\0' || type == 0)
295867d70fcSchristos return (ctf_set_errno (fp, ECTF_SYNTAX));
296867d70fcSchristos
297867d70fcSchristos return type;
298867d70fcSchristos
299*c42dbd0eSchristos notype:
300*c42dbd0eSchristos ctf_set_errno (fp, ECTF_NOTYPE);
301*c42dbd0eSchristos if (fp->ctf_parent != NULL)
302*c42dbd0eSchristos {
303*c42dbd0eSchristos /* Need to look up in the parent, from the child's perspective.
304*c42dbd0eSchristos Make sure the pptrtab is up to date. */
305*c42dbd0eSchristos
306*c42dbd0eSchristos if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
307*c42dbd0eSchristos {
308*c42dbd0eSchristos if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
309*c42dbd0eSchristos return -1; /* errno is set for us. */
310*c42dbd0eSchristos }
311*c42dbd0eSchristos
312*c42dbd0eSchristos if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
313*c42dbd0eSchristos name)) != CTF_ERR)
314867d70fcSchristos return ptype;
315*c42dbd0eSchristos return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
316*c42dbd0eSchristos }
317867d70fcSchristos
318867d70fcSchristos return CTF_ERR;
319867d70fcSchristos }
320867d70fcSchristos
321867d70fcSchristos ctf_id_t
ctf_lookup_by_name(ctf_dict_t * fp,const char * name)322*c42dbd0eSchristos ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
323867d70fcSchristos {
324*c42dbd0eSchristos return ctf_lookup_by_name_internal (fp, NULL, name);
325867d70fcSchristos }
326867d70fcSchristos
327867d70fcSchristos /* Return the pointer to the internal CTF type data corresponding to the
328867d70fcSchristos given type ID. If the ID is invalid, the function returns NULL.
329867d70fcSchristos This function is not exported outside of the library. */
330867d70fcSchristos
331867d70fcSchristos const ctf_type_t *
ctf_lookup_by_id(ctf_dict_t ** fpp,ctf_id_t type)332*c42dbd0eSchristos ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
333867d70fcSchristos {
334*c42dbd0eSchristos ctf_dict_t *fp = *fpp; /* Caller passes in starting CTF dict. */
335867d70fcSchristos ctf_id_t idx;
336867d70fcSchristos
337*c42dbd0eSchristos if ((fp = ctf_get_dict (fp, type)) == NULL)
338867d70fcSchristos {
339867d70fcSchristos (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
340867d70fcSchristos return NULL;
341867d70fcSchristos }
342867d70fcSchristos
343*c42dbd0eSchristos /* If this dict is writable, check for a dynamic type. */
344867d70fcSchristos
345867d70fcSchristos if (fp->ctf_flags & LCTF_RDWR)
346867d70fcSchristos {
347867d70fcSchristos ctf_dtdef_t *dtd;
348867d70fcSchristos
349867d70fcSchristos if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
350867d70fcSchristos {
351867d70fcSchristos *fpp = fp;
352867d70fcSchristos return &dtd->dtd_data;
353867d70fcSchristos }
354867d70fcSchristos (void) ctf_set_errno (*fpp, ECTF_BADID);
355867d70fcSchristos return NULL;
356867d70fcSchristos }
357867d70fcSchristos
358867d70fcSchristos /* Check for a type in the static portion. */
359867d70fcSchristos
360867d70fcSchristos idx = LCTF_TYPE_TO_INDEX (fp, type);
361867d70fcSchristos if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax)
362867d70fcSchristos {
363*c42dbd0eSchristos *fpp = fp; /* Function returns ending CTF dict. */
364867d70fcSchristos return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
365867d70fcSchristos }
366867d70fcSchristos
367867d70fcSchristos (void) ctf_set_errno (*fpp, ECTF_BADID);
368867d70fcSchristos return NULL;
369867d70fcSchristos }
370867d70fcSchristos
371*c42dbd0eSchristos typedef struct ctf_lookup_idx_key
372*c42dbd0eSchristos {
373*c42dbd0eSchristos ctf_dict_t *clik_fp;
374*c42dbd0eSchristos const char *clik_name;
375*c42dbd0eSchristos uint32_t *clik_names;
376*c42dbd0eSchristos } ctf_lookup_idx_key_t;
377867d70fcSchristos
378*c42dbd0eSchristos /* A bsearch function for variable names. */
379*c42dbd0eSchristos
380*c42dbd0eSchristos static int
ctf_lookup_var(const void * key_,const void * lookup_)381*c42dbd0eSchristos ctf_lookup_var (const void *key_, const void *lookup_)
382*c42dbd0eSchristos {
383*c42dbd0eSchristos const ctf_lookup_idx_key_t *key = key_;
384*c42dbd0eSchristos const ctf_varent_t *lookup = lookup_;
385*c42dbd0eSchristos
386*c42dbd0eSchristos return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name)));
387*c42dbd0eSchristos }
388*c42dbd0eSchristos
389*c42dbd0eSchristos /* Given a variable name, return the type of the variable with that name. */
390*c42dbd0eSchristos
391*c42dbd0eSchristos ctf_id_t
ctf_lookup_variable(ctf_dict_t * fp,const char * name)392*c42dbd0eSchristos ctf_lookup_variable (ctf_dict_t *fp, const char *name)
393*c42dbd0eSchristos {
394*c42dbd0eSchristos ctf_varent_t *ent;
395*c42dbd0eSchristos ctf_lookup_idx_key_t key = { fp, name, NULL };
396*c42dbd0eSchristos
397*c42dbd0eSchristos /* This array is sorted, so we can bsearch for it. */
398*c42dbd0eSchristos
399*c42dbd0eSchristos ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t),
400*c42dbd0eSchristos ctf_lookup_var);
401*c42dbd0eSchristos
402*c42dbd0eSchristos if (ent == NULL)
403*c42dbd0eSchristos {
404*c42dbd0eSchristos if (fp->ctf_parent != NULL)
405*c42dbd0eSchristos return ctf_lookup_variable (fp->ctf_parent, name);
406*c42dbd0eSchristos
407*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
408*c42dbd0eSchristos }
409*c42dbd0eSchristos
410*c42dbd0eSchristos return ent->ctv_type;
411*c42dbd0eSchristos }
412*c42dbd0eSchristos
413*c42dbd0eSchristos typedef struct ctf_symidx_sort_arg_cb
414*c42dbd0eSchristos {
415*c42dbd0eSchristos ctf_dict_t *fp;
416*c42dbd0eSchristos uint32_t *names;
417*c42dbd0eSchristos } ctf_symidx_sort_arg_cb_t;
418*c42dbd0eSchristos
419*c42dbd0eSchristos static int
sort_symidx_by_name(const void * one_,const void * two_,void * arg_)420*c42dbd0eSchristos sort_symidx_by_name (const void *one_, const void *two_, void *arg_)
421*c42dbd0eSchristos {
422*c42dbd0eSchristos const uint32_t *one = one_;
423*c42dbd0eSchristos const uint32_t *two = two_;
424*c42dbd0eSchristos ctf_symidx_sort_arg_cb_t *arg = arg_;
425*c42dbd0eSchristos
426*c42dbd0eSchristos return (strcmp (ctf_strptr (arg->fp, arg->names[*one]),
427*c42dbd0eSchristos ctf_strptr (arg->fp, arg->names[*two])));
428*c42dbd0eSchristos }
429*c42dbd0eSchristos
430*c42dbd0eSchristos /* Sort a symbol index section by name. Takes a 1:1 mapping of names to the
431*c42dbd0eSchristos corresponding symbol table. Returns a lexicographically sorted array of idx
432*c42dbd0eSchristos indexes (and thus, of indexes into the corresponding func info / data object
433*c42dbd0eSchristos section). */
434*c42dbd0eSchristos
435*c42dbd0eSchristos static uint32_t *
ctf_symidx_sort(ctf_dict_t * fp,uint32_t * idx,size_t * nidx,size_t len)436*c42dbd0eSchristos ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx,
437*c42dbd0eSchristos size_t len)
438*c42dbd0eSchristos {
439*c42dbd0eSchristos uint32_t *sorted;
440*c42dbd0eSchristos size_t i;
441*c42dbd0eSchristos
442*c42dbd0eSchristos if ((sorted = malloc (len)) == NULL)
443*c42dbd0eSchristos {
444*c42dbd0eSchristos ctf_set_errno (fp, ENOMEM);
445*c42dbd0eSchristos return NULL;
446*c42dbd0eSchristos }
447*c42dbd0eSchristos
448*c42dbd0eSchristos *nidx = len / sizeof (uint32_t);
449*c42dbd0eSchristos for (i = 0; i < *nidx; i++)
450*c42dbd0eSchristos sorted[i] = i;
451*c42dbd0eSchristos
452*c42dbd0eSchristos if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED))
453*c42dbd0eSchristos {
454*c42dbd0eSchristos ctf_symidx_sort_arg_cb_t arg = { fp, idx };
455*c42dbd0eSchristos ctf_dprintf ("Index section unsorted: sorting.");
456*c42dbd0eSchristos ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg);
457*c42dbd0eSchristos fp->ctf_header->cth_flags |= CTF_F_IDXSORTED;
458*c42dbd0eSchristos }
459*c42dbd0eSchristos
460*c42dbd0eSchristos return sorted;
461*c42dbd0eSchristos }
462*c42dbd0eSchristos
463*c42dbd0eSchristos /* Given a symbol index, return the name of that symbol from the table provided
464*c42dbd0eSchristos by ctf_link_shuffle_syms, or failing that from the secondary string table, or
465*c42dbd0eSchristos the null string. */
466*c42dbd0eSchristos static const char *
ctf_lookup_symbol_name(ctf_dict_t * fp,unsigned long symidx)467*c42dbd0eSchristos ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
468867d70fcSchristos {
469867d70fcSchristos const ctf_sect_t *sp = &fp->ctf_symtab;
470*c42dbd0eSchristos ctf_link_sym_t sym;
471*c42dbd0eSchristos int err;
472867d70fcSchristos
473*c42dbd0eSchristos if (fp->ctf_dynsymidx)
474*c42dbd0eSchristos {
475*c42dbd0eSchristos err = EINVAL;
476*c42dbd0eSchristos if (symidx > fp->ctf_dynsymmax)
477*c42dbd0eSchristos goto try_parent;
478*c42dbd0eSchristos
479*c42dbd0eSchristos ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx];
480*c42dbd0eSchristos
481*c42dbd0eSchristos if (!symp)
482*c42dbd0eSchristos goto try_parent;
483*c42dbd0eSchristos
484*c42dbd0eSchristos return symp->st_name;
485*c42dbd0eSchristos }
486*c42dbd0eSchristos
487*c42dbd0eSchristos err = ECTF_NOSYMTAB;
488867d70fcSchristos if (sp->cts_data == NULL)
489*c42dbd0eSchristos goto try_parent;
490867d70fcSchristos
491867d70fcSchristos if (symidx >= fp->ctf_nsyms)
492*c42dbd0eSchristos goto try_parent;
493867d70fcSchristos
494*c42dbd0eSchristos switch (sp->cts_entsize)
495*c42dbd0eSchristos {
496*c42dbd0eSchristos case sizeof (Elf64_Sym):
497*c42dbd0eSchristos {
498*c42dbd0eSchristos const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx;
499*c42dbd0eSchristos ctf_elf64_to_link_sym (fp, &sym, symp, symidx);
500*c42dbd0eSchristos }
501*c42dbd0eSchristos break;
502*c42dbd0eSchristos case sizeof (Elf32_Sym):
503867d70fcSchristos {
504867d70fcSchristos const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx;
505*c42dbd0eSchristos ctf_elf32_to_link_sym (fp, &sym, symp, symidx);
506*c42dbd0eSchristos }
507*c42dbd0eSchristos break;
508*c42dbd0eSchristos default:
509*c42dbd0eSchristos ctf_set_errno (fp, ECTF_SYMTAB);
510*c42dbd0eSchristos return _CTF_NULLSTR;
511*c42dbd0eSchristos }
512*c42dbd0eSchristos
513*c42dbd0eSchristos assert (!sym.st_nameidx_set);
514*c42dbd0eSchristos
515*c42dbd0eSchristos return sym.st_name;
516*c42dbd0eSchristos
517*c42dbd0eSchristos try_parent:
518*c42dbd0eSchristos if (fp->ctf_parent)
519*c42dbd0eSchristos {
520*c42dbd0eSchristos const char *ret;
521*c42dbd0eSchristos ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx);
522*c42dbd0eSchristos if (ret == NULL)
523*c42dbd0eSchristos ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
524*c42dbd0eSchristos return ret;
525867d70fcSchristos }
526867d70fcSchristos else
527867d70fcSchristos {
528*c42dbd0eSchristos ctf_set_errno (fp, err);
529*c42dbd0eSchristos return _CTF_NULLSTR;
530*c42dbd0eSchristos }
531867d70fcSchristos }
532867d70fcSchristos
533*c42dbd0eSchristos /* Given a symbol name, return the index of that symbol, or -1 on error or if
534*c42dbd0eSchristos not found. */
535*c42dbd0eSchristos static unsigned long
ctf_lookup_symbol_idx(ctf_dict_t * fp,const char * symname)536*c42dbd0eSchristos ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
537*c42dbd0eSchristos {
538*c42dbd0eSchristos const ctf_sect_t *sp = &fp->ctf_symtab;
539*c42dbd0eSchristos ctf_link_sym_t sym;
540*c42dbd0eSchristos void *known_idx;
541*c42dbd0eSchristos int err;
542*c42dbd0eSchristos ctf_dict_t *cache = fp;
543867d70fcSchristos
544*c42dbd0eSchristos if (fp->ctf_dynsyms)
545*c42dbd0eSchristos {
546*c42dbd0eSchristos err = EINVAL;
547867d70fcSchristos
548*c42dbd0eSchristos ctf_link_sym_t *symp;
549867d70fcSchristos
550*c42dbd0eSchristos if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
551*c42dbd0eSchristos goto try_parent;
552867d70fcSchristos
553*c42dbd0eSchristos return symp->st_symidx;
554*c42dbd0eSchristos }
555*c42dbd0eSchristos
556*c42dbd0eSchristos err = ECTF_NOSYMTAB;
557*c42dbd0eSchristos if (sp->cts_data == NULL)
558*c42dbd0eSchristos goto try_parent;
559*c42dbd0eSchristos
560*c42dbd0eSchristos /* First, try a hash lookup to see if we have already spotted this symbol
561*c42dbd0eSchristos during a past iteration: create the hash first if need be. The lifespan
562*c42dbd0eSchristos of the strings is equal to the lifespan of the cts_data, so we don't
563*c42dbd0eSchristos need to strdup them. If this dict was opened as part of an archive,
564*c42dbd0eSchristos and this archive has designed a crossdict_cache to cache results that
565*c42dbd0eSchristos are the same across all dicts in an archive, use it. */
566*c42dbd0eSchristos
567*c42dbd0eSchristos if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache)
568*c42dbd0eSchristos cache = fp->ctf_archive->ctfi_crossdict_cache;
569*c42dbd0eSchristos
570*c42dbd0eSchristos if (!cache->ctf_symhash)
571*c42dbd0eSchristos if ((cache->ctf_symhash = ctf_dynhash_create (ctf_hash_string,
572*c42dbd0eSchristos ctf_hash_eq_string,
573*c42dbd0eSchristos NULL, NULL)) == NULL)
574*c42dbd0eSchristos goto oom;
575*c42dbd0eSchristos
576*c42dbd0eSchristos if (ctf_dynhash_lookup_kv (cache->ctf_symhash, symname, NULL, &known_idx))
577*c42dbd0eSchristos return (unsigned long) (uintptr_t) known_idx;
578*c42dbd0eSchristos
579*c42dbd0eSchristos /* Hash lookup unsuccessful: linear search, populating the hashtab for later
580*c42dbd0eSchristos lookups as we go. */
581*c42dbd0eSchristos
582*c42dbd0eSchristos for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize;
583*c42dbd0eSchristos cache->ctf_symhash_latest++)
584*c42dbd0eSchristos {
585*c42dbd0eSchristos switch (sp->cts_entsize)
586*c42dbd0eSchristos {
587*c42dbd0eSchristos case sizeof (Elf64_Sym):
588*c42dbd0eSchristos {
589*c42dbd0eSchristos Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data;
590*c42dbd0eSchristos ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
591*c42dbd0eSchristos cache->ctf_symhash_latest);
592*c42dbd0eSchristos if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
593*c42dbd0eSchristos NULL, NULL))
594*c42dbd0eSchristos if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
595*c42dbd0eSchristos (const void *) (uintptr_t)
596*c42dbd0eSchristos cache->ctf_symhash_latest) < 0)
597*c42dbd0eSchristos goto oom;
598*c42dbd0eSchristos if (strcmp (sym.st_name, symname) == 0)
599*c42dbd0eSchristos return cache->ctf_symhash_latest++;
600*c42dbd0eSchristos }
601*c42dbd0eSchristos break;
602*c42dbd0eSchristos case sizeof (Elf32_Sym):
603*c42dbd0eSchristos {
604*c42dbd0eSchristos Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data;
605*c42dbd0eSchristos ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
606*c42dbd0eSchristos cache->ctf_symhash_latest);
607*c42dbd0eSchristos if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
608*c42dbd0eSchristos NULL, NULL))
609*c42dbd0eSchristos if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
610*c42dbd0eSchristos (const void *) (uintptr_t)
611*c42dbd0eSchristos cache->ctf_symhash_latest) < 0)
612*c42dbd0eSchristos goto oom;
613*c42dbd0eSchristos if (strcmp (sym.st_name, symname) == 0)
614*c42dbd0eSchristos return cache->ctf_symhash_latest++;
615*c42dbd0eSchristos }
616*c42dbd0eSchristos break;
617*c42dbd0eSchristos default:
618*c42dbd0eSchristos ctf_set_errno (fp, ECTF_SYMTAB);
619*c42dbd0eSchristos return (unsigned long) -1;
620*c42dbd0eSchristos }
621*c42dbd0eSchristos }
622*c42dbd0eSchristos
623*c42dbd0eSchristos /* Searched everything, still not found. */
624*c42dbd0eSchristos
625*c42dbd0eSchristos return (unsigned long) -1;
626*c42dbd0eSchristos
627*c42dbd0eSchristos try_parent:
628*c42dbd0eSchristos if (fp->ctf_parent)
629*c42dbd0eSchristos return ctf_lookup_symbol_idx (fp->ctf_parent, symname);
630*c42dbd0eSchristos else
631*c42dbd0eSchristos {
632*c42dbd0eSchristos ctf_set_errno (fp, err);
633*c42dbd0eSchristos return (unsigned long) -1;
634*c42dbd0eSchristos }
635*c42dbd0eSchristos oom:
636*c42dbd0eSchristos ctf_set_errno (fp, ENOMEM);
637*c42dbd0eSchristos ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
638*c42dbd0eSchristos "lookup hashtab"));
639*c42dbd0eSchristos return (unsigned long) -1;
640*c42dbd0eSchristos
641*c42dbd0eSchristos }
642*c42dbd0eSchristos
643*c42dbd0eSchristos /* Iterate over all symbols with types: if FUNC, function symbols, otherwise,
644*c42dbd0eSchristos data symbols. The name argument is not optional. The return order is
645*c42dbd0eSchristos arbitrary, though is likely to be in symbol index or name order. You can
646*c42dbd0eSchristos change the value of 'functions' in the middle of iteration over non-dynamic
647*c42dbd0eSchristos dicts, but doing so on dynamic dicts will fail. (This is probably not very
648*c42dbd0eSchristos useful, but there is no reason to prohibit it.) */
649*c42dbd0eSchristos
650*c42dbd0eSchristos ctf_id_t
ctf_symbol_next(ctf_dict_t * fp,ctf_next_t ** it,const char ** name,int functions)651*c42dbd0eSchristos ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
652*c42dbd0eSchristos int functions)
653*c42dbd0eSchristos {
654*c42dbd0eSchristos ctf_id_t sym;
655*c42dbd0eSchristos ctf_next_t *i = *it;
656*c42dbd0eSchristos int err;
657*c42dbd0eSchristos
658*c42dbd0eSchristos if (!i)
659*c42dbd0eSchristos {
660*c42dbd0eSchristos if ((i = ctf_next_create ()) == NULL)
661*c42dbd0eSchristos return ctf_set_errno (fp, ENOMEM);
662*c42dbd0eSchristos
663*c42dbd0eSchristos i->cu.ctn_fp = fp;
664*c42dbd0eSchristos i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
665*c42dbd0eSchristos i->ctn_n = 0;
666*c42dbd0eSchristos *it = i;
667*c42dbd0eSchristos }
668*c42dbd0eSchristos
669*c42dbd0eSchristos if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
670*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
671*c42dbd0eSchristos
672*c42dbd0eSchristos if (fp != i->cu.ctn_fp)
673*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
674*c42dbd0eSchristos
675*c42dbd0eSchristos /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
676*c42dbd0eSchristos incurring additional sorting cost for unsorted symtypetabs coming from the
677*c42dbd0eSchristos compiler, to allow ctf_symbol_next to work in the absence of a symtab, and
678*c42dbd0eSchristos finally because it's easier to work out what the name of each symbol is if
679*c42dbd0eSchristos we do that. */
680*c42dbd0eSchristos
681*c42dbd0eSchristos if (fp->ctf_flags & LCTF_RDWR)
682*c42dbd0eSchristos {
683*c42dbd0eSchristos ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
684*c42dbd0eSchristos void *dyn_name = NULL, *dyn_value = NULL;
685*c42dbd0eSchristos
686*c42dbd0eSchristos if (!dynh)
687*c42dbd0eSchristos {
688*c42dbd0eSchristos ctf_next_destroy (i);
689*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NEXT_END));
690*c42dbd0eSchristos }
691*c42dbd0eSchristos
692*c42dbd0eSchristos err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
693*c42dbd0eSchristos /* This covers errors and also end-of-iteration. */
694*c42dbd0eSchristos if (err != 0)
695*c42dbd0eSchristos {
696*c42dbd0eSchristos ctf_next_destroy (i);
697*c42dbd0eSchristos *it = NULL;
698*c42dbd0eSchristos return ctf_set_errno (fp, err);
699*c42dbd0eSchristos }
700*c42dbd0eSchristos
701*c42dbd0eSchristos *name = dyn_name;
702*c42dbd0eSchristos sym = (ctf_id_t) (uintptr_t) dyn_value;
703*c42dbd0eSchristos }
704*c42dbd0eSchristos else if ((!functions && fp->ctf_objtidx_names) ||
705*c42dbd0eSchristos (functions && fp->ctf_funcidx_names))
706*c42dbd0eSchristos {
707*c42dbd0eSchristos ctf_header_t *hp = fp->ctf_header;
708*c42dbd0eSchristos uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names;
709*c42dbd0eSchristos uint32_t *tab;
710*c42dbd0eSchristos size_t len;
711*c42dbd0eSchristos
712*c42dbd0eSchristos if (functions)
713*c42dbd0eSchristos {
714*c42dbd0eSchristos len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t);
715*c42dbd0eSchristos tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
716*c42dbd0eSchristos }
717*c42dbd0eSchristos else
718*c42dbd0eSchristos {
719*c42dbd0eSchristos len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t);
720*c42dbd0eSchristos tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff);
721*c42dbd0eSchristos }
722*c42dbd0eSchristos
723*c42dbd0eSchristos do
724*c42dbd0eSchristos {
725*c42dbd0eSchristos if (i->ctn_n >= len)
726*c42dbd0eSchristos goto end;
727*c42dbd0eSchristos
728*c42dbd0eSchristos *name = ctf_strptr (fp, idx[i->ctn_n]);
729*c42dbd0eSchristos sym = tab[i->ctn_n++];
730*c42dbd0eSchristos }
731*c42dbd0eSchristos while (sym == -1u || sym == 0);
732*c42dbd0eSchristos }
733*c42dbd0eSchristos else
734*c42dbd0eSchristos {
735*c42dbd0eSchristos /* Skip over pads in ctf_xslate, padding for typeless symbols in the
736*c42dbd0eSchristos symtypetab itself, and symbols in the wrong table. */
737*c42dbd0eSchristos for (; i->ctn_n < fp->ctf_nsyms; i->ctn_n++)
738*c42dbd0eSchristos {
739*c42dbd0eSchristos ctf_header_t *hp = fp->ctf_header;
740*c42dbd0eSchristos
741*c42dbd0eSchristos if (fp->ctf_sxlate[i->ctn_n] == -1u)
742*c42dbd0eSchristos continue;
743*c42dbd0eSchristos
744*c42dbd0eSchristos sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[i->ctn_n]);
745*c42dbd0eSchristos
746*c42dbd0eSchristos if (sym == 0)
747*c42dbd0eSchristos continue;
748*c42dbd0eSchristos
749*c42dbd0eSchristos if (functions)
750*c42dbd0eSchristos {
751*c42dbd0eSchristos if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_funcoff
752*c42dbd0eSchristos && fp->ctf_sxlate[i->ctn_n] < hp->cth_objtidxoff)
753*c42dbd0eSchristos break;
754*c42dbd0eSchristos }
755*c42dbd0eSchristos else
756*c42dbd0eSchristos {
757*c42dbd0eSchristos if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_objtoff
758*c42dbd0eSchristos && fp->ctf_sxlate[i->ctn_n] < hp->cth_funcoff)
759*c42dbd0eSchristos break;
760*c42dbd0eSchristos }
761*c42dbd0eSchristos }
762*c42dbd0eSchristos
763*c42dbd0eSchristos if (i->ctn_n >= fp->ctf_nsyms)
764*c42dbd0eSchristos goto end;
765*c42dbd0eSchristos
766*c42dbd0eSchristos *name = ctf_lookup_symbol_name (fp, i->ctn_n++);
767*c42dbd0eSchristos }
768*c42dbd0eSchristos
769*c42dbd0eSchristos return sym;
770*c42dbd0eSchristos
771*c42dbd0eSchristos end:
772*c42dbd0eSchristos ctf_next_destroy (i);
773*c42dbd0eSchristos *it = NULL;
774*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NEXT_END));
775*c42dbd0eSchristos }
776*c42dbd0eSchristos
777*c42dbd0eSchristos /* A bsearch function for function and object index names. */
778*c42dbd0eSchristos
779*c42dbd0eSchristos static int
ctf_lookup_idx_name(const void * key_,const void * idx_)780*c42dbd0eSchristos ctf_lookup_idx_name (const void *key_, const void *idx_)
781*c42dbd0eSchristos {
782*c42dbd0eSchristos const ctf_lookup_idx_key_t *key = key_;
783*c42dbd0eSchristos const uint32_t *idx = idx_;
784*c42dbd0eSchristos
785*c42dbd0eSchristos return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx])));
786*c42dbd0eSchristos }
787*c42dbd0eSchristos
788*c42dbd0eSchristos /* Given a symbol name or (failing that) number, look up that symbol in the
789*c42dbd0eSchristos function or object index table (which must exist). Return 0 if not found
790*c42dbd0eSchristos there (or pad). */
791*c42dbd0eSchristos
792*c42dbd0eSchristos static ctf_id_t
ctf_try_lookup_indexed(ctf_dict_t * fp,unsigned long symidx,const char * symname,int is_function)793*c42dbd0eSchristos ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
794*c42dbd0eSchristos const char *symname, int is_function)
795*c42dbd0eSchristos {
796*c42dbd0eSchristos struct ctf_header *hp = fp->ctf_header;
797*c42dbd0eSchristos uint32_t *symtypetab;
798*c42dbd0eSchristos uint32_t *names;
799*c42dbd0eSchristos uint32_t *sxlate;
800*c42dbd0eSchristos size_t nidx;
801*c42dbd0eSchristos
802*c42dbd0eSchristos if (symname == NULL)
803*c42dbd0eSchristos symname = ctf_lookup_symbol_name (fp, symidx);
804*c42dbd0eSchristos
805*c42dbd0eSchristos ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in "
806*c42dbd0eSchristos "indexed symtypetab\n", symidx, symname);
807*c42dbd0eSchristos
808*c42dbd0eSchristos if (symname[0] == '\0')
809*c42dbd0eSchristos return -1; /* errno is set for us. */
810*c42dbd0eSchristos
811*c42dbd0eSchristos if (is_function)
812*c42dbd0eSchristos {
813*c42dbd0eSchristos if (!fp->ctf_funcidx_sxlate)
814*c42dbd0eSchristos {
815*c42dbd0eSchristos if ((fp->ctf_funcidx_sxlate
816*c42dbd0eSchristos = ctf_symidx_sort (fp, (uint32_t *)
817*c42dbd0eSchristos (fp->ctf_buf + hp->cth_funcidxoff),
818*c42dbd0eSchristos &fp->ctf_nfuncidx,
819*c42dbd0eSchristos hp->cth_varoff - hp->cth_funcidxoff))
820*c42dbd0eSchristos == NULL)
821*c42dbd0eSchristos {
822*c42dbd0eSchristos ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
823*c42dbd0eSchristos return -1; /* errno is set for us. */
824*c42dbd0eSchristos }
825*c42dbd0eSchristos }
826*c42dbd0eSchristos symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
827*c42dbd0eSchristos sxlate = fp->ctf_funcidx_sxlate;
828*c42dbd0eSchristos names = fp->ctf_funcidx_names;
829*c42dbd0eSchristos nidx = fp->ctf_nfuncidx;
830*c42dbd0eSchristos }
831*c42dbd0eSchristos else
832*c42dbd0eSchristos {
833*c42dbd0eSchristos if (!fp->ctf_objtidx_sxlate)
834*c42dbd0eSchristos {
835*c42dbd0eSchristos if ((fp->ctf_objtidx_sxlate
836*c42dbd0eSchristos = ctf_symidx_sort (fp, (uint32_t *)
837*c42dbd0eSchristos (fp->ctf_buf + hp->cth_objtidxoff),
838*c42dbd0eSchristos &fp->ctf_nobjtidx,
839*c42dbd0eSchristos hp->cth_funcidxoff - hp->cth_objtidxoff))
840*c42dbd0eSchristos == NULL)
841*c42dbd0eSchristos {
842*c42dbd0eSchristos ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
843*c42dbd0eSchristos return -1; /* errno is set for us. */
844*c42dbd0eSchristos }
845*c42dbd0eSchristos }
846*c42dbd0eSchristos
847*c42dbd0eSchristos symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff);
848*c42dbd0eSchristos sxlate = fp->ctf_objtidx_sxlate;
849*c42dbd0eSchristos names = fp->ctf_objtidx_names;
850*c42dbd0eSchristos nidx = fp->ctf_nobjtidx;
851*c42dbd0eSchristos }
852*c42dbd0eSchristos
853*c42dbd0eSchristos ctf_lookup_idx_key_t key = { fp, symname, names };
854*c42dbd0eSchristos uint32_t *idx;
855*c42dbd0eSchristos
856*c42dbd0eSchristos idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name);
857*c42dbd0eSchristos
858*c42dbd0eSchristos if (!idx)
859*c42dbd0eSchristos {
860*c42dbd0eSchristos ctf_dprintf ("%s not found in idx\n", symname);
861*c42dbd0eSchristos return 0;
862*c42dbd0eSchristos }
863*c42dbd0eSchristos
864*c42dbd0eSchristos /* Should be impossible, but be paranoid. */
865*c42dbd0eSchristos if ((idx - sxlate) > (ptrdiff_t) nidx)
866867d70fcSchristos return (ctf_set_errno (fp, ECTF_CORRUPT));
867867d70fcSchristos
868*c42dbd0eSchristos ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
869*c42dbd0eSchristos symtypetab[*idx]);
870*c42dbd0eSchristos return symtypetab[*idx];
871867d70fcSchristos }
872867d70fcSchristos
873*c42dbd0eSchristos /* Given a symbol name or (if NULL) symbol index, return the type of the
874*c42dbd0eSchristos function or data object described by the corresponding entry in the symbol
875*c42dbd0eSchristos table. We can only return symbols in read-only dicts and in dicts for which
876*c42dbd0eSchristos ctf_link_shuffle_syms has been called to assign symbol indexes to symbol
877*c42dbd0eSchristos names. */
878*c42dbd0eSchristos
879*c42dbd0eSchristos static ctf_id_t
ctf_lookup_by_sym_or_name(ctf_dict_t * fp,unsigned long symidx,const char * symname)880*c42dbd0eSchristos ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
881*c42dbd0eSchristos const char *symname)
882*c42dbd0eSchristos {
883*c42dbd0eSchristos const ctf_sect_t *sp = &fp->ctf_symtab;
884*c42dbd0eSchristos ctf_id_t type = 0;
885*c42dbd0eSchristos int err = 0;
886*c42dbd0eSchristos
887*c42dbd0eSchristos /* Shuffled dynsymidx present? Use that. */
888*c42dbd0eSchristos if (fp->ctf_dynsymidx)
889*c42dbd0eSchristos {
890*c42dbd0eSchristos const ctf_link_sym_t *sym;
891*c42dbd0eSchristos
892*c42dbd0eSchristos if (symname)
893*c42dbd0eSchristos ctf_dprintf ("Looking up type of object with symname %s in "
894*c42dbd0eSchristos "writable dict symtypetab\n", symname);
895*c42dbd0eSchristos else
896*c42dbd0eSchristos ctf_dprintf ("Looking up type of object with symtab idx %lx in "
897*c42dbd0eSchristos "writable dict symtypetab\n", symidx);
898*c42dbd0eSchristos
899*c42dbd0eSchristos /* The dict must be dynamic. */
900*c42dbd0eSchristos if (!ctf_assert (fp, fp->ctf_flags & LCTF_RDWR))
901*c42dbd0eSchristos return CTF_ERR;
902*c42dbd0eSchristos
903*c42dbd0eSchristos /* No name? Need to look it up. */
904*c42dbd0eSchristos if (!symname)
905*c42dbd0eSchristos {
906*c42dbd0eSchristos err = EINVAL;
907*c42dbd0eSchristos if (symidx > fp->ctf_dynsymmax)
908*c42dbd0eSchristos goto try_parent;
909*c42dbd0eSchristos
910*c42dbd0eSchristos sym = fp->ctf_dynsymidx[symidx];
911*c42dbd0eSchristos err = ECTF_NOTYPEDAT;
912*c42dbd0eSchristos if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
913*c42dbd0eSchristos goto try_parent;
914*c42dbd0eSchristos
915*c42dbd0eSchristos if (!ctf_assert (fp, !sym->st_nameidx_set))
916*c42dbd0eSchristos return CTF_ERR;
917*c42dbd0eSchristos symname = sym->st_name;
918*c42dbd0eSchristos }
919*c42dbd0eSchristos
920*c42dbd0eSchristos if (fp->ctf_objthash == NULL
921*c42dbd0eSchristos || ((type = (ctf_id_t) (uintptr_t)
922*c42dbd0eSchristos ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
923*c42dbd0eSchristos {
924*c42dbd0eSchristos if (fp->ctf_funchash == NULL
925*c42dbd0eSchristos || ((type = (ctf_id_t) (uintptr_t)
926*c42dbd0eSchristos ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
927*c42dbd0eSchristos goto try_parent;
928*c42dbd0eSchristos }
929*c42dbd0eSchristos
930*c42dbd0eSchristos return type;
931*c42dbd0eSchristos }
932*c42dbd0eSchristos
933*c42dbd0eSchristos /* Lookup by name in a dynamic dict: just do it directly. */
934*c42dbd0eSchristos if (symname && fp->ctf_flags & LCTF_RDWR)
935*c42dbd0eSchristos {
936*c42dbd0eSchristos if (fp->ctf_objthash == NULL
937*c42dbd0eSchristos || ((type = (ctf_id_t) (uintptr_t)
938*c42dbd0eSchristos ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
939*c42dbd0eSchristos {
940*c42dbd0eSchristos if (fp->ctf_funchash == NULL
941*c42dbd0eSchristos || ((type = (ctf_id_t) (uintptr_t)
942*c42dbd0eSchristos ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
943*c42dbd0eSchristos goto try_parent;
944*c42dbd0eSchristos }
945*c42dbd0eSchristos return type;
946*c42dbd0eSchristos }
947*c42dbd0eSchristos
948*c42dbd0eSchristos err = ECTF_NOSYMTAB;
949*c42dbd0eSchristos if (sp->cts_data == NULL)
950*c42dbd0eSchristos goto try_parent;
951*c42dbd0eSchristos
952*c42dbd0eSchristos /* This covers both out-of-range lookups and a dynamic dict which hasn't been
953*c42dbd0eSchristos shuffled yet. */
954*c42dbd0eSchristos err = EINVAL;
955*c42dbd0eSchristos if (symname == NULL && symidx >= fp->ctf_nsyms)
956*c42dbd0eSchristos goto try_parent;
957*c42dbd0eSchristos
958*c42dbd0eSchristos if (fp->ctf_objtidx_names)
959*c42dbd0eSchristos {
960*c42dbd0eSchristos if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR)
961*c42dbd0eSchristos return CTF_ERR; /* errno is set for us. */
962*c42dbd0eSchristos }
963*c42dbd0eSchristos if (type == 0 && fp->ctf_funcidx_names)
964*c42dbd0eSchristos {
965*c42dbd0eSchristos if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
966*c42dbd0eSchristos return CTF_ERR; /* errno is set for us. */
967*c42dbd0eSchristos }
968*c42dbd0eSchristos if (type != 0)
969*c42dbd0eSchristos return type;
970*c42dbd0eSchristos
971*c42dbd0eSchristos err = ECTF_NOTYPEDAT;
972*c42dbd0eSchristos if (fp->ctf_objtidx_names && fp->ctf_funcidx_names)
973*c42dbd0eSchristos goto try_parent;
974*c42dbd0eSchristos
975*c42dbd0eSchristos /* Table must be nonindexed. */
976*c42dbd0eSchristos
977*c42dbd0eSchristos ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx);
978*c42dbd0eSchristos
979*c42dbd0eSchristos if (symname != NULL)
980*c42dbd0eSchristos if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
981*c42dbd0eSchristos goto try_parent;
982*c42dbd0eSchristos
983*c42dbd0eSchristos if (fp->ctf_sxlate[symidx] == -1u)
984*c42dbd0eSchristos goto try_parent;
985*c42dbd0eSchristos
986*c42dbd0eSchristos type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]);
987*c42dbd0eSchristos
988*c42dbd0eSchristos if (type == 0)
989*c42dbd0eSchristos goto try_parent;
990*c42dbd0eSchristos
991*c42dbd0eSchristos return type;
992*c42dbd0eSchristos try_parent:
993*c42dbd0eSchristos if (fp->ctf_parent)
994*c42dbd0eSchristos {
995*c42dbd0eSchristos ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
996*c42dbd0eSchristos symname);
997*c42dbd0eSchristos if (ret == CTF_ERR)
998*c42dbd0eSchristos ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
999*c42dbd0eSchristos return ret;
1000*c42dbd0eSchristos }
1001*c42dbd0eSchristos else
1002*c42dbd0eSchristos return (ctf_set_errno (fp, err));
1003*c42dbd0eSchristos }
1004*c42dbd0eSchristos
1005*c42dbd0eSchristos /* Given a symbol table index, return the type of the function or data object
1006*c42dbd0eSchristos described by the corresponding entry in the symbol table. */
1007*c42dbd0eSchristos ctf_id_t
ctf_lookup_by_symbol(ctf_dict_t * fp,unsigned long symidx)1008*c42dbd0eSchristos ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
1009*c42dbd0eSchristos {
1010*c42dbd0eSchristos return ctf_lookup_by_sym_or_name (fp, symidx, NULL);
1011*c42dbd0eSchristos }
1012*c42dbd0eSchristos
1013*c42dbd0eSchristos /* Given a symbol name, return the type of the function or data object described
1014*c42dbd0eSchristos by the corresponding entry in the symbol table. */
1015*c42dbd0eSchristos ctf_id_t
ctf_lookup_by_symbol_name(ctf_dict_t * fp,const char * symname)1016*c42dbd0eSchristos ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname)
1017*c42dbd0eSchristos {
1018*c42dbd0eSchristos return ctf_lookup_by_sym_or_name (fp, 0, symname);
1019*c42dbd0eSchristos }
1020*c42dbd0eSchristos
1021*c42dbd0eSchristos /* Given a symbol table index, return the info for the function described
1022*c42dbd0eSchristos by the corresponding entry in the symbol table, which may be a function
1023*c42dbd0eSchristos symbol or may be a data symbol that happens to be a function pointer. */
1024*c42dbd0eSchristos
1025*c42dbd0eSchristos int
ctf_func_info(ctf_dict_t * fp,unsigned long symidx,ctf_funcinfo_t * fip)1026*c42dbd0eSchristos ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
1027*c42dbd0eSchristos {
1028*c42dbd0eSchristos ctf_id_t type;
1029*c42dbd0eSchristos
1030*c42dbd0eSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
1031*c42dbd0eSchristos return -1; /* errno is set for us. */
1032*c42dbd0eSchristos
1033*c42dbd0eSchristos if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
1034*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NOTFUNC));
1035*c42dbd0eSchristos
1036*c42dbd0eSchristos return ctf_func_type_info (fp, type, fip);
1037867d70fcSchristos }
1038867d70fcSchristos
1039867d70fcSchristos /* Given a symbol table index, return the arguments for the function described
1040867d70fcSchristos by the corresponding entry in the symbol table. */
1041867d70fcSchristos
1042867d70fcSchristos int
ctf_func_args(ctf_dict_t * fp,unsigned long symidx,uint32_t argc,ctf_id_t * argv)1043*c42dbd0eSchristos ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
1044867d70fcSchristos ctf_id_t *argv)
1045867d70fcSchristos {
1046*c42dbd0eSchristos ctf_id_t type;
1047867d70fcSchristos
1048*c42dbd0eSchristos if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
1049867d70fcSchristos return -1; /* errno is set for us. */
1050867d70fcSchristos
1051*c42dbd0eSchristos if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
1052*c42dbd0eSchristos return (ctf_set_errno (fp, ECTF_NOTFUNC));
1053867d70fcSchristos
1054*c42dbd0eSchristos return ctf_func_type_args (fp, type, argc, argv);
1055867d70fcSchristos }
1056