Home | History | Annotate | Line # | Download | only in libctf
      1 /* C declarator syntax glue.
      2    Copyright (C) 2019-2025 Free Software Foundation, Inc.
      3 
      4    This file is part of libctf.
      5 
      6    libctf is free software; you can redistribute it and/or modify it under
      7    the terms of the GNU General Public License as published by the Free
      8    Software Foundation; either version 3, or (at your option) any later
      9    version.
     10 
     11    This program is distributed in the hope that it will be useful, but
     12    WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14    See the GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program; see the file COPYING.  If not see
     18    <http://www.gnu.org/licenses/>.  */
     19 
     20 /* CTF Declaration Stack
     21 
     22    In order to implement ctf_type_name(), we must convert a type graph back
     23    into a C type declaration.  Unfortunately, a type graph represents a storage
     24    class ordering of the type whereas a type declaration must obey the C rules
     25    for operator precedence, and the two orderings are frequently in conflict.
     26    For example, consider these CTF type graphs and their C declarations:
     27 
     28    CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER  : int (*)()
     29    CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER     : int (*)[]
     30 
     31    In each case, parentheses are used to raise operator * to higher lexical
     32    precedence, so the string form of the C declaration cannot be constructed by
     33    walking the type graph links and forming the string from left to right.
     34 
     35    The functions in this file build a set of stacks from the type graph nodes
     36    corresponding to the C operator precedence levels in the appropriate order.
     37    The code in ctf_type_name() can then iterate over the levels and nodes in
     38    lexical precedence order and construct the final C declaration string.  */
     39 
     40 #include <ctf-impl.h>
     41 #include <string.h>
     42 
     43 void
     44 ctf_decl_init (ctf_decl_t *cd)
     45 {
     46   int i;
     47 
     48   memset (cd, 0, sizeof (ctf_decl_t));
     49 
     50   for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
     51     cd->cd_order[i] = CTF_PREC_BASE - 1;
     52 
     53   cd->cd_qualp = CTF_PREC_BASE;
     54   cd->cd_ordp = CTF_PREC_BASE;
     55 }
     56 
     57 void
     58 ctf_decl_fini (ctf_decl_t *cd)
     59 {
     60   ctf_decl_node_t *cdp, *ndp;
     61   int i;
     62 
     63   for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
     64     {
     65       for (cdp = ctf_list_next (&cd->cd_nodes[i]); cdp != NULL; cdp = ndp)
     66 	{
     67 	  ndp = ctf_list_next (cdp);
     68 	  free (cdp);
     69 	}
     70     }
     71   free (cd->cd_buf);
     72 }
     73 
     74 void
     75 ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type)
     76 {
     77   ctf_decl_node_t *cdp;
     78   ctf_decl_prec_t prec;
     79   uint32_t kind, n = 1;
     80   int is_qual = 0;
     81 
     82   const ctf_type_t *tp;
     83   ctf_arinfo_t ar;
     84 
     85   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
     86     {
     87       cd->cd_err = fp->ctf_errno;
     88       return;
     89     }
     90 
     91   switch (kind = LCTF_INFO_KIND (fp, tp->ctt_info))
     92     {
     93     case CTF_K_ARRAY:
     94       (void) ctf_array_info (fp, type, &ar);
     95       ctf_decl_push (cd, fp, ar.ctr_contents);
     96       n = ar.ctr_nelems;
     97       prec = CTF_PREC_ARRAY;
     98       break;
     99 
    100     case CTF_K_TYPEDEF:
    101       if (ctf_strptr (fp, tp->ctt_name)[0] == '\0')
    102 	{
    103 	  ctf_decl_push (cd, fp, tp->ctt_type);
    104 	  return;
    105 	}
    106       prec = CTF_PREC_BASE;
    107       break;
    108 
    109     case CTF_K_FUNCTION:
    110       ctf_decl_push (cd, fp, tp->ctt_type);
    111       prec = CTF_PREC_FUNCTION;
    112       break;
    113 
    114     case CTF_K_POINTER:
    115       ctf_decl_push (cd, fp, tp->ctt_type);
    116       prec = CTF_PREC_POINTER;
    117       break;
    118 
    119     case CTF_K_SLICE:
    120       /* Slices themselves have no print representation and should not appear in
    121 	 the decl stack.  */
    122       ctf_decl_push (cd, fp, ctf_type_reference (fp, type));
    123       return;
    124 
    125     case CTF_K_VOLATILE:
    126     case CTF_K_CONST:
    127     case CTF_K_RESTRICT:
    128       ctf_decl_push (cd, fp, tp->ctt_type);
    129       prec = cd->cd_qualp;
    130       is_qual++;
    131       break;
    132 
    133     default:
    134       prec = CTF_PREC_BASE;
    135     }
    136 
    137   if ((cdp = malloc (sizeof (ctf_decl_node_t))) == NULL)
    138     {
    139       cd->cd_err = EAGAIN;
    140       return;
    141     }
    142 
    143   cdp->cd_type = type;
    144   cdp->cd_kind = kind;
    145   cdp->cd_n = n;
    146 
    147   if (ctf_list_next (&cd->cd_nodes[prec]) == NULL)
    148     cd->cd_order[prec] = cd->cd_ordp++;
    149 
    150   /* Reset cd_qualp to the highest precedence level that we've seen so
    151      far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).  */
    152 
    153   if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
    154     cd->cd_qualp = prec;
    155 
    156   /* By convention qualifiers of base types precede the type specifier (e.g.
    157      const int vs. int const) even though the two forms are equivalent.  */
    158 
    159   if (is_qual && prec == CTF_PREC_BASE)
    160     ctf_list_prepend (&cd->cd_nodes[prec], cdp);
    161   else
    162     ctf_list_append (&cd->cd_nodes[prec], cdp);
    163 }
    164 
    165 _libctf_printflike_ (2, 3)
    166 void ctf_decl_sprintf (ctf_decl_t *cd, const char *format, ...)
    167 {
    168   va_list ap;
    169   char *str;
    170   int n;
    171 
    172   if (cd->cd_enomem)
    173     return;
    174 
    175   va_start (ap, format);
    176   n = vasprintf (&str, format, ap);
    177   va_end (ap);
    178 
    179   if (n > 0)
    180     {
    181       char *newbuf;
    182       if ((newbuf = ctf_str_append (cd->cd_buf, str)) != NULL)
    183 	cd->cd_buf = newbuf;
    184     }
    185 
    186   /* Sticky error condition.  */
    187   if (n < 0 || cd->cd_buf == NULL)
    188     {
    189       free (cd->cd_buf);
    190       cd->cd_buf = NULL;
    191       cd->cd_enomem = 1;
    192     }
    193 
    194   free (str);
    195 }
    196 
    197 char *ctf_decl_buf (ctf_decl_t *cd)
    198 {
    199   char *buf = cd->cd_buf;
    200   cd->cd_buf = NULL;
    201   return buf;
    202 }
    203