Print this page
9899 cw(1onbld) should shadow more compilation


 245  * -xtransition                 -Wtransition
 246  * -xunroll=n                   error
 247  * -W0,-xdbggen=no%usedonly     -fno-eliminate-unused-debug-symbols
 248  *                              -fno-eliminate-unused-debug-types
 249  * -Y<c>,<dir>                      error
 250  * -YA,<dir>                      error
 251  * -YI,<dir>                      -nostdinc -I<dir>
 252  * -YP,<dir>                      error
 253  * -YS,<dir>                      error
 254  */
 255 
 256 #include <ctype.h>
 257 #include <err.h>
 258 #include <errno.h>
 259 #include <fcntl.h>
 260 #include <getopt.h>
 261 #include <stdio.h>
 262 #include <stdlib.h>
 263 #include <string.h>
 264 #include <unistd.h>

 265 
 266 #include <sys/param.h>
 267 #include <sys/stat.h>
 268 #include <sys/types.h>
 269 #include <sys/utsname.h>
 270 #include <sys/wait.h>
 271 
 272 #define CW_F_CXX        0x01
 273 #define CW_F_SHADOW     0x02
 274 #define CW_F_EXEC       0x04
 275 #define CW_F_ECHO       0x08
 276 #define CW_F_XLATE      0x10
 277 #define CW_F_PROG       0x20
 278 
 279 typedef enum cw_op {
 280         CW_O_NONE = 0,
 281         CW_O_PREPROCESS,
 282         CW_O_COMPILE,
 283         CW_O_LINK
 284 } cw_op_t;


 294 typedef enum {
 295         GNU,
 296         SUN,
 297         SMATCH
 298 } compiler_style_t;
 299 
 300 typedef struct {
 301         char *c_name;
 302         char *c_path;
 303         compiler_style_t c_style;
 304 } cw_compiler_t;
 305 
 306 typedef struct cw_ictx {
 307         struct cw_ictx  *i_next;
 308         cw_compiler_t   *i_compiler;
 309         struct aelist   *i_ae;
 310         uint32_t        i_flags;
 311         int             i_oldargc;
 312         char            **i_oldargv;
 313         pid_t           i_pid;
 314         char            i_discard[MAXPATHLEN];
 315         char            *i_stderr;
 316 } cw_ictx_t;
 317 
 318 /*
 319  * Status values to indicate which Studio compiler and associated
 320  * flags are being used.
 321  */
 322 #define M32             0x01    /* -m32 - only on Studio 12 */
 323 #define M64             0x02    /* -m64 - only on Studio 12 */
 324 #define SS11            0x100   /* Studio 11 */
 325 #define SS12            0x200   /* Studio 12 */
 326 
 327 #define TRANS_ENTRY     5
 328 /*
 329  * Translation table definition for the -xarch= flag. The "x_arg"
 330  * value is translated into the appropriate gcc flags according
 331  * to the values in x_trans[n]. The x_flags indicates what compiler
 332  * is being used and what flags have been set via the use of
 333  * "x_arg".
 334  */


 539 static void
 540 xlate(struct aelist *h, const char *xarg, const char **table)
 541 {
 542         while (*table != NULL && strcmp(xarg, *table) != 0) {
 543                 while (*table != NULL)
 544                         table++;
 545                 table++;
 546         }
 547 
 548         if (*table == NULL)
 549                 error(xarg);
 550 
 551         table++;
 552 
 553         while (*table != NULL) {
 554                 newae(h, *table);
 555                 table++;
 556         }
 557 }
 558 





































 559 static void
 560 do_gcc(cw_ictx_t *ctx)
 561 {
 562         int c;
 563         int nolibc = 0;
 564         int in_output = 0, seen_o = 0, c_files = 0;
 565         cw_op_t op = CW_O_LINK;
 566         char *model = NULL;
 567         char *nameflag;
 568         int     mflag = 0;
 569 
 570         if (ctx->i_flags & CW_F_PROG) {
 571                 newae(ctx->i_ae, "--version");
 572                 return;
 573         }
 574 
 575         newae(ctx->i_ae, "-fident");
 576         newae(ctx->i_ae, "-finline");
 577         newae(ctx->i_ae, "-fno-inline-functions");
 578         newae(ctx->i_ae, "-fno-builtin");


 616                 } else {
 617                         /*
 618                          * Discard inline files that gcc doesn't grok
 619                          */
 620                         if (!in_output && arglen > 3 &&
 621                             strcmp(arg + arglen - 3, ".il") == 0)
 622                                 continue;
 623 
 624                         if (!in_output && arglen > 2 &&
 625                             arg[arglen - 2] == '.' &&
 626                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
 627                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
 628                                 c_files++;
 629 
 630                         /*
 631                          * Otherwise, filenames and partial arguments
 632                          * are passed through for gcc to chew on.  However,
 633                          * output is always discarded for the secondary
 634                          * compiler.
 635                          */
 636                         if ((ctx->i_flags & CW_F_SHADOW) && in_output)
 637                                 newae(ctx->i_ae, ctx->i_discard);
 638                         else
 639                                 newae(ctx->i_ae, arg);

 640                         in_output = 0;
 641                         continue;
 642                 }
 643 
 644                 if (ctx->i_flags & CW_F_CXX) {
 645                         if (strncmp(arg, "-_g++=", 6) == 0) {
 646                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
 647                                 continue;
 648                         }
 649                         if (strncmp(arg, "-compat=", 8) == 0) {
 650                                 /* discard -compat=4 and -compat=5 */
 651                                 continue;
 652                         }
 653                         if (strcmp(arg, "-Qoption") == 0) {
 654                                 /* discard -Qoption and its two arguments */
 655                                 if (ctx->i_oldargc < 3)
 656                                         error(arg);
 657                                 ctx->i_oldargc -= 2;
 658                                 ctx->i_oldargv += 2;
 659                                 continue;


 735                         break;
 736                 case 'A':
 737                 case 'h':
 738                 case 'I':
 739                 case 'i':
 740                 case 'L':
 741                 case 'l':
 742                 case 'R':
 743                 case 'U':
 744                 case 'u':
 745                 case 'w':
 746                         newae(ctx->i_ae, arg);
 747                         break;
 748                 case 'o':
 749                         seen_o = 1;
 750                         if (arglen == 1) {
 751                                 in_output = 1;
 752                                 newae(ctx->i_ae, arg);
 753                         } else if (ctx->i_flags & CW_F_SHADOW) {
 754                                 newae(ctx->i_ae, "-o");
 755                                 newae(ctx->i_ae, ctx->i_discard);
 756                         } else {
 757                                 newae(ctx->i_ae, arg);
 758                         }
 759                         break;
 760                 case 'D':
 761                         newae(ctx->i_ae, arg);
 762                         /*
 763                          * XXX  Clearly a hack ... do we need _KADB too?
 764                          */
 765                         if (strcmp(arg, "-D_KERNEL") == 0 ||
 766                             strcmp(arg, "-D_BOOT") == 0)
 767                                 newae(ctx->i_ae, "-ffreestanding");
 768                         break;
 769                 case 'd':
 770                         if (arglen == 2) {
 771                                 if (strcmp(arg, "-dy") == 0) {
 772                                         newae(ctx->i_ae, "-Wl,-dy");
 773                                         break;
 774                                 }
 775                                 if (strcmp(arg, "-dn") == 0) {


1173                                 s[1] = 'I';
1174                                 newae(ctx->i_ae, "-nostdinc");
1175                                 newae(ctx->i_ae, s);
1176                                 free(s);
1177                                 break;
1178                         }
1179                         error(arg);
1180                         break;
1181                 case 'Q':
1182                         /*
1183                          * We could map -Qy into -Wl,-Qy etc.
1184                          */
1185                 default:
1186                         error(arg);
1187                         break;
1188                 }
1189         }
1190 
1191         free(nameflag);
1192 
1193         if (c_files > 1 && (ctx->i_flags & CW_F_SHADOW) &&
1194             op != CW_O_PREPROCESS) {








1195                 errx(2, "multiple source files are "
1196                     "allowed only with -E or -P");
1197         }
1198 
1199         /*
1200          * Make sure that we do not have any unintended interactions between
1201          * the xarch options passed in and the version of the Studio compiler
1202          * used.
1203          */
1204         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1205                 errx(2,
1206                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1207         }
1208 
1209         switch (mflag) {
1210         case 0:
1211                 /* FALLTHROUGH */
1212         case M32:
1213 #if defined(__sparc)
1214                 /*


1242                 break;
1243         case (SS12|M32):
1244 #if defined(__sparc)
1245                 /*
1246                  * Need to add in further 32 bit options because with SS12
1247                  * the xarch=sparcvis option can be applied to 32 or 64
1248                  * bit, and so the translatation table (xtbl) cannot handle
1249                  * that.
1250                  */
1251                 newae(ctx->i_ae, "-mv8plus");
1252 #endif
1253                 break;
1254         case (SS12|M64):
1255                 break;
1256         default:
1257                 (void) fprintf(stderr,
1258                     "Incompatible -xarch= and/or -m32/-m64 options used.\n");
1259                 exit(2);
1260         }
1261 
1262         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1263             (ctx->i_flags & CW_F_SHADOW))


1264                 exit(0);

1265 
1266         if (model != NULL)
1267                 newae(ctx->i_ae, model);
1268         if (!nolibc)
1269                 newae(ctx->i_ae, "-lc");
1270         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1271                 newae(ctx->i_ae, "-o");
1272                 newae(ctx->i_ae, ctx->i_discard);
1273         }
1274 }
1275 
1276 static void
1277 do_smatch(cw_ictx_t *ctx)
1278 {
1279         if (ctx->i_flags & CW_F_PROG) {
1280                 newae(ctx->i_ae, "--version");
1281                 return;
1282         }
1283 
1284         /*
1285          * Some sources shouldn't run smatch at all.
1286          */
1287         for (int i = 0; i < ctx->i_oldargc; i++) {
1288                 char *arg = ctx->i_oldargv[i];
1289 
1290                 if (strcmp(arg, "-_smatch=off") == 0) {
1291                         ctx->i_flags &= ~ (CW_F_EXEC | CW_F_ECHO);
1292                         return;
1293                 }
1294         }
1295 
1296         /*
1297          * smatch can handle gcc's options.
1298          */
1299         do_gcc(ctx);
1300 }
1301 
1302 static void
1303 do_cc(cw_ictx_t *ctx)
1304 {
1305         int in_output = 0, seen_o = 0;
1306         cw_op_t op = CW_O_LINK;
1307         char *nameflag;
1308 
1309         if (ctx->i_flags & CW_F_PROG) {
1310                 newae(ctx->i_ae, "-V");
1311                 return;
1312         }
1313 
1314         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1315                 nomem();
1316 
1317         while (--ctx->i_oldargc > 0) {
1318                 char *arg = *++ctx->i_oldargv;

1319 
1320                 if (strncmp(arg, "-_CC=", 5) == 0) {
1321                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1322                         continue;
1323                 }
1324 
1325                 if (*arg != '-') {






1326                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1327                                 newae(ctx->i_ae, arg);
1328                         } else {
1329                                 in_output = 0;
1330                                 newae(ctx->i_ae, ctx->i_discard);
1331                         }
1332                         continue;
1333                 }
1334                 switch (*(arg + 1)) {
1335                 case '_':
1336                         if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
1337                             (strncmp(arg, "-_cc=", 5) == 0) ||
1338                             (strncmp(arg, "-_sun=", 6) == 0)) {
1339                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
1340                         }
1341                         break;
1342 
1343                 case 'V':
1344                         ctx->i_flags &= ~CW_F_ECHO;
1345                         newae(ctx->i_ae, arg);
1346                         break;
1347                 case 'o':
1348                         seen_o = 1;
1349                         if (strlen(arg) == 2) {
1350                                 in_output = 1;
1351                                 newae(ctx->i_ae, arg);
1352                         } else if (ctx->i_flags & CW_F_SHADOW) {
1353                                 newae(ctx->i_ae, "-o");
1354                                 newae(ctx->i_ae, ctx->i_discard);
1355                         } else {
1356                                 newae(ctx->i_ae, arg);
1357                         }
1358                         break;
1359                 case 'c':
1360                 case 'S':
1361                         if (strlen(arg) == 2)
1362                                 op = CW_O_COMPILE;
1363                         newae(ctx->i_ae, arg);
1364                         break;
1365                 case 'E':
1366                 case 'P':
1367                         if (strlen(arg) == 2)
1368                                 op = CW_O_PREPROCESS;
1369                 /*FALLTHROUGH*/
1370                 default:
1371                         newae(ctx->i_ae, arg);
1372                 }
1373         }
1374 
1375         free(nameflag);
1376 
1377         if ((op == CW_O_LINK || op == CW_O_PREPROCESS) &&
1378             (ctx->i_flags & CW_F_SHADOW))






