| 1 | /* C declarator syntax glue. |
| 2 | Copyright (C) 2019-2020 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 | } |
| 72 | |
| 73 | void |
| 74 | ctf_decl_push (ctf_decl_t *cd, ctf_file_t *fp, ctf_id_t type) |
| 75 | { |
| 76 | ctf_decl_node_t *cdp; |
| 77 | ctf_decl_prec_t prec; |
| 78 | uint32_t kind, n = 1; |
| 79 | int is_qual = 0; |
| 80 | |
| 81 | const ctf_type_t *tp; |
| 82 | ctf_arinfo_t ar; |
| 83 | |
| 84 | if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) |
| 85 | { |
| 86 | cd->cd_err = fp->ctf_errno; |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | switch (kind = LCTF_INFO_KIND (fp, tp->ctt_info)) |
| 91 | { |
| 92 | case CTF_K_ARRAY: |
| 93 | (void) ctf_array_info (fp, type, &ar); |
| 94 | ctf_decl_push (cd, fp, ar.ctr_contents); |
| 95 | n = ar.ctr_nelems; |
| 96 | prec = CTF_PREC_ARRAY; |
| 97 | break; |
| 98 | |
| 99 | case CTF_K_TYPEDEF: |
| 100 | if (ctf_strptr (fp, tp->ctt_name)[0] == '\0') |
| 101 | { |
| 102 | ctf_decl_push (cd, fp, tp->ctt_type); |
| 103 | return; |
| 104 | } |
| 105 | prec = CTF_PREC_BASE; |
| 106 | break; |
| 107 | |
| 108 | case CTF_K_FUNCTION: |
| 109 | ctf_decl_push (cd, fp, tp->ctt_type); |
| 110 | prec = CTF_PREC_FUNCTION; |
| 111 | break; |
| 112 | |
| 113 | case CTF_K_POINTER: |
| 114 | ctf_decl_push (cd, fp, tp->ctt_type); |
| 115 | prec = CTF_PREC_POINTER; |
| 116 | break; |
| 117 | |
| 118 | case CTF_K_SLICE: |
| 119 | ctf_decl_push (cd, fp, ctf_type_reference (fp, type)); |
| 120 | prec = CTF_PREC_BASE; |
| 121 | break; |
| 122 | |
| 123 | case CTF_K_VOLATILE: |
| 124 | case CTF_K_CONST: |
| 125 | case CTF_K_RESTRICT: |
| 126 | ctf_decl_push (cd, fp, tp->ctt_type); |
| 127 | prec = cd->cd_qualp; |
| 128 | is_qual++; |
| 129 | break; |
| 130 | |
| 131 | default: |
| 132 | prec = CTF_PREC_BASE; |
| 133 | } |
| 134 | |
| 135 | if ((cdp = malloc (sizeof (ctf_decl_node_t))) == NULL) |
| 136 | { |
| 137 | cd->cd_err = EAGAIN; |
| 138 | return; |
| 139 | } |
| 140 | |
| 141 | cdp->cd_type = type; |
| 142 | cdp->cd_kind = kind; |
| 143 | cdp->cd_n = n; |
| 144 | |
| 145 | if (ctf_list_next (&cd->cd_nodes[prec]) == NULL) |
| 146 | cd->cd_order[prec] = cd->cd_ordp++; |
| 147 | |
| 148 | /* Reset cd_qualp to the highest precedence level that we've seen so |
| 149 | far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). */ |
| 150 | |
| 151 | if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) |
| 152 | cd->cd_qualp = prec; |
| 153 | |
| 154 | /* C array declarators are ordered inside out so prepend them. Also by |
| 155 | convention qualifiers of base types precede the type specifier (e.g. |
| 156 | const int vs. int const) even though the two forms are equivalent. */ |
| 157 | |
| 158 | if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) |
| 159 | ctf_list_prepend (&cd->cd_nodes[prec], cdp); |
| 160 | else |
| 161 | ctf_list_append (&cd->cd_nodes[prec], cdp); |
| 162 | } |
| 163 | |
| 164 | _libctf_printflike_ (2, 3) |
| 165 | void ctf_decl_sprintf (ctf_decl_t *cd, const char *format, ...) |
| 166 | { |
| 167 | va_list ap; |
| 168 | char *str; |
| 169 | int n; |
| 170 | |
| 171 | if (cd->cd_enomem) |
| 172 | return; |
| 173 | |
| 174 | va_start (ap, format); |
| 175 | n = vasprintf (&str, format, ap); |
| 176 | va_end (ap); |
| 177 | |
| 178 | if (n > 0) |
| 179 | { |
| 180 | char *newbuf; |
| 181 | if ((newbuf = ctf_str_append (cd->cd_buf, str)) != NULL) |
| 182 | cd->cd_buf = newbuf; |
| 183 | } |
| 184 | |
| 185 | /* Sticky error condition. */ |
| 186 | if (n < 0 || cd->cd_buf == NULL) |
| 187 | { |
| 188 | free (cd->cd_buf); |
| 189 | cd->cd_buf = NULL; |
| 190 | cd->cd_enomem = 1; |
| 191 | } |
| 192 | |
| 193 | free (str); |
| 194 | } |
| 195 | |
| 196 | char *ctf_decl_buf (ctf_decl_t *cd) |
| 197 | { |
| 198 | return cd->cd_buf; |
| 199 | } |