Wolfgang Thallergcc16 merge934c3885 months agoHistory
2085 lines · 60.9 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 <string.h>#include <unistd.h> #ifndef EOVERFLOW#define EOVERFLOW ERANGE#endif #ifndef roundup#define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))#endif /* The initial size of a dynamic type's vlen in members.  Arbitrary: the bigger   this is, the less allocation needs to be done for small structure   initialization, and the more memory is wasted for small structures during CTF   construction.  No effect on generated CTF or ctf_open()ed CTF. */#define INITIAL_VLEN 16 /* Make sure the ptrtab has enough space for at least one more type.    We start with 4KiB of ptrtab, enough for a thousand types, then grow it 25%   at a time.  */ static intctf_grow_ptrtab (ctf_dict_t *fp){  size_t new_ptrtab_len = fp->ctf_ptrtab_len;   /* We allocate one more ptrtab entry than we need, for the initial zero,     plus one because the caller will probably allocate a new type.      Equally, if the ptrtab is small -- perhaps due to ctf_open of a small     dict -- boost it by quite a lot at first, so we don't need to keep     realloc()ing.  */   if (fp->ctf_ptrtab == NULL || fp->ctf_ptrtab_len < 1024)    new_ptrtab_len = 1024;  else if ((fp->ctf_typemax + 2) > fp->ctf_ptrtab_len)    new_ptrtab_len = fp->ctf_ptrtab_len * 1.25;   if (new_ptrtab_len != fp->ctf_ptrtab_len)    {      uint32_t *new_ptrtab;       if ((new_ptrtab = realloc (fp->ctf_ptrtab,				 new_ptrtab_len * sizeof (uint32_t))) == NULL)	return (ctf_set_errno (fp, ENOMEM));       fp->ctf_ptrtab = new_ptrtab;      memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,	      (new_ptrtab_len - fp->ctf_ptrtab_len) * sizeof (uint32_t));      fp->ctf_ptrtab_len = new_ptrtab_len;    }  return 0;} /* Make sure a vlen has enough space: expand it otherwise.  Unlike the ptrtab,   which grows quite slowly, the vlen grows in big jumps because it is quite   expensive to expand: the caller has to scan the old vlen for string refs   first and remove them, then re-add them afterwards.  The initial size is   more or less arbitrary.  */static intctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen){  unsigned char *old = dtd->dtd_vlen;   if (dtd->dtd_vlen_alloc > vlen)    return 0;   if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen,				dtd->dtd_vlen_alloc * 2)) == NULL)    {      dtd->dtd_vlen = old;      return (ctf_set_errno (fp, ENOMEM));    }  memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);  dtd->dtd_vlen_alloc *= 2;  return 0;} /* To create an empty CTF dict, we just declare a zeroed header and call   ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new dict r/w and   initialize the dynamic members.  We start assigning type IDs at 1 because   type ID 0 is used as a sentinel and a not-found indicator.  */ ctf_dict_t *ctf_create (int *errp){  static const ctf_header_t hdr = { .cth_preamble = { CTF_MAGIC, CTF_VERSION, 0 } };   ctf_dynhash_t *structs = NULL, *unions = NULL, *enums = NULL, *names = NULL;  ctf_sect_t cts;  ctf_dict_t *fp;   libctf_init_debug();   structs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,				NULL, NULL);  unions = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,			       NULL, NULL);  enums = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,			      NULL, NULL);  names = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,			      NULL, NULL);  if (!structs || !unions || !enums || !names)    {      ctf_set_open_errno (errp, EAGAIN);      goto err;    }   cts.cts_name = _CTF_SECTION;  cts.cts_data = &hdr;  cts.cts_size = sizeof (hdr);  cts.cts_entsize = 1;   if ((fp = ctf_bufopen (&cts, NULL, NULL, errp)) == NULL)    goto err;   /* These hashes will have been initialized with a starting size of zero,     which is surely wrong.  Use ones with slightly larger sizes.  */  ctf_dynhash_destroy (fp->ctf_structs);  ctf_dynhash_destroy (fp->ctf_unions);  ctf_dynhash_destroy (fp->ctf_enums);  ctf_dynhash_destroy (fp->ctf_names);  fp->ctf_structs = structs;  fp->ctf_unions = unions;  fp->ctf_enums = enums;  fp->ctf_names = names;  fp->ctf_dtoldid = 0;  fp->ctf_snapshot_lu = 0;   /* Make sure the ptrtab starts out at a reasonable size.  */   ctf_set_ctl_hashes (fp);  if (ctf_grow_ptrtab (fp) < 0)    {      ctf_set_open_errno (errp, ctf_errno (fp));      ctf_dict_close (fp);      return NULL;    }   return fp;  err:  ctf_dynhash_destroy (structs);  ctf_dynhash_destroy (unions);  ctf_dynhash_destroy (enums);  ctf_dynhash_destroy (names);  return NULL;} /* Compatibility: just update the threshold for ctf_discard.  */intctf_update (ctf_dict_t *fp){  fp->ctf_dtoldid = fp->ctf_typemax;  return 0;} ctf_dynhash_t *ctf_name_table (ctf_dict_t *fp, int kind){  switch (kind)    {    case CTF_K_STRUCT:      return fp->ctf_structs;    case CTF_K_UNION:      return fp->ctf_unions;    case CTF_K_ENUM:      return fp->ctf_enums;    default:      return fp->ctf_names;    }} intctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind){  const char *name;  if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,			  dtd) < 0)    return ctf_set_errno (fp, ENOMEM);   if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name      && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)    {      if (ctf_dynhash_insert (ctf_name_table (fp, kind),			      (char *) name, (void *) (uintptr_t)			      dtd->dtd_type) < 0)	{	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)			      dtd->dtd_type);	  return ctf_set_errno (fp, ENOMEM);	}    }  ctf_list_append (&fp->ctf_dtdefs, dtd);  return 0;} voidctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd){  int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);  size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);  int name_kind = kind;  const char *name;   ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);   switch (kind)    {    case CTF_K_STRUCT:    case CTF_K_UNION:      {	ctf_lmember_t *memb = (ctf_lmember_t *) dtd->dtd_vlen;	size_t i; 	for (i = 0; i < vlen; i++)	  ctf_str_remove_ref (fp, ctf_strraw (fp, memb[i].ctlm_name),			      &memb[i].ctlm_name);      }      break;    case CTF_K_ENUM:      {	ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;	size_t i; 	for (i = 0; i < vlen; i++)	  ctf_str_remove_ref (fp, ctf_strraw (fp, en[i].cte_name),			      &en[i].cte_name);      }      break;    case CTF_K_FORWARD:      name_kind = dtd->dtd_data.ctt_type;      break;    }  free (dtd->dtd_vlen);  dtd->dtd_vlen_alloc = 0;   if (dtd->dtd_data.ctt_name      && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)    {      if (LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))	ctf_dynhash_remove (ctf_name_table (fp, name_kind), name);      ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name);    }   ctf_list_delete (&fp->ctf_dtdefs, dtd);  free (dtd);} ctf_dtdef_t *ctf_dtd_lookup (const ctf_dict_t *fp, ctf_id_t type){  if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type))    fp = fp->ctf_parent;   return (ctf_dtdef_t *)    ctf_dynhash_lookup (fp->ctf_dthash, (void *) (uintptr_t) type);} ctf_dtdef_t *ctf_dynamic_type (const ctf_dict_t *fp, ctf_id_t id){  ctf_id_t idx;   if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id))    fp = fp->ctf_parent;   idx = LCTF_TYPE_TO_INDEX(fp, id);   if ((unsigned long) idx <= fp->ctf_typemax)    return ctf_dtd_lookup (fp, id);  return NULL;} static intctf_static_type (const ctf_dict_t *fp, ctf_id_t id){  ctf_id_t idx;   if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id))    fp = fp->ctf_parent;   idx = LCTF_TYPE_TO_INDEX(fp, id);   return ((unsigned long) idx <= fp->ctf_stypes);} intctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd){  if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)    return ctf_set_errno (fp, ENOMEM);  ctf_list_append (&fp->ctf_dvdefs, dvd);  return 0;} voidctf_dvd_delete (ctf_dict_t *fp, ctf_dvdef_t *dvd){  ctf_dynhash_remove (fp->ctf_dvhash, dvd->dvd_name);  free (dvd->dvd_name);   ctf_list_delete (&fp->ctf_dvdefs, dvd);  free (dvd);} ctf_dvdef_t *ctf_dvd_lookup (const ctf_dict_t *fp, const char *name){  return (ctf_dvdef_t *) ctf_dynhash_lookup (fp->ctf_dvhash, name);} /* Discard all of the dynamic type definitions and variable definitions that   have been added to the dict since the last call to ctf_update().  We locate   such types by scanning the dtd list and deleting elements that have type IDs   greater than ctf_dtoldid, which is set by ctf_update(), above, and by   scanning the variable list and deleting elements that have update IDs equal   to the current value of the last-update snapshot count (indicating that they   were added after the most recent call to ctf_update()).  */intctf_discard (ctf_dict_t *fp){  ctf_snapshot_id_t last_update =    { fp->ctf_dtoldid,      fp->ctf_snapshot_lu + 1 };   return (ctf_rollback (fp, last_update));} ctf_snapshot_id_tctf_snapshot (ctf_dict_t *fp){  ctf_snapshot_id_t snapid;  snapid.dtd_id = fp->ctf_typemax;  snapid.snapshot_id = fp->ctf_snapshots++;  return snapid;} /* Like ctf_discard(), only discards everything after a particular ID.  */intctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id){  ctf_dtdef_t *dtd, *ntd;  ctf_dvdef_t *dvd, *nvd;   if (id.snapshot_id < fp->ctf_stypes)    return (ctf_set_errno (fp, ECTF_RDONLY));   if (fp->ctf_snapshot_lu >= id.snapshot_id)    return (ctf_set_errno (fp, ECTF_OVERROLLBACK));   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)    {      int kind;      const char *name;       ntd = ctf_list_next (dtd);       if (LCTF_TYPE_TO_INDEX (fp, dtd->dtd_type) <= id.dtd_id)	continue;       kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);      if (kind == CTF_K_FORWARD)	kind = dtd->dtd_data.ctt_type;       if (dtd->dtd_data.ctt_name	  && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL	  && LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))	{	  ctf_dynhash_remove (ctf_name_table (fp, kind), name);	  ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name);	}       ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);      ctf_dtd_delete (fp, dtd);    }   for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)    {      nvd = ctf_list_next (dvd);       if (dvd->dvd_snapshots <= id.snapshot_id)	continue;       ctf_dvd_delete (fp, dvd);    }   fp->ctf_typemax = id.dtd_id;  fp->ctf_snapshots = id.snapshot_id;   return 0;} /* Note: vlen is the amount of space *allocated* for the vlen.  It may well not   be the amount of space used (yet): the space used is declared in per-kind   fashion in the dtd_data's info word.  */static ctf_id_tctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,		 size_t vlen, ctf_dtdef_t **rp){  ctf_dtdef_t *dtd;  ctf_id_t type;   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)    return (ctf_set_typed_errno (fp, EINVAL));   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)    return (ctf_set_typed_errno (fp, ECTF_FULL));   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))    return (ctf_set_typed_errno (fp, ECTF_FULL));   /* Prohibit addition of a root-visible type that is already present     in the non-dynamic portion. */   if (flag == CTF_ADD_ROOT && name != NULL && name[0] != '\0')    {      ctf_id_t existing;       if (((existing = ctf_dynhash_lookup_type (ctf_name_table (fp, kind),						name)) > 0)	  && ctf_static_type (fp, existing))	return (ctf_set_typed_errno (fp, ECTF_RDONLY));    }   /* Make sure ptrtab always grows to be big enough for all types.  */  if (ctf_grow_ptrtab (fp) < 0)      return CTF_ERR;				/* errno is set for us. */   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)    return (ctf_set_typed_errno (fp, EAGAIN));   dtd->dtd_vlen_alloc = vlen;  if (vlen > 0)    {      if ((dtd->dtd_vlen = calloc (1, vlen)) == NULL)	goto oom;    }  else    dtd->dtd_vlen = NULL;   type = ++fp->ctf_typemax;  type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD));   dtd->dtd_data.ctt_name = ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name);  dtd->dtd_type = type;   if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')    goto oom;   if (ctf_dtd_insert (fp, dtd, flag, kind) < 0)    goto err;					/* errno is set for us.  */   *rp = dtd;  return type;  oom:  ctf_set_errno (fp, EAGAIN); err:  free (dtd->dtd_vlen);  free (dtd);  return CTF_ERR;} /* When encoding integer sizes, we want to convert a byte count in the range   1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function   is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.  */static size_tclp2 (size_t x){  x--;   x |= (x >> 1);  x |= (x >> 2);  x |= (x >> 4);  x |= (x >> 8);  x |= (x >> 16);   return (x + 1);

Lines 1–500 of 2085.

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