1379                 exit(0);



1380 
1381         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1382                 newae(ctx->i_ae, "-o");
1383                 newae(ctx->i_ae, ctx->i_discard);
1384         }
1385 }
1386 
1387 static void
1388 prepctx(cw_ictx_t *ctx)
1389 {
1390         newae(ctx->i_ae, ctx->i_compiler->c_path);
1391 
1392         if (ctx->i_flags & CW_F_PROG) {
1393                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1394                     "shadow" : "primary", ctx->i_compiler->c_path);
1395                 (void) fflush(stdout);
1396         }
1397 
1398         if (!(ctx->i_flags & CW_F_XLATE))
1399                 return;
1400 
1401         switch (ctx->i_compiler->c_style) {
1402         case SUN:
1403                 do_cc(ctx);


1474          */
1475         if (ctx->i_pid <= 0)
1476                 return (-1);
1477 
1478         do {
1479                 if (waitpid(ctx->i_pid, &status, 0) < 0) {
1480                         warn("cannot reap child");
1481                         return (-1);
1482                 }
1483                 if (status != 0) {
1484                         if (WIFSIGNALED(status)) {
1485                                 ret = -WTERMSIG(status);
1486                                 break;
1487                         } else if (WIFEXITED(status)) {
1488                                 ret = WEXITSTATUS(status);
1489                                 break;
1490                         }
1491                 }
1492         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1493 
1494         (void) unlink(ctx->i_discard);
1495 
1496         if (stat(ctx->i_stderr, &s) < 0) {
1497                 warn("stat failed on child cleanup");
1498                 return (-1);
1499         }
1500         if (s.st_size != 0) {
1501                 FILE *f;
1502 
1503                 if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
1504                         while (fgets(buf, sizeof (buf), f))
1505                                 (void) fprintf(stderr, "%s", buf);
1506                         (void) fflush(stderr);
1507                         (void) fclose(f);
1508                 }
1509         }
1510         (void) unlink(ctx->i_stderr);
1511         free(ctx->i_stderr);
1512 
1513         /*
1514          * cc returns an error code when given -V; we want that to succeed.
1515          */
1516         if (ctx->i_flags & CW_F_PROG)
1517                 return (0);
1518 
1519         return (ret);
1520 }
1521 
1522 static int
1523 exec_ctx(cw_ictx_t *ctx, int block)
1524 {
1525         char *file;
1526 
1527         /*
1528          * To avoid offending cc's sensibilities, the name of its output
1529          * file must end in '.o'.
1530          */
1531         if ((file = tempnam(NULL, ".cw")) == NULL) {
1532                 nomem();
1533                 return (-1);
1534         }
1535         (void) strlcpy(ctx->i_discard, file, MAXPATHLEN);
1536         (void) strlcat(ctx->i_discard, ".o", MAXPATHLEN);
1537         free(file);
1538 
1539         if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) {
1540                 nomem();
1541                 return (-1);
1542         }
1543 
1544         if ((ctx->i_pid = fork()) == 0) {
1545                 int fd;
1546 
1547                 (void) fclose(stderr);
1548                 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
1549                     0666)) < 0) {
1550                         err(1, "open failed for standard error");
1551                 }
1552                 if (dup2(fd, 2) < 0) {
1553                         err(1, "dup2 failed for standard error");
1554                 }
1555                 if (fd != 2)
1556                         (void) close(fd);
1557                 if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1558                         err(1, "freopen failed for /dev/fd/2");
1559                 }


