xref: /netbsd-src/external/gpl3/gdb.old/dist/libctf/ctf-lookup.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
17d62b00eSchristos /* Symbol, variable and name lookup.
2*6881a400Schristos    Copyright (C) 2019-2022 Free Software Foundation, Inc.
37d62b00eSchristos 
47d62b00eSchristos    This file is part of libctf.
57d62b00eSchristos 
67d62b00eSchristos    libctf is free software; you can redistribute it and/or modify it under
77d62b00eSchristos    the terms of the GNU General Public License as published by the Free
87d62b00eSchristos    Software Foundation; either version 3, or (at your option) any later
97d62b00eSchristos    version.
107d62b00eSchristos 
117d62b00eSchristos    This program is distributed in the hope that it will be useful, but
127d62b00eSchristos    WITHOUT ANY WARRANTY; without even the implied warranty of
137d62b00eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
147d62b00eSchristos    See the GNU General Public License for more details.
157d62b00eSchristos 
167d62b00eSchristos    You should have received a copy of the GNU General Public License
177d62b00eSchristos    along with this program; see the file COPYING.  If not see
187d62b00eSchristos    <http://www.gnu.org/licenses/>.  */
197d62b00eSchristos 
207d62b00eSchristos #include <ctf-impl.h>
217d62b00eSchristos #include <elf.h>
227d62b00eSchristos #include <string.h>
23*6881a400Schristos #include <assert.h>
24*6881a400Schristos 
25*6881a400Schristos /* Grow the pptrtab so that it is at least NEW_LEN long.  */
26*6881a400Schristos static int
27*6881a400Schristos grow_pptrtab (ctf_dict_t *fp, size_t new_len)
28*6881a400Schristos {
29*6881a400Schristos   uint32_t *new_pptrtab;
30*6881a400Schristos 
31*6881a400Schristos   if ((new_pptrtab = realloc (fp->ctf_pptrtab, sizeof (uint32_t)
32*6881a400Schristos 			      * new_len)) == NULL)
33*6881a400Schristos     return (ctf_set_errno (fp, ENOMEM));
34*6881a400Schristos 
35*6881a400Schristos   fp->ctf_pptrtab = new_pptrtab;
36*6881a400Schristos 
37*6881a400Schristos   memset (fp->ctf_pptrtab + fp->ctf_pptrtab_len, 0,
38*6881a400Schristos 	  sizeof (uint32_t) * (new_len - fp->ctf_pptrtab_len));
39*6881a400Schristos 
40*6881a400Schristos   fp->ctf_pptrtab_len = new_len;
41*6881a400Schristos   return 0;
42*6881a400Schristos }
43*6881a400Schristos 
44*6881a400Schristos /* Update entries in the pptrtab that relate to types newly added in the
45*6881a400Schristos    child.  */
46*6881a400Schristos static int
47*6881a400Schristos refresh_pptrtab (ctf_dict_t *fp, ctf_dict_t *pfp)
48*6881a400Schristos {
49*6881a400Schristos   uint32_t i;
50*6881a400Schristos   for (i = fp->ctf_pptrtab_typemax; i <= fp->ctf_typemax; i++)
51*6881a400Schristos     {
52*6881a400Schristos       ctf_id_t type = LCTF_INDEX_TO_TYPE (fp, i, 1);
53*6881a400Schristos       ctf_id_t reffed_type;
54*6881a400Schristos 
55*6881a400Schristos       if (ctf_type_kind (fp, type) != CTF_K_POINTER)
56*6881a400Schristos 	continue;
57*6881a400Schristos 
58*6881a400Schristos       reffed_type = ctf_type_reference (fp, type);
59*6881a400Schristos 
60*6881a400Schristos       if (LCTF_TYPE_ISPARENT (fp, reffed_type))
61*6881a400Schristos 	{
62*6881a400Schristos 	  uint32_t idx = LCTF_TYPE_TO_INDEX (fp, reffed_type);
63*6881a400Schristos 
64*6881a400Schristos 	  /* Guard against references to invalid types.  No need to consider
65*6881a400Schristos 	     the CTF dict corrupt in this case: this pointer just can't be a
66*6881a400Schristos 	     pointer to any type we know about.  */
67*6881a400Schristos 	  if (idx <= pfp->ctf_typemax)
68*6881a400Schristos 	    {
69*6881a400Schristos 	      if (idx >= fp->ctf_pptrtab_len
70*6881a400Schristos 		  && grow_pptrtab (fp, pfp->ctf_ptrtab_len) < 0)
71*6881a400Schristos 		return -1;			/* errno is set for us.  */
72*6881a400Schristos 
73*6881a400Schristos 	      fp->ctf_pptrtab[idx] = i;
74*6881a400Schristos 	    }
75*6881a400Schristos 	}
76*6881a400Schristos     }
77*6881a400Schristos 
78*6881a400Schristos   fp->ctf_pptrtab_typemax = fp->ctf_typemax;
79*6881a400Schristos 
80*6881a400Schristos   return 0;
81*6881a400Schristos }
827d62b00eSchristos 
837d62b00eSchristos /* Compare the given input string and length against a table of known C storage
847d62b00eSchristos    qualifier keywords.  We just ignore these in ctf_lookup_by_name, below.  To
857d62b00eSchristos    do this quickly, we use a pre-computed Perfect Hash Function similar to the
867d62b00eSchristos    technique originally described in the classic paper:
877d62b00eSchristos 
887d62b00eSchristos    R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple",
897d62b00eSchristos    Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19.
907d62b00eSchristos 
917d62b00eSchristos    For an input string S of length N, we use hash H = S[N - 1] + N - 105, which
927d62b00eSchristos    for the current set of qualifiers yields a unique H in the range [0 .. 20].
937d62b00eSchristos    The hash can be modified when the keyword set changes as necessary.  We also
947d62b00eSchristos    store the length of each keyword and check it prior to the final strcmp().
957d62b00eSchristos 
967d62b00eSchristos    TODO: just use gperf.  */
977d62b00eSchristos 
987d62b00eSchristos static int
997d62b00eSchristos isqualifier (const char *s, size_t len)
1007d62b00eSchristos {
1017d62b00eSchristos   static const struct qual
1027d62b00eSchristos   {
1037d62b00eSchristos     const char *q_name;
1047d62b00eSchristos     size_t q_len;
1057d62b00eSchristos   } qhash[] = {
1067d62b00eSchristos     {"static", 6}, {"", 0}, {"", 0}, {"", 0},
1077d62b00eSchristos     {"volatile", 8}, {"", 0}, {"", 0}, {"", 0}, {"", 0},
1087d62b00eSchristos     {"", 0}, {"auto", 4}, {"extern", 6}, {"", 0}, {"", 0},
1097d62b00eSchristos     {"", 0}, {"", 0}, {"const", 5}, {"register", 8},
1107d62b00eSchristos     {"", 0}, {"restrict", 8}, {"_Restrict", 9}
1117d62b00eSchristos   };
1127d62b00eSchristos 
1137d62b00eSchristos   int h = s[len - 1] + (int) len - 105;
114*6881a400Schristos   const struct qual *qp;
1157d62b00eSchristos 
116*6881a400Schristos   if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0]))
117*6881a400Schristos     return 0;
118*6881a400Schristos 
119*6881a400Schristos   qp = &qhash[h];
120*6881a400Schristos 
121*6881a400Schristos   return ((size_t) len == qp->q_len &&
1227d62b00eSchristos 	  strncmp (qp->q_name, s, qp->q_len) == 0);
1237d62b00eSchristos }
1247d62b00eSchristos 
1257d62b00eSchristos /* Attempt to convert the given C type name into the corresponding CTF type ID.
1267d62b00eSchristos    It is not possible to do complete and proper conversion of type names
1277d62b00eSchristos    without implementing a more full-fledged parser, which is necessary to
1287d62b00eSchristos    handle things like types that are function pointers to functions that
1297d62b00eSchristos    have arguments that are function pointers, and fun stuff like that.
1307d62b00eSchristos    Instead, this function implements a very simple conversion algorithm that
1317d62b00eSchristos    finds the things that we actually care about: structs, unions, enums,
1327d62b00eSchristos    integers, floats, typedefs, and pointers to any of these named types.  */
1337d62b00eSchristos 
134*6881a400Schristos static ctf_id_t
135*6881a400Schristos ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
136*6881a400Schristos 			     const char *name)
1377d62b00eSchristos {
1387d62b00eSchristos   static const char delimiters[] = " \t\n\r\v\f*";
1397d62b00eSchristos 
1407d62b00eSchristos   const ctf_lookup_t *lp;
1417d62b00eSchristos   const char *p, *q, *end;
1427d62b00eSchristos   ctf_id_t type = 0;
1437d62b00eSchristos   ctf_id_t ntype, ptype;
1447d62b00eSchristos 
1457d62b00eSchristos   if (name == NULL)
1467d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
1477d62b00eSchristos 
1487d62b00eSchristos   for (p = name, end = name + strlen (name); *p != '\0'; p = q)
1497d62b00eSchristos     {
1507d62b00eSchristos       while (isspace ((int) *p))
1517d62b00eSchristos 	p++;			/* Skip leading whitespace.  */
1527d62b00eSchristos 
1537d62b00eSchristos       if (p == end)
1547d62b00eSchristos 	break;
1557d62b00eSchristos 
1567d62b00eSchristos       if ((q = strpbrk (p + 1, delimiters)) == NULL)
1577d62b00eSchristos 	q = end;		/* Compare until end.  */
1587d62b00eSchristos 
1597d62b00eSchristos       if (*p == '*')
1607d62b00eSchristos 	{
161*6881a400Schristos 	  /* Find a pointer to type by looking in child->ctf_pptrtab (if child
162*6881a400Schristos 	     is set) and fp->ctf_ptrtab.  If we can't find a pointer to the
163*6881a400Schristos 	     given type, see if we can compute a pointer to the type resulting
164*6881a400Schristos 	     from resolving the type down to its base type and use that instead.
165*6881a400Schristos 	     This helps with cases where the CTF data includes "struct foo *"
166*6881a400Schristos 	     but not "foo_t *" and the user tries to access "foo_t *" in the
167*6881a400Schristos 	     debugger.
1687d62b00eSchristos 
169*6881a400Schristos 	     There is extra complexity here because uninitialized elements in
170*6881a400Schristos 	     the pptrtab and ptrtab are set to zero, but zero (as the type ID
171*6881a400Schristos 	     meaning the unimplemented type) is a valid return type from
172*6881a400Schristos 	     ctf_lookup_by_name.  (Pointers to types are never of type 0, so
173*6881a400Schristos 	     this is unambiguous, just fiddly to deal with.)  */
1747d62b00eSchristos 
175*6881a400Schristos 	  uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type);
176*6881a400Schristos 	  int in_child = 0;
177*6881a400Schristos 
178*6881a400Schristos 	  ntype = CTF_ERR;
179*6881a400Schristos 	  if (child && idx < child->ctf_pptrtab_len)
180*6881a400Schristos 	    {
181*6881a400Schristos 	      ntype = child->ctf_pptrtab[idx];
182*6881a400Schristos 	      if (ntype)
183*6881a400Schristos 		in_child = 1;
184*6881a400Schristos 	      else
185*6881a400Schristos 		ntype = CTF_ERR;
186*6881a400Schristos 	    }
187*6881a400Schristos 
188*6881a400Schristos 	  if (ntype == CTF_ERR)
189*6881a400Schristos 	    {
190*6881a400Schristos 	      ntype = fp->ctf_ptrtab[idx];
1917d62b00eSchristos 	      if (ntype == 0)
192*6881a400Schristos 		ntype = CTF_ERR;
1937d62b00eSchristos 	    }
1947d62b00eSchristos 
195*6881a400Schristos 	  /* Try resolving to its base type and check again.  */
196*6881a400Schristos 	  if (ntype == CTF_ERR)
197*6881a400Schristos 	    {
198*6881a400Schristos 	      if (child)
199*6881a400Schristos 		ntype = ctf_type_resolve_unsliced (child, type);
200*6881a400Schristos 	      else
201*6881a400Schristos 		ntype = ctf_type_resolve_unsliced (fp, type);
202*6881a400Schristos 
203*6881a400Schristos 	      if (ntype == CTF_ERR)
204*6881a400Schristos 		goto notype;
205*6881a400Schristos 
206*6881a400Schristos 	      idx = LCTF_TYPE_TO_INDEX (fp, ntype);
207*6881a400Schristos 
208*6881a400Schristos 	      ntype = CTF_ERR;
209*6881a400Schristos 	      if (child && idx < child->ctf_pptrtab_len)
210*6881a400Schristos 		{
211*6881a400Schristos 		  ntype = child->ctf_pptrtab[idx];
212*6881a400Schristos 		  if (ntype)
213*6881a400Schristos 		    in_child = 1;
214*6881a400Schristos 		  else
215*6881a400Schristos 		    ntype = CTF_ERR;
216*6881a400Schristos 		}
217*6881a400Schristos 
218*6881a400Schristos 	      if (ntype == CTF_ERR)
219*6881a400Schristos 		{
220*6881a400Schristos 		  ntype = fp->ctf_ptrtab[idx];
221*6881a400Schristos 		  if (ntype == 0)
222*6881a400Schristos 		    ntype = CTF_ERR;
223*6881a400Schristos 		}
224*6881a400Schristos 	      if (ntype == CTF_ERR)
225*6881a400Schristos 		goto notype;
226*6881a400Schristos 	    }
227*6881a400Schristos 
228*6881a400Schristos 	  type = LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD)
229*6881a400Schristos 				     || in_child);
230*6881a400Schristos 
231*6881a400Schristos 	  /* We are looking up a type in the parent, but the pointed-to type is
232*6881a400Schristos 	     in the child.  Switch to looking in the child: if we need to go
233*6881a400Schristos 	     back into the parent, we can recurse again.  */
234*6881a400Schristos 	  if (in_child)
235*6881a400Schristos 	    {
236*6881a400Schristos 	      fp = child;
237*6881a400Schristos 	      child = NULL;
238*6881a400Schristos 	    }
2397d62b00eSchristos 
2407d62b00eSchristos 	  q = p + 1;
2417d62b00eSchristos 	  continue;
2427d62b00eSchristos 	}
2437d62b00eSchristos 
2447d62b00eSchristos       if (isqualifier (p, (size_t) (q - p)))
2457d62b00eSchristos 	continue;		/* Skip qualifier keyword.  */
2467d62b00eSchristos 
2477d62b00eSchristos       for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++)
2487d62b00eSchristos 	{
2497d62b00eSchristos 	  /* TODO: This is not MT-safe.  */
2507d62b00eSchristos 	  if ((lp->ctl_prefix[0] == '\0' ||
2517d62b00eSchristos 	       strncmp (p, lp->ctl_prefix, (size_t) (q - p)) == 0) &&
2527d62b00eSchristos 	      (size_t) (q - p) >= lp->ctl_len)
2537d62b00eSchristos 	    {
2547d62b00eSchristos 	      for (p += lp->ctl_len; isspace ((int) *p); p++)
2557d62b00eSchristos 		continue;	/* Skip prefix and next whitespace.  */
2567d62b00eSchristos 
2577d62b00eSchristos 	      if ((q = strchr (p, '*')) == NULL)
2587d62b00eSchristos 		q = end;	/* Compare until end.  */
2597d62b00eSchristos 
2607d62b00eSchristos 	      while (isspace ((int) q[-1]))
2617d62b00eSchristos 		q--;		/* Exclude trailing whitespace.  */
2627d62b00eSchristos 
2637d62b00eSchristos 	      /* Expand and/or allocate storage for a slice of the name, then
2647d62b00eSchristos 		 copy it in.  */
2657d62b00eSchristos 
2667d62b00eSchristos 	      if (fp->ctf_tmp_typeslicelen >= (size_t) (q - p) + 1)
2677d62b00eSchristos 		{
2687d62b00eSchristos 		  memcpy (fp->ctf_tmp_typeslice, p, (size_t) (q - p));
2697d62b00eSchristos 		  fp->ctf_tmp_typeslice[(size_t) (q - p)] = '\0';
2707d62b00eSchristos 		}
2717d62b00eSchristos 	      else
2727d62b00eSchristos 		{
2737d62b00eSchristos 		  free (fp->ctf_tmp_typeslice);
2747d62b00eSchristos 		  fp->ctf_tmp_typeslice = xstrndup (p, (size_t) (q - p));
2757d62b00eSchristos 		  if (fp->ctf_tmp_typeslice == NULL)
2767d62b00eSchristos 		    {
277*6881a400Schristos 		      ctf_set_errno (fp, ENOMEM);
2787d62b00eSchristos 		      return CTF_ERR;
2797d62b00eSchristos 		    }
2807d62b00eSchristos 		}
2817d62b00eSchristos 
2827d62b00eSchristos 	      if ((type = ctf_lookup_by_rawhash (fp, lp->ctl_hash,
2837d62b00eSchristos 						 fp->ctf_tmp_typeslice)) == 0)
284*6881a400Schristos 		goto notype;
2857d62b00eSchristos 
2867d62b00eSchristos 	      break;
2877d62b00eSchristos 	    }
2887d62b00eSchristos 	}
2897d62b00eSchristos 
2907d62b00eSchristos       if (lp->ctl_prefix == NULL)
291*6881a400Schristos 	goto notype;
2927d62b00eSchristos     }
2937d62b00eSchristos 
2947d62b00eSchristos   if (*p != '\0' || type == 0)
2957d62b00eSchristos     return (ctf_set_errno (fp, ECTF_SYNTAX));
2967d62b00eSchristos 
2977d62b00eSchristos   return type;
2987d62b00eSchristos 
299*6881a400Schristos  notype:
300*6881a400Schristos   ctf_set_errno (fp, ECTF_NOTYPE);
301*6881a400Schristos   if (fp->ctf_parent != NULL)
302*6881a400Schristos     {
303*6881a400Schristos       /* Need to look up in the parent, from the child's perspective.
304*6881a400Schristos 	 Make sure the pptrtab is up to date.  */
305*6881a400Schristos 
306*6881a400Schristos       if (fp->ctf_pptrtab_typemax < fp->ctf_typemax)
307*6881a400Schristos 	{
308*6881a400Schristos 	  if (refresh_pptrtab (fp, fp->ctf_parent) < 0)
309*6881a400Schristos 	    return -1;			/* errno is set for us.  */
310*6881a400Schristos 	}
311*6881a400Schristos 
312*6881a400Schristos       if ((ptype = ctf_lookup_by_name_internal (fp->ctf_parent, fp,
313*6881a400Schristos 						name)) != CTF_ERR)
3147d62b00eSchristos 	return ptype;
315*6881a400Schristos       return (ctf_set_errno (fp, ctf_errno (fp->ctf_parent)));
316*6881a400Schristos     }
3177d62b00eSchristos 
3187d62b00eSchristos   return CTF_ERR;
3197d62b00eSchristos }
3207d62b00eSchristos 
3217d62b00eSchristos ctf_id_t
322*6881a400Schristos ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
3237d62b00eSchristos {
324*6881a400Schristos   return ctf_lookup_by_name_internal (fp, NULL, name);
3257d62b00eSchristos }
3267d62b00eSchristos 
3277d62b00eSchristos /* Return the pointer to the internal CTF type data corresponding to the
3287d62b00eSchristos    given type ID.  If the ID is invalid, the function returns NULL.
3297d62b00eSchristos    This function is not exported outside of the library.  */
3307d62b00eSchristos 
3317d62b00eSchristos const ctf_type_t *
332*6881a400Schristos ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
3337d62b00eSchristos {
334*6881a400Schristos   ctf_dict_t *fp = *fpp;	/* Caller passes in starting CTF dict.  */
3357d62b00eSchristos   ctf_id_t idx;
3367d62b00eSchristos 
3377d62b00eSchristos   if ((fp = ctf_get_dict (fp, type)) == NULL)
3387d62b00eSchristos     {
3397d62b00eSchristos       (void) ctf_set_errno (*fpp, ECTF_NOPARENT);
3407d62b00eSchristos       return NULL;
3417d62b00eSchristos     }
3427d62b00eSchristos 
3437d62b00eSchristos   /* If this dict is writable, check for a dynamic type.  */
3447d62b00eSchristos 
3457d62b00eSchristos   if (fp->ctf_flags & LCTF_RDWR)
3467d62b00eSchristos     {
3477d62b00eSchristos       ctf_dtdef_t *dtd;
3487d62b00eSchristos 
3497d62b00eSchristos       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
3507d62b00eSchristos 	{
3517d62b00eSchristos 	  *fpp = fp;
3527d62b00eSchristos 	  return &dtd->dtd_data;
3537d62b00eSchristos 	}
3547d62b00eSchristos       (void) ctf_set_errno (*fpp, ECTF_BADID);
3557d62b00eSchristos       return NULL;
3567d62b00eSchristos     }
3577d62b00eSchristos 
3587d62b00eSchristos   /* Check for a type in the static portion.  */
3597d62b00eSchristos 
3607d62b00eSchristos   idx = LCTF_TYPE_TO_INDEX (fp, type);
3617d62b00eSchristos   if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax)
3627d62b00eSchristos     {
363*6881a400Schristos       *fpp = fp;		/* Function returns ending CTF dict.  */
3647d62b00eSchristos       return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
3657d62b00eSchristos     }
3667d62b00eSchristos 
3677d62b00eSchristos   (void) ctf_set_errno (*fpp, ECTF_BADID);
3687d62b00eSchristos   return NULL;
3697d62b00eSchristos }
3707d62b00eSchristos 
371*6881a400Schristos typedef struct ctf_lookup_idx_key
372*6881a400Schristos {
373*6881a400Schristos   ctf_dict_t *clik_fp;
374*6881a400Schristos   const char *clik_name;
375*6881a400Schristos   uint32_t *clik_names;
376*6881a400Schristos } ctf_lookup_idx_key_t;
3777d62b00eSchristos 
378*6881a400Schristos /* A bsearch function for variable names.  */
379*6881a400Schristos 
380*6881a400Schristos static int
381*6881a400Schristos ctf_lookup_var (const void *key_, const void *lookup_)
382*6881a400Schristos {
383*6881a400Schristos   const ctf_lookup_idx_key_t *key = key_;
384*6881a400Schristos   const ctf_varent_t *lookup = lookup_;
385*6881a400Schristos 
386*6881a400Schristos   return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name)));
387*6881a400Schristos }
388*6881a400Schristos 
389*6881a400Schristos /* Given a variable name, return the type of the variable with that name.  */
390*6881a400Schristos 
391*6881a400Schristos ctf_id_t
392*6881a400Schristos ctf_lookup_variable (ctf_dict_t *fp, const char *name)
393*6881a400Schristos {
394*6881a400Schristos   ctf_varent_t *ent;
395*6881a400Schristos   ctf_lookup_idx_key_t key = { fp, name, NULL };
396*6881a400Schristos 
397*6881a400Schristos   /* This array is sorted, so we can bsearch for it.  */
398*6881a400Schristos 
399*6881a400Schristos   ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t),
400*6881a400Schristos 		 ctf_lookup_var);
401*6881a400Schristos 
402*6881a400Schristos   if (ent == NULL)
403*6881a400Schristos     {
404*6881a400Schristos       if (fp->ctf_parent != NULL)
405*6881a400Schristos 	return ctf_lookup_variable (fp->ctf_parent, name);
406*6881a400Schristos 
407*6881a400Schristos       return (ctf_set_errno (fp, ECTF_NOTYPEDAT));
408*6881a400Schristos     }
409*6881a400Schristos 
410*6881a400Schristos   return ent->ctv_type;
411*6881a400Schristos }
412*6881a400Schristos 
413*6881a400Schristos typedef struct ctf_symidx_sort_arg_cb
414*6881a400Schristos {
415*6881a400Schristos   ctf_dict_t *fp;
416*6881a400Schristos   uint32_t *names;
417*6881a400Schristos } ctf_symidx_sort_arg_cb_t;
418*6881a400Schristos 
419*6881a400Schristos static int
420*6881a400Schristos sort_symidx_by_name (const void *one_, const void *two_, void *arg_)
421*6881a400Schristos {
422*6881a400Schristos   const uint32_t *one = one_;
423*6881a400Schristos   const uint32_t *two = two_;
424*6881a400Schristos   ctf_symidx_sort_arg_cb_t *arg = arg_;
425*6881a400Schristos 
426*6881a400Schristos   return (strcmp (ctf_strptr (arg->fp, arg->names[*one]),
427*6881a400Schristos 		  ctf_strptr (arg->fp, arg->names[*two])));
428*6881a400Schristos }
429*6881a400Schristos 
430*6881a400Schristos /* Sort a symbol index section by name.  Takes a 1:1 mapping of names to the
431*6881a400Schristos    corresponding symbol table.  Returns a lexicographically sorted array of idx
432*6881a400Schristos    indexes (and thus, of indexes into the corresponding func info / data object
433*6881a400Schristos    section).  */
434*6881a400Schristos 
435*6881a400Schristos static uint32_t *
436*6881a400Schristos ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx,
437*6881a400Schristos 			 size_t len)
438*6881a400Schristos {
439*6881a400Schristos   uint32_t *sorted;
440*6881a400Schristos   size_t i;
441*6881a400Schristos 
442*6881a400Schristos   if ((sorted = malloc (len)) == NULL)
443*6881a400Schristos     {
444*6881a400Schristos       ctf_set_errno (fp, ENOMEM);
445*6881a400Schristos       return NULL;
446*6881a400Schristos     }
447*6881a400Schristos 
448*6881a400Schristos   *nidx = len / sizeof (uint32_t);
449*6881a400Schristos   for (i = 0; i < *nidx; i++)
450*6881a400Schristos     sorted[i] = i;
451*6881a400Schristos 
452*6881a400Schristos   if (!(fp->ctf_header->cth_flags & CTF_F_IDXSORTED))
453*6881a400Schristos     {
454*6881a400Schristos       ctf_symidx_sort_arg_cb_t arg = { fp, idx };
455*6881a400Schristos       ctf_dprintf ("Index section unsorted: sorting.");
456*6881a400Schristos       ctf_qsort_r (sorted, *nidx, sizeof (uint32_t), sort_symidx_by_name, &arg);
457*6881a400Schristos       fp->ctf_header->cth_flags |= CTF_F_IDXSORTED;
458*6881a400Schristos     }
459*6881a400Schristos 
460*6881a400Schristos   return sorted;
461*6881a400Schristos }
462*6881a400Schristos 
463*6881a400Schristos /* Given a symbol index, return the name of that symbol from the table provided
464*6881a400Schristos    by ctf_link_shuffle_syms, or failing that from the secondary string table, or
465*6881a400Schristos    the null string.  */
466*6881a400Schristos static const char *
467*6881a400Schristos ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
4687d62b00eSchristos {
4697d62b00eSchristos   const ctf_sect_t *sp = &fp->ctf_symtab;
470*6881a400Schristos   ctf_link_sym_t sym;
471*6881a400Schristos   int err;
4727d62b00eSchristos 
473*6881a400Schristos   if (fp->ctf_dynsymidx)
474*6881a400Schristos     {
475*6881a400Schristos       err = EINVAL;
476*6881a400Schristos       if (symidx > fp->ctf_dynsymmax)
477*6881a400Schristos 	goto try_parent;
478*6881a400Schristos 
479*6881a400Schristos       ctf_link_sym_t *symp = fp->ctf_dynsymidx[symidx];
480*6881a400Schristos 
481*6881a400Schristos       if (!symp)
482*6881a400Schristos 	goto try_parent;
483*6881a400Schristos 
484*6881a400Schristos       return symp->st_name;
485*6881a400Schristos     }
486*6881a400Schristos 
487*6881a400Schristos   err = ECTF_NOSYMTAB;
4887d62b00eSchristos   if (sp->cts_data == NULL)
489*6881a400Schristos     goto try_parent;
4907d62b00eSchristos 
4917d62b00eSchristos   if (symidx >= fp->ctf_nsyms)
492*6881a400Schristos     goto try_parent;
4937d62b00eSchristos 
494*6881a400Schristos   switch (sp->cts_entsize)
495*6881a400Schristos     {
496*6881a400Schristos     case sizeof (Elf64_Sym):
497*6881a400Schristos       {
498*6881a400Schristos 	const Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data + symidx;
499*6881a400Schristos 	ctf_elf64_to_link_sym (fp, &sym, symp, symidx);
500*6881a400Schristos       }
501*6881a400Schristos       break;
502*6881a400Schristos     case sizeof (Elf32_Sym):
5037d62b00eSchristos       {
5047d62b00eSchristos 	const Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data + symidx;
505*6881a400Schristos 	ctf_elf32_to_link_sym (fp, &sym, symp, symidx);
506*6881a400Schristos       }
507*6881a400Schristos       break;
508*6881a400Schristos     default:
509*6881a400Schristos       ctf_set_errno (fp, ECTF_SYMTAB);
510*6881a400Schristos       return _CTF_NULLSTR;
511*6881a400Schristos     }
512*6881a400Schristos 
513*6881a400Schristos   assert (!sym.st_nameidx_set);
514*6881a400Schristos 
515*6881a400Schristos   return sym.st_name;
516*6881a400Schristos 
517*6881a400Schristos  try_parent:
518*6881a400Schristos   if (fp->ctf_parent)
519*6881a400Schristos     {
520*6881a400Schristos       const char *ret;
521*6881a400Schristos       ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx);
522*6881a400Schristos       if (ret == NULL)
523*6881a400Schristos 	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
524*6881a400Schristos       return ret;
5257d62b00eSchristos     }
5267d62b00eSchristos   else
5277d62b00eSchristos     {
528*6881a400Schristos       ctf_set_errno (fp, err);
529*6881a400Schristos       return _CTF_NULLSTR;
530*6881a400Schristos     }
5317d62b00eSchristos }
5327d62b00eSchristos 
533*6881a400Schristos /* Given a symbol name, return the index of that symbol, or -1 on error or if
534*6881a400Schristos    not found.  */
535*6881a400Schristos static unsigned long
536*6881a400Schristos ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
537*6881a400Schristos {
538*6881a400Schristos   const ctf_sect_t *sp = &fp->ctf_symtab;
539*6881a400Schristos   ctf_link_sym_t sym;
540*6881a400Schristos   void *known_idx;
541*6881a400Schristos   int err;
542*6881a400Schristos   ctf_dict_t *cache = fp;
5437d62b00eSchristos 
544*6881a400Schristos   if (fp->ctf_dynsyms)
545*6881a400Schristos     {
546*6881a400Schristos       err = EINVAL;
5477d62b00eSchristos 
548*6881a400Schristos       ctf_link_sym_t *symp;
5497d62b00eSchristos 
550*6881a400Schristos       if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
551*6881a400Schristos 	goto try_parent;
5527d62b00eSchristos 
553*6881a400Schristos       return symp->st_symidx;
554*6881a400Schristos     }
555*6881a400Schristos 
556*6881a400Schristos   err = ECTF_NOSYMTAB;
557*6881a400Schristos   if (sp->cts_data == NULL)
558*6881a400Schristos     goto try_parent;
559*6881a400Schristos 
560*6881a400Schristos   /* First, try a hash lookup to see if we have already spotted this symbol
561*6881a400Schristos      during a past iteration: create the hash first if need be.  The lifespan
562*6881a400Schristos      of the strings is equal to the lifespan of the cts_data, so we don't
563*6881a400Schristos      need to strdup them.  If this dict was opened as part of an archive,
564*6881a400Schristos      and this archive has designed a crossdict_cache to cache results that
565*6881a400Schristos      are the same across all dicts in an archive, use it.  */
566*6881a400Schristos 
567*6881a400Schristos   if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache)
568*6881a400Schristos     cache = fp->ctf_archive->ctfi_crossdict_cache;
569*6881a400Schristos 
570*6881a400Schristos   if (!cache->ctf_symhash)
571*6881a400Schristos     if ((cache->ctf_symhash = ctf_dynhash_create (ctf_hash_string,
572*6881a400Schristos 						  ctf_hash_eq_string,
573*6881a400Schristos 						  NULL, NULL)) == NULL)
574*6881a400Schristos       goto oom;
575*6881a400Schristos 
576*6881a400Schristos   if (ctf_dynhash_lookup_kv (cache->ctf_symhash, symname, NULL, &known_idx))
577*6881a400Schristos     return (unsigned long) (uintptr_t) known_idx;
578*6881a400Schristos 
579*6881a400Schristos   /* Hash lookup unsuccessful: linear search, populating the hashtab for later
580*6881a400Schristos      lookups as we go.  */
581*6881a400Schristos 
582*6881a400Schristos   for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize;
583*6881a400Schristos        cache->ctf_symhash_latest++)
584*6881a400Schristos     {
585*6881a400Schristos       switch (sp->cts_entsize)
586*6881a400Schristos 	{
587*6881a400Schristos 	case sizeof (Elf64_Sym):
588*6881a400Schristos 	  {
589*6881a400Schristos 	    Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data;
590*6881a400Schristos 	    ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
591*6881a400Schristos 				   cache->ctf_symhash_latest);
592*6881a400Schristos 	    if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
593*6881a400Schristos 					NULL, NULL))
594*6881a400Schristos 	      if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
595*6881a400Schristos 				       (const void *) (uintptr_t)
596*6881a400Schristos 				       cache->ctf_symhash_latest) < 0)
597*6881a400Schristos 		goto oom;
598*6881a400Schristos 	    if (strcmp (sym.st_name, symname) == 0)
599*6881a400Schristos 	      return cache->ctf_symhash_latest++;
600*6881a400Schristos 	  }
601*6881a400Schristos 	  break;
602*6881a400Schristos 	case sizeof (Elf32_Sym):
603*6881a400Schristos 	  {
604*6881a400Schristos 	    Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data;
605*6881a400Schristos 	    ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
606*6881a400Schristos 				   cache->ctf_symhash_latest);
607*6881a400Schristos 	    if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
608*6881a400Schristos 					NULL, NULL))
609*6881a400Schristos 	      if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
610*6881a400Schristos 				       (const void *) (uintptr_t)
611*6881a400Schristos 				       cache->ctf_symhash_latest) < 0)
612*6881a400Schristos 		goto oom;
613*6881a400Schristos 	    if (strcmp (sym.st_name, symname) == 0)
614*6881a400Schristos 	      return cache->ctf_symhash_latest++;
615*6881a400Schristos 	  }
616*6881a400Schristos 	  break;
617*6881a400Schristos 	default:
618*6881a400Schristos 	  ctf_set_errno (fp, ECTF_SYMTAB);
619*6881a400Schristos 	  return (unsigned long) -1;
620*6881a400Schristos 	}
621*6881a400Schristos     }
622*6881a400Schristos 
623*6881a400Schristos   /* Searched everything, still not found.  */
624*6881a400Schristos 
625*6881a400Schristos   return (unsigned long) -1;
626*6881a400Schristos 
627*6881a400Schristos  try_parent:
628*6881a400Schristos   if (fp->ctf_parent)
629*6881a400Schristos     return ctf_lookup_symbol_idx (fp->ctf_parent, symname);
630*6881a400Schristos   else
631*6881a400Schristos     {
632*6881a400Schristos       ctf_set_errno (fp, err);
633*6881a400Schristos       return (unsigned long) -1;
634*6881a400Schristos     }
635*6881a400Schristos oom:
636*6881a400Schristos   ctf_set_errno (fp, ENOMEM);
637*6881a400Schristos   ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
638*6881a400Schristos 				 "lookup hashtab"));
639*6881a400Schristos   return (unsigned long) -1;
640*6881a400Schristos 
641*6881a400Schristos }
642*6881a400Schristos 
643*6881a400Schristos /* Iterate over all symbols with types: if FUNC, function symbols, otherwise,
644*6881a400Schristos    data symbols.  The name argument is not optional.  The return order is
645*6881a400Schristos    arbitrary, though is likely to be in symbol index or name order.  You can
646*6881a400Schristos    change the value of 'functions' in the middle of iteration over non-dynamic
647*6881a400Schristos    dicts, but doing so on dynamic dicts will fail.  (This is probably not very
648*6881a400Schristos    useful, but there is no reason to prohibit it.)  */
649*6881a400Schristos 
650*6881a400Schristos ctf_id_t
651*6881a400Schristos ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
652*6881a400Schristos 		 int functions)
653*6881a400Schristos {
654*6881a400Schristos   ctf_id_t sym;
655*6881a400Schristos   ctf_next_t *i = *it;
656*6881a400Schristos   int err;
657*6881a400Schristos 
658*6881a400Schristos   if (!i)
659*6881a400Schristos     {
660*6881a400Schristos       if ((i = ctf_next_create ()) == NULL)
661*6881a400Schristos 	return ctf_set_errno (fp, ENOMEM);
662*6881a400Schristos 
663*6881a400Schristos       i->cu.ctn_fp = fp;
664*6881a400Schristos       i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
665*6881a400Schristos       i->ctn_n = 0;
666*6881a400Schristos       *it = i;
667*6881a400Schristos     }
668*6881a400Schristos 
669*6881a400Schristos   if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
670*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN));
671*6881a400Schristos 
672*6881a400Schristos   if (fp != i->cu.ctn_fp)
673*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP));
674*6881a400Schristos 
675*6881a400Schristos   /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
676*6881a400Schristos      incurring additional sorting cost for unsorted symtypetabs coming from the
677*6881a400Schristos      compiler, to allow ctf_symbol_next to work in the absence of a symtab, and
678*6881a400Schristos      finally because it's easier to work out what the name of each symbol is if
679*6881a400Schristos      we do that.  */
680*6881a400Schristos 
681*6881a400Schristos   if (fp->ctf_flags & LCTF_RDWR)
682*6881a400Schristos     {
683*6881a400Schristos       ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
684*6881a400Schristos       void *dyn_name = NULL, *dyn_value = NULL;
685*6881a400Schristos 
686*6881a400Schristos       if (!dynh)
687*6881a400Schristos 	{
688*6881a400Schristos 	  ctf_next_destroy (i);
689*6881a400Schristos 	  return (ctf_set_errno (fp, ECTF_NEXT_END));
690*6881a400Schristos 	}
691*6881a400Schristos 
692*6881a400Schristos       err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
693*6881a400Schristos       /* This covers errors and also end-of-iteration.  */
694*6881a400Schristos       if (err != 0)
695*6881a400Schristos 	{
696*6881a400Schristos 	  ctf_next_destroy (i);
697*6881a400Schristos 	  *it = NULL;
698*6881a400Schristos 	  return ctf_set_errno (fp, err);
699*6881a400Schristos 	}
700*6881a400Schristos 
701*6881a400Schristos       *name = dyn_name;
702*6881a400Schristos       sym = (ctf_id_t) (uintptr_t) dyn_value;
703*6881a400Schristos     }
704*6881a400Schristos   else if ((!functions && fp->ctf_objtidx_names) ||
705*6881a400Schristos 	   (functions && fp->ctf_funcidx_names))
706*6881a400Schristos     {
707*6881a400Schristos       ctf_header_t *hp = fp->ctf_header;
708*6881a400Schristos       uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names;
709*6881a400Schristos       uint32_t *tab;
710*6881a400Schristos       size_t len;
711*6881a400Schristos 
712*6881a400Schristos       if (functions)
713*6881a400Schristos 	{
714*6881a400Schristos 	  len = (hp->cth_varoff - hp->cth_funcidxoff) / sizeof (uint32_t);
715*6881a400Schristos 	  tab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
716*6881a400Schristos 	}
717*6881a400Schristos       else
718*6881a400Schristos 	{
719*6881a400Schristos 	  len = (hp->cth_funcidxoff - hp->cth_objtidxoff) / sizeof (uint32_t);
720*6881a400Schristos 	  tab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff);
721*6881a400Schristos 	}
722*6881a400Schristos 
723*6881a400Schristos       do
724*6881a400Schristos 	{
725*6881a400Schristos 	  if (i->ctn_n >= len)
726*6881a400Schristos 	    goto end;
727*6881a400Schristos 
728*6881a400Schristos 	  *name = ctf_strptr (fp, idx[i->ctn_n]);
729*6881a400Schristos 	  sym = tab[i->ctn_n++];
730*6881a400Schristos 	}
731*6881a400Schristos       while (sym == -1u || sym == 0);
732*6881a400Schristos     }
733*6881a400Schristos   else
734*6881a400Schristos     {
735*6881a400Schristos       /* Skip over pads in ctf_xslate, padding for typeless symbols in the
736*6881a400Schristos 	 symtypetab itself, and symbols in the wrong table.  */
737*6881a400Schristos       for (; i->ctn_n < fp->ctf_nsyms; i->ctn_n++)
738*6881a400Schristos 	{
739*6881a400Schristos 	  ctf_header_t *hp = fp->ctf_header;
740*6881a400Schristos 
741*6881a400Schristos 	  if (fp->ctf_sxlate[i->ctn_n] == -1u)
742*6881a400Schristos 	    continue;
743*6881a400Schristos 
744*6881a400Schristos 	  sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[i->ctn_n]);
745*6881a400Schristos 
746*6881a400Schristos 	  if (sym == 0)
747*6881a400Schristos 	    continue;
748*6881a400Schristos 
749*6881a400Schristos 	  if (functions)
750*6881a400Schristos 	    {
751*6881a400Schristos 	      if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_funcoff
752*6881a400Schristos 		  && fp->ctf_sxlate[i->ctn_n] < hp->cth_objtidxoff)
753*6881a400Schristos 		break;
754*6881a400Schristos 	    }
755*6881a400Schristos 	  else
756*6881a400Schristos 	    {
757*6881a400Schristos 	      if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_objtoff
758*6881a400Schristos 		  && fp->ctf_sxlate[i->ctn_n] < hp->cth_funcoff)
759*6881a400Schristos 		break;
760*6881a400Schristos 	    }
761*6881a400Schristos 	}
762*6881a400Schristos 
763*6881a400Schristos       if (i->ctn_n >= fp->ctf_nsyms)
764*6881a400Schristos 	goto end;
765*6881a400Schristos 
766*6881a400Schristos       *name = ctf_lookup_symbol_name (fp, i->ctn_n++);
767*6881a400Schristos     }
768*6881a400Schristos 
769*6881a400Schristos   return sym;
770*6881a400Schristos 
771*6881a400Schristos  end:
772*6881a400Schristos   ctf_next_destroy (i);
773*6881a400Schristos   *it = NULL;
774*6881a400Schristos   return (ctf_set_errno (fp, ECTF_NEXT_END));
775*6881a400Schristos }
776*6881a400Schristos 
777*6881a400Schristos /* A bsearch function for function and object index names.  */
778*6881a400Schristos 
779*6881a400Schristos static int
780*6881a400Schristos ctf_lookup_idx_name (const void *key_, const void *idx_)
781*6881a400Schristos {
782*6881a400Schristos   const ctf_lookup_idx_key_t *key = key_;
783*6881a400Schristos   const uint32_t *idx = idx_;
784*6881a400Schristos 
785*6881a400Schristos   return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx])));
786*6881a400Schristos }
787*6881a400Schristos 
788*6881a400Schristos /* Given a symbol name or (failing that) number, look up that symbol in the
789*6881a400Schristos    function or object index table (which must exist).  Return 0 if not found
790*6881a400Schristos    there (or pad).  */
791*6881a400Schristos 
792*6881a400Schristos static ctf_id_t
793*6881a400Schristos ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
794*6881a400Schristos 			const char *symname, int is_function)
795*6881a400Schristos {
796*6881a400Schristos   struct ctf_header *hp = fp->ctf_header;
797*6881a400Schristos   uint32_t *symtypetab;
798*6881a400Schristos   uint32_t *names;
799*6881a400Schristos   uint32_t *sxlate;
800*6881a400Schristos   size_t nidx;
801*6881a400Schristos 
802*6881a400Schristos   if (symname == NULL)
803*6881a400Schristos     symname = ctf_lookup_symbol_name (fp, symidx);
804*6881a400Schristos 
805*6881a400Schristos   ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in "
806*6881a400Schristos 	       "indexed symtypetab\n", symidx, symname);
807*6881a400Schristos 
808*6881a400Schristos   if (symname[0] == '\0')
809*6881a400Schristos     return -1;					/* errno is set for us.  */
810*6881a400Schristos 
811*6881a400Schristos   if (is_function)
812*6881a400Schristos     {
813*6881a400Schristos       if (!fp->ctf_funcidx_sxlate)
814*6881a400Schristos 	{
815*6881a400Schristos 	  if ((fp->ctf_funcidx_sxlate
816*6881a400Schristos 	       = ctf_symidx_sort (fp, (uint32_t *)
817*6881a400Schristos 				  (fp->ctf_buf + hp->cth_funcidxoff),
818*6881a400Schristos 				  &fp->ctf_nfuncidx,
819*6881a400Schristos 				  hp->cth_varoff - hp->cth_funcidxoff))
820*6881a400Schristos 	      == NULL)
821*6881a400Schristos 	    {
822*6881a400Schristos 	      ctf_err_warn (fp, 0, 0, _("cannot sort function symidx"));
823*6881a400Schristos 	      return -1;				/* errno is set for us.  */
824*6881a400Schristos 	    }
825*6881a400Schristos 	}
826*6881a400Schristos       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_funcoff);
827*6881a400Schristos       sxlate = fp->ctf_funcidx_sxlate;
828*6881a400Schristos       names = fp->ctf_funcidx_names;
829*6881a400Schristos       nidx = fp->ctf_nfuncidx;
830*6881a400Schristos     }
831*6881a400Schristos   else
832*6881a400Schristos     {
833*6881a400Schristos       if (!fp->ctf_objtidx_sxlate)
834*6881a400Schristos 	{
835*6881a400Schristos 	  if ((fp->ctf_objtidx_sxlate
836*6881a400Schristos 	       = ctf_symidx_sort (fp, (uint32_t *)
837*6881a400Schristos 				  (fp->ctf_buf + hp->cth_objtidxoff),
838*6881a400Schristos 				  &fp->ctf_nobjtidx,
839*6881a400Schristos 				  hp->cth_funcidxoff - hp->cth_objtidxoff))
840*6881a400Schristos 	      == NULL)
841*6881a400Schristos 	    {
842*6881a400Schristos 	      ctf_err_warn (fp, 0, 0, _("cannot sort object symidx"));
843*6881a400Schristos 	      return -1;				/* errno is set for us. */
844*6881a400Schristos 	    }
845*6881a400Schristos 	}
846*6881a400Schristos 
847*6881a400Schristos       symtypetab = (uint32_t *) (fp->ctf_buf + hp->cth_objtoff);
848*6881a400Schristos       sxlate = fp->ctf_objtidx_sxlate;
849*6881a400Schristos       names = fp->ctf_objtidx_names;
850*6881a400Schristos       nidx = fp->ctf_nobjtidx;
851*6881a400Schristos     }
852*6881a400Schristos 
853*6881a400Schristos   ctf_lookup_idx_key_t key = { fp, symname, names };
854*6881a400Schristos   uint32_t *idx;
855*6881a400Schristos 
856*6881a400Schristos   idx = bsearch (&key, sxlate, nidx, sizeof (uint32_t), ctf_lookup_idx_name);
857*6881a400Schristos 
858*6881a400Schristos   if (!idx)
859*6881a400Schristos     {
860*6881a400Schristos       ctf_dprintf ("%s not found in idx\n", symname);
861*6881a400Schristos       return 0;
862*6881a400Schristos     }
863*6881a400Schristos 
864*6881a400Schristos   /* Should be impossible, but be paranoid.  */
865*6881a400Schristos   if ((idx - sxlate) > (ptrdiff_t) nidx)
8667d62b00eSchristos     return (ctf_set_errno (fp, ECTF_CORRUPT));
8677d62b00eSchristos 
868*6881a400Schristos   ctf_dprintf ("Symbol %lx (%s) is of type %x\n", symidx, symname,
869*6881a400Schristos 	       symtypetab[*idx]);
870*6881a400Schristos   return symtypetab[*idx];
8717d62b00eSchristos }
8727d62b00eSchristos 
873*6881a400Schristos /* Given a symbol name or (if NULL) symbol index, return the type of the
874*6881a400Schristos    function or data object described by the corresponding entry in the symbol
875*6881a400Schristos    table.  We can only return symbols in read-only dicts and in dicts for which
876*6881a400Schristos    ctf_link_shuffle_syms has been called to assign symbol indexes to symbol
877*6881a400Schristos    names.  */
878*6881a400Schristos 
879*6881a400Schristos static ctf_id_t
880*6881a400Schristos ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
881*6881a400Schristos 			   const char *symname)
882*6881a400Schristos {
883*6881a400Schristos   const ctf_sect_t *sp = &fp->ctf_symtab;
884*6881a400Schristos   ctf_id_t type = 0;
885*6881a400Schristos   int err = 0;
886*6881a400Schristos 
887*6881a400Schristos   /* Shuffled dynsymidx present?  Use that.  */
888*6881a400Schristos   if (fp->ctf_dynsymidx)
889*6881a400Schristos     {
890*6881a400Schristos       const ctf_link_sym_t *sym;
891*6881a400Schristos 
892*6881a400Schristos       if (symname)
893*6881a400Schristos 	ctf_dprintf ("Looking up type of object with symname %s in "
894*6881a400Schristos 		     "writable dict symtypetab\n", symname);
895*6881a400Schristos       else
896*6881a400Schristos 	ctf_dprintf ("Looking up type of object with symtab idx %lx in "
897*6881a400Schristos 		     "writable dict symtypetab\n", symidx);
898*6881a400Schristos 
899*6881a400Schristos       /* The dict must be dynamic.  */
900*6881a400Schristos       if (!ctf_assert (fp, fp->ctf_flags & LCTF_RDWR))
901*6881a400Schristos 	return CTF_ERR;
902*6881a400Schristos 
903*6881a400Schristos       /* No name? Need to look it up.  */
904*6881a400Schristos       if (!symname)
905*6881a400Schristos 	{
906*6881a400Schristos 	  err = EINVAL;
907*6881a400Schristos 	  if (symidx > fp->ctf_dynsymmax)
908*6881a400Schristos 	    goto try_parent;
909*6881a400Schristos 
910*6881a400Schristos 	  sym = fp->ctf_dynsymidx[symidx];
911*6881a400Schristos 	  err = ECTF_NOTYPEDAT;
912*6881a400Schristos 	  if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
913*6881a400Schristos 	    goto try_parent;
914*6881a400Schristos 
915*6881a400Schristos 	  if (!ctf_assert (fp, !sym->st_nameidx_set))
916*6881a400Schristos 	    return CTF_ERR;
917*6881a400Schristos 	  symname = sym->st_name;
918*6881a400Schristos      }
919*6881a400Schristos 
920*6881a400Schristos       if (fp->ctf_objthash == NULL
921*6881a400Schristos 	  || ((type = (ctf_id_t) (uintptr_t)
922*6881a400Schristos 	       ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
923*6881a400Schristos 	{
924*6881a400Schristos 	  if (fp->ctf_funchash == NULL
925*6881a400Schristos 	      || ((type = (ctf_id_t) (uintptr_t)
926*6881a400Schristos 		   ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
927*6881a400Schristos 	    goto try_parent;
928*6881a400Schristos 	}
929*6881a400Schristos 
930*6881a400Schristos       return type;
931*6881a400Schristos     }
932*6881a400Schristos 
933*6881a400Schristos   /* Lookup by name in a dynamic dict: just do it directly.  */
934*6881a400Schristos   if (symname && fp->ctf_flags & LCTF_RDWR)
935*6881a400Schristos     {
936*6881a400Schristos       if (fp->ctf_objthash == NULL
937*6881a400Schristos 	  || ((type = (ctf_id_t) (uintptr_t)
938*6881a400Schristos 	       ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
939*6881a400Schristos 	{
940*6881a400Schristos 	  if (fp->ctf_funchash == NULL
941*6881a400Schristos 	      || ((type = (ctf_id_t) (uintptr_t)
942*6881a400Schristos 		   ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
943*6881a400Schristos 	    goto try_parent;
944*6881a400Schristos 	}
945*6881a400Schristos       return type;
946*6881a400Schristos     }
947*6881a400Schristos 
948*6881a400Schristos   err = ECTF_NOSYMTAB;
949*6881a400Schristos   if (sp->cts_data == NULL)
950*6881a400Schristos     goto try_parent;
951*6881a400Schristos 
952*6881a400Schristos   /* This covers both out-of-range lookups and a dynamic dict which hasn't been
953*6881a400Schristos      shuffled yet.  */
954*6881a400Schristos   err = EINVAL;
955*6881a400Schristos   if (symname == NULL && symidx >= fp->ctf_nsyms)
956*6881a400Schristos     goto try_parent;
957*6881a400Schristos 
958*6881a400Schristos   if (fp->ctf_objtidx_names)
959*6881a400Schristos     {
960*6881a400Schristos       if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR)
961*6881a400Schristos 	return CTF_ERR;				/* errno is set for us.  */
962*6881a400Schristos     }
963*6881a400Schristos   if (type == 0 && fp->ctf_funcidx_names)
964*6881a400Schristos     {
965*6881a400Schristos       if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
966*6881a400Schristos 	return CTF_ERR;				/* errno is set for us.  */
967*6881a400Schristos     }
968*6881a400Schristos   if (type != 0)
969*6881a400Schristos     return type;
970*6881a400Schristos 
971*6881a400Schristos   err = ECTF_NOTYPEDAT;
972*6881a400Schristos   if (fp->ctf_objtidx_names && fp->ctf_funcidx_names)
973*6881a400Schristos     goto try_parent;
974*6881a400Schristos 
975*6881a400Schristos   /* Table must be nonindexed.  */
976*6881a400Schristos 
977*6881a400Schristos   ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx);
978*6881a400Schristos 
979*6881a400Schristos   if (symname != NULL)
980*6881a400Schristos     if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
981*6881a400Schristos       goto try_parent;
982*6881a400Schristos 
983*6881a400Schristos   if (fp->ctf_sxlate[symidx] == -1u)
984*6881a400Schristos     goto try_parent;
985*6881a400Schristos 
986*6881a400Schristos   type = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[symidx]);
987*6881a400Schristos 
988*6881a400Schristos   if (type == 0)
989*6881a400Schristos     goto try_parent;
990*6881a400Schristos 
991*6881a400Schristos   return type;
992*6881a400Schristos  try_parent:
993*6881a400Schristos   if (fp->ctf_parent)
994*6881a400Schristos     {
995*6881a400Schristos       ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
996*6881a400Schristos 						symname);
997*6881a400Schristos       if (ret == CTF_ERR)
998*6881a400Schristos 	ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
999*6881a400Schristos       return ret;
1000*6881a400Schristos     }
1001*6881a400Schristos   else
1002*6881a400Schristos     return (ctf_set_errno (fp, err));
1003*6881a400Schristos }
1004*6881a400Schristos 
1005*6881a400Schristos /* Given a symbol table index, return the type of the function or data object
1006*6881a400Schristos    described by the corresponding entry in the symbol table.  */
1007*6881a400Schristos ctf_id_t
1008*6881a400Schristos ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
1009*6881a400Schristos {
1010*6881a400Schristos   return ctf_lookup_by_sym_or_name (fp, symidx, NULL);
1011*6881a400Schristos }
1012*6881a400Schristos 
1013*6881a400Schristos /* Given a symbol name, return the type of the function or data object described
1014*6881a400Schristos    by the corresponding entry in the symbol table.  */
1015*6881a400Schristos ctf_id_t
1016*6881a400Schristos ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname)
1017*6881a400Schristos {
1018*6881a400Schristos   return ctf_lookup_by_sym_or_name (fp, 0, symname);
1019*6881a400Schristos }
1020*6881a400Schristos 
1021*6881a400Schristos /* Given a symbol table index, return the info for the function described
1022*6881a400Schristos    by the corresponding entry in the symbol table, which may be a function
1023*6881a400Schristos    symbol or may be a data symbol that happens to be a function pointer.  */
1024*6881a400Schristos 
1025*6881a400Schristos int
1026*6881a400Schristos ctf_func_info (ctf_dict_t *fp, unsigned long symidx, ctf_funcinfo_t *fip)
1027*6881a400Schristos {
1028*6881a400Schristos   ctf_id_t type;
1029*6881a400Schristos 
1030*6881a400Schristos   if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
1031*6881a400Schristos     return -1;					/* errno is set for us.  */
1032*6881a400Schristos 
1033*6881a400Schristos   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
1034*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NOTFUNC));
1035*6881a400Schristos 
1036*6881a400Schristos   return ctf_func_type_info (fp, type, fip);
10377d62b00eSchristos }
10387d62b00eSchristos 
10397d62b00eSchristos /* Given a symbol table index, return the arguments for the function described
10407d62b00eSchristos    by the corresponding entry in the symbol table.  */
10417d62b00eSchristos 
10427d62b00eSchristos int
1043*6881a400Schristos ctf_func_args (ctf_dict_t *fp, unsigned long symidx, uint32_t argc,
10447d62b00eSchristos 	       ctf_id_t *argv)
10457d62b00eSchristos {
1046*6881a400Schristos   ctf_id_t type;
10477d62b00eSchristos 
1048*6881a400Schristos   if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
10497d62b00eSchristos     return -1;					/* errno is set for us.  */
10507d62b00eSchristos 
1051*6881a400Schristos   if (ctf_type_kind (fp, type) != CTF_K_FUNCTION)
1052*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NOTFUNC));
10537d62b00eSchristos 
1054*6881a400Schristos   return ctf_func_type_args (fp, type, argc, argv);
10557d62b00eSchristos }
1056