Home | History | Annotate | Line # | Download | only in gdb
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