1590 
1591         if ((token = strsep(&tspec, ",")) == NULL)
1592                 errx(1, "Compiler is missing a style: %s", spec);
1593 
1594         if ((strcasecmp(token, "gnu") == 0) ||
1595             (strcasecmp(token, "gcc") == 0)) {
1596                 compiler->c_style = GNU;
1597         } else if ((strcasecmp(token, "sun") == 0) ||
1598             (strcasecmp(token, "cc") == 0)) {
1599                 compiler->c_style = SUN;
1600         } else if ((strcasecmp(token, "smatch") == 0)) {
1601                 compiler->c_style = SMATCH;
1602         } else {
1603                 errx(1, "unknown compiler style: %s", token);
1604         }
1605 
1606         if (tspec != NULL)
1607                 errx(1, "Excess tokens in compiler: %s", spec);
1608 }
1609 










































1610 int
1611 main(int argc, char **argv)
1612 {
1613         int ch;
1614         cw_compiler_t primary = { NULL, NULL, 0 };
1615         cw_compiler_t shadows[10];
1616         int nshadows = 0;
1617         int ret = 0;
1618         boolean_t do_serial = B_FALSE;
1619         boolean_t do_exec = B_FALSE;
1620         boolean_t vflg = B_FALSE;
1621         boolean_t Cflg = B_FALSE;
1622         boolean_t cflg = B_FALSE;
1623         boolean_t nflg = B_FALSE;

1624 
1625         cw_ictx_t *main_ctx;
1626 
1627         static struct option longopts[] = {
1628                 { "compiler", no_argument, NULL, 'c' },
1629                 { "noecho", no_argument, NULL, 'n' },
1630                 { "primary", required_argument, NULL, 'p' },
1631                 { "shadow", required_argument, NULL, 's' },
1632                 { "versions", no_argument, NULL, 'v' },
1633                 { NULL, 0, NULL, 0 },
1634         };
1635 
1636 
1637         if ((main_ctx = newictx()) == NULL)
1638                 nomem();
1639 
1640         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1641                 switch (ch) {
1642                 case 'c':
1643                         cflg = B_TRUE;


1691         if (nflg == 0)
1692                 main_ctx->i_flags |= CW_F_ECHO;
1693         if (do_exec)
1694                 main_ctx->i_flags |= CW_F_EXEC;
1695         if (Cflg)
1696                 main_ctx->i_flags |= CW_F_CXX;
1697         main_ctx->i_compiler = &primary;
1698 
1699         if (cflg) {
1700                 (void) fputs(primary.c_path, stdout);
1701         }
1702 
1703         if (vflg) {
1704                 (void) printf("cw version %s\n", CW_VERSION);
1705                 (void) fflush(stdout);
1706                 main_ctx->i_flags &= ~CW_F_ECHO;
1707                 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
1708                 do_serial = 1;
1709         }
1710 










1711         ret |= exec_ctx(main_ctx, do_serial);
1712 
1713         for (int i = 0; i < nshadows; i++) {
1714                 int r;
1715                 cw_ictx_t *shadow_ctx;
1716 
1717                 if ((shadow_ctx = newictx()) == NULL)
1718                         nomem();
1719 
1720                 memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1721 
1722                 shadow_ctx->i_flags |= CW_F_SHADOW;
1723                 shadow_ctx->i_compiler = &shadows[i];
1724 
1725                 r = exec_ctx(shadow_ctx, do_serial);
1726                 if (r == 0) {
1727                         shadow_ctx->i_next = main_ctx->i_next;
1728                         main_ctx->i_next = shadow_ctx;
1729                 }
1730                 ret |= r;
1731         }
1732 
1733         if (!do_serial) {
1734                 cw_ictx_t *next = main_ctx;
1735                 while (next != NULL) {
1736                         cw_ictx_t *toreap = next;
1737                         next = next->i_next;
1738                         ret |= reap(toreap);
1739                 }
1740         }
1741 

1742         return (ret);
1743 }


 245  * -xtransition                 -Wtransition
 246  * -xunroll=n                   error
 247  * -W0,-xdbggen=no%usedonly     -fno-eliminate-unused-debug-symbols
 248  *                              -fno-eliminate-unused-debug-types
 249  * -Y<c>,<dir>                      error
 250  * -YA,<dir>                      error
 251  * -YI,<dir>                      -nostdinc -I<dir>
 252  * -YP,<dir>                      error
 253  * -YS,<dir>                      error
 254  */
 255 
 256 #include <ctype.h>
 257 #include <err.h>
 258 #include <errno.h>
 259 #include <fcntl.h>
 260 #include <getopt.h>
 261 #include <stdio.h>
 262 #include <stdlib.h>
 263 #include <string.h>
 264 #include <unistd.h>
 265 #include <dirent.h>
 266 
 267 #include <sys/param.h>
 268 #include <sys/stat.h>
 269 #include <sys/types.h>
 270 #include <sys/utsname.h>
 271 #include <sys/wait.h>
 272 
 273 #define CW_F_CXX        0x01
 274 #define CW_F_SHADOW     0x02
 275 #define CW_F_EXEC       0x04
 276 #define CW_F_ECHO       0x08
 277 #define CW_F_XLATE      0x10
 278 #define CW_F_PROG       0x20
 279 
 280 typedef enum cw_op {
 281         CW_O_NONE = 0,
 282         CW_O_PREPROCESS,
 283         CW_O_COMPILE,
 284         CW_O_LINK
 285 } cw_op_t;


 295 typedef enum {
 296         GNU,
 297         SUN,
 298         SMATCH
 299 } compiler_style_t;
 300 
 301 typedef struct {
 302         char *c_name;
 303         char *c_path;
 304         compiler_style_t c_style;
 305 } cw_compiler_t;
 306 
 307 typedef struct cw_ictx {
 308         struct cw_ictx  *i_next;
 309         cw_compiler_t   *i_compiler;
 310         struct aelist   *i_ae;
 311         uint32_t        i_flags;
 312         int             i_oldargc;
 313         char            **i_oldargv;
 314         pid_t           i_pid;
 315         char            *i_tmpdir;
 316         char            *i_stderr;
 317 } cw_ictx_t;
 318 
 319 /*
 320  * Status values to indicate which Studio compiler and associated
 321  * flags are being used.
 322  */
 323 #define M32             0x01    /* -m32 - only on Studio 12 */
 324 #define M64             0x02    /* -m64 - only on Studio 12 */
 325 #define SS11            0x100   /* Studio 11 */
 326 #define SS12            0x200   /* Studio 12 */
 327 
 328 #define TRANS_ENTRY     5
 329 /*
 330  * Translation table definition for the -xarch= flag. The "x_arg"
 331  * value is translated into the appropriate gcc flags according
 332  * to the values in x_trans[n]. The x_flags indicates what compiler
 333  * is being used and what flags have been set via the use of
 334  * "x_arg".
 335  */


 540 static void
 541 xlate(struct aelist *h, const char *xarg, const char **table)
 542 {
 543         while (*table != NULL && strcmp(xarg, *table) != 0) {
 544                 while (*table != NULL)
 545                         table++;
 546                 table++;
 547         }
 548 
 549         if (*table == NULL)
 550                 error(xarg);
 551 
 552         table++;
 553 
 554         while (*table != NULL) {
 555                 newae(h, *table);
 556                 table++;
 557         }
 558 }
 559 
 560 /*
 561  * The compiler wants the output file to end in appropriate extension.  If
 562  * we're generating a name from whole cloth (path == NULL), we assume that
 563  * extension to be .o, otherwise we match the extension of the caller.
 564  */
 565 static char *
 566 discard_file_name(cw_ictx_t *ctx, const char *path)
 567 {
 568         char *ret, *ext;
 569         char tmpl[] = "cwXXXXXX";
 570 
 571         if (path == NULL) {
 572                 ext = ".o";
 573         } else {
 574                 ext = strrchr(path, '.');
 575         }
 576 
 577         /*
 578          * We need absolute control over where the temporary file goes, since
 579          * we rely on it for cleanup so tempnam(3C) and tmpnam(3C) are
 580          * inappropriate (they use TMPDIR, preferentially).
 581          *
 582          * mkstemp(3C) doesn't actually help us, since the temporary file
 583          * isn't used by us, only its name.
 584          */
 585         if (mktemp(tmpl) == NULL)
 586                 nomem();
 587 
 588         (void) asprintf(&ret, "%s/%s%s", ctx->i_tmpdir, tmpl,
 589             (ext != NULL) ? ext : "");
 590 
 591         if (ret == NULL)
 592                 nomem();
 593 
 594         return (ret);
 595 }
 596 
 597 static void
 598 do_gcc(cw_ictx_t *ctx)
 599 {
 600         int c;
 601         int nolibc = 0;
 602         int in_output = 0, seen_o = 0, c_files = 0;
 603         cw_op_t op = CW_O_LINK;
 604         char *model = NULL;
 605         char *nameflag;
 606         int mflag = 0;
 607 
 608         if (ctx->i_flags & CW_F_PROG) {
 609                 newae(ctx->i_ae, "--version");
 610                 return;
 611         }
 612 
 613         newae(ctx->i_ae, "-fident");
 614         newae(ctx->i_ae, "-finline");
 615         newae(ctx->i_ae, "-fno-inline-functions");
 616         newae(ctx->i_ae, "-fno-builtin");


 654                 } else {
 655                         /*
 656                          * Discard inline files that gcc doesn't grok
 657                          */
 658                         if (!in_output && arglen > 3 &&
 659                             strcmp(arg + arglen - 3, ".il") == 0)
 660                                 continue;
 661 
 662                         if (!in_output && arglen > 2 &&
 663                             arg[arglen - 2] == '.' &&
 664                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
 665                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
 666                                 c_files++;
 667 
 668                         /*
 669                          * Otherwise, filenames and partial arguments
 670                          * are passed through for gcc to chew on.  However,
 671                          * output is always discarded for the secondary
 672                          * compiler.
 673                          */
 674                         if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
 675                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
 676                         } else {
 677                                 newae(ctx->i_ae, arg);
 678                         }
 679                         in_output = 0;
 680                         continue;
 681                 }
 682 
 683                 if (ctx->i_flags & CW_F_CXX) {
 684                         if (strncmp(arg, "-_g++=", 6) == 0) {
 685                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
 686                                 continue;
 687                         }
 688                         if (strncmp(arg, "-compat=", 8) == 0) {
 689                                 /* discard -compat=4 and -compat=5 */
 690                                 continue;
 691                         }
 692                         if (strcmp(arg, "-Qoption") == 0) {
 693                                 /* discard -Qoption and its two arguments */
 694                                 if (ctx->i_oldargc < 3)
 695                                         error(arg);
 696                                 ctx->i_oldargc -= 2;
 697                                 ctx->i_oldargv += 2;
 698                                 continue;


 774                         break;
 775                 case 'A':
 776                 case 'h':
 777                 case 'I':
 778                 case 'i':
 779                 case 'L':
 780                 case 'l':
 781                 case 'R':
 782                 case 'U':
 783                 case 'u':
 784                 case 'w':
 785                         newae(ctx->i_ae, arg);
 786                         break;
 787                 case 'o':
 788                         seen_o = 1;
 789                         if (arglen == 1) {
 790                                 in_output = 1;
 791                                 newae(ctx->i_ae, arg);
 792                         } else if (ctx->i_flags & CW_F_SHADOW) {
 793                                 newae(ctx->i_ae, "-o");
 794                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
 795                         } else {
 796                                 newae(ctx->i_ae, arg);
 797                         }
 798                         break;
 799                 case 'D':
 800                         newae(ctx->i_ae, arg);
 801                         /*
 802                          * XXX  Clearly a hack ... do we need _KADB too?
 803                          */
 804                         if (strcmp(arg, "-D_KERNEL") == 0 ||
 805                             strcmp(arg, "-D_BOOT") == 0)
 806                                 newae(ctx->i_ae, "-ffreestanding");
 807                         break;
 808                 case 'd':
 809                         if (arglen == 2) {
 810                                 if (strcmp(arg, "-dy") == 0) {
 811                                         newae(ctx->i_ae, "-Wl,-dy");
 812                                         break;
 813                                 }
 814                                 if (strcmp(arg, "-dn") == 0) {


1212                                 s[1] = 'I';
1213                                 newae(ctx->i_ae, "-nostdinc");
1214                                 newae(ctx->i_ae, s);
1215                                 free(s);
1216                                 break;
1217                         }
1218                         error(arg);
1219                         break;
1220                 case 'Q':
1221                         /*
1222                          * We could map -Qy into -Wl,-Qy etc.
1223                          */
1224                 default:
1225                         error(arg);
1226                         break;
1227                 }
1228         }
1229 
1230         free(nameflag);
1231 
1232         /*
1233          * When compiling multiple source files in a single invocation some
1234          * compilers output objects into the current directory with
1235          * predictable and conventional names.
1236          *
1237          * We prevent any attempt to compile multiple files at once so that
1238          * any such objects created by a shadow can't escape into a later
1239          * link-edit.
1240          */
1241         if (c_files > 1 && op != CW_O_PREPROCESS) {
1242                 errx(2, "multiple source files are "
1243                     "allowed only with -E or -P");
1244         }
1245 
1246         /*
1247          * Make sure that we do not have any unintended interactions between
1248          * the xarch options passed in and the version of the Studio compiler
1249          * used.
1250          */
1251         if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
1252                 errx(2,
1253                     "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
1254         }
1255 
1256         switch (mflag) {
1257         case 0:
1258                 /* FALLTHROUGH */
1259         case M32:
1260 #if defined(__sparc)
1261                 /*


1289                 break;
1290         case (SS12|M32):
1291 #if defined(__sparc)
1292                 /*
1293                  * Need to add in further 32 bit options because with SS12
1294                  * the xarch=sparcvis option can be applied to 32 or 64
1295                  * bit, and so the translatation table (xtbl) cannot handle
1296                  * that.
1297                  */
1298                 newae(ctx->i_ae, "-mv8plus");
1299 #endif
1300                 break;
1301         case (SS12|M64):
1302                 break;
1303         default:
1304                 (void) fprintf(stderr,
1305                     "Incompatible -xarch= and/or -m32/-m64 options used.\n");
1306                 exit(2);
1307         }
1308 
1309         if (ctx->i_flags & CW_F_SHADOW) {
1310                 if (op == CW_O_PREPROCESS)
1311                         exit(0);
1312                 else if (op == CW_O_LINK && c_files == 0)
1313                         exit(0);
1314         }
1315 
1316         if (model != NULL)
1317                 newae(ctx->i_ae, model);
1318         if (!nolibc)
1319                 newae(ctx->i_ae, "-lc");
1320         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1321                 newae(ctx->i_ae, "-o");
1322                 newae(ctx->i_ae, discard_file_name(ctx, NULL));
1323         }
1324 }
1325 
1326 static void
1327 do_smatch(cw_ictx_t *ctx)
1328 {
1329         if (ctx->i_flags & CW_F_PROG) {
1330                 newae(ctx->i_ae, "--version");
1331                 return;
1332         }
1333 
1334         /*
1335          * Some sources shouldn't run smatch at all.
1336          */
1337         for (int i = 0; i < ctx->i_oldargc; i++) {
1338                 char *arg = ctx->i_oldargv[i];
1339 
1340                 if (strcmp(arg, "-_smatch=off") == 0) {
1341                         ctx->i_flags &= ~ (CW_F_EXEC | CW_F_ECHO);
1342                         return;
1343                 }
1344         }
1345 
1346         /*
1347          * smatch can handle gcc's options.
1348          */
1349         do_gcc(ctx);
1350 }
1351 
1352 static void
1353 do_cc(cw_ictx_t *ctx)
1354 {
1355         int in_output = 0, seen_o = 0, c_files = 0;
1356         cw_op_t op = CW_O_LINK;
1357         char *nameflag;
1358 
1359         if (ctx->i_flags & CW_F_PROG) {
1360                 newae(ctx->i_ae, "-V");
1361                 return;
1362         }
1363 
1364         if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
1365                 nomem();
1366 
1367         while (--ctx->i_oldargc > 0) {
1368                 char *arg = *++ctx->i_oldargv;
1369                 size_t arglen = strlen(arg);
1370 
1371                 if (strncmp(arg, "-_CC=", 5) == 0) {
1372                         newae(ctx->i_ae, strchr(arg, '=') + 1);
1373                         continue;
1374                 }
1375 
1376                 if (*arg != '-') {
1377                         if (!in_output && arglen > 2 &&
1378                             arg[arglen - 2] == '.' &&
1379                             (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
1380                             arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
1381                                 c_files++;
1382 
1383                         if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
1384                                 newae(ctx->i_ae, arg);
1385                         } else {
1386                                 in_output = 0;
1387                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
1388                         }
1389                         continue;
1390                 }
1391                 switch (*(arg + 1)) {
1392                 case '_':
1393                         if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
1394                             (strncmp(arg, "-_cc=", 5) == 0) ||
1395                             (strncmp(arg, "-_sun=", 6) == 0)) {
1396                                 newae(ctx->i_ae, strchr(arg, '=') + 1);
1397                         }
1398                         break;
1399 
1400                 case 'V':
1401                         ctx->i_flags &= ~CW_F_ECHO;
1402                         newae(ctx->i_ae, arg);
1403                         break;
1404                 case 'o':
1405                         seen_o = 1;
1406                         if (strlen(arg) == 2) {
1407                                 in_output = 1;
1408                                 newae(ctx->i_ae, arg);
1409                         } else if (ctx->i_flags & CW_F_SHADOW) {
1410                                 newae(ctx->i_ae, "-o");
1411                                 newae(ctx->i_ae, discard_file_name(ctx, arg));
1412                         } else {
1413                                 newae(ctx->i_ae, arg);
1414                         }
1415                         break;
1416                 case 'c':
1417                 case 'S':
1418                         if (strlen(arg) == 2)
1419                                 op = CW_O_COMPILE;
1420                         newae(ctx->i_ae, arg);
1421                         break;
1422                 case 'E':
1423                 case 'P':
1424                         if (strlen(arg) == 2)
1425                                 op = CW_O_PREPROCESS;
1426                 /*FALLTHROUGH*/
1427                 default:
1428                         newae(ctx->i_ae, arg);
1429                 }
1430         }
1431 
1432         free(nameflag);
1433 
1434         /* See the comment on this same code in do_gcc() */
1435         if (c_files > 1 && op != CW_O_PREPROCESS) {
1436                 errx(2, "multiple source files are "
1437                     "allowed only with -E or -P");
1438         }
1439 
1440         if (ctx->i_flags & CW_F_SHADOW) {
1441                 if (op == CW_O_PREPROCESS)
1442                         exit(0);
1443                 else if (op == CW_O_LINK && c_files == 0)
1444                         exit(0);
1445         }
1446 
1447         if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
1448                 newae(ctx->i_ae, "-o");
1449                 newae(ctx->i_ae, discard_file_name(ctx, NULL));
1450         }
1451 }
1452 
1453 static void
1454 prepctx(cw_ictx_t *ctx)
1455 {
1456         newae(ctx->i_ae, ctx->i_compiler->c_path);
1457 
1458         if (ctx->i_flags & CW_F_PROG) {
1459                 (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
1460                     "shadow" : "primary", ctx->i_compiler->c_path);
1461                 (void) fflush(stdout);
1462         }
1463 
1464         if (!(ctx->i_flags & CW_F_XLATE))
1465                 return;
1466 
1467         switch (ctx->i_compiler->c_style) {
1468         case SUN:
1469                 do_cc(ctx);


1540          */
1541         if (ctx->i_pid <= 0)
1542                 return (-1);
1543 
1544         do {
1545                 if (waitpid(ctx->i_pid, &status, 0) < 0) {
1546                         warn("cannot reap child");
1547                         return (-1);
1548                 }
1549                 if (status != 0) {
1550                         if (WIFSIGNALED(status)) {
1551                                 ret = -WTERMSIG(status);
1552                                 break;
1553                         } else if (WIFEXITED(status)) {
1554                                 ret = WEXITSTATUS(status);
1555                                 break;
1556                         }
1557                 }
1558         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
1559 


1560         if (stat(ctx->i_stderr, &s) < 0) {
1561                 warn("stat failed on child cleanup");
1562                 return (-1);
1563         }
1564         if (s.st_size != 0) {
1565                 FILE *f;
1566 
1567                 if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
1568                         while (fgets(buf, sizeof (buf), f))
1569                                 (void) fprintf(stderr, "%s", buf);
1570                         (void) fflush(stderr);
1571                         (void) fclose(f);
1572                 }
1573         }
1574         (void) unlink(ctx->i_stderr);
1575         free(ctx->i_stderr);
1576 
1577         /*
1578          * cc returns an error code when given -V; we want that to succeed.
1579          */
1580         if (ctx->i_flags & CW_F_PROG)
1581                 return (0);
1582 
1583         return (ret);
1584 }
1585 
1586 static int
1587 exec_ctx(cw_ictx_t *ctx, int block)
1588 {
1589         if ((ctx->i_stderr = tempnam(ctx->i_tmpdir, "cw")) == NULL) {














1590                 nomem();
1591                 return (-1);
1592         }
1593 
1594         if ((ctx->i_pid = fork()) == 0) {
1595                 int fd;
1596 
1597                 (void) fclose(stderr);
1598                 if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
1599                     0666)) < 0) {
1600                         err(1, "open failed for standard error");
1601                 }
1602                 if (dup2(fd, 2) < 0) {
1603                         err(1, "dup2 failed for standard error");
1604                 }
1605                 if (fd != 2)
1606                         (void) close(fd);
1607                 if (freopen("/dev/fd/2", "w", stderr) == NULL) {
1608                         err(1, "freopen failed for /dev/fd/2");
1609                 }


