producer.c revision 1.1.1.4 1 1.1 christos /* Producer string parsers for GDB.
2 1.1 christos
3 1.1.1.4 christos Copyright (C) 2012-2024 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This file is part of GDB.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include "producer.h"
21 1.1.1.2 christos #include "gdbsupport/selftest.h"
22 1.1.1.3 christos #include "gdbsupport/gdb_regex.h"
23 1.1 christos
24 1.1 christos /* See producer.h. */
25 1.1 christos
26 1.1 christos int
27 1.1 christos producer_is_gcc_ge_4 (const char *producer)
28 1.1 christos {
29 1.1 christos int major, minor;
30 1.1 christos
31 1.1 christos if (! producer_is_gcc (producer, &major, &minor))
32 1.1 christos return -1;
33 1.1 christos if (major < 4)
34 1.1 christos return -1;
35 1.1 christos if (major > 4)
36 1.1 christos return INT_MAX;
37 1.1 christos return minor;
38 1.1 christos }
39 1.1 christos
40 1.1 christos /* See producer.h. */
41 1.1 christos
42 1.1 christos int
43 1.1 christos producer_is_gcc (const char *producer, int *major, int *minor)
44 1.1 christos {
45 1.1 christos const char *cs;
46 1.1 christos
47 1.1 christos if (producer != NULL && startswith (producer, "GNU "))
48 1.1 christos {
49 1.1 christos int maj, min;
50 1.1 christos
51 1.1 christos if (major == NULL)
52 1.1 christos major = &maj;
53 1.1 christos if (minor == NULL)
54 1.1 christos minor = &min;
55 1.1 christos
56 1.1.1.4 christos /* Skip GNU. */
57 1.1.1.4 christos cs = &producer[strlen ("GNU ")];
58 1.1.1.4 christos
59 1.1.1.4 christos /* Bail out for GNU AS. */
60 1.1.1.4 christos if (startswith (cs, "AS "))
61 1.1.1.4 christos return 0;
62 1.1.1.4 christos
63 1.1 christos /* Skip any identifier after "GNU " - such as "C11" "C++" or "Java".
64 1.1 christos A full producer string might look like:
65 1.1 christos "GNU C 4.7.2"
66 1.1 christos "GNU Fortran 4.8.2 20140120 (Red Hat 4.8.2-16) -mtune=generic ..."
67 1.1 christos "GNU C++14 5.0.0 20150123 (experimental)"
68 1.1 christos */
69 1.1.1.4 christos while (*cs && !isspace ((unsigned char)*cs))
70 1.1.1.3 christos cs++;
71 1.1.1.4 christos if (*cs && isspace ((unsigned char)*cs))
72 1.1.1.3 christos cs++;
73 1.1 christos if (sscanf (cs, "%d.%d", major, minor) == 2)
74 1.1 christos return 1;
75 1.1 christos }
76 1.1 christos
77 1.1 christos /* Not recognized as GCC. */
78 1.1 christos return 0;
79 1.1 christos }
80 1.1 christos
81 1.1.1.3 christos /* See producer.h. */
82 1.1.1.3 christos
83 1.1.1.3 christos bool
84 1.1.1.4 christos producer_is_gas (const char *producer, int *major, int *minor)
85 1.1.1.4 christos {
86 1.1.1.4 christos if (producer == nullptr)
87 1.1.1.4 christos {
88 1.1.1.4 christos /* No producer, don't know. */
89 1.1.1.4 christos return false;
90 1.1.1.4 christos }
91 1.1.1.4 christos
92 1.1.1.4 christos /* Detect prefix. */
93 1.1.1.4 christos const char prefix[] = "GNU AS ";
94 1.1.1.4 christos if (!startswith (producer, prefix))
95 1.1.1.4 christos {
96 1.1.1.4 christos /* Producer is not gas. */
97 1.1.1.4 christos return false;
98 1.1.1.4 christos }
99 1.1.1.4 christos
100 1.1.1.4 christos /* Skip prefix. */
101 1.1.1.4 christos const char *cs = &producer[strlen (prefix)];
102 1.1.1.4 christos
103 1.1.1.4 christos /* Ensure that major/minor are not nullptrs. */
104 1.1.1.4 christos int maj, min;
105 1.1.1.4 christos if (major == nullptr)
106 1.1.1.4 christos major = &maj;
107 1.1.1.4 christos if (minor == nullptr)
108 1.1.1.4 christos minor = &min;
109 1.1.1.4 christos
110 1.1.1.4 christos int scanned = sscanf (cs, "%d.%d", major, minor);
111 1.1.1.4 christos if (scanned != 2)
112 1.1.1.4 christos {
113 1.1.1.4 christos /* Unable to scan major/minor version. */
114 1.1.1.4 christos return false;
115 1.1.1.4 christos }
116 1.1.1.4 christos
117 1.1.1.4 christos return true;
118 1.1.1.4 christos }
119 1.1.1.4 christos
120 1.1.1.4 christos /* See producer.h. */
121 1.1.1.4 christos
122 1.1.1.4 christos bool
123 1.1.1.3 christos producer_is_icc_ge_19 (const char *producer)
124 1.1.1.3 christos {
125 1.1.1.3 christos int major, minor;
126 1.1.1.3 christos
127 1.1.1.3 christos if (! producer_is_icc (producer, &major, &minor))
128 1.1.1.3 christos return false;
129 1.1.1.3 christos
130 1.1.1.3 christos return major >= 19;
131 1.1.1.3 christos }
132 1.1 christos
133 1.1 christos /* See producer.h. */
134 1.1 christos
135 1.1 christos bool
136 1.1 christos producer_is_icc (const char *producer, int *major, int *minor)
137 1.1 christos {
138 1.1.1.3 christos compiled_regex i_re ("Intel(R)", 0, "producer_is_icc");
139 1.1.1.3 christos if (producer == nullptr || i_re.exec (producer, 0, nullptr, 0) != 0)
140 1.1 christos return false;
141 1.1 christos
142 1.1 christos /* Prepare the used fields. */
143 1.1 christos int maj, min;
144 1.1.1.3 christos if (major == nullptr)
145 1.1 christos major = &maj;
146 1.1.1.3 christos if (minor == nullptr)
147 1.1 christos minor = &min;
148 1.1 christos
149 1.1 christos *minor = 0;
150 1.1 christos *major = 0;
151 1.1 christos
152 1.1.1.3 christos compiled_regex re ("[0-9]+\\.[0-9]+", REG_EXTENDED, "producer_is_icc");
153 1.1.1.3 christos regmatch_t version[1];
154 1.1.1.3 christos if (re.exec (producer, ARRAY_SIZE (version), version, 0) == 0
155 1.1.1.3 christos && version[0].rm_so != -1)
156 1.1 christos {
157 1.1.1.3 christos const char *version_str = producer + version[0].rm_so;
158 1.1.1.3 christos sscanf (version_str, "%d.%d", major, minor);
159 1.1.1.3 christos return true;
160 1.1 christos }
161 1.1 christos
162 1.1 christos return false;
163 1.1 christos }
164 1.1 christos
165 1.1.1.2 christos /* See producer.h. */
166 1.1.1.2 christos
167 1.1.1.2 christos bool
168 1.1.1.2 christos producer_is_llvm (const char *producer)
169 1.1.1.2 christos {
170 1.1.1.2 christos return ((producer != NULL) && (startswith (producer, "clang ")
171 1.1.1.3 christos || startswith (producer, " F90 Flang ")));
172 1.1.1.3 christos }
173 1.1.1.3 christos
174 1.1.1.3 christos /* See producer.h. */
175 1.1.1.3 christos
176 1.1.1.3 christos bool
177 1.1.1.3 christos producer_is_clang (const char *producer, int *major, int *minor)
178 1.1.1.3 christos {
179 1.1.1.3 christos if (producer != nullptr && startswith (producer, "clang version "))
180 1.1.1.3 christos {
181 1.1.1.3 christos int maj, min;
182 1.1.1.3 christos if (major == nullptr)
183 1.1.1.3 christos major = &maj;
184 1.1.1.3 christos if (minor == nullptr)
185 1.1.1.3 christos minor = &min;
186 1.1.1.3 christos
187 1.1.1.3 christos /* The full producer string will look something like
188 1.1.1.3 christos "clang version XX.X.X ..."
189 1.1.1.3 christos So we can safely ignore all characters before the first digit. */
190 1.1.1.3 christos const char *cs = producer + strlen ("clang version ");
191 1.1.1.3 christos
192 1.1.1.3 christos if (sscanf (cs, "%d.%d", major, minor) == 2)
193 1.1.1.3 christos return true;
194 1.1.1.3 christos }
195 1.1.1.3 christos return false;
196 1.1.1.2 christos }
197 1.1.1.2 christos
198 1.1 christos #if defined GDB_SELF_TEST
199 1.1 christos namespace selftests {
200 1.1 christos namespace producer {
201 1.1 christos
202 1.1 christos static void
203 1.1 christos producer_parsing_tests ()
204 1.1 christos {
205 1.1 christos {
206 1.1 christos /* Check that we don't crash if "Version" is not found in what
207 1.1 christos looks like an ICC producer string. */
208 1.1 christos static const char icc_no_version[] = "Intel(R) foo bar";
209 1.1 christos
210 1.1 christos int major = 0, minor = 0;
211 1.1 christos SELF_CHECK (!producer_is_icc (icc_no_version, &major, &minor));
212 1.1 christos SELF_CHECK (!producer_is_gcc (icc_no_version, &major, &minor));
213 1.1 christos }
214 1.1 christos
215 1.1 christos {
216 1.1.1.3 christos static const char extern_f_14_0[] = "\
217 1.1 christos Intel(R) Fortran Intel(R) 64 Compiler XE for applications running on \
218 1.1 christos Intel(R) 64, \
219 1.1 christos Version 14.0.1.074 Build 20130716";
220 1.1 christos
221 1.1 christos int major = 0, minor = 0;
222 1.1.1.3 christos SELF_CHECK (producer_is_icc (extern_f_14_0, &major, &minor)
223 1.1.1.3 christos && major == 14 && minor == 0);
224 1.1.1.3 christos SELF_CHECK (!producer_is_gcc (extern_f_14_0, &major, &minor));
225 1.1 christos }
226 1.1 christos
227 1.1 christos {
228 1.1 christos static const char intern_f_14[] = "\
229 1.1 christos Intel(R) Fortran Intel(R) 64 Compiler XE for applications running on \
230 1.1 christos Intel(R) 64, \
231 1.1 christos Version 14.0";
232 1.1 christos
233 1.1 christos int major = 0, minor = 0;
234 1.1 christos SELF_CHECK (producer_is_icc (intern_f_14, &major, &minor)
235 1.1 christos && major == 14 && minor == 0);
236 1.1 christos SELF_CHECK (!producer_is_gcc (intern_f_14, &major, &minor));
237 1.1 christos }
238 1.1 christos
239 1.1 christos {
240 1.1 christos static const char intern_c_14[] = "\
241 1.1 christos Intel(R) C++ Intel(R) 64 Compiler XE for applications running on \
242 1.1 christos Intel(R) 64, \
243 1.1 christos Version 14.0";
244 1.1 christos int major = 0, minor = 0;
245 1.1 christos SELF_CHECK (producer_is_icc (intern_c_14, &major, &minor)
246 1.1 christos && major == 14 && minor == 0);
247 1.1 christos SELF_CHECK (!producer_is_gcc (intern_c_14, &major, &minor));
248 1.1 christos }
249 1.1 christos
250 1.1 christos {
251 1.1 christos static const char intern_c_18[] = "\
252 1.1 christos Intel(R) C++ Intel(R) 64 Compiler for applications running on \
253 1.1 christos Intel(R) 64, \
254 1.1 christos Version 18.0 Beta";
255 1.1 christos int major = 0, minor = 0;
256 1.1 christos SELF_CHECK (producer_is_icc (intern_c_18, &major, &minor)
257 1.1 christos && major == 18 && minor == 0);
258 1.1 christos }
259 1.1 christos
260 1.1 christos {
261 1.1 christos static const char gnu[] = "GNU C 4.7.2";
262 1.1 christos SELF_CHECK (!producer_is_icc (gnu, NULL, NULL));
263 1.1 christos
264 1.1 christos int major = 0, minor = 0;
265 1.1 christos SELF_CHECK (producer_is_gcc (gnu, &major, &minor)
266 1.1 christos && major == 4 && minor == 7);
267 1.1 christos }
268 1.1 christos
269 1.1 christos {
270 1.1 christos static const char gnu_exp[] = "GNU C++14 5.0.0 20150123 (experimental)";
271 1.1 christos int major = 0, minor = 0;
272 1.1 christos SELF_CHECK (!producer_is_icc (gnu_exp, NULL, NULL));
273 1.1 christos SELF_CHECK (producer_is_gcc (gnu_exp, &major, &minor)
274 1.1 christos && major == 5 && minor == 0);
275 1.1 christos }
276 1.1.1.2 christos
277 1.1.1.2 christos {
278 1.1.1.2 christos static const char clang_llvm_exp[] = "clang version 12.0.0 (CLANG: bld#8)";
279 1.1.1.2 christos int major = 0, minor = 0;
280 1.1.1.2 christos SELF_CHECK (!producer_is_icc (clang_llvm_exp, NULL, NULL));
281 1.1.1.2 christos SELF_CHECK (!producer_is_gcc (clang_llvm_exp, &major, &minor));
282 1.1.1.2 christos SELF_CHECK (producer_is_llvm (clang_llvm_exp));
283 1.1.1.2 christos }
284 1.1.1.2 christos
285 1.1.1.2 christos {
286 1.1.1.2 christos static const char flang_llvm_exp[] = " F90 Flang - 1.5 2017-05-01";
287 1.1.1.2 christos int major = 0, minor = 0;
288 1.1.1.2 christos SELF_CHECK (!producer_is_icc (flang_llvm_exp, NULL, NULL));
289 1.1.1.2 christos SELF_CHECK (!producer_is_gcc (flang_llvm_exp, &major, &minor));
290 1.1.1.2 christos SELF_CHECK (producer_is_llvm (flang_llvm_exp));
291 1.1.1.2 christos }
292 1.1.1.4 christos
293 1.1.1.4 christos {
294 1.1.1.4 christos static const char gas_exp[] = "GNU AS 2.39.0";
295 1.1.1.4 christos int major = 0, minor = 0;
296 1.1.1.4 christos SELF_CHECK (!producer_is_gcc (gas_exp, &major, &minor));
297 1.1.1.4 christos SELF_CHECK (producer_is_gas (gas_exp, &major, &minor));
298 1.1.1.4 christos SELF_CHECK (major == 2 && minor == 39);
299 1.1.1.4 christos
300 1.1.1.4 christos static const char gas_incomplete_exp[] = "GNU AS ";
301 1.1.1.4 christos SELF_CHECK (!producer_is_gas (gas_incomplete_exp, &major, &minor));
302 1.1.1.4 christos SELF_CHECK (!producer_is_gcc (gas_incomplete_exp, &major, &minor));
303 1.1.1.4 christos
304 1.1.1.4 christos static const char gas_incomplete_exp_2[] = "GNU AS 2";
305 1.1.1.4 christos SELF_CHECK (!producer_is_gas (gas_incomplete_exp_2, &major, &minor));
306 1.1.1.4 christos SELF_CHECK (!producer_is_gcc (gas_incomplete_exp_2, &major, &minor));
307 1.1.1.4 christos }
308 1.1.1.4 christos
309 1.1 christos }
310 1.1 christos }
311 1.1 christos }
312 1.1 christos #endif
313 1.1 christos
314 1.1.1.2 christos void _initialize_producer ();
315 1.1 christos void
316 1.1 christos _initialize_producer ()
317 1.1 christos {
318 1.1 christos #if defined GDB_SELF_TEST
319 1.1 christos selftests::register_test
320 1.1 christos ("producer-parser", selftests::producer::producer_parsing_tests);
321 1.1 christos #endif
322 1.1 christos }
323