xref: /netbsd-src/external/gpl3/binutils.old/dist/libctf/ctf-lookup.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
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