1640 
1641         if ((token = strsep(&tspec, ",")) == NULL)
1642                 errx(1, "Compiler is missing a style: %s", spec);
1643 
1644         if ((strcasecmp(token, "gnu") == 0) ||
1645             (strcasecmp(token, "gcc") == 0)) {
1646                 compiler->c_style = GNU;
1647         } else if ((strcasecmp(token, "sun") == 0) ||
1648             (strcasecmp(token, "cc") == 0)) {
1649                 compiler->c_style = SUN;
1650         } else if ((strcasecmp(token, "smatch") == 0)) {
1651                 compiler->c_style = SMATCH;
1652         } else {
1653                 errx(1, "unknown compiler style: %s", token);
1654         }
1655 
1656         if (tspec != NULL)
1657                 errx(1, "Excess tokens in compiler: %s", spec);
1658 }
1659 
1660 static void
1661 cleanup(cw_ictx_t *ctx)
1662 {
1663         DIR *dirp;
1664         struct dirent *dp;
1665         char buf[MAXPATHLEN];
1666 
1667         if ((dirp = opendir(ctx->i_tmpdir)) == NULL) {
1668                 if (errno != ENOENT) {
1669                         err(1, "couldn't open temp directory: %s",
1670                             ctx->i_tmpdir);
1671                 } else {
1672                         return;
1673                 }
1674         }
1675 
1676         errno = 0;
1677         while ((dp = readdir(dirp)) != NULL) {
1678                 (void) snprintf(buf, MAXPATHLEN, "%s/%s", ctx->i_tmpdir,
1679                     dp->d_name);
1680 
1681                 if (strncmp(dp->d_name, ".", strlen(dp->d_name)) == 0 ||
1682                     strncmp(dp->d_name, "..", strlen(dp->d_name)) == 0)
1683                         continue;
1684 
1685                 if (unlink(buf) == -1)
1686                         err(1, "failed to unlink temp file: %s", dp->d_name);
1687                 errno = 0;
1688         }
1689 
1690         if (errno != 0) {
1691                 err(1, "failed to read temporary directory: %s",
1692                     ctx->i_tmpdir);
1693         }
1694 
1695         (void) closedir(dirp);
1696         if (rmdir(ctx->i_tmpdir) != 0) {
1697                 err(1, "failed to unlink temporary directory: %s",
1698                     ctx->i_tmpdir);
1699         }
1700 }
1701 
1702 int
1703 main(int argc, char **argv)
1704 {
1705         int ch;
1706         cw_compiler_t primary = { NULL, NULL, 0 };
1707         cw_compiler_t shadows[10];
1708         int nshadows = 0;
1709         int ret = 0;
1710         boolean_t do_serial = B_FALSE;
1711         boolean_t do_exec = B_FALSE;
1712         boolean_t vflg = B_FALSE;
1713         boolean_t Cflg = B_FALSE;
1714         boolean_t cflg = B_FALSE;
1715         boolean_t nflg = B_FALSE;
1716         char *tmpdir;
1717 
1718         cw_ictx_t *main_ctx;
1719 
1720         static struct option longopts[] = {
1721                 { "compiler", no_argument, NULL, 'c' },
1722                 { "noecho", no_argument, NULL, 'n' },
1723                 { "primary", required_argument, NULL, 'p' },
1724                 { "shadow", required_argument, NULL, 's' },
1725                 { "versions", no_argument, NULL, 'v' },
1726                 { NULL, 0, NULL, 0 },
1727         };
1728 
1729 
1730         if ((main_ctx = newictx()) == NULL)
1731                 nomem();
1732 
1733         while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
1734                 switch (ch) {
1735                 case 'c':
1736                         cflg = B_TRUE;


1784         if (nflg == 0)
1785                 main_ctx->i_flags |= CW_F_ECHO;
1786         if (do_exec)
1787                 main_ctx->i_flags |= CW_F_EXEC;
1788         if (Cflg)
1789                 main_ctx->i_flags |= CW_F_CXX;
1790         main_ctx->i_compiler = &primary;
1791 
1792         if (cflg) {
1793                 (void) fputs(primary.c_path, stdout);
1794         }
1795 
1796         if (vflg) {
1797                 (void) printf("cw version %s\n", CW_VERSION);
1798                 (void) fflush(stdout);
1799                 main_ctx->i_flags &= ~CW_F_ECHO;
1800                 main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
1801                 do_serial = 1;
1802         }
1803 
1804         tmpdir = getenv("TMPDIR");
1805         if (tmpdir == NULL)
1806                 tmpdir = "/tmp";
1807 
1808         if (asprintf(&main_ctx->i_tmpdir, "%s/cw.XXXXXX", tmpdir) == -1)
1809                 nomem();
1810 
1811         if ((main_ctx->i_tmpdir = mkdtemp(main_ctx->i_tmpdir)) == NULL)
1812                 errx(1, "failed to create temporary directory");
1813 
1814         ret |= exec_ctx(main_ctx, do_serial);
1815 
1816         for (int i = 0; i < nshadows; i++) {
1817                 int r;
1818                 cw_ictx_t *shadow_ctx;
1819 
1820                 if ((shadow_ctx = newictx()) == NULL)
1821                         nomem();
1822 
1823                 (void) memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
1824 
1825                 shadow_ctx->i_flags |= CW_F_SHADOW;
1826                 shadow_ctx->i_compiler = &shadows[i];
1827 
1828                 r = exec_ctx(shadow_ctx, do_serial);
1829                 if (r == 0) {
1830                         shadow_ctx->i_next = main_ctx->i_next;
1831                         main_ctx->i_next = shadow_ctx;
1832                 }
1833                 ret |= r;
1834         }
1835 
1836         if (!do_serial) {
1837                 cw_ictx_t *next = main_ctx;
1838                 while (next != NULL) {
1839                         cw_ictx_t *toreap = next;
1840                         next = next->i_next;
1841                         ret |= reap(toreap);
1842                 }
1843         }
1844 
1845         cleanup(main_ctx);
1846         return (ret);
1847 }