xref: /netbsd-src/external/gpl3/gdb/dist/libctf/ctf-serialize.c (revision 12989c96ee862c63521a9ead8c44629b7a2ba9b1)
14b169a6bSchristos /* CTF dict creation.
2*12989c96Schristos    Copyright (C) 2019-2024 Free Software Foundation, Inc.
34b169a6bSchristos 
44b169a6bSchristos    This file is part of libctf.
54b169a6bSchristos 
64b169a6bSchristos    libctf is free software; you can redistribute it and/or modify it under
74b169a6bSchristos    the terms of the GNU General Public License as published by the Free
84b169a6bSchristos    Software Foundation; either version 3, or (at your option) any later
94b169a6bSchristos    version.
104b169a6bSchristos 
114b169a6bSchristos    This program is distributed in the hope that it will be useful, but
124b169a6bSchristos    WITHOUT ANY WARRANTY; without even the implied warranty of
134b169a6bSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
144b169a6bSchristos    See the GNU General Public License for more details.
154b169a6bSchristos 
164b169a6bSchristos    You should have received a copy of the GNU General Public License
174b169a6bSchristos    along with this program; see the file COPYING.  If not see
184b169a6bSchristos    <http://www.gnu.org/licenses/>.  */
194b169a6bSchristos 
204b169a6bSchristos #include <ctf-impl.h>
214b169a6bSchristos #include <assert.h>
224b169a6bSchristos #include <string.h>
234b169a6bSchristos #include <unistd.h>
244b169a6bSchristos #include <zlib.h>
254b169a6bSchristos 
264b169a6bSchristos #include <elf.h>
274b169a6bSchristos #include "elf-bfd.h"
284b169a6bSchristos 
294b169a6bSchristos /* Symtypetab sections.  */
304b169a6bSchristos 
314b169a6bSchristos /* Symtypetab emission flags.  */
324b169a6bSchristos 
334b169a6bSchristos #define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1
344b169a6bSchristos #define CTF_SYMTYPETAB_EMIT_PAD 0x2
354b169a6bSchristos #define CTF_SYMTYPETAB_FORCE_INDEXED 0x4
364b169a6bSchristos 
374b169a6bSchristos /* Properties of symtypetab emission, shared by symtypetab section
384b169a6bSchristos    sizing and symtypetab emission itself.  */
394b169a6bSchristos 
404b169a6bSchristos typedef struct emit_symtypetab_state
414b169a6bSchristos {
424b169a6bSchristos   /* True if linker-reported symbols are being filtered out.  symfp is set if
434b169a6bSchristos      this is true: otherwise, indexing is forced and the symflags indicate as
444b169a6bSchristos      much. */
454b169a6bSchristos   int filter_syms;
464b169a6bSchristos 
474b169a6bSchristos   /* True if symbols are being sorted.  */
484b169a6bSchristos   int sort_syms;
494b169a6bSchristos 
504b169a6bSchristos   /* Flags for symtypetab emission.  */
514b169a6bSchristos   int symflags;
524b169a6bSchristos 
534b169a6bSchristos   /* The dict to which the linker has reported symbols.  */
544b169a6bSchristos   ctf_dict_t *symfp;
554b169a6bSchristos 
564b169a6bSchristos   /* The maximum number of objects seen.  */
574b169a6bSchristos   size_t maxobjt;
584b169a6bSchristos 
594b169a6bSchristos   /* The maximum number of func info entris seen.  */
604b169a6bSchristos   size_t maxfunc;
614b169a6bSchristos } emit_symtypetab_state_t;
624b169a6bSchristos 
634b169a6bSchristos /* Determine if a symbol is "skippable" and should never appear in the
644b169a6bSchristos    symtypetab sections.  */
654b169a6bSchristos 
664b169a6bSchristos int
674b169a6bSchristos ctf_symtab_skippable (ctf_link_sym_t *sym)
684b169a6bSchristos {
694b169a6bSchristos   /* Never skip symbols whose name is not yet known.  */
704b169a6bSchristos   if (sym->st_nameidx_set)
714b169a6bSchristos     return 0;
724b169a6bSchristos 
734b169a6bSchristos   return (sym->st_name == NULL || sym->st_name[0] == 0
744b169a6bSchristos 	  || sym->st_shndx == SHN_UNDEF
754b169a6bSchristos 	  || strcmp (sym->st_name, "_START_") == 0
764b169a6bSchristos 	  || strcmp (sym->st_name, "_END_") == 0
774b169a6bSchristos 	  || (sym->st_type == STT_OBJECT && sym->st_shndx == SHN_EXTABS
784b169a6bSchristos 	      && sym->st_value == 0));
794b169a6bSchristos }
804b169a6bSchristos 
814b169a6bSchristos /* Get the number of symbols in a symbol hash, the count of symbols, the maximum
824b169a6bSchristos    seen, the eventual size, without any padding elements, of the func/data and
834b169a6bSchristos    (if generated) index sections, and the size of accumulated padding elements.
844b169a6bSchristos    The linker-reported set of symbols is found in SYMFP: it may be NULL if
854b169a6bSchristos    symbol filtering is not desired, in which case CTF_SYMTYPETAB_FORCE_INDEXED
864b169a6bSchristos    will always be set in the flags.
874b169a6bSchristos 
884b169a6bSchristos    Also figure out if any symbols need to be moved to the variable section, and
894b169a6bSchristos    add them (if not already present).  */
904b169a6bSchristos 
914b169a6bSchristos _libctf_nonnull_ ((1,3,4,5,6,7,8))
924b169a6bSchristos static int
934b169a6bSchristos symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
944b169a6bSchristos 		    size_t *count, size_t *max, size_t *unpadsize,
954b169a6bSchristos 		    size_t *padsize, size_t *idxsize, int flags)
964b169a6bSchristos {
974b169a6bSchristos   ctf_next_t *i = NULL;
984b169a6bSchristos   const void *name;
994b169a6bSchristos   const void *ctf_sym;
1004b169a6bSchristos   ctf_dynhash_t *linker_known = NULL;
1014b169a6bSchristos   int err;
1024b169a6bSchristos   int beyond_max = 0;
1034b169a6bSchristos 
1044b169a6bSchristos   *count = 0;
1054b169a6bSchristos   *max = 0;
1064b169a6bSchristos   *unpadsize = 0;
1074b169a6bSchristos   *idxsize = 0;
1084b169a6bSchristos   *padsize = 0;
1094b169a6bSchristos 
1104b169a6bSchristos   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
1114b169a6bSchristos     {
1124b169a6bSchristos       /* Make a dynhash citing only symbols reported by the linker of the
1134b169a6bSchristos 	 appropriate type, then traverse all potential-symbols we know the types
1144b169a6bSchristos 	 of, removing them from linker_known as we go.  Once this is done, the
1154b169a6bSchristos 	 only symbols remaining in linker_known are symbols we don't know the
1164b169a6bSchristos 	 types of: we must emit pads for those symbols that are below the
1174b169a6bSchristos 	 maximum symbol we will emit (any beyond that are simply skipped).
1184b169a6bSchristos 
1194b169a6bSchristos 	 If there are none, this symtypetab will be empty: just report that.  */
1204b169a6bSchristos 
1214b169a6bSchristos       if (!symfp->ctf_dynsyms)
1224b169a6bSchristos 	return 0;
1234b169a6bSchristos 
1244b169a6bSchristos       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1254b169a6bSchristos 					      NULL, NULL)) == NULL)
1264b169a6bSchristos 	return (ctf_set_errno (fp, ENOMEM));
1274b169a6bSchristos 
1284b169a6bSchristos       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
1294b169a6bSchristos 				       &name, &ctf_sym)) == 0)
1304b169a6bSchristos 	{
1314b169a6bSchristos 	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
1324b169a6bSchristos 
1334b169a6bSchristos 	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
1344b169a6bSchristos 	       && sym->st_type != STT_FUNC)
1354b169a6bSchristos 	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
1364b169a6bSchristos 		  && sym->st_type != STT_OBJECT))
1374b169a6bSchristos 	    continue;
1384b169a6bSchristos 
1394b169a6bSchristos 	  if (ctf_symtab_skippable (sym))
1404b169a6bSchristos 	    continue;
1414b169a6bSchristos 
1424b169a6bSchristos 	  /* This should only be true briefly before all the names are
1434b169a6bSchristos 	     finalized, long before we get this far.  */
1444b169a6bSchristos 	  if (!ctf_assert (fp, !sym->st_nameidx_set))
1454b169a6bSchristos 	    return -1;				/* errno is set for us.  */
1464b169a6bSchristos 
1474b169a6bSchristos 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
1484b169a6bSchristos 	    {
1494b169a6bSchristos 	      ctf_dynhash_destroy (linker_known);
1504b169a6bSchristos 	      return (ctf_set_errno (fp, ENOMEM));
1514b169a6bSchristos 	    }
1524b169a6bSchristos 	}
1534b169a6bSchristos       if (err != ECTF_NEXT_END)
1544b169a6bSchristos 	{
1554b169a6bSchristos 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
1564b169a6bSchristos 				  "serialization"));
1574b169a6bSchristos 	  ctf_dynhash_destroy (linker_known);
1584b169a6bSchristos 	  return (ctf_set_errno (fp, err));
1594b169a6bSchristos 	}
1604b169a6bSchristos     }
1614b169a6bSchristos 
1624b169a6bSchristos   while ((err = ctf_dynhash_cnext (symhash, &i, &name, NULL)) == 0)
1634b169a6bSchristos     {
1644b169a6bSchristos       ctf_link_sym_t *sym;
1654b169a6bSchristos 
1664b169a6bSchristos       if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
1674b169a6bSchristos 	{
1684b169a6bSchristos 	  /* Linker did not report symbol in symtab.  Remove it from the
1694b169a6bSchristos 	     set of known data symbols and continue.  */
1704b169a6bSchristos 	  if ((sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, name)) == NULL)
1714b169a6bSchristos 	    {
1724b169a6bSchristos 	      ctf_dynhash_remove (symhash, name);
1734b169a6bSchristos 	      continue;
1744b169a6bSchristos 	    }
1754b169a6bSchristos 
1764b169a6bSchristos 	  /* We don't remove skippable symbols from the symhash because we don't
1774b169a6bSchristos 	     want them to be migrated into variables.  */
1784b169a6bSchristos 	  if (ctf_symtab_skippable (sym))
1794b169a6bSchristos 	    continue;
1804b169a6bSchristos 
1814b169a6bSchristos 	  if ((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
1824b169a6bSchristos 	      && sym->st_type != STT_FUNC)
1834b169a6bSchristos 	    {
1844b169a6bSchristos 	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
1854b169a6bSchristos 					"function but is of type %x.  "
1864b169a6bSchristos 					"The symbol type lookup tables "
1874b169a6bSchristos 					"are probably corrupted"),
1884b169a6bSchristos 			    sym->st_name, sym->st_symidx, sym->st_type);
1894b169a6bSchristos 	      ctf_dynhash_remove (symhash, name);
1904b169a6bSchristos 	      continue;
1914b169a6bSchristos 	    }
1924b169a6bSchristos 	  else if (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
1934b169a6bSchristos 		   && sym->st_type != STT_OBJECT)
1944b169a6bSchristos 	    {
1954b169a6bSchristos 	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
1964b169a6bSchristos 					"data object but is of type %x.  "
1974b169a6bSchristos 					"The symbol type lookup tables "
1984b169a6bSchristos 					"are probably corrupted"),
1994b169a6bSchristos 			    sym->st_name, sym->st_symidx, sym->st_type);
2004b169a6bSchristos 	      ctf_dynhash_remove (symhash, name);
2014b169a6bSchristos 	      continue;
2024b169a6bSchristos 	    }
2034b169a6bSchristos 
2044b169a6bSchristos 	  ctf_dynhash_remove (linker_known, name);
2054b169a6bSchristos 
2064b169a6bSchristos 	  if (*max < sym->st_symidx)
2074b169a6bSchristos 	    *max = sym->st_symidx;
2084b169a6bSchristos 	}
2094b169a6bSchristos       else
2104b169a6bSchristos 	(*max)++;
211*12989c96Schristos 
212*12989c96Schristos       *unpadsize += sizeof (uint32_t);
213*12989c96Schristos       (*count)++;
2144b169a6bSchristos     }
2154b169a6bSchristos   if (err != ECTF_NEXT_END)
2164b169a6bSchristos     {
2174b169a6bSchristos       ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
2184b169a6bSchristos 				  "serialization"));
2194b169a6bSchristos       ctf_dynhash_destroy (linker_known);
2204b169a6bSchristos       return (ctf_set_errno (fp, err));
2214b169a6bSchristos     }
2224b169a6bSchristos 
2234b169a6bSchristos   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
2244b169a6bSchristos     {
2254b169a6bSchristos       while ((err = ctf_dynhash_cnext (linker_known, &i, NULL, &ctf_sym)) == 0)
2264b169a6bSchristos 	{
2274b169a6bSchristos 	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
2284b169a6bSchristos 
2294b169a6bSchristos 	  if (sym->st_symidx > *max)
2304b169a6bSchristos 	    beyond_max++;
2314b169a6bSchristos 	}
2324b169a6bSchristos       if (err != ECTF_NEXT_END)
2334b169a6bSchristos 	{
2344b169a6bSchristos 	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
2354b169a6bSchristos 				      "during CTF serialization"));
2364b169a6bSchristos 	  ctf_dynhash_destroy (linker_known);
2374b169a6bSchristos 	  return (ctf_set_errno (fp, err));
2384b169a6bSchristos 	}
2394b169a6bSchristos     }
2404b169a6bSchristos 
2414b169a6bSchristos   *idxsize = *count * sizeof (uint32_t);
2424b169a6bSchristos   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
2434b169a6bSchristos     *padsize = (ctf_dynhash_elements (linker_known) - beyond_max) * sizeof (uint32_t);
2444b169a6bSchristos 
2454b169a6bSchristos   ctf_dynhash_destroy (linker_known);
2464b169a6bSchristos   return 0;
2474b169a6bSchristos }
2484b169a6bSchristos 
2494b169a6bSchristos /* Emit an objt or func symtypetab into DP in a particular order defined by an
2504b169a6bSchristos    array of ctf_link_sym_t or symbol names passed in.  The index has NIDX
2514b169a6bSchristos    elements in it: unindexed output would terminate at symbol OUTMAX and is in
2524b169a6bSchristos    any case no larger than SIZE bytes.  Some index elements are expected to be
2534b169a6bSchristos    skipped: see symtypetab_density.  The linker-reported set of symbols (if any)
2544b169a6bSchristos    is found in SYMFP. */
2554b169a6bSchristos static int
2564b169a6bSchristos emit_symtypetab (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
2574b169a6bSchristos 		 ctf_link_sym_t **idx, const char **nameidx, uint32_t nidx,
2584b169a6bSchristos 		 uint32_t outmax, int size, int flags)
2594b169a6bSchristos {
2604b169a6bSchristos   uint32_t i;
2614b169a6bSchristos   uint32_t *dpp = dp;
2624b169a6bSchristos   ctf_dynhash_t *symhash;
2634b169a6bSchristos 
2644b169a6bSchristos   ctf_dprintf ("Emitting table of size %i, outmax %u, %u symtypetab entries, "
2654b169a6bSchristos 	       "flags %i\n", size, outmax, nidx, flags);
2664b169a6bSchristos 
2674b169a6bSchristos   /* Empty table? Nothing to do.  */
2684b169a6bSchristos   if (size == 0)
2694b169a6bSchristos     return 0;
2704b169a6bSchristos 
2714b169a6bSchristos   if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
2724b169a6bSchristos     symhash = fp->ctf_funchash;
2734b169a6bSchristos   else
2744b169a6bSchristos     symhash = fp->ctf_objthash;
2754b169a6bSchristos 
2764b169a6bSchristos   for (i = 0; i < nidx; i++)
2774b169a6bSchristos     {
2784b169a6bSchristos       const char *sym_name;
2794b169a6bSchristos       void *type;
2804b169a6bSchristos 
2814b169a6bSchristos       /* If we have a linker-reported set of symbols, we may be given that set
2824b169a6bSchristos 	 to work from, or a set of symbol names.  In both cases we want to look
2834b169a6bSchristos 	 at the corresponding linker-reported symbol (if any).  */
2844b169a6bSchristos       if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
2854b169a6bSchristos 	{
2864b169a6bSchristos 	  ctf_link_sym_t *this_link_sym;
2874b169a6bSchristos 
2884b169a6bSchristos 	  if (idx)
2894b169a6bSchristos 	    this_link_sym = idx[i];
2904b169a6bSchristos 	  else
2914b169a6bSchristos 	    this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, nameidx[i]);
2924b169a6bSchristos 
2934b169a6bSchristos 	  /* Unreported symbol number.  No pad, no nothing.  */
2944b169a6bSchristos 	  if (!this_link_sym)
2954b169a6bSchristos 	    continue;
2964b169a6bSchristos 
2974b169a6bSchristos 	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
2984b169a6bSchristos 	     table.  */
2994b169a6bSchristos 	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
3004b169a6bSchristos 	       && this_link_sym->st_type != STT_FUNC)
3014b169a6bSchristos 	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
3024b169a6bSchristos 		  && this_link_sym->st_type != STT_OBJECT))
3034b169a6bSchristos 	    continue;
3044b169a6bSchristos 
3054b169a6bSchristos 	  if (ctf_symtab_skippable (this_link_sym))
3064b169a6bSchristos 	    continue;
3074b169a6bSchristos 
3084b169a6bSchristos 	  sym_name = this_link_sym->st_name;
3094b169a6bSchristos 
3104b169a6bSchristos 	  /* Linker reports symbol of a different type to the symbol we actually
3114b169a6bSchristos 	     added?  Skip the symbol.  No pad, since the symbol doesn't actually
3124b169a6bSchristos 	     belong in this table at all.  (Warned about in
3134b169a6bSchristos 	     symtypetab_density.)  */
3144b169a6bSchristos 	  if ((this_link_sym->st_type == STT_FUNC)
3154b169a6bSchristos 	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
3164b169a6bSchristos 	    continue;
3174b169a6bSchristos 
3184b169a6bSchristos 	  if ((this_link_sym->st_type == STT_OBJECT)
3194b169a6bSchristos 	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
3204b169a6bSchristos 	    continue;
3214b169a6bSchristos 	}
3224b169a6bSchristos       else
3234b169a6bSchristos 	sym_name = nameidx[i];
3244b169a6bSchristos 
3254b169a6bSchristos       /* Symbol in index but no type set? Silently skip and (optionally)
3264b169a6bSchristos 	 pad.  (In force-indexed mode, this is also where we track symbols of
3274b169a6bSchristos 	 the wrong type for this round of insertion.)  */
3284b169a6bSchristos       if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
3294b169a6bSchristos 	{
3304b169a6bSchristos 	  if (flags & CTF_SYMTYPETAB_EMIT_PAD)
3314b169a6bSchristos 	    *dpp++ = 0;
3324b169a6bSchristos 	  continue;
3334b169a6bSchristos 	}
3344b169a6bSchristos 
3354b169a6bSchristos       if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) < size))
3364b169a6bSchristos 	return -1;				/* errno is set for us.  */
3374b169a6bSchristos 
3384b169a6bSchristos       *dpp++ = (ctf_id_t) (uintptr_t) type;
3394b169a6bSchristos 
3404b169a6bSchristos       /* When emitting unindexed output, all later symbols are pads: stop
3414b169a6bSchristos 	 early.  */
3424b169a6bSchristos       if ((flags & CTF_SYMTYPETAB_EMIT_PAD) && idx[i]->st_symidx == outmax)
3434b169a6bSchristos 	break;
3444b169a6bSchristos     }
3454b169a6bSchristos 
3464b169a6bSchristos   return 0;
3474b169a6bSchristos }
3484b169a6bSchristos 
3494b169a6bSchristos /* Emit an objt or func symtypetab index into DP in a paticular order defined by
3504b169a6bSchristos    an array of symbol names passed in.  Stop at NIDX.  The linker-reported set
3514b169a6bSchristos    of symbols (if any) is found in SYMFP. */
3524b169a6bSchristos static int
3534b169a6bSchristos emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
3544b169a6bSchristos 		       const char **idx, uint32_t nidx, int size, int flags)
3554b169a6bSchristos {
3564b169a6bSchristos   uint32_t i;
3574b169a6bSchristos   uint32_t *dpp = dp;
3584b169a6bSchristos   ctf_dynhash_t *symhash;
3594b169a6bSchristos 
3604b169a6bSchristos   ctf_dprintf ("Emitting index of size %i, %u entries reported by linker, "
3614b169a6bSchristos 	       "flags %i\n", size, nidx, flags);
3624b169a6bSchristos 
3634b169a6bSchristos   /* Empty table? Nothing to do.  */
3644b169a6bSchristos   if (size == 0)
3654b169a6bSchristos     return 0;
3664b169a6bSchristos 
3674b169a6bSchristos   if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
3684b169a6bSchristos     symhash = fp->ctf_funchash;
3694b169a6bSchristos   else
3704b169a6bSchristos     symhash = fp->ctf_objthash;
3714b169a6bSchristos 
3724b169a6bSchristos   /* Indexes should always be unpadded.  */
3734b169a6bSchristos   if (!ctf_assert (fp, !(flags & CTF_SYMTYPETAB_EMIT_PAD)))
3744b169a6bSchristos     return -1;					/* errno is set for us.  */
3754b169a6bSchristos 
3764b169a6bSchristos   for (i = 0; i < nidx; i++)
3774b169a6bSchristos     {
3784b169a6bSchristos       const char *sym_name;
3794b169a6bSchristos       void *type;
3804b169a6bSchristos 
3814b169a6bSchristos       if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
3824b169a6bSchristos 	{
3834b169a6bSchristos 	  ctf_link_sym_t *this_link_sym;
3844b169a6bSchristos 
3854b169a6bSchristos 	  this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, idx[i]);
3864b169a6bSchristos 
3874b169a6bSchristos 	  /* This is an index: unreported symbols should never appear in it.  */
3884b169a6bSchristos 	  if (!ctf_assert (fp, this_link_sym != NULL))
3894b169a6bSchristos 	    return -1;				/* errno is set for us.  */
3904b169a6bSchristos 
3914b169a6bSchristos 	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
3924b169a6bSchristos 	     table.  */
3934b169a6bSchristos 	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
3944b169a6bSchristos 	       && this_link_sym->st_type != STT_FUNC)
3954b169a6bSchristos 	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
3964b169a6bSchristos 		  && this_link_sym->st_type != STT_OBJECT))
3974b169a6bSchristos 	    continue;
3984b169a6bSchristos 
3994b169a6bSchristos 	  if (ctf_symtab_skippable (this_link_sym))
4004b169a6bSchristos 	    continue;
4014b169a6bSchristos 
4024b169a6bSchristos 	  sym_name = this_link_sym->st_name;
4034b169a6bSchristos 
4044b169a6bSchristos 	  /* Linker reports symbol of a different type to the symbol we actually
4054b169a6bSchristos 	     added?  Skip the symbol.  */
4064b169a6bSchristos 	  if ((this_link_sym->st_type == STT_FUNC)
4074b169a6bSchristos 	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
4084b169a6bSchristos 	    continue;
4094b169a6bSchristos 
4104b169a6bSchristos 	  if ((this_link_sym->st_type == STT_OBJECT)
4114b169a6bSchristos 	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
4124b169a6bSchristos 	    continue;
4134b169a6bSchristos 	}
4144b169a6bSchristos       else
4154b169a6bSchristos 	sym_name = idx[i];
4164b169a6bSchristos 
4174b169a6bSchristos       /* Symbol in index and reported by linker, but no type set? Silently skip
4184b169a6bSchristos 	 and (optionally) pad.  (In force-indexed mode, this is also where we
4194b169a6bSchristos 	 track symbols of the wrong type for this round of insertion.)  */
4204b169a6bSchristos       if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
4214b169a6bSchristos 	continue;
4224b169a6bSchristos 
4234b169a6bSchristos       ctf_str_add_ref (fp, sym_name, dpp++);
4244b169a6bSchristos 
4254b169a6bSchristos       if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) <= size))
4264b169a6bSchristos 	return -1;				/* errno is set for us.  */
4274b169a6bSchristos     }
4284b169a6bSchristos 
4294b169a6bSchristos   return 0;
4304b169a6bSchristos }
4314b169a6bSchristos 
4324b169a6bSchristos /* Delete symbols that have been assigned names from the variable section.  Must
4334b169a6bSchristos    be called from within ctf_serialize, because that is the only place you can
4344b169a6bSchristos    safely delete variables without messing up ctf_rollback.  */
4354b169a6bSchristos 
4364b169a6bSchristos static int
4374b169a6bSchristos symtypetab_delete_nonstatics (ctf_dict_t *fp, ctf_dict_t *symfp)
4384b169a6bSchristos {
4394b169a6bSchristos   ctf_dvdef_t *dvd, *nvd;
4404b169a6bSchristos   ctf_id_t type;
4414b169a6bSchristos 
4424b169a6bSchristos   for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
4434b169a6bSchristos     {
4444b169a6bSchristos       nvd = ctf_list_next (dvd);
4454b169a6bSchristos 
4464b169a6bSchristos       if ((((type = (ctf_id_t) (uintptr_t)
4474b169a6bSchristos 	     ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
4484b169a6bSchristos 	   || (type = (ctf_id_t) (uintptr_t)
4494b169a6bSchristos 	       ctf_dynhash_lookup (fp->ctf_funchash, dvd->dvd_name)) > 0)
4504b169a6bSchristos 	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
4514b169a6bSchristos 	  && type == dvd->dvd_type)
4524b169a6bSchristos 	ctf_dvd_delete (fp, dvd);
4534b169a6bSchristos     }
4544b169a6bSchristos 
4554b169a6bSchristos   return 0;
4564b169a6bSchristos }
4574b169a6bSchristos 
4584b169a6bSchristos /* Figure out the sizes of the symtypetab sections, their indexed state,
4594b169a6bSchristos    etc.  */
4604b169a6bSchristos static int
4614b169a6bSchristos ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s,
4624b169a6bSchristos 			   ctf_header_t *hdr, size_t *objt_size,
4634b169a6bSchristos 			   size_t *func_size, size_t *objtidx_size,
4644b169a6bSchristos 			   size_t *funcidx_size)
4654b169a6bSchristos {
4664b169a6bSchristos   size_t nfuncs, nobjts;
4674b169a6bSchristos   size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize;
4684b169a6bSchristos 
4694b169a6bSchristos   /* If doing a writeout as part of linking, and the link flags request it,
4704b169a6bSchristos      filter out reported symbols from the variable section, and filter out all
4714b169a6bSchristos      other symbols from the symtypetab sections.  (If we are not linking, the
4724b169a6bSchristos      symbols are sorted; if we are linking, don't bother sorting if we are not
473*12989c96Schristos      filtering out reported symbols: this is almost certainly an ld -r and only
4744b169a6bSchristos      the linker is likely to consume these symtypetabs again.  The linker
475*12989c96Schristos      doesn't care what order the symtypetab entries are in, since it only
4764b169a6bSchristos      iterates over symbols and does not use the ctf_lookup_by_symbol* API.)  */
4774b169a6bSchristos 
4784b169a6bSchristos   s->sort_syms = 1;
4794b169a6bSchristos   if (fp->ctf_flags & LCTF_LINKING)
4804b169a6bSchristos     {
4814b169a6bSchristos       s->filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);
4824b169a6bSchristos       if (!s->filter_syms)
4834b169a6bSchristos 	s->sort_syms = 0;
4844b169a6bSchristos     }
4854b169a6bSchristos 
4864b169a6bSchristos   /* Find the dict to which the linker has reported symbols, if any.  */
4874b169a6bSchristos 
4884b169a6bSchristos   if (s->filter_syms)
4894b169a6bSchristos     {
4904b169a6bSchristos       if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms)
4914b169a6bSchristos 	s->symfp = fp->ctf_parent;
4924b169a6bSchristos       else
4934b169a6bSchristos 	s->symfp = fp;
4944b169a6bSchristos     }
4954b169a6bSchristos 
4964b169a6bSchristos   /* If not filtering, keep all potential symbols in an unsorted, indexed
4974b169a6bSchristos      dict.  */
4984b169a6bSchristos   if (!s->filter_syms)
4994b169a6bSchristos     s->symflags = CTF_SYMTYPETAB_FORCE_INDEXED;
5004b169a6bSchristos   else
5014b169a6bSchristos     hdr->cth_flags |= CTF_F_IDXSORTED;
5024b169a6bSchristos 
5034b169a6bSchristos   if (!ctf_assert (fp, (s->filter_syms && s->symfp)
5044b169a6bSchristos 		   || (!s->filter_syms && !s->symfp
5054b169a6bSchristos 		       && ((s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0))))
5064b169a6bSchristos     return -1;
5074b169a6bSchristos 
5084b169a6bSchristos   /* Work out the sizes of the object and function sections, and work out the
5094b169a6bSchristos      number of pad (unassigned) symbols in each, and the overall size of the
5104b169a6bSchristos      sections.  */
5114b169a6bSchristos 
5124b169a6bSchristos   if (symtypetab_density (fp, s->symfp, fp->ctf_objthash, &nobjts, &s->maxobjt,
5134b169a6bSchristos 			  &objt_unpadsize, &objt_padsize, objtidx_size,
5144b169a6bSchristos 			  s->symflags) < 0)
5154b169a6bSchristos     return -1;					/* errno is set for us.  */
5164b169a6bSchristos 
5174b169a6bSchristos   ctf_dprintf ("Object symtypetab: %i objects, max %i, unpadded size %i, "
5184b169a6bSchristos 	       "%i bytes of pads, index size %i\n", (int) nobjts,
5194b169a6bSchristos 	       (int) s->maxobjt, (int) objt_unpadsize, (int) objt_padsize,
5204b169a6bSchristos 	       (int) *objtidx_size);
5214b169a6bSchristos 
5224b169a6bSchristos   if (symtypetab_density (fp, s->symfp, fp->ctf_funchash, &nfuncs, &s->maxfunc,
5234b169a6bSchristos 			  &func_unpadsize, &func_padsize, funcidx_size,
5244b169a6bSchristos 			  s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
5254b169a6bSchristos     return -1;					/* errno is set for us.  */
5264b169a6bSchristos 
5274b169a6bSchristos   ctf_dprintf ("Function symtypetab: %i functions, max %i, unpadded size %i, "
5284b169a6bSchristos 	       "%i bytes of pads, index size %i\n", (int) nfuncs,
5294b169a6bSchristos 	       (int) s->maxfunc, (int) func_unpadsize, (int) func_padsize,
5304b169a6bSchristos 	       (int) *funcidx_size);
5314b169a6bSchristos 
5324b169a6bSchristos   /* It is worth indexing each section if it would save space to do so, due to
5334b169a6bSchristos      reducing the number of pads sufficiently.  A pad is the same size as a
5344b169a6bSchristos      single index entry: but index sections compress relatively poorly compared
5354b169a6bSchristos      to constant pads, so it takes a lot of contiguous padding to equal one
5364b169a6bSchristos      index section entry.  It would be nice to be able to *verify* whether we
5374b169a6bSchristos      would save space after compression rather than guessing, but this seems
5384b169a6bSchristos      difficult, since it would require complete reserialization.  Regardless, if
5394b169a6bSchristos      the linker has not reported any symbols (e.g. if this is not a final link
5404b169a6bSchristos      but just an ld -r), we must emit things in indexed fashion just as the
5414b169a6bSchristos      compiler does.  */
5424b169a6bSchristos 
5434b169a6bSchristos   *objt_size = objt_unpadsize;
5444b169a6bSchristos   if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
5454b169a6bSchristos       && ((objt_padsize + objt_unpadsize) * CTF_INDEX_PAD_THRESHOLD
5464b169a6bSchristos 	  > objt_padsize))
5474b169a6bSchristos     {
5484b169a6bSchristos       *objt_size += objt_padsize;
5494b169a6bSchristos       *objtidx_size = 0;
5504b169a6bSchristos     }
5514b169a6bSchristos 
5524b169a6bSchristos   *func_size = func_unpadsize;
5534b169a6bSchristos   if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
5544b169a6bSchristos       && ((func_padsize + func_unpadsize) * CTF_INDEX_PAD_THRESHOLD
5554b169a6bSchristos 	  > func_padsize))
5564b169a6bSchristos     {
5574b169a6bSchristos       *func_size += func_padsize;
5584b169a6bSchristos       *funcidx_size = 0;
5594b169a6bSchristos     }
5604b169a6bSchristos 
5614b169a6bSchristos   /* If we are filtering symbols out, those symbols that the linker has not
5624b169a6bSchristos      reported have now been removed from the ctf_objthash and ctf_funchash.
5634b169a6bSchristos      Delete entries from the variable section that duplicate newly-added
5644b169a6bSchristos      symbols.  There's no need to migrate new ones in: we do that (if necessary)
5654b169a6bSchristos      in ctf_link_deduplicating_variables.  */
5664b169a6bSchristos 
5674b169a6bSchristos   if (s->filter_syms && s->symfp->ctf_dynsyms &&
5684b169a6bSchristos       symtypetab_delete_nonstatics (fp, s->symfp) < 0)
5694b169a6bSchristos     return -1;
5704b169a6bSchristos 
5714b169a6bSchristos   return 0;
5724b169a6bSchristos }
5734b169a6bSchristos 
5744b169a6bSchristos static int
5754b169a6bSchristos ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s,
5764b169a6bSchristos 			   unsigned char **tptr, size_t objt_size,
5774b169a6bSchristos 			   size_t func_size, size_t objtidx_size,
5784b169a6bSchristos 			   size_t funcidx_size)
5794b169a6bSchristos {
5804b169a6bSchristos   unsigned char *t = *tptr;
5814b169a6bSchristos   size_t nsymtypes = 0;
5824b169a6bSchristos   const char **sym_name_order = NULL;
5834b169a6bSchristos   int err;
5844b169a6bSchristos 
5854b169a6bSchristos   /* Sort the linker's symbols into name order if need be.  */
5864b169a6bSchristos 
5874b169a6bSchristos   if ((objtidx_size != 0) || (funcidx_size != 0))
5884b169a6bSchristos     {
5894b169a6bSchristos       ctf_next_t *i = NULL;
5904b169a6bSchristos       void *symname;
5914b169a6bSchristos       const char **walk;
5924b169a6bSchristos 
5934b169a6bSchristos       if (s->filter_syms)
5944b169a6bSchristos 	{
5954b169a6bSchristos 	  if (s->symfp->ctf_dynsyms)
5964b169a6bSchristos 	    nsymtypes = ctf_dynhash_elements (s->symfp->ctf_dynsyms);
5974b169a6bSchristos 	  else
5984b169a6bSchristos 	    nsymtypes = 0;
5994b169a6bSchristos 	}
6004b169a6bSchristos       else
6014b169a6bSchristos 	nsymtypes = ctf_dynhash_elements (fp->ctf_objthash)
6024b169a6bSchristos 	  + ctf_dynhash_elements (fp->ctf_funchash);
6034b169a6bSchristos 
6044b169a6bSchristos       if ((sym_name_order = calloc (nsymtypes, sizeof (const char *))) == NULL)
6054b169a6bSchristos 	goto oom;
6064b169a6bSchristos 
6074b169a6bSchristos       walk = sym_name_order;
6084b169a6bSchristos 
6094b169a6bSchristos       if (s->filter_syms)
6104b169a6bSchristos 	{
6114b169a6bSchristos 	  if (s->symfp->ctf_dynsyms)
6124b169a6bSchristos 	    {
6134b169a6bSchristos 	      while ((err = ctf_dynhash_next_sorted (s->symfp->ctf_dynsyms, &i,
6144b169a6bSchristos 						     &symname, NULL,
6154b169a6bSchristos 						     ctf_dynhash_sort_by_name,
6164b169a6bSchristos 						     NULL)) == 0)
6174b169a6bSchristos 		*walk++ = (const char *) symname;
6184b169a6bSchristos 	      if (err != ECTF_NEXT_END)
6194b169a6bSchristos 		goto symerr;
6204b169a6bSchristos 	    }
6214b169a6bSchristos 	}
6224b169a6bSchristos       else
6234b169a6bSchristos 	{
6244b169a6bSchristos 	  ctf_hash_sort_f sort_fun = NULL;
6254b169a6bSchristos 
6264b169a6bSchristos 	  /* Since we partition the set of symbols back into objt and func,
6274b169a6bSchristos 	     we can sort the two independently without harm.  */
6284b169a6bSchristos 	  if (s->sort_syms)
6294b169a6bSchristos 	    sort_fun = ctf_dynhash_sort_by_name;
6304b169a6bSchristos 
6314b169a6bSchristos 	  while ((err = ctf_dynhash_next_sorted (fp->ctf_objthash, &i, &symname,
6324b169a6bSchristos 						 NULL, sort_fun, NULL)) == 0)
6334b169a6bSchristos 	    *walk++ = (const char *) symname;
6344b169a6bSchristos 	  if (err != ECTF_NEXT_END)
6354b169a6bSchristos 	    goto symerr;
6364b169a6bSchristos 
6374b169a6bSchristos 	  while ((err = ctf_dynhash_next_sorted (fp->ctf_funchash, &i, &symname,
6384b169a6bSchristos 						 NULL, sort_fun, NULL)) == 0)
6394b169a6bSchristos 	    *walk++ = (const char *) symname;
6404b169a6bSchristos 	  if (err != ECTF_NEXT_END)
6414b169a6bSchristos 	    goto symerr;
6424b169a6bSchristos 	}
6434b169a6bSchristos     }
6444b169a6bSchristos 
6454b169a6bSchristos   /* Emit the object and function sections, and if necessary their indexes.
6464b169a6bSchristos      Emission is done in symtab order if there is no index, and in index
6474b169a6bSchristos      (name) order otherwise.  */
6484b169a6bSchristos 
6494b169a6bSchristos   if ((objtidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx)
6504b169a6bSchristos     {
6514b169a6bSchristos       ctf_dprintf ("Emitting unindexed objt symtypetab\n");
6524b169a6bSchristos       if (emit_symtypetab (fp, s->symfp, (uint32_t *) t,
6534b169a6bSchristos 			   s->symfp->ctf_dynsymidx, NULL,
6544b169a6bSchristos 			   s->symfp->ctf_dynsymmax + 1, s->maxobjt,
6554b169a6bSchristos 			   objt_size, s->symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0)
6564b169a6bSchristos 	goto err;				/* errno is set for us.  */
6574b169a6bSchristos     }
6584b169a6bSchristos   else
6594b169a6bSchristos     {
6604b169a6bSchristos       ctf_dprintf ("Emitting indexed objt symtypetab\n");
6614b169a6bSchristos       if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL,
6624b169a6bSchristos 			   sym_name_order, nsymtypes, s->maxobjt,
6634b169a6bSchristos 			   objt_size, s->symflags) < 0)
6644b169a6bSchristos 	goto err;				/* errno is set for us.  */
6654b169a6bSchristos     }
6664b169a6bSchristos 
6674b169a6bSchristos   t += objt_size;
6684b169a6bSchristos 
6694b169a6bSchristos   if ((funcidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx)
6704b169a6bSchristos     {
6714b169a6bSchristos       ctf_dprintf ("Emitting unindexed func symtypetab\n");
6724b169a6bSchristos       if (emit_symtypetab (fp, s->symfp, (uint32_t *) t,
6734b169a6bSchristos 			   s->symfp->ctf_dynsymidx, NULL,
6744b169a6bSchristos 			   s->symfp->ctf_dynsymmax + 1, s->maxfunc,
6754b169a6bSchristos 			   func_size, s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION
6764b169a6bSchristos 			   | CTF_SYMTYPETAB_EMIT_PAD) < 0)
6774b169a6bSchristos 	goto err;				/* errno is set for us.  */
6784b169a6bSchristos     }
6794b169a6bSchristos   else
6804b169a6bSchristos     {
6814b169a6bSchristos       ctf_dprintf ("Emitting indexed func symtypetab\n");
6824b169a6bSchristos       if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL, sym_name_order,
6834b169a6bSchristos 			   nsymtypes, s->maxfunc, func_size,
6844b169a6bSchristos 			   s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
6854b169a6bSchristos 	goto err;				/* errno is set for us.  */
6864b169a6bSchristos     }
6874b169a6bSchristos 
6884b169a6bSchristos   t += func_size;
6894b169a6bSchristos 
6904b169a6bSchristos   if (objtidx_size > 0)
6914b169a6bSchristos     if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order,
6924b169a6bSchristos 			       nsymtypes, objtidx_size, s->symflags) < 0)
6934b169a6bSchristos       goto err;
6944b169a6bSchristos 
6954b169a6bSchristos   t += objtidx_size;
6964b169a6bSchristos 
6974b169a6bSchristos   if (funcidx_size > 0)
6984b169a6bSchristos     if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order,
6994b169a6bSchristos 			       nsymtypes, funcidx_size,
7004b169a6bSchristos 			       s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
7014b169a6bSchristos       goto err;
7024b169a6bSchristos 
7034b169a6bSchristos   t += funcidx_size;
7044b169a6bSchristos   free (sym_name_order);
7054b169a6bSchristos   *tptr = t;
7064b169a6bSchristos 
7074b169a6bSchristos   return 0;
7084b169a6bSchristos 
7094b169a6bSchristos  oom:
7104b169a6bSchristos   ctf_set_errno (fp, EAGAIN);
7114b169a6bSchristos   goto err;
7124b169a6bSchristos symerr:
7134b169a6bSchristos   ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
7144b169a6bSchristos  err:
7154b169a6bSchristos   free (sym_name_order);
7164b169a6bSchristos   return -1;
7174b169a6bSchristos }
7184b169a6bSchristos 
7194b169a6bSchristos /* Type section.  */
7204b169a6bSchristos 
721*12989c96Schristos /* Iterate through the static types and the dynamic type definition list and
722*12989c96Schristos    compute the size of the CTF type section.  */
7234b169a6bSchristos 
7244b169a6bSchristos static size_t
7254b169a6bSchristos ctf_type_sect_size (ctf_dict_t *fp)
7264b169a6bSchristos {
7274b169a6bSchristos   ctf_dtdef_t *dtd;
7284b169a6bSchristos   size_t type_size;
7294b169a6bSchristos 
7304b169a6bSchristos   for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
7314b169a6bSchristos        dtd != NULL; dtd = ctf_list_next (dtd))
7324b169a6bSchristos     {
7334b169a6bSchristos       uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
7344b169a6bSchristos       uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
7354b169a6bSchristos       size_t type_ctt_size = dtd->dtd_data.ctt_size;
7364b169a6bSchristos 
7374b169a6bSchristos       /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
7384b169a6bSchristos 	 if possible.  */
7394b169a6bSchristos 
7404b169a6bSchristos       if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
7414b169a6bSchristos 	{
7424b169a6bSchristos 	  size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
7434b169a6bSchristos 
7444b169a6bSchristos 	  if (lsize <= CTF_MAX_SIZE)
7454b169a6bSchristos 	    type_ctt_size = lsize;
7464b169a6bSchristos 	}
7474b169a6bSchristos 
7484b169a6bSchristos       if (type_ctt_size != CTF_LSIZE_SENT)
7494b169a6bSchristos 	type_size += sizeof (ctf_stype_t);
7504b169a6bSchristos       else
7514b169a6bSchristos 	type_size += sizeof (ctf_type_t);
7524b169a6bSchristos 
7534b169a6bSchristos       switch (kind)
7544b169a6bSchristos 	{
7554b169a6bSchristos 	case CTF_K_INTEGER:
7564b169a6bSchristos 	case CTF_K_FLOAT:
7574b169a6bSchristos 	  type_size += sizeof (uint32_t);
7584b169a6bSchristos 	  break;
7594b169a6bSchristos 	case CTF_K_ARRAY:
7604b169a6bSchristos 	  type_size += sizeof (ctf_array_t);
7614b169a6bSchristos 	  break;
7624b169a6bSchristos 	case CTF_K_SLICE:
7634b169a6bSchristos 	  type_size += sizeof (ctf_slice_t);
7644b169a6bSchristos 	  break;
7654b169a6bSchristos 	case CTF_K_FUNCTION:
7664b169a6bSchristos 	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
7674b169a6bSchristos 	  break;
7684b169a6bSchristos 	case CTF_K_STRUCT:
7694b169a6bSchristos 	case CTF_K_UNION:
7704b169a6bSchristos 	  if (type_ctt_size < CTF_LSTRUCT_THRESH)
7714b169a6bSchristos 	    type_size += sizeof (ctf_member_t) * vlen;
7724b169a6bSchristos 	  else
7734b169a6bSchristos 	    type_size += sizeof (ctf_lmember_t) * vlen;
7744b169a6bSchristos 	  break;
7754b169a6bSchristos 	case CTF_K_ENUM:
7764b169a6bSchristos 	  type_size += sizeof (ctf_enum_t) * vlen;
7774b169a6bSchristos 	  break;
7784b169a6bSchristos 	}
7794b169a6bSchristos     }
7804b169a6bSchristos 
781*12989c96Schristos   return type_size + fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff;
7824b169a6bSchristos }
7834b169a6bSchristos 
7844b169a6bSchristos /* Take a final lap through the dynamic type definition list and copy the
7854b169a6bSchristos    appropriate type records to the output buffer, noting down the strings as
7864b169a6bSchristos    we go.  */
7874b169a6bSchristos 
7884b169a6bSchristos static void
7894b169a6bSchristos ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
7904b169a6bSchristos {
7914b169a6bSchristos   unsigned char *t = *tptr;
7924b169a6bSchristos   ctf_dtdef_t *dtd;
7934b169a6bSchristos 
7944b169a6bSchristos   for (dtd = ctf_list_next (&fp->ctf_dtdefs);
7954b169a6bSchristos        dtd != NULL; dtd = ctf_list_next (dtd))
7964b169a6bSchristos     {
7974b169a6bSchristos       uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
7984b169a6bSchristos       uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
7994b169a6bSchristos       size_t type_ctt_size = dtd->dtd_data.ctt_size;
8004b169a6bSchristos       size_t len;
8014b169a6bSchristos       ctf_stype_t *copied;
8024b169a6bSchristos       const char *name;
8034b169a6bSchristos       size_t i;
8044b169a6bSchristos 
8054b169a6bSchristos       /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
8064b169a6bSchristos 	 if possible.  */
8074b169a6bSchristos 
8084b169a6bSchristos       if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
8094b169a6bSchristos 	{
8104b169a6bSchristos 	  size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
8114b169a6bSchristos 
8124b169a6bSchristos 	  if (lsize <= CTF_MAX_SIZE)
8134b169a6bSchristos 	    type_ctt_size = lsize;
8144b169a6bSchristos 	}
8154b169a6bSchristos 
8164b169a6bSchristos       if (type_ctt_size != CTF_LSIZE_SENT)
8174b169a6bSchristos 	len = sizeof (ctf_stype_t);
8184b169a6bSchristos       else
8194b169a6bSchristos 	len = sizeof (ctf_type_t);
8204b169a6bSchristos 
8214b169a6bSchristos       memcpy (t, &dtd->dtd_data, len);
8224b169a6bSchristos       copied = (ctf_stype_t *) t;  /* name is at the start: constant offset.  */
8234b169a6bSchristos       if (copied->ctt_name
8244b169a6bSchristos 	  && (name = ctf_strraw (fp, copied->ctt_name)) != NULL)
8254b169a6bSchristos         ctf_str_add_ref (fp, name, &copied->ctt_name);
8264b169a6bSchristos       copied->ctt_size = type_ctt_size;
8274b169a6bSchristos       t += len;
8284b169a6bSchristos 
8294b169a6bSchristos       switch (kind)
8304b169a6bSchristos 	{
8314b169a6bSchristos 	case CTF_K_INTEGER:
8324b169a6bSchristos 	case CTF_K_FLOAT:
8334b169a6bSchristos 	  memcpy (t, dtd->dtd_vlen, sizeof (uint32_t));
8344b169a6bSchristos 	  t += sizeof (uint32_t);
8354b169a6bSchristos 	  break;
8364b169a6bSchristos 
8374b169a6bSchristos 	case CTF_K_SLICE:
8384b169a6bSchristos 	  memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_slice));
8394b169a6bSchristos 	  t += sizeof (struct ctf_slice);
8404b169a6bSchristos 	  break;
8414b169a6bSchristos 
8424b169a6bSchristos 	case CTF_K_ARRAY:
8434b169a6bSchristos 	  memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_array));
8444b169a6bSchristos 	  t += sizeof (struct ctf_array);
8454b169a6bSchristos 	  break;
8464b169a6bSchristos 
8474b169a6bSchristos 	case CTF_K_FUNCTION:
8484b169a6bSchristos 	  /* Functions with no args also have no vlen.  */
8494b169a6bSchristos 	  if (dtd->dtd_vlen)
8504b169a6bSchristos 	    memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
8514b169a6bSchristos 	  t += sizeof (uint32_t) * (vlen + (vlen & 1));
8524b169a6bSchristos 	  break;
8534b169a6bSchristos 
8544b169a6bSchristos 	  /* These need to be copied across element by element, depending on
8554b169a6bSchristos 	     their ctt_size.  */
8564b169a6bSchristos 	case CTF_K_STRUCT:
8574b169a6bSchristos 	case CTF_K_UNION:
8584b169a6bSchristos 	  {
8594b169a6bSchristos 	    ctf_lmember_t *dtd_vlen = (ctf_lmember_t *) dtd->dtd_vlen;
8604b169a6bSchristos 	    ctf_lmember_t *t_lvlen = (ctf_lmember_t *) t;
8614b169a6bSchristos 	    ctf_member_t *t_vlen = (ctf_member_t *) t;
8624b169a6bSchristos 
8634b169a6bSchristos 	    for (i = 0; i < vlen; i++)
8644b169a6bSchristos 	      {
8654b169a6bSchristos 		const char *name = ctf_strraw (fp, dtd_vlen[i].ctlm_name);
8664b169a6bSchristos 
8674b169a6bSchristos 		ctf_str_add_ref (fp, name, &dtd_vlen[i].ctlm_name);
8684b169a6bSchristos 
8694b169a6bSchristos 		if (type_ctt_size < CTF_LSTRUCT_THRESH)
8704b169a6bSchristos 		  {
8714b169a6bSchristos 		    t_vlen[i].ctm_name = dtd_vlen[i].ctlm_name;
8724b169a6bSchristos 		    t_vlen[i].ctm_type = dtd_vlen[i].ctlm_type;
8734b169a6bSchristos 		    t_vlen[i].ctm_offset = CTF_LMEM_OFFSET (&dtd_vlen[i]);
8744b169a6bSchristos 		    ctf_str_add_ref (fp, name, &t_vlen[i].ctm_name);
8754b169a6bSchristos 		  }
8764b169a6bSchristos 		else
8774b169a6bSchristos 		  {
8784b169a6bSchristos 		    t_lvlen[i] = dtd_vlen[i];
8794b169a6bSchristos 		    ctf_str_add_ref (fp, name, &t_lvlen[i].ctlm_name);
8804b169a6bSchristos 		  }
8814b169a6bSchristos 	      }
8824b169a6bSchristos 	  }
8834b169a6bSchristos 
8844b169a6bSchristos 	  if (type_ctt_size < CTF_LSTRUCT_THRESH)
8854b169a6bSchristos 	    t += sizeof (ctf_member_t) * vlen;
8864b169a6bSchristos 	  else
8874b169a6bSchristos 	    t += sizeof (ctf_lmember_t) * vlen;
8884b169a6bSchristos 	  break;
8894b169a6bSchristos 
8904b169a6bSchristos 	case CTF_K_ENUM:
8914b169a6bSchristos 	  {
8924b169a6bSchristos 	    ctf_enum_t *dtd_vlen = (struct ctf_enum *) dtd->dtd_vlen;
8934b169a6bSchristos 	    ctf_enum_t *t_vlen = (struct ctf_enum *) t;
8944b169a6bSchristos 
8954b169a6bSchristos 	    memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_enum) * vlen);
8964b169a6bSchristos 	    for (i = 0; i < vlen; i++)
8974b169a6bSchristos 	      {
8984b169a6bSchristos 		const char *name = ctf_strraw (fp, dtd_vlen[i].cte_name);
8994b169a6bSchristos 
9004b169a6bSchristos 		ctf_str_add_ref (fp, name, &t_vlen[i].cte_name);
9014b169a6bSchristos 		ctf_str_add_ref (fp, name, &dtd_vlen[i].cte_name);
9024b169a6bSchristos 	      }
9034b169a6bSchristos 	    t += sizeof (struct ctf_enum) * vlen;
9044b169a6bSchristos 
9054b169a6bSchristos 	    break;
9064b169a6bSchristos 	  }
9074b169a6bSchristos 	}
9084b169a6bSchristos     }
9094b169a6bSchristos 
9104b169a6bSchristos   *tptr = t;
9114b169a6bSchristos }
9124b169a6bSchristos 
9134b169a6bSchristos /* Variable section.  */
9144b169a6bSchristos 
9154b169a6bSchristos /* Sort a newly-constructed static variable array.  */
9164b169a6bSchristos 
9174b169a6bSchristos typedef struct ctf_sort_var_arg_cb
9184b169a6bSchristos {
9194b169a6bSchristos   ctf_dict_t *fp;
9204b169a6bSchristos   ctf_strs_t *strtab;
9214b169a6bSchristos } ctf_sort_var_arg_cb_t;
9224b169a6bSchristos 
9234b169a6bSchristos static int
9244b169a6bSchristos ctf_sort_var (const void *one_, const void *two_, void *arg_)
9254b169a6bSchristos {
9264b169a6bSchristos   const ctf_varent_t *one = one_;
9274b169a6bSchristos   const ctf_varent_t *two = two_;
9284b169a6bSchristos   ctf_sort_var_arg_cb_t *arg = arg_;
9294b169a6bSchristos 
9304b169a6bSchristos   return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
9314b169a6bSchristos 		  ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
9324b169a6bSchristos }
9334b169a6bSchristos 
9344b169a6bSchristos /* Overall serialization.  */
9354b169a6bSchristos 
936*12989c96Schristos /* Emit a new CTF dict which is a serialized copy of this one: also reify
937*12989c96Schristos    the string table and update all offsets in the current dict suitably.
938*12989c96Schristos    (This simplifies ctf-string.c a little, at the cost of storing a second
939*12989c96Schristos    copy of the strtab if this dict was originally read in via ctf_open.)
940*12989c96Schristos 
941*12989c96Schristos    Other aspects of the existing dict are unchanged, although some
942*12989c96Schristos    static entries may be duplicated in the dynamic state (which should
943*12989c96Schristos    have no effect on visible operation).  */
944*12989c96Schristos 
945*12989c96Schristos static unsigned char *
946*12989c96Schristos ctf_serialize (ctf_dict_t *fp, size_t *bufsiz)
9474b169a6bSchristos {
9484b169a6bSchristos   ctf_header_t hdr, *hdrp;
9494b169a6bSchristos   ctf_dvdef_t *dvd;
9504b169a6bSchristos   ctf_varent_t *dvarents;
951*12989c96Schristos   const ctf_strs_writable_t *strtab;
952*12989c96Schristos   int sym_functions = 0;
9534b169a6bSchristos 
9544b169a6bSchristos   unsigned char *t;
9554b169a6bSchristos   unsigned long i;
9564b169a6bSchristos   size_t buf_size, type_size, objt_size, func_size;
9574b169a6bSchristos   size_t funcidx_size, objtidx_size;
9584b169a6bSchristos   size_t nvars;
9594b169a6bSchristos   unsigned char *buf = NULL, *newbuf;
9604b169a6bSchristos 
9614b169a6bSchristos   emit_symtypetab_state_t symstate;
9624b169a6bSchristos   memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
9634b169a6bSchristos 
9644b169a6bSchristos   /* Fill in an initial CTF header.  We will leave the label, object,
9654b169a6bSchristos      and function sections empty and only output a header, type section,
9664b169a6bSchristos      and string table.  The type section begins at a 4-byte aligned
9674b169a6bSchristos      boundary past the CTF header itself (at relative offset zero).  The flag
9684b169a6bSchristos      indicating a new-style function info section (an array of CTF_K_FUNCTION
9694b169a6bSchristos      type IDs in the types section) is flipped on.  */
9704b169a6bSchristos 
9714b169a6bSchristos   memset (&hdr, 0, sizeof (hdr));
9724b169a6bSchristos   hdr.cth_magic = CTF_MAGIC;
9734b169a6bSchristos   hdr.cth_version = CTF_VERSION;
9744b169a6bSchristos 
9754b169a6bSchristos   /* This is a new-format func info section, and the symtab and strtab come out
9764b169a6bSchristos      of the dynsym and dynstr these days.  */
9774b169a6bSchristos   hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
9784b169a6bSchristos 
979*12989c96Schristos   /* Propagate all symbols in the symtypetabs into the dynamic state, so that
980*12989c96Schristos      we can put them back in the right order.  Symbols already in the dynamic
981*12989c96Schristos      state, likely due to repeated serialization, are left unchanged.  */
982*12989c96Schristos   do
983*12989c96Schristos     {
984*12989c96Schristos       ctf_next_t *it = NULL;
985*12989c96Schristos       const char *sym_name;
986*12989c96Schristos       ctf_id_t sym;
987*12989c96Schristos 
988*12989c96Schristos       while ((sym = ctf_symbol_next_static (fp, &it, &sym_name,
989*12989c96Schristos 					    sym_functions)) != CTF_ERR)
990*12989c96Schristos 	if ((ctf_add_funcobjt_sym_forced (fp, sym_functions, sym_name, sym)) < 0)
991*12989c96Schristos 	  if (ctf_errno (fp) != ECTF_DUPLICATE)
992*12989c96Schristos 	    return NULL;			/* errno is set for us.  */
993*12989c96Schristos 
994*12989c96Schristos       if (ctf_errno (fp) != ECTF_NEXT_END)
995*12989c96Schristos 	return NULL;				/* errno is set for us.  */
996*12989c96Schristos     } while (sym_functions++ < 1);
997*12989c96Schristos 
998*12989c96Schristos   /* Figure out how big the symtypetabs are now.  */
999*12989c96Schristos 
10004b169a6bSchristos   if (ctf_symtypetab_sect_sizes (fp, &symstate, &hdr, &objt_size, &func_size,
10014b169a6bSchristos 				 &objtidx_size, &funcidx_size) < 0)
1002*12989c96Schristos     return NULL;				/* errno is set for us.  */
1003*12989c96Schristos 
1004*12989c96Schristos   /* Propagate all vars into the dynamic state, so we can put them back later.
1005*12989c96Schristos      Variables already in the dynamic state, likely due to repeated
1006*12989c96Schristos      serialization, are left unchanged.  */
1007*12989c96Schristos 
1008*12989c96Schristos   for (i = 0; i < fp->ctf_nvars; i++)
1009*12989c96Schristos     {
1010*12989c96Schristos       const char *name = ctf_strptr (fp, fp->ctf_vars[i].ctv_name);
1011*12989c96Schristos 
1012*12989c96Schristos       if (name != NULL && !ctf_dvd_lookup (fp, name))
1013*12989c96Schristos 	if (ctf_add_variable_forced (fp, name, fp->ctf_vars[i].ctv_type) < 0)
1014*12989c96Schristos 	  return NULL;				/* errno is set for us.  */
1015*12989c96Schristos     }
10164b169a6bSchristos 
10174b169a6bSchristos   for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
10184b169a6bSchristos        dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
10194b169a6bSchristos 
10204b169a6bSchristos   type_size = ctf_type_sect_size (fp);
10214b169a6bSchristos 
10224b169a6bSchristos   /* Compute the size of the CTF buffer we need, sans only the string table,
10234b169a6bSchristos      then allocate a new buffer and memcpy the finished header to the start of
10244b169a6bSchristos      the buffer.  (We will adjust this later with strtab length info.)  */
10254b169a6bSchristos 
10264b169a6bSchristos   hdr.cth_lbloff = hdr.cth_objtoff = 0;
10274b169a6bSchristos   hdr.cth_funcoff = hdr.cth_objtoff + objt_size;
10284b169a6bSchristos   hdr.cth_objtidxoff = hdr.cth_funcoff + func_size;
10294b169a6bSchristos   hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size;
10304b169a6bSchristos   hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size;
10314b169a6bSchristos   hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
10324b169a6bSchristos   hdr.cth_stroff = hdr.cth_typeoff + type_size;
10334b169a6bSchristos   hdr.cth_strlen = 0;
10344b169a6bSchristos 
10354b169a6bSchristos   buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
10364b169a6bSchristos 
10374b169a6bSchristos   if ((buf = malloc (buf_size)) == NULL)
1038*12989c96Schristos     {
1039*12989c96Schristos       ctf_set_errno (fp, EAGAIN);
1040*12989c96Schristos       return NULL;
1041*12989c96Schristos     }
10424b169a6bSchristos 
10434b169a6bSchristos   memcpy (buf, &hdr, sizeof (ctf_header_t));
10444b169a6bSchristos   t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
10454b169a6bSchristos 
10464b169a6bSchristos   hdrp = (ctf_header_t *) buf;
10474b169a6bSchristos   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
10484b169a6bSchristos     ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
10494b169a6bSchristos   if (fp->ctf_cuname != NULL)
10504b169a6bSchristos     ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
10514b169a6bSchristos 
10524b169a6bSchristos   if (ctf_emit_symtypetab_sects (fp, &symstate, &t, objt_size, func_size,
10534b169a6bSchristos 				 objtidx_size, funcidx_size) < 0)
10544b169a6bSchristos     goto err;
10554b169a6bSchristos 
10564b169a6bSchristos   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_varoff);
10574b169a6bSchristos 
10584b169a6bSchristos   /* Work over the variable list, translating everything into ctf_varent_t's and
10594b169a6bSchristos      prepping the string table.  */
10604b169a6bSchristos 
10614b169a6bSchristos   dvarents = (ctf_varent_t *) t;
10624b169a6bSchristos   for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
10634b169a6bSchristos        dvd = ctf_list_next (dvd), i++)
10644b169a6bSchristos     {
10654b169a6bSchristos       ctf_varent_t *var = &dvarents[i];
10664b169a6bSchristos 
10674b169a6bSchristos       ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name);
10684b169a6bSchristos       var->ctv_type = (uint32_t) dvd->dvd_type;
10694b169a6bSchristos     }
10704b169a6bSchristos   assert (i == nvars);
10714b169a6bSchristos 
10724b169a6bSchristos   t += sizeof (ctf_varent_t) * nvars;
10734b169a6bSchristos 
10744b169a6bSchristos   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
10754b169a6bSchristos 
1076*12989c96Schristos   /* Copy in existing static types, then emit new dynamic types.  */
1077*12989c96Schristos 
1078*12989c96Schristos   memcpy (t, fp->ctf_buf + fp->ctf_header->cth_typeoff,
1079*12989c96Schristos 	  fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff);
1080*12989c96Schristos   t += fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff;
10814b169a6bSchristos   ctf_emit_type_sect (fp, &t);
10824b169a6bSchristos 
10834b169a6bSchristos   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
10844b169a6bSchristos 
10854b169a6bSchristos   /* Construct the final string table and fill out all the string refs with the
1086*12989c96Schristos      final offsets.  */
10874b169a6bSchristos 
1088*12989c96Schristos   strtab = ctf_str_write_strtab (fp);
1089*12989c96Schristos 
1090*12989c96Schristos   if (strtab == NULL)
10914b169a6bSchristos     goto oom;
10924b169a6bSchristos 
10934b169a6bSchristos   /* Now the string table is constructed, we can sort the buffer of
10944b169a6bSchristos      ctf_varent_t's.  */
1095*12989c96Schristos   ctf_sort_var_arg_cb_t sort_var_arg = { fp, (ctf_strs_t *) strtab };
10964b169a6bSchristos   ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var,
10974b169a6bSchristos 	       &sort_var_arg);
10984b169a6bSchristos 
1099*12989c96Schristos   if ((newbuf = realloc (buf, buf_size + strtab->cts_len)) == NULL)
11004b169a6bSchristos     goto oom;
1101*12989c96Schristos 
11024b169a6bSchristos   buf = newbuf;
1103*12989c96Schristos   memcpy (buf + buf_size, strtab->cts_strs, strtab->cts_len);
11044b169a6bSchristos   hdrp = (ctf_header_t *) buf;
1105*12989c96Schristos   hdrp->cth_strlen = strtab->cts_len;
11064b169a6bSchristos   buf_size += hdrp->cth_strlen;
1107*12989c96Schristos   *bufsiz = buf_size;
11084b169a6bSchristos 
1109*12989c96Schristos   return buf;
11104b169a6bSchristos 
11114b169a6bSchristos oom:
1112*12989c96Schristos   ctf_set_errno (fp, EAGAIN);
11134b169a6bSchristos err:
11144b169a6bSchristos   free (buf);
1115*12989c96Schristos   return NULL;					/* errno is set for us.  */
11164b169a6bSchristos }
11174b169a6bSchristos 
11184b169a6bSchristos /* File writing.  */
11194b169a6bSchristos 
11204b169a6bSchristos /* Write the compressed CTF data stream to the specified gzFile descriptor.  The
11214b169a6bSchristos    whole stream is compressed, and cannot be read by CTF opening functions in
11224b169a6bSchristos    this library until it is decompressed.  (The functions below this one leave
11234b169a6bSchristos    the header uncompressed, and the CTF opening functions work on them without
11244b169a6bSchristos    manual decompression.)
11254b169a6bSchristos 
11264b169a6bSchristos    No support for (testing-only) endian-flipping.  */
11274b169a6bSchristos int
11284b169a6bSchristos ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
11294b169a6bSchristos {
1130*12989c96Schristos   unsigned char *buf;
1131*12989c96Schristos   unsigned char *p;
1132*12989c96Schristos   size_t bufsiz;
1133*12989c96Schristos   size_t len, written = 0;
11344b169a6bSchristos 
1135*12989c96Schristos   if ((buf = ctf_serialize (fp, &bufsiz)) == NULL)
1136*12989c96Schristos     return -1;					/* errno is set for us.  */
1137*12989c96Schristos 
1138*12989c96Schristos   p = buf;
1139*12989c96Schristos   while (written < bufsiz)
11404b169a6bSchristos     {
1141*12989c96Schristos       if ((len = gzwrite (fd, p, bufsiz - written)) <= 0)
1142*12989c96Schristos 	{
1143*12989c96Schristos 	  free (buf);
11444b169a6bSchristos 	  return (ctf_set_errno (fp, errno));
1145*12989c96Schristos 	}
1146*12989c96Schristos       written += len;
1147*12989c96Schristos       p += len;
11484b169a6bSchristos     }
11494b169a6bSchristos 
1150*12989c96Schristos   free (buf);
11514b169a6bSchristos   return 0;
11524b169a6bSchristos }
11534b169a6bSchristos 
11544b169a6bSchristos /* Optionally compress the specified CTF data stream and return it as a new
11554b169a6bSchristos    dynamically-allocated string.  Possibly write it with reversed
11564b169a6bSchristos    endianness.  */
11574b169a6bSchristos unsigned char *
11584b169a6bSchristos ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
11594b169a6bSchristos {
1160*12989c96Schristos   unsigned char *rawbuf;
1161*12989c96Schristos   unsigned char *buf = NULL;
11624b169a6bSchristos   unsigned char *bp;
1163*12989c96Schristos   ctf_header_t *rawhp, *hp;
1164*12989c96Schristos   unsigned char *src;
1165*12989c96Schristos   size_t rawbufsiz;
1166*12989c96Schristos   size_t alloc_len = 0;
1167*12989c96Schristos   int uncompressed = 0;
11684b169a6bSchristos   int flip_endian;
11694b169a6bSchristos   int rc;
11704b169a6bSchristos 
11714b169a6bSchristos   flip_endian = getenv ("LIBCTF_WRITE_FOREIGN_ENDIAN") != NULL;
11724b169a6bSchristos 
1173*12989c96Schristos   if ((rawbuf = ctf_serialize (fp, &rawbufsiz)) == NULL)
11744b169a6bSchristos     return NULL;				/* errno is set for us.  */
11754b169a6bSchristos 
1176*12989c96Schristos   if (!ctf_assert (fp, rawbufsiz >= sizeof (ctf_header_t)))
1177*12989c96Schristos     goto err;
1178*12989c96Schristos 
1179*12989c96Schristos   if (rawbufsiz >= threshold)
1180*12989c96Schristos     alloc_len = compressBound (rawbufsiz - sizeof (ctf_header_t))
1181*12989c96Schristos       + sizeof (ctf_header_t);
1182*12989c96Schristos 
1183*12989c96Schristos   /* Trivial operation if the buffer is incompressible or too small to bother
1184*12989c96Schristos      compressing, and we're not doing a forced write-time flip.  */
1185*12989c96Schristos 
1186*12989c96Schristos   if (rawbufsiz < threshold || rawbufsiz < alloc_len)
1187*12989c96Schristos     {
1188*12989c96Schristos       alloc_len = rawbufsiz;
1189*12989c96Schristos       uncompressed = 1;
1190*12989c96Schristos     }
1191*12989c96Schristos 
1192*12989c96Schristos   if (!flip_endian && uncompressed)
1193*12989c96Schristos     {
1194*12989c96Schristos       *size = rawbufsiz;
1195*12989c96Schristos       return rawbuf;
1196*12989c96Schristos     }
1197*12989c96Schristos 
1198*12989c96Schristos   if ((buf = malloc (alloc_len)) == NULL)
11994b169a6bSchristos     {
12004b169a6bSchristos       ctf_set_errno (fp, ENOMEM);
12014b169a6bSchristos       ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
1202*12989c96Schristos 		    (unsigned long) (alloc_len));
1203*12989c96Schristos       goto err;
12044b169a6bSchristos     }
12054b169a6bSchristos 
1206*12989c96Schristos   rawhp = (ctf_header_t *) rawbuf;
12074b169a6bSchristos   hp = (ctf_header_t *) buf;
1208*12989c96Schristos   memcpy (hp, rawbuf, sizeof (ctf_header_t));
1209*12989c96Schristos   bp = buf + sizeof (ctf_header_t);
1210*12989c96Schristos   *size = sizeof (ctf_header_t);
12114b169a6bSchristos 
1212*12989c96Schristos   if (!uncompressed)
12134b169a6bSchristos     hp->cth_flags |= CTF_F_COMPRESS;
12144b169a6bSchristos 
1215*12989c96Schristos   src = rawbuf + sizeof (ctf_header_t);
12164b169a6bSchristos 
12174b169a6bSchristos   if (flip_endian)
12184b169a6bSchristos     {
12194b169a6bSchristos       ctf_flip_header (hp);
1220*12989c96Schristos       if (ctf_flip (fp, rawhp, src, 1) < 0)
1221*12989c96Schristos 	goto err;				/* errno is set for us.  */
12224b169a6bSchristos     }
12234b169a6bSchristos 
1224*12989c96Schristos   if (!uncompressed)
12254b169a6bSchristos     {
1226*12989c96Schristos       size_t compress_len = alloc_len - sizeof (ctf_header_t);
1227*12989c96Schristos 
12284b169a6bSchristos       if ((rc = compress (bp, (uLongf *) &compress_len,
1229*12989c96Schristos 			  src, rawbufsiz - sizeof (ctf_header_t))) != Z_OK)
12304b169a6bSchristos 	{
12314b169a6bSchristos 	  ctf_set_errno (fp, ECTF_COMPRESS);
12324b169a6bSchristos 	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
1233*12989c96Schristos 	  goto err;
12344b169a6bSchristos 	}
12354b169a6bSchristos       *size += compress_len;
12364b169a6bSchristos     }
1237*12989c96Schristos   else
1238*12989c96Schristos     {
1239*12989c96Schristos       memcpy (bp, src, rawbufsiz - sizeof (ctf_header_t));
1240*12989c96Schristos       *size += rawbufsiz - sizeof (ctf_header_t);
1241*12989c96Schristos     }
12424b169a6bSchristos 
1243*12989c96Schristos   free (rawbuf);
12444b169a6bSchristos   return buf;
1245*12989c96Schristos err:
1246*12989c96Schristos   free (buf);
1247*12989c96Schristos   free (rawbuf);
1248*12989c96Schristos   return NULL;
12494b169a6bSchristos }
12504b169a6bSchristos 
12514b169a6bSchristos /* Compress the specified CTF data stream and write it to the specified file
12524b169a6bSchristos    descriptor.  */
12534b169a6bSchristos int
12544b169a6bSchristos ctf_compress_write (ctf_dict_t *fp, int fd)
12554b169a6bSchristos {
12564b169a6bSchristos   unsigned char *buf;
12574b169a6bSchristos   unsigned char *bp;
12584b169a6bSchristos   size_t tmp;
12594b169a6bSchristos   ssize_t buf_len;
12604b169a6bSchristos   ssize_t len;
12614b169a6bSchristos   int err = 0;
12624b169a6bSchristos 
12634b169a6bSchristos   if ((buf = ctf_write_mem (fp, &tmp, 0)) == NULL)
12644b169a6bSchristos     return -1;					/* errno is set for us.  */
12654b169a6bSchristos 
12664b169a6bSchristos   buf_len = tmp;
12674b169a6bSchristos   bp = buf;
12684b169a6bSchristos 
12694b169a6bSchristos   while (buf_len > 0)
12704b169a6bSchristos     {
12714b169a6bSchristos       if ((len = write (fd, bp, buf_len)) < 0)
12724b169a6bSchristos 	{
12734b169a6bSchristos 	  err = ctf_set_errno (fp, errno);
12744b169a6bSchristos 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
12754b169a6bSchristos 	  goto ret;
12764b169a6bSchristos 	}
12774b169a6bSchristos       buf_len -= len;
12784b169a6bSchristos       bp += len;
12794b169a6bSchristos     }
12804b169a6bSchristos 
12814b169a6bSchristos ret:
12824b169a6bSchristos   free (buf);
12834b169a6bSchristos   return err;
12844b169a6bSchristos }
12854b169a6bSchristos 
12864b169a6bSchristos /* Write the uncompressed CTF data stream to the specified file descriptor.  */
12874b169a6bSchristos int
12884b169a6bSchristos ctf_write (ctf_dict_t *fp, int fd)
12894b169a6bSchristos {
12904b169a6bSchristos   unsigned char *buf;
12914b169a6bSchristos   unsigned char *bp;
12924b169a6bSchristos   size_t tmp;
12934b169a6bSchristos   ssize_t buf_len;
12944b169a6bSchristos   ssize_t len;
12954b169a6bSchristos   int err = 0;
12964b169a6bSchristos 
12974b169a6bSchristos   if ((buf = ctf_write_mem (fp, &tmp, (size_t) -1)) == NULL)
12984b169a6bSchristos     return -1;					/* errno is set for us.  */
12994b169a6bSchristos 
13004b169a6bSchristos   buf_len = tmp;
13014b169a6bSchristos   bp = buf;
13024b169a6bSchristos 
13034b169a6bSchristos   while (buf_len > 0)
13044b169a6bSchristos     {
13054b169a6bSchristos       if ((len = write (fd, bp, buf_len)) < 0)
13064b169a6bSchristos 	{
13074b169a6bSchristos 	  err = ctf_set_errno (fp, errno);
13084b169a6bSchristos 	  ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
13094b169a6bSchristos 	  goto ret;
13104b169a6bSchristos 	}
13114b169a6bSchristos       buf_len -= len;
13124b169a6bSchristos       bp += len;
13134b169a6bSchristos     }
13144b169a6bSchristos 
13154b169a6bSchristos ret:
13164b169a6bSchristos   free (buf);
13174b169a6bSchristos   return err;
13184b169a6bSchristos }
1319