/src/binutils-gdb/libctf/ctf-decl.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
46 | 0 | int i; |
47 | |
|
48 | 0 | memset (cd, 0, sizeof (ctf_decl_t)); |
49 | |
|
50 | 0 | for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) |
51 | 0 | cd->cd_order[i] = CTF_PREC_BASE - 1; |
52 | |
|
53 | 0 | cd->cd_qualp = CTF_PREC_BASE; |
54 | 0 | cd->cd_ordp = CTF_PREC_BASE; |
55 | 0 | } |
56 | | |
57 | | void |
58 | | ctf_decl_fini (ctf_decl_t *cd) |
59 | 0 | { |
60 | 0 | ctf_decl_node_t *cdp, *ndp; |
61 | 0 | int i; |
62 | |
|
63 | 0 | for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) |
64 | 0 | { |
65 | 0 | for (cdp = ctf_list_next (&cd->cd_nodes[i]); cdp != NULL; cdp = ndp) |
66 | 0 | { |
67 | 0 | ndp = ctf_list_next (cdp); |
68 | 0 | free (cdp); |
69 | 0 | } |
70 | 0 | } |
71 | 0 | free (cd->cd_buf); |
72 | 0 | } |
73 | | |
74 | | void |
75 | | ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type) |
76 | 0 | { |
77 | 0 | ctf_decl_node_t *cdp; |
78 | 0 | ctf_decl_prec_t prec; |
79 | 0 | uint32_t kind, n = 1; |
80 | 0 | int is_qual = 0; |
81 | |
|
82 | 0 | const ctf_type_t *tp; |
83 | 0 | ctf_arinfo_t ar; |
84 | |
|
85 | 0 | if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) |
86 | 0 | { |
87 | 0 | cd->cd_err = fp->ctf_errno; |
88 | 0 | return; |
89 | 0 | } |
90 | | |
91 | 0 | switch (kind = LCTF_INFO_KIND (fp, tp->ctt_info)) |
92 | 0 | { |
93 | 0 | case CTF_K_ARRAY: |
94 | 0 | (void) ctf_array_info (fp, type, &ar); |
95 | 0 | ctf_decl_push (cd, fp, ar.ctr_contents); |
96 | 0 | n = ar.ctr_nelems; |
97 | 0 | prec = CTF_PREC_ARRAY; |
98 | 0 | break; |
99 | | |
100 | 0 | case CTF_K_TYPEDEF: |
101 | 0 | if (ctf_strptr (fp, tp->ctt_name)[0] == '\0') |
102 | 0 | { |
103 | 0 | ctf_decl_push (cd, fp, tp->ctt_type); |
104 | 0 | return; |
105 | 0 | } |
106 | 0 | prec = CTF_PREC_BASE; |
107 | 0 | break; |
108 | | |
109 | 0 | case CTF_K_FUNCTION: |
110 | 0 | ctf_decl_push (cd, fp, tp->ctt_type); |
111 | 0 | prec = CTF_PREC_FUNCTION; |
112 | 0 | break; |
113 | | |
114 | 0 | case CTF_K_POINTER: |
115 | 0 | ctf_decl_push (cd, fp, tp->ctt_type); |
116 | 0 | prec = CTF_PREC_POINTER; |
117 | 0 | break; |
118 | | |
119 | 0 | case CTF_K_SLICE: |
120 | | /* Slices themselves have no print representation and should not appear in |
121 | | the decl stack. */ |
122 | 0 | ctf_decl_push (cd, fp, ctf_type_reference (fp, type)); |
123 | 0 | return; |
124 | | |
125 | 0 | case CTF_K_VOLATILE: |
126 | 0 | case CTF_K_CONST: |
127 | 0 | case CTF_K_RESTRICT: |
128 | 0 | ctf_decl_push (cd, fp, tp->ctt_type); |
129 | 0 | prec = cd->cd_qualp; |
130 | 0 | is_qual++; |
131 | 0 | break; |
132 | | |
133 | 0 | default: |
134 | 0 | prec = CTF_PREC_BASE; |
135 | 0 | } |
136 | | |
137 | 0 | if ((cdp = malloc (sizeof (ctf_decl_node_t))) == NULL) |
138 | 0 | { |
139 | 0 | cd->cd_err = EAGAIN; |
140 | 0 | return; |
141 | 0 | } |
142 | | |
143 | 0 | cdp->cd_type = type; |
144 | 0 | cdp->cd_kind = kind; |
145 | 0 | cdp->cd_n = n; |
146 | |
|
147 | 0 | if (ctf_list_next (&cd->cd_nodes[prec]) == NULL) |
148 | 0 | 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 | 0 | if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) |
154 | 0 | 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 | 0 | if (is_qual && prec == CTF_PREC_BASE) |
160 | 0 | ctf_list_prepend (&cd->cd_nodes[prec], cdp); |
161 | 0 | else |
162 | 0 | ctf_list_append (&cd->cd_nodes[prec], cdp); |
163 | 0 | } |
164 | | |
165 | | _libctf_printflike_ (2, 3) |
166 | | void ctf_decl_sprintf (ctf_decl_t *cd, const char *format, ...) |
167 | 0 | { |
168 | 0 | va_list ap; |
169 | 0 | char *str; |
170 | 0 | int n; |
171 | |
|
172 | 0 | if (cd->cd_enomem) |
173 | 0 | return; |
174 | | |
175 | 0 | va_start (ap, format); |
176 | 0 | n = vasprintf (&str, format, ap); |
177 | 0 | va_end (ap); |
178 | |
|
179 | 0 | if (n > 0) |
180 | 0 | { |
181 | 0 | char *newbuf; |
182 | 0 | if ((newbuf = ctf_str_append (cd->cd_buf, str)) != NULL) |
183 | 0 | cd->cd_buf = newbuf; |
184 | 0 | } |
185 | | |
186 | | /* Sticky error condition. */ |
187 | 0 | if (n < 0 || cd->cd_buf == NULL) |
188 | 0 | { |
189 | 0 | free (cd->cd_buf); |
190 | 0 | cd->cd_buf = NULL; |
191 | 0 | cd->cd_enomem = 1; |
192 | 0 | } |
193 | |
|
194 | 0 | free (str); |
195 | 0 | } |
196 | | |
197 | | char *ctf_decl_buf (ctf_decl_t *cd) |
198 | 0 | { |
199 | 0 | char *buf = cd->cd_buf; |
200 | 0 | cd->cd_buf = NULL; |
201 | 0 | return buf; |
202 | 0 | } |