Wolfgang Thallergcc16 merge934c3885 months agoHistory
1723 lines · 44.6 KB · C
RawDownload
/* Type handling functions.   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> /* Determine whether a type is a parent or a child.  */ intctf_type_isparent (ctf_dict_t *fp, ctf_id_t id){  return (LCTF_TYPE_ISPARENT (fp, id));} intctf_type_ischild (ctf_dict_t * fp, ctf_id_t id){  return (LCTF_TYPE_ISCHILD (fp, id));} /* Expand a structure element into the passed-in ctf_lmember_t.  */ static intctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp,		   unsigned char *vlen, size_t vbytes, size_t n){  if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info)))    return -1;					/* errno is set for us.  */   /* Already large.  */  if (tp->ctt_size >= CTF_LSTRUCT_THRESH)    {      ctf_lmember_t *lmp = (ctf_lmember_t *) vlen;       if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes))	return -1;				/* errno is set for us.  */       memcpy (dst, &lmp[n], sizeof (ctf_lmember_t));    }  else    {      ctf_member_t *mp = (ctf_member_t *) vlen;      dst->ctlm_name = mp[n].ctm_name;      dst->ctlm_type = mp[n].ctm_type;      dst->ctlm_offsetlo = mp[n].ctm_offset;      dst->ctlm_offsethi = 0;    }  return 0;} /* Iterate over the members of a STRUCT or UNION.  We pass the name, member   type, and offset of each member to the specified callback function.  */ intctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg){  ctf_next_t *i = NULL;  ssize_t offset;  const char *name;  ctf_id_t membtype;   while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0)    {      int rc;      if ((rc = func (name, membtype, offset, arg)) != 0)	{	  ctf_next_destroy (i);	  return rc;	}    }  if (ctf_errno (fp) != ECTF_NEXT_END)    return -1;					/* errno is set for us.  */   return 0;} /* Iterate over the members of a STRUCT or UNION, returning each member's   offset and optionally name and member type in turn.  On end-of-iteration,   returns -1.  If FLAGS is CTF_MN_RECURSE, recurse into unnamed members.  */ ssize_tctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,		 const char **name, ctf_id_t *membtype, int flags){  ctf_dict_t *ofp = fp;  uint32_t kind;  ssize_t offset;  uint32_t max_vlen;  ctf_next_t *i = *it;   if (!i)    {      const ctf_type_t *tp;      ctf_dtdef_t *dtd;      ssize_t size;      ssize_t increment;       if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)	return -1;			/* errno is set for us.  */       if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)	return -1;			/* errno is set for us.  */       if ((i = ctf_next_create ()) == NULL)	return ctf_set_errno (ofp, ENOMEM);      i->cu.ctn_fp = ofp;      i->ctn_tp = tp;       ctf_get_ctt_size (fp, tp, &size, &increment);      kind = LCTF_INFO_KIND (fp, tp->ctt_info);       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)	{	  ctf_next_destroy (i);	  return (ctf_set_errno (ofp, ECTF_NOTSOU));	}       if ((dtd = ctf_dynamic_type (fp, type)) != NULL)	{	  i->u.ctn_vlen = dtd->dtd_vlen;	  i->ctn_size = dtd->dtd_vlen_alloc;	}      else	{	  unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); 	  i->u.ctn_vlen = (unsigned char *) tp + increment;	  i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);;	}      i->ctn_iter_fun = (void (*) (void)) ctf_member_next;      i->ctn_n = 0;      *it = i;    }   if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun)    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN));   if (ofp != i->cu.ctn_fp)    return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP));   /* Resolve to the native dict of this type.  */  if ((fp = ctf_get_dict (ofp, type)) == NULL)    return (ctf_set_errno (ofp, ECTF_NOPARENT));   max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);   /* When we hit an unnamed struct/union member, we set ctn_type to indicate     that we are inside one, then return the unnamed member: on the next call,     we must skip over top-level member iteration in favour of iteration within     the sub-struct until it later turns out that that iteration has ended.  */  retry:  if (!i->ctn_type)    {      ctf_lmember_t memb;      const char *membname;       if (i->ctn_n == max_vlen)	goto end_iter;       if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,			     i->ctn_n) < 0)        return (ctf_set_errno (ofp, ctf_errno (fp)));       membname = ctf_strptr (fp, memb.ctlm_name);       if (name)	*name = membname;      if (membtype)	*membtype = memb.ctlm_type;      offset = (unsigned long) CTF_LMEM_OFFSET (&memb);       if (membname[0] == 0)	{	  ctf_id_t resolved; 	  if ((resolved = ctf_type_resolve (fp, memb.ctlm_type)) == CTF_ERR)	    {	      if (ctf_errno (fp) != ECTF_NONREPRESENTABLE)		return -1;			/* errno is set for us.  */	      resolved = memb.ctlm_type;	    } 	  if (ctf_type_kind (fp, resolved) == CTF_K_STRUCT	      || ctf_type_kind (fp, resolved) == CTF_K_UNION)	    i->ctn_type = resolved;	}      i->ctn_n++;       /* The callers might want automatic recursive sub-struct traversal.  */      if (!(flags & CTF_MN_RECURSE))	i->ctn_type = 0;       /* Sub-struct traversal starting?  Take note of the offset of this member,	 for later boosting of sub-struct members' offsets.  */      if (i->ctn_type)	i->ctn_increment = offset;    }  /* Traversing a sub-struct?  Just return it, with the offset adjusted.  */  else    {      ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name,				     membtype, flags);       if (ret >= 0)	return ret + i->ctn_increment;       if (ctf_errno (fp) != ECTF_NEXT_END)	{	  ctf_next_destroy (i);	  *it = NULL;	  i->ctn_type = 0;	  ctf_set_errno (ofp, ctf_errno (fp));	  return ret;	}       if (!ctf_assert (fp, (i->ctn_next == NULL)))        return (ctf_set_errno (ofp, ctf_errno (fp)));       i->ctn_type = 0;      /* This sub-struct has ended: on to the next real member.  */      goto retry;    }   return offset;  end_iter:  ctf_next_destroy (i);  *it = NULL;  return ctf_set_errno (ofp, ECTF_NEXT_END);} /* Iterate over the members of an ENUM.  We pass the string name and associated   integer value of each enum element to the specified callback function.  */ intctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg){  ctf_next_t *i = NULL;  const char *name;  int val;   while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)    {      int rc;      if ((rc = func (name, val, arg)) != 0)	{	  ctf_next_destroy (i);	  return rc;	}    }  if (ctf_errno (fp) != ECTF_NEXT_END)    return -1;					/* errno is set for us.  */   return 0;} /* Iterate over the members of an enum TYPE, returning each enumerand's NAME or   NULL at end of iteration or error, and optionally passing back the   enumerand's integer VALue.  */ const char *ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,	       int *val){  ctf_dict_t *ofp = fp;  uint32_t kind;  const char *name;  ctf_next_t *i = *it;   if (!i)    {      const ctf_type_t *tp;      ctf_dtdef_t *dtd;       if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)	return NULL;			/* errno is set for us.  */       if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)	return NULL;			/* errno is set for us.  */       if ((i = ctf_next_create ()) == NULL)	{	  ctf_set_errno (ofp, ENOMEM);	  return NULL;	}      i->cu.ctn_fp = ofp;       (void) ctf_get_ctt_size (fp, tp, NULL,			       &i->ctn_increment);      kind = LCTF_INFO_KIND (fp, tp->ctt_info);       if (kind != CTF_K_ENUM)	{	  ctf_next_destroy (i);	  ctf_set_errno (ofp, ECTF_NOTENUM);	  return NULL;	}       dtd = ctf_dynamic_type (fp, type);      i->ctn_iter_fun = (void (*) (void)) ctf_enum_next;      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);       if (dtd == NULL)	i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +					    i->ctn_increment);      else	i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;       *it = i;    }   if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun)    {      ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN);      return NULL;    }   if (ofp != i->cu.ctn_fp)    {      ctf_set_errno (ofp, ECTF_NEXT_WRONGFP);      return NULL;    }   /* Resolve to the native dict of this type.  */  if ((fp = ctf_get_dict (ofp, type)) == NULL)    {      ctf_set_errno (ofp, ECTF_NOPARENT);      return NULL;    }   if (i->ctn_n == 0)    goto end_iter;   name = ctf_strptr (fp, i->u.ctn_en->cte_name);  if (val)    *val = i->u.ctn_en->cte_value;  i->u.ctn_en++;  i->ctn_n--;   return name;  end_iter:  ctf_next_destroy (i);  *it = NULL;  ctf_set_errno (ofp, ECTF_NEXT_END);  return NULL;} /* Iterate over every root (user-visible) type in the given CTF dict.   We pass the type ID of each type to the specified callback function.    Does not traverse parent types: you have to do that explicitly.  This is by   design, to avoid traversing them more than once if traversing many children   of a single parent.  */ intctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg){  ctf_next_t *i = NULL;  ctf_id_t type;   while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR)    {      int rc;      if ((rc = func (type, arg)) != 0)	{	  ctf_next_destroy (i);	  return rc;	}    }  if (ctf_errno (fp) != ECTF_NEXT_END)    return -1;					/* errno is set for us.  */   return 0;} /* Iterate over every type in the given CTF dict, user-visible or not.   We pass the type ID of each type to the specified callback function.    Does not traverse parent types: you have to do that explicitly.  This is by   design, to avoid traversing them more than once if traversing many children   of a single parent.  */ intctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg){  ctf_next_t *i = NULL;  ctf_id_t type;  int flag;   while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR)    {      int rc;      if ((rc = func (type, flag, arg)) != 0)	{	  ctf_next_destroy (i);	  return rc;	}    }  if (ctf_errno (fp) != ECTF_NEXT_END)    return -1;					/* errno is set for us.  */   return 0;} /* Iterate over every type in the given CTF dict, optionally including   non-user-visible types, returning each type ID and hidden flag in turn.   Returns CTF_ERR on end of iteration or error.    Does not traverse parent types: you have to do that explicitly.  This is by   design, to avoid traversing them more than once if traversing many children   of a single parent.  */ ctf_id_tctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden){  ctf_next_t *i = *it;   if (!i)    {      if ((i = ctf_next_create ()) == NULL)	return ctf_set_typed_errno (fp, ENOMEM);       i->cu.ctn_fp = fp;      i->ctn_type = 1;      i->ctn_iter_fun = (void (*) (void)) ctf_type_next;      *it = i;    }   if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun)    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));   if (fp != i->cu.ctn_fp)    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));   while (i->ctn_type <= fp->ctf_typemax)    {      const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type);       if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info)))	{	  i->ctn_type++;	  continue;	}       if (flag)	*flag = LCTF_INFO_ISROOT (fp, tp->ctt_info);      return LCTF_INDEX_TO_TYPE (fp, i->ctn_type++, fp->ctf_flags & LCTF_CHILD);    }  ctf_next_destroy (i);  *it = NULL;  return ctf_set_typed_errno (fp, ECTF_NEXT_END);} /* Iterate over every variable in the given CTF dict, in arbitrary order.   We pass the name of each variable to the specified callback function.  */ intctf_variable_iter (ctf_dict_t *fp, ctf_variable_f *func, void *arg){  ctf_next_t *i = NULL;  ctf_id_t type;  const char *name;   while ((type = ctf_variable_next (fp, &i, &name)) != CTF_ERR)    {      int rc;      if ((rc = func (name, type, arg)) != 0)	{	  ctf_next_destroy (i);	  return rc;	}    }  if (ctf_errno (fp) != ECTF_NEXT_END)    return -1;					/* errno is set for us.  */   return 0;} /* Iterate over every variable in the given CTF dict, in arbitrary order,   returning the name and type of each variable in turn.  The name argument is   not optional.  Returns CTF_ERR on end of iteration or error.  */

Lines 1–500 of 1723.

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