Wolfgang Thallergcc16 merge934c3885 months agoHistory
1305 lines · 38.5 KB · C
RawDownload
/* CTF dict creation.   Copyright (C) 2019-2026 Free Software Foundation, Inc.    This file is part of libctf.    libctf is free software; you can redistribute it and/or modify it under   the terms of the GNU General Public License as published by the Free   Software Foundation; either version 3, or (at your option) any later   version.    This program is distributed in the hope that it will be useful, but   WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License for more details.    You should have received a copy of the GNU General Public License   along with this program; see the file COPYING.  If not see   <http://www.gnu.org/licenses/>.  */ #include <ctf-impl.h>#include <assert.h>#include <string.h>#include <unistd.h>#include <zlib.h> #include <elf.h>#include "elf-bfd.h" /* Symtypetab sections.  */ /* Symtypetab emission flags.  */ #define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1#define CTF_SYMTYPETAB_EMIT_PAD 0x2#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4 /* Properties of symtypetab emission, shared by symtypetab section   sizing and symtypetab emission itself.  */ typedef struct emit_symtypetab_state{  /* True if linker-reported symbols are being filtered out.  symfp is set if     this is true: otherwise, indexing is forced and the symflags indicate as     much. */  int filter_syms;   /* True if symbols are being sorted.  */  int sort_syms;   /* Flags for symtypetab emission.  */  int symflags;   /* The dict to which the linker has reported symbols.  */  ctf_dict_t *symfp;   /* The maximum number of objects seen.  */  size_t maxobjt;   /* The maximum number of func info entris seen.  */  size_t maxfunc;} emit_symtypetab_state_t; /* Determine if a symbol is "skippable" and should never appear in the   symtypetab sections.  */ intctf_symtab_skippable (ctf_link_sym_t *sym){  /* Never skip symbols whose name is not yet known.  */  if (sym->st_nameidx_set)    return 0;   return (sym->st_name == NULL || sym->st_name[0] == 0	  || sym->st_shndx == SHN_UNDEF	  || strcmp (sym->st_name, "_START_") == 0	  || strcmp (sym->st_name, "_END_") == 0	  || strcmp (sym->st_name, "_DYNAMIC") == 0	  || strcmp (sym->st_name, "_GLOBAL_OFFSET_TABLE_") == 0	  || strcmp (sym->st_name, "_PROCEDURE_LINKAGE_TABLE_") == 0	  || strcmp (sym->st_name, "_edata") == 0	  || strcmp (sym->st_name, "_end") == 0	  || strcmp (sym->st_name, "_etext") == 0	  || (sym->st_type == STT_OBJECT && sym->st_shndx == SHN_EXTABS	      && sym->st_value == 0));} /* Get the number of symbols in a symbol hash, the count of symbols, the maximum   seen, the eventual size, without any padding elements, of the func/data and   (if generated) index sections, and the size of accumulated padding elements.   The linker-reported set of symbols is found in SYMFP: it may be NULL if   symbol filtering is not desired, in which case CTF_SYMTYPETAB_FORCE_INDEXED   will always be set in the flags.    Also figure out if any symbols need to be moved to the variable section, and   add them (if not already present).  */ _libctf_nonnull_ ((1,3,4,5,6,7,8))static intsymtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,		    size_t *count, size_t *max, size_t *unpadsize,		    size_t *padsize, size_t *idxsize, int flags){  ctf_next_t *i = NULL;  const void *name;  const void *ctf_sym;  ctf_dynhash_t *linker_known = NULL;  int err;  int beyond_max = 0;   *count = 0;  *max = 0;  *unpadsize = 0;  *idxsize = 0;  *padsize = 0;   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))    {      /* Make a dynhash citing only symbols reported by the linker of the	 appropriate type, then traverse all potential-symbols we know the types	 of, removing them from linker_known as we go.  Once this is done, the	 only symbols remaining in linker_known are symbols we don't know the	 types of: we must emit pads for those symbols that are below the	 maximum symbol we will emit (any beyond that are simply skipped). 	 If there are none, this symtypetab will be empty: just report that.  */       if (!symfp->ctf_dynsyms)	return 0;       if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,					      NULL, NULL)) == NULL)	return (ctf_set_errno (fp, ENOMEM));       while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,				       &name, &ctf_sym)) == 0)	{	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym; 	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)	       && sym->st_type != STT_FUNC)	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)		  && sym->st_type != STT_OBJECT))	    continue; 	  if (ctf_symtab_skippable (sym))	    continue; 	  /* This should only be true briefly before all the names are	     finalized, long before we get this far.  */	  if (!ctf_assert (fp, !sym->st_nameidx_set))	    return -1;				/* errno is set for us.  */ 	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)	    {	      ctf_dynhash_destroy (linker_known);	      return (ctf_set_errno (fp, ENOMEM));	    }	}      if (err != ECTF_NEXT_END)	{	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "				  "serialization"));	  ctf_dynhash_destroy (linker_known);	  return (ctf_set_errno (fp, err));	}    }   while ((err = ctf_dynhash_cnext (symhash, &i, &name, NULL)) == 0)    {      ctf_link_sym_t *sym;       if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))	{	  /* Linker did not report symbol in symtab.  Remove it from the	     set of known data symbols and continue.  */	  if ((sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, name)) == NULL)	    {	      ctf_dynhash_remove (symhash, name);	      continue;	    } 	  /* We don't remove skippable symbols from the symhash because we don't	     want them to be migrated into variables.  */	  if (ctf_symtab_skippable (sym))	    continue; 	  if ((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)	      && sym->st_type != STT_FUNC)	    {	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "					"function but is of type %x.  "					"The symbol type lookup tables "					"are probably corrupted"),			    sym->st_name, sym->st_symidx, sym->st_type);	      ctf_dynhash_remove (symhash, name);	      continue;	    }	  else if (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)		   && sym->st_type != STT_OBJECT)	    {	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "					"data object but is of type %x.  "					"The symbol type lookup tables "					"are probably corrupted"),			    sym->st_name, sym->st_symidx, sym->st_type);	      ctf_dynhash_remove (symhash, name);	      continue;	    } 	  ctf_dynhash_remove (linker_known, name); 	  if (*max < sym->st_symidx)	    *max = sym->st_symidx;	}      else	(*max)++;       *unpadsize += sizeof (uint32_t);      (*count)++;    }  if (err != ECTF_NEXT_END)    {      ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "				  "serialization"));      ctf_dynhash_destroy (linker_known);      return (ctf_set_errno (fp, err));    }   if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))    {      while ((err = ctf_dynhash_cnext (linker_known, &i, NULL, &ctf_sym)) == 0)	{	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym; 	  if (sym->st_symidx > *max)	    beyond_max++;	}      if (err != ECTF_NEXT_END)	{	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "				      "during CTF serialization"));	  ctf_dynhash_destroy (linker_known);	  return (ctf_set_errno (fp, err));	}    }   *idxsize = *count * sizeof (uint32_t);  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))    *padsize = (ctf_dynhash_elements (linker_known) - beyond_max) * sizeof (uint32_t);   ctf_dynhash_destroy (linker_known);  return 0;} /* Emit an objt or func symtypetab into DP in a particular order defined by an   array of ctf_link_sym_t or symbol names passed in.  The index has NIDX   elements in it: unindexed output would terminate at symbol OUTMAX and is in   any case no larger than SIZE bytes.  Some index elements are expected to be   skipped: see symtypetab_density.  The linker-reported set of symbols (if any)   is found in SYMFP. */static intemit_symtypetab (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,		 ctf_link_sym_t **idx, const char **nameidx, uint32_t nidx,		 uint32_t outmax, int size, int flags){  uint32_t i;  uint32_t *dpp = dp;  ctf_dynhash_t *symhash;   ctf_dprintf ("Emitting table of size %i, outmax %u, %u symtypetab entries, "	       "flags %i\n", size, outmax, nidx, flags);   /* Empty table? Nothing to do.  */  if (size == 0)    return 0;   if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)    symhash = fp->ctf_funchash;  else    symhash = fp->ctf_objthash;   for (i = 0; i < nidx; i++)    {      const char *sym_name;      void *type;       /* If we have a linker-reported set of symbols, we may be given that set	 to work from, or a set of symbol names.  In both cases we want to look	 at the corresponding linker-reported symbol (if any).  */      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))	{	  ctf_link_sym_t *this_link_sym; 	  if (idx)	    this_link_sym = idx[i];	  else	    this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, nameidx[i]); 	  /* Unreported symbol number.  No pad, no nothing.  */	  if (!this_link_sym)	    continue; 	  /* Symbol of the wrong type, or skippable?  This symbol is not in this	     table.  */	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)	       && this_link_sym->st_type != STT_FUNC)	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)		  && this_link_sym->st_type != STT_OBJECT))	    continue; 	  if (ctf_symtab_skippable (this_link_sym))	    continue; 	  sym_name = this_link_sym->st_name; 	  /* Linker reports symbol of a different type to the symbol we actually	     added?  Skip the symbol.  No pad, since the symbol doesn't actually	     belong in this table at all.  (Warned about in	     symtypetab_density.)  */	  if ((this_link_sym->st_type == STT_FUNC)	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))	    continue; 	  if ((this_link_sym->st_type == STT_OBJECT)	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))	    continue;	}      else	sym_name = nameidx[i];       /* Symbol in index but no type set? Silently skip and (optionally)	 pad.  (In force-indexed mode, this is also where we track symbols of	 the wrong type for this round of insertion.)  */      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)	{	  if (flags & CTF_SYMTYPETAB_EMIT_PAD)	    *dpp++ = 0;	  continue;	}       if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) < size))	return -1;				/* errno is set for us.  */       *dpp++ = (ctf_id_t) (uintptr_t) type;       /* When emitting unindexed output, all later symbols are pads: stop	 early.  */      if ((flags & CTF_SYMTYPETAB_EMIT_PAD) && idx[i]->st_symidx == outmax)	break;    }   return 0;} /* Emit an objt or func symtypetab index into DP in a paticular order defined by   an array of symbol names passed in.  Stop at NIDX.  The linker-reported set   of symbols (if any) is found in SYMFP. */static intemit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,		       const char **idx, uint32_t nidx, int size, int flags){  uint32_t i;  uint32_t *dpp = dp;  ctf_dynhash_t *symhash;   ctf_dprintf ("Emitting index of size %i, %u entries reported by linker, "	       "flags %i\n", size, nidx, flags);   /* Empty table? Nothing to do.  */  if (size == 0)    return 0;   if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)    symhash = fp->ctf_funchash;  else    symhash = fp->ctf_objthash;   /* Indexes should always be unpadded.  */  if (!ctf_assert (fp, !(flags & CTF_SYMTYPETAB_EMIT_PAD)))    return -1;					/* errno is set for us.  */   for (i = 0; i < nidx; i++)    {      const char *sym_name;      void *type;       if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))	{	  ctf_link_sym_t *this_link_sym; 	  this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, idx[i]); 	  /* This is an index: unreported symbols should never appear in it.  */	  if (!ctf_assert (fp, this_link_sym != NULL))	    return -1;				/* errno is set for us.  */ 	  /* Symbol of the wrong type, or skippable?  This symbol is not in this	     table.  */	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)	       && this_link_sym->st_type != STT_FUNC)	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)		  && this_link_sym->st_type != STT_OBJECT))	    continue; 	  if (ctf_symtab_skippable (this_link_sym))	    continue; 	  sym_name = this_link_sym->st_name; 	  /* Linker reports symbol of a different type to the symbol we actually	     added?  Skip the symbol.  */	  if ((this_link_sym->st_type == STT_FUNC)	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))	    continue; 	  if ((this_link_sym->st_type == STT_OBJECT)	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))	    continue;	}      else	sym_name = idx[i];       /* Symbol in index and reported by linker, but no type set? Silently skip	 and (optionally) pad.  (In force-indexed mode, this is also where we	 track symbols of the wrong type for this round of insertion.)  */      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)	continue;       ctf_str_add_ref (fp, sym_name, dpp++);       if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) <= size))	return -1;				/* errno is set for us.  */    }   return 0;} /* Delete symbols that have been assigned names from the variable section.  Must   be called from within ctf_serialize, because that is the only place you can   safely delete variables without messing up ctf_rollback.  */ static intsymtypetab_delete_nonstatics (ctf_dict_t *fp, ctf_dict_t *symfp){  ctf_dvdef_t *dvd, *nvd;  ctf_id_t type;   for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)    {      nvd = ctf_list_next (dvd);       if ((((type = (ctf_id_t) (uintptr_t)	     ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)	   || (type = (ctf_id_t) (uintptr_t)	       ctf_dynhash_lookup (fp->ctf_funchash, dvd->dvd_name)) > 0)	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL	  && type == dvd->dvd_type)	ctf_dvd_delete (fp, dvd);    }   return 0;} /* Figure out the sizes of the symtypetab sections, their indexed state,   etc.  */static intctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s,			   ctf_header_t *hdr, size_t *objt_size,			   size_t *func_size, size_t *objtidx_size,			   size_t *funcidx_size){  size_t nfuncs, nobjts;  size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize;   /* If doing a writeout as part of linking, and the link flags request it,     filter out reported symbols from the variable section, and filter out all     other symbols from the symtypetab sections.  (If we are not linking, the     symbols are sorted; if we are linking, don't bother sorting if we are not     filtering out reported symbols: this is almost certainly an ld -r and only     the linker is likely to consume these symtypetabs again.  The linker     doesn't care what order the symtypetab entries are in, since it only     iterates over symbols and does not use the ctf_lookup_by_symbol* API.)  */   s->sort_syms = 1;  if (fp->ctf_flags & LCTF_LINKING)    {      s->filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);      if (!s->filter_syms)	s->sort_syms = 0;    }   /* Find the dict to which the linker has reported symbols, if any.  */   if (s->filter_syms)    {      if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms)	s->symfp = fp->ctf_parent;      else	s->symfp = fp;    }

Lines 1–500 of 1305.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t