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