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