Home | History | Annotate | Line # | Download | only in gdb
producer.c revision 1.1.1.3
      1 /* Producer string parsers for GDB.
      2 
      3    Copyright (C) 2012-2023 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 }
    262