xref: /aosp_15_r20/external/AFLplusplus/src/afl-cc.c (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
1 /*
2    american fuzzy lop++ - compiler instrumentation wrapper
3    -------------------------------------------------------
4 
5    Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse
6 
7    Copyright 2015, 2016 Google Inc. All rights reserved.
8    Copyright 2019-2024 AFLplusplus Project. All rights reserved.
9 
10    Licensed under the Apache License, Version 2.0 (the "License");
11    you may not use this file except in compliance with the License.
12    You may obtain a copy of the License at:
13 
14      https://www.apache.org/licenses/LICENSE-2.0
15 
16  */
17 
18 #define AFL_MAIN
19 
20 #include "common.h"
21 #include "config.h"
22 #include "types.h"
23 #include "debug.h"
24 #include "alloc-inl.h"
25 #include "llvm-alternative-coverage.h"
26 
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <limits.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <sys/stat.h>
36 
37 #if (LLVM_MAJOR - 0 == 0)
38   #undef LLVM_MAJOR
39 #endif
40 #if !defined(LLVM_MAJOR)
41   #define LLVM_MAJOR 0
42 #endif
43 #if (LLVM_MINOR - 0 == 0)
44   #undef LLVM_MINOR
45 #endif
46 #if !defined(LLVM_MINOR)
47   #define LLVM_MINOR 0
48 #endif
49 
50 #ifndef MAX_PARAMS_NUM
51   #define MAX_PARAMS_NUM 2048
52 #endif
53 
54 /** Global declarations -----BEGIN----- **/
55 
56 typedef enum {
57 
58   PARAM_MISS,  // not matched
59   PARAM_SCAN,  // scan only
60   PARAM_KEEP,  // kept as-is
61   PARAM_DROP,  // ignored
62 
63 } param_st;
64 
65 typedef enum {
66 
67   INSTRUMENT_DEFAULT = 0,
68   INSTRUMENT_CLASSIC = 1,
69   INSTRUMENT_AFL = 1,
70   INSTRUMENT_PCGUARD = 2,
71   INSTRUMENT_CFG = 3,
72   INSTRUMENT_LTO = 4,
73   INSTRUMENT_LLVMNATIVE = 5,
74   INSTRUMENT_GCC = 6,
75   INSTRUMENT_CLANG = 7,
76   INSTRUMENT_OPT_CTX = 8,
77   INSTRUMENT_OPT_NGRAM = 16,
78   INSTRUMENT_OPT_CALLER = 32,
79   INSTRUMENT_OPT_CTX_K = 64,
80   INSTRUMENT_OPT_CODECOV = 128,
81 
82 } instrument_mode_id;
83 
84 typedef enum {
85 
86   UNSET = 0,
87   LTO = 1,
88   LLVM = 2,
89   GCC_PLUGIN = 3,
90   GCC = 4,
91   CLANG = 5
92 
93 } compiler_mode_id;
94 
95 static u8 cwd[4096];
96 
97 char instrument_mode_string[18][18] = {
98 
99     "DEFAULT",
100     "CLASSIC",
101     "PCGUARD",
102     "CFG",
103     "LTO",
104     "PCGUARD-NATIVE",
105     "GCC",
106     "CLANG",
107     "CTX",
108     "CALLER",
109     "",
110     "",
111     "",
112     "",
113     "",
114     "",
115     "NGRAM",
116     ""
117 
118 };
119 
120 char compiler_mode_string[7][12] = {
121 
122     "AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN",
123     "GCC",        "CLANG",    ""
124 
125 };
126 
instrument_mode_2str(instrument_mode_id i)127 u8 *instrument_mode_2str(instrument_mode_id i) {
128 
129   return instrument_mode_string[i];
130 
131 }
132 
compiler_mode_2str(compiler_mode_id i)133 u8 *compiler_mode_2str(compiler_mode_id i) {
134 
135   return compiler_mode_string[i];
136 
137 }
138 
getthecwd()139 u8 *getthecwd() {
140 
141   if (getcwd(cwd, sizeof(cwd)) == NULL) {
142 
143     static u8 fail[] = "";
144     return fail;
145 
146   }
147 
148   return cwd;
149 
150 }
151 
152 typedef struct aflcc_state {
153 
154   u8 **cc_params;                      /* Parameters passed to the real CC  */
155   u32  cc_par_cnt;                     /* Param count, including argv0      */
156 
157   u8 *argv0;                           /* Original argv0 (by strdup)        */
158   u8 *callname;                        /* Executable file argv0 indicated   */
159 
160   u8 debug;
161 
162   u8 compiler_mode, plusplus_mode, lto_mode;
163 
164   u8 *lto_flag;
165 
166   u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k;
167 
168   u8 cmplog_mode;
169 
170   u8 have_instr_env, have_gcc, have_clang, have_llvm, have_gcc_plugin, have_lto,
171       have_optimized_pcguard, have_instr_list;
172 
173   u8 fortify_set, x_set, bit_mode, preprocessor_only, have_unroll, have_o,
174       have_pic, have_c, shared_linking, partial_linking, non_dash, have_fp,
175       have_flto, have_hidden, have_fortify, have_fcf, have_staticasan,
176       have_rust_asanrt, have_asan, have_msan, have_ubsan, have_lsan, have_tsan,
177       have_cfisan;
178 
179   // u8 *march_opt;
180   u8  need_aflpplib;
181   int passthrough;
182 
183   u8  use_stdin;                                                   /* dummy */
184   u8 *argvnull;                                                    /* dummy */
185 
186 } aflcc_state_t;
187 
188 void aflcc_state_init(aflcc_state_t *, u8 *argv0);
189 
190 u8 *find_object(aflcc_state_t *, u8 *obj);
191 
192 void find_built_deps(aflcc_state_t *);
193 
194 /* Insert param into the new argv, raise error if MAX_PARAMS_NUM exceeded. */
insert_param(aflcc_state_t * aflcc,u8 * param)195 static inline void insert_param(aflcc_state_t *aflcc, u8 *param) {
196 
197   if (unlikely(aflcc->cc_par_cnt + 1 >= MAX_PARAMS_NUM))
198     FATAL("Too many command line parameters, please increase MAX_PARAMS_NUM.");
199 
200   aflcc->cc_params[aflcc->cc_par_cnt++] = param;
201 
202 }
203 
204 /*
205   Insert a param which contains path to the object file. It uses find_object to
206   get the path based on the name `obj`, and then uses a sprintf like method to
207   format it with `fmt`. If `fmt` is NULL, the inserted arg is same as the path.
208   If `msg` provided, it should be an error msg raised if the path can't be
209   found. `obj` must not be NULL.
210 */
insert_object(aflcc_state_t * aflcc,u8 * obj,u8 * fmt,u8 * msg)211 static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
212                                  u8 *msg) {
213 
214   u8 *_obj_path = find_object(aflcc, obj);
215   if (!_obj_path) {
216 
217     if (msg)
218       FATAL("%s", msg);
219     else
220       FATAL("Unable to find '%s'", obj);
221 
222   } else {
223 
224     if (fmt) {
225 
226       u8 *_obj_path_fmt = alloc_printf(fmt, _obj_path);
227       ck_free(_obj_path);
228       aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path_fmt;
229 
230     } else {
231 
232       aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path;
233 
234     }
235 
236   }
237 
238 }
239 
240 /* Insert params into the new argv, make clang load the pass. */
load_llvm_pass(aflcc_state_t * aflcc,u8 * pass)241 static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
242 
243 #if LLVM_MAJOR >= 11                                /* use new pass manager */
244   #if LLVM_MAJOR < 16
245   insert_param(aflcc, "-fexperimental-new-pass-manager");
246   #endif
247   insert_object(aflcc, pass, "-fpass-plugin=%s", 0);
248 #else
249   insert_param(aflcc, "-Xclang");
250   insert_param(aflcc, "-load");
251   insert_param(aflcc, "-Xclang");
252   insert_object(aflcc, pass, 0, 0);
253 #endif
254 
255 }
256 
debugf_args(int argc,char ** argv)257 static inline void debugf_args(int argc, char **argv) {
258 
259   DEBUGF("cd '%s';", getthecwd());
260   for (int i = 0; i < argc; i++)
261     SAYF(" '%s'", argv[i]);
262   SAYF("\n");
263   fflush(stdout);
264   fflush(stderr);
265 
266 }
267 
268 void compiler_mode_by_callname(aflcc_state_t *);
269 void compiler_mode_by_environ(aflcc_state_t *);
270 void compiler_mode_by_cmdline(aflcc_state_t *, int argc, char **argv);
271 void instrument_mode_by_environ(aflcc_state_t *);
272 void mode_final_checkout(aflcc_state_t *, int argc, char **argv);
273 void mode_notification(aflcc_state_t *);
274 
275 void add_real_argv0(aflcc_state_t *);
276 
277 void add_defs_common(aflcc_state_t *);
278 void add_defs_selective_instr(aflcc_state_t *);
279 void add_defs_persistent_mode(aflcc_state_t *);
280 void add_defs_fortify(aflcc_state_t *, u8);
281 void add_defs_lsan_ctrl(aflcc_state_t *);
282 
283 param_st parse_fsanitize(aflcc_state_t *, u8 *, u8);
284 void     add_sanitizers(aflcc_state_t *, char **envp);
285 void     add_optimized_pcguard(aflcc_state_t *);
286 void     add_native_pcguard(aflcc_state_t *);
287 
288 void add_assembler(aflcc_state_t *);
289 void add_gcc_plugin(aflcc_state_t *);
290 
291 param_st parse_misc_params(aflcc_state_t *, u8 *, u8);
292 void     add_misc_params(aflcc_state_t *);
293 
294 param_st parse_linking_params(aflcc_state_t *, u8 *, u8, u8 *skip_next,
295                               char **argv);
296 
297 void add_lto_linker(aflcc_state_t *);
298 void add_lto_passes(aflcc_state_t *);
299 void add_runtime(aflcc_state_t *);
300 
301 /** Global declarations -----END----- **/
302 
303 /*
304   Init global state struct. We also extract the callname,
305   check debug options and if in C++ mode here.
306 */
aflcc_state_init(aflcc_state_t * aflcc,u8 * argv0)307 void aflcc_state_init(aflcc_state_t *aflcc, u8 *argv0) {
308 
309   // Default NULL/0 is a good start
310   memset(aflcc, 0, sizeof(aflcc_state_t));
311 
312   aflcc->cc_params = ck_alloc(MAX_PARAMS_NUM * sizeof(u8 *));
313   aflcc->cc_par_cnt = 1;
314 
315   aflcc->lto_flag = AFL_CLANG_FLTO;
316 
317   // aflcc->march_opt = CFLAGS_OPT;
318 
319   /* callname & if C++ mode */
320 
321   aflcc->argv0 = ck_strdup(argv0);
322 
323   char *cname = NULL;
324 
325   if ((cname = strrchr(aflcc->argv0, '/')) != NULL) {
326 
327     cname++;
328 
329   } else {
330 
331     cname = aflcc->argv0;
332 
333   }
334 
335   aflcc->callname = cname;
336 
337   if (strlen(cname) > 2 && (strncmp(cname + strlen(cname) - 2, "++", 2) == 0 ||
338                             strstr(cname, "-g++") != NULL)) {
339 
340     aflcc->plusplus_mode = 1;
341 
342   }
343 
344   /* debug */
345 
346   if (getenv("AFL_DEBUG")) {
347 
348     aflcc->debug = 1;
349     if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
350 
351   } else if (getenv("AFL_QUIET")) {
352 
353     be_quiet = 1;
354 
355   }
356 
357   if ((getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) && (!aflcc->debug)) {
358 
359     be_quiet = 1;
360 
361   }
362 
363 }
364 
365 /*
366   Try to find a specific runtime we need, in here:
367 
368   1. firstly we check the $AFL_PATH environment variable location if set
369   2. next we check argv[0] if it has path information and use it
370     a) we also check ../lib/afl
371   3. if 2. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
372      FreeBSD with procfs)
373     a) and check here in ../lib/afl too
374   4. we look into the AFL_PATH define (usually /usr/local/lib/afl)
375   5. we finally try the current directory
376 
377   if all these attempts fail - we return NULL and the caller has to decide
378   what to do. Otherwise the path to obj would be allocated and returned.
379 */
find_object(aflcc_state_t * aflcc,u8 * obj)380 u8 *find_object(aflcc_state_t *aflcc, u8 *obj) {
381 
382   u8 *argv0 = aflcc->argv0;
383 
384   u8 *afl_path = getenv("AFL_PATH");
385   u8 *slash = NULL, *tmp;
386 
387   if (afl_path) {
388 
389     tmp = alloc_printf("%s/%s", afl_path, obj);
390 
391     if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
392 
393     if (!access(tmp, R_OK)) { return tmp; }
394 
395     ck_free(tmp);
396 
397   }
398 
399   if (argv0) {
400 
401     slash = strrchr(argv0, '/');
402 
403     if (slash) {
404 
405       u8 *dir = ck_strdup(argv0);
406 
407       slash = strrchr(dir, '/');
408       *slash = 0;
409 
410       tmp = alloc_printf("%s/%s", dir, obj);
411 
412       if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
413 
414       if (!access(tmp, R_OK)) {
415 
416         ck_free(dir);
417         return tmp;
418 
419       }
420 
421       ck_free(tmp);
422       tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
423 
424       if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
425 
426       if (!access(tmp, R_OK)) {
427 
428         ck_free(dir);
429         return tmp;
430 
431       }
432 
433       ck_free(tmp);
434       ck_free(dir);
435 
436     }
437 
438 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
439     defined(__ANDROID__) || defined(__NetBSD__)
440   #define HAS_PROC_FS 1
441 #endif
442 #ifdef HAS_PROC_FS
443     else {
444 
445       char *procname = NULL;
446   #if defined(__FreeBSD__) || defined(__DragonFly__)
447       procname = "/proc/curproc/file";
448   #elif defined(__linux__) || defined(__ANDROID__)
449       procname = "/proc/self/exe";
450   #elif defined(__NetBSD__)
451       procname = "/proc/curproc/exe";
452   #endif
453       if (procname) {
454 
455         char    exepath[PATH_MAX];
456         ssize_t exepath_len = readlink(procname, exepath, sizeof(exepath));
457         if (exepath_len > 0 && exepath_len < PATH_MAX) {
458 
459           exepath[exepath_len] = 0;
460           slash = strrchr(exepath, '/');
461 
462           if (slash) {
463 
464             *slash = 0;
465             tmp = alloc_printf("%s/%s", exepath, obj);
466 
467             if (!access(tmp, R_OK)) { return tmp; }
468 
469             ck_free(tmp);
470             tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
471 
472             if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
473 
474             if (!access(tmp, R_OK)) { return tmp; }
475 
476             ck_free(tmp);
477 
478           }
479 
480         }
481 
482       }
483 
484     }
485 
486 #endif
487 #undef HAS_PROC_FS
488 
489   }
490 
491   tmp = alloc_printf("%s/%s", AFL_PATH, obj);
492 
493   if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
494 
495   if (!access(tmp, R_OK)) { return tmp; }
496 
497   ck_free(tmp);
498   tmp = alloc_printf("./%s", obj);
499 
500   if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
501 
502   if (!access(tmp, R_OK)) { return tmp; }
503 
504   ck_free(tmp);
505 
506   if (aflcc->debug) DEBUGF("Trying ... giving up\n");
507 
508   return NULL;
509 
510 }
511 
512 /*
513   Deduce some info about compiler toolchains in current system,
514   from the building results of AFL++
515 */
find_built_deps(aflcc_state_t * aflcc)516 void find_built_deps(aflcc_state_t *aflcc) {
517 
518   char *ptr = NULL;
519 
520 #if defined(__x86_64__)
521   if ((ptr = find_object(aflcc, "as")) != NULL) {
522 
523   #ifndef __APPLE__
524     // on OSX clang masquerades as GCC
525     aflcc->have_gcc = 1;
526   #endif
527     aflcc->have_clang = 1;
528     ck_free(ptr);
529 
530   }
531 
532 #endif
533 
534   if ((ptr = find_object(aflcc, "SanitizerCoveragePCGUARD.so")) != NULL) {
535 
536     aflcc->have_optimized_pcguard = 1;
537     ck_free(ptr);
538 
539   }
540 
541 #if (LLVM_MAJOR >= 3)
542 
543   if ((ptr = find_object(aflcc, "SanitizerCoverageLTO.so")) != NULL) {
544 
545     aflcc->have_lto = 1;
546     ck_free(ptr);
547 
548   }
549 
550   if ((ptr = find_object(aflcc, "cmplog-routines-pass.so")) != NULL) {
551 
552     aflcc->have_llvm = 1;
553     ck_free(ptr);
554 
555   }
556 
557 #endif
558 
559 #ifdef __ANDROID__
560   aflcc->have_llvm = 1;
561 #endif
562 
563   if ((ptr = find_object(aflcc, "afl-gcc-pass.so")) != NULL) {
564 
565     aflcc->have_gcc_plugin = 1;
566     ck_free(ptr);
567 
568   }
569 
570 #if !defined(__ANDROID__) && !defined(ANDROID)
571   ptr = find_object(aflcc, "afl-compiler-rt.o");
572 
573   if (!ptr) {
574 
575     FATAL(
576         "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
577         "environment variable.");
578 
579   }
580 
581   if (aflcc->debug) { DEBUGF("rt=%s\n", ptr); }
582 
583   ck_free(ptr);
584 #endif
585 
586 }
587 
588 /** compiler_mode & instrument_mode selecting -----BEGIN----- **/
589 
590 /* Select compiler_mode by callname, such as "afl-clang-fast", etc. */
compiler_mode_by_callname(aflcc_state_t * aflcc)591 void compiler_mode_by_callname(aflcc_state_t *aflcc) {
592 
593   if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
594 
595     /* afl-clang-fast is always created there by makefile
596       just like afl-clang, burdened with special purposes:
597       - If llvm-config is not available (i.e. LLVM_MAJOR is 0),
598         or too old, it falls back to LLVM-NATIVE mode and let
599         the actual compiler complain if doesn't work.
600       - Otherwise try default llvm instruments except LTO.
601     */
602 #if (LLVM_MAJOR >= 3)
603     aflcc->compiler_mode = LLVM;
604 #else
605     aflcc->compiler_mode = CLANG;
606 #endif
607 
608   } else
609 
610 #if (LLVM_MAJOR >= 3)
611 
612       if (strncmp(aflcc->callname, "afl-clang-lto", 13) == 0 ||
613 
614           strncmp(aflcc->callname, "afl-lto", 7) == 0) {
615 
616     aflcc->compiler_mode = LTO;
617 
618   } else
619 
620 #endif
621 
622       if (strncmp(aflcc->callname, "afl-gcc-fast", 12) == 0 ||
623 
624           strncmp(aflcc->callname, "afl-g++-fast", 12) == 0) {
625 
626     aflcc->compiler_mode = GCC_PLUGIN;
627 
628   } else if (strncmp(aflcc->callname, "afl-gcc", 7) == 0 ||
629 
630              strncmp(aflcc->callname, "afl-g++", 7) == 0) {
631 
632     aflcc->compiler_mode = GCC;
633 
634   } else if (strcmp(aflcc->callname, "afl-clang") == 0 ||
635 
636              strcmp(aflcc->callname, "afl-clang++") == 0) {
637 
638     aflcc->compiler_mode = CLANG;
639 
640   }
641 
642 }
643 
644 /*
645   Select compiler_mode by env AFL_CC_COMPILER. And passthrough mode can be
646   regarded as a special compiler_mode, so we check for it here, too.
647 */
compiler_mode_by_environ(aflcc_state_t * aflcc)648 void compiler_mode_by_environ(aflcc_state_t *aflcc) {
649 
650   if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
651 
652     aflcc->passthrough = 1;
653 
654   }
655 
656   char *ptr = getenv("AFL_CC_COMPILER");
657 
658   if (!ptr) { return; }
659 
660   if (aflcc->compiler_mode) {
661 
662     if (!be_quiet) {
663 
664       WARNF(
665           "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
666           "selected by command line parameter or symlink, ignoring the "
667           "environment variable!");
668 
669     }
670 
671   } else {
672 
673     if (strncasecmp(ptr, "LTO", 3) == 0) {
674 
675       aflcc->compiler_mode = LTO;
676 
677     } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
678 
679       aflcc->compiler_mode = LLVM;
680 
681     } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
682 
683                strncasecmp(ptr, "GCC-P", 5) == 0 ||
684                strncasecmp(ptr, "GCCP", 4) == 0) {
685 
686       aflcc->compiler_mode = GCC_PLUGIN;
687 
688     } else if (strcasecmp(ptr, "GCC") == 0) {
689 
690       aflcc->compiler_mode = GCC;
691 
692     } else if (strcasecmp(ptr, "CLANG") == 0) {
693 
694       aflcc->compiler_mode = CLANG;
695 
696     } else
697 
698       FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
699 
700   }
701 
702 }
703 
704 /*
705   Select compiler_mode by command line options --afl-...
706   If it can be inferred, instrument_mode would also be set.
707   This can supersedes previous result based on callname
708   or AFL_CC_COMPILER. And "--afl_noopt"/"--afl-noopt" will
709   be overwritten by "-g".
710 */
compiler_mode_by_cmdline(aflcc_state_t * aflcc,int argc,char ** argv)711 void compiler_mode_by_cmdline(aflcc_state_t *aflcc, int argc, char **argv) {
712 
713   char *ptr = NULL;
714 
715   for (int i = 1; i < argc; i++) {
716 
717     if (strncmp(argv[i], "--afl", 5) == 0) {
718 
719       if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
720 
721         aflcc->passthrough = 1;
722         argv[i] = "-g";  // we have to overwrite it, -g is always good
723         continue;
724 
725       }
726 
727       if (aflcc->compiler_mode && !be_quiet) {
728 
729         WARNF(
730             "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
731             "symlink compiler selection!");
732 
733       }
734 
735       ptr = argv[i];
736       ptr += 5;
737       while (*ptr == '-')
738         ptr++;
739 
740       if (strncasecmp(ptr, "LTO", 3) == 0) {
741 
742         aflcc->compiler_mode = LTO;
743 
744       } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
745 
746         aflcc->compiler_mode = LLVM;
747 
748       } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
749 
750                  strncasecmp(ptr, "PC-GUARD", 8) == 0) {
751 
752         aflcc->compiler_mode = LLVM;
753         aflcc->instrument_mode = INSTRUMENT_PCGUARD;
754 
755       } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
756 
757                  strcasecmp(ptr, "CFG") == 0) {
758 
759         FATAL(
760             "InsTrim instrumentation was removed. Use a modern LLVM and "
761             "PCGUARD (default in afl-cc).\n");
762 
763       } else if (strcasecmp(ptr, "AFL") == 0 ||
764 
765                  strcasecmp(ptr, "CLASSIC") == 0) {
766 
767         aflcc->compiler_mode = LLVM;
768         aflcc->instrument_mode = INSTRUMENT_CLASSIC;
769 
770       } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
771 
772                  strcasecmp(ptr, "NATIVE") == 0 ||
773                  strcasecmp(ptr, "LLVM-NATIVE") == 0) {
774 
775         aflcc->compiler_mode = LLVM;
776         aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
777 
778       } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
779 
780                  strncasecmp(ptr, "GCC-P", 5) == 0 ||
781                  strncasecmp(ptr, "GCCP", 4) == 0) {
782 
783         aflcc->compiler_mode = GCC_PLUGIN;
784 
785       } else if (strcasecmp(ptr, "GCC") == 0) {
786 
787         aflcc->compiler_mode = GCC;
788 
789       } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
790 
791         aflcc->compiler_mode = CLANG;
792 
793       } else
794 
795         FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
796 
797     }
798 
799   }
800 
801 }
802 
803 /*
804   Select instrument_mode by those envs in old style:
805   - USE_TRACE_PC, AFL_USE_TRACE_PC, AFL_LLVM_USE_TRACE_PC, AFL_TRACE_PC
806   - AFL_LLVM_CALLER, AFL_LLVM_CTX, AFL_LLVM_CTX_K
807   - AFL_LLVM_NGRAM_SIZE
808 */
instrument_mode_old_environ(aflcc_state_t * aflcc)809 static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
810 
811   if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
812       getenv("INSTRIM_LIB")) {
813 
814     FATAL(
815         "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
816         "(default in afl-cc).\n");
817 
818   }
819 
820   if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
821       getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
822 
823     if (aflcc->instrument_mode == 0)
824       aflcc->instrument_mode = INSTRUMENT_PCGUARD;
825     else if (aflcc->instrument_mode != INSTRUMENT_PCGUARD)
826       FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
827 
828   }
829 
830   if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
831   if (getenv("AFL_LLVM_CALLER"))
832     aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
833 
834   if (getenv("AFL_LLVM_NGRAM_SIZE")) {
835 
836     aflcc->instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
837     aflcc->ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
838     if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX)
839       FATAL(
840           "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
841           "(%u)",
842           NGRAM_SIZE_MAX);
843 
844   }
845 
846   if (getenv("AFL_LLVM_CTX_K")) {
847 
848     aflcc->ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
849     if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
850       FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
851             CTX_MAX_K);
852     if (aflcc->ctx_k == 1) {
853 
854       setenv("AFL_LLVM_CALLER", "1", 1);
855       unsetenv("AFL_LLVM_CTX_K");
856       aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
857 
858     } else {
859 
860       aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
861 
862     }
863 
864   }
865 
866 }
867 
868 /*
869   Select instrument_mode by env 'AFL_LLVM_INSTRUMENT'.
870   Previous compiler_mode will be superseded, if required by some
871   values of instrument_mode.
872 */
instrument_mode_new_environ(aflcc_state_t * aflcc)873 static void instrument_mode_new_environ(aflcc_state_t *aflcc) {
874 
875   if (!getenv("AFL_LLVM_INSTRUMENT")) { return; }
876 
877   u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
878 
879   while (ptr2) {
880 
881     if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
882         strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
883 
884       if (aflcc->instrument_mode == INSTRUMENT_LTO) {
885 
886         aflcc->instrument_mode = INSTRUMENT_CLASSIC;
887         aflcc->lto_mode = 1;
888 
889       } else if (!aflcc->instrument_mode ||
890 
891                  aflcc->instrument_mode == INSTRUMENT_AFL) {
892 
893         aflcc->instrument_mode = INSTRUMENT_AFL;
894 
895       } else {
896 
897         FATAL("main instrumentation mode already set with %s",
898               instrument_mode_2str(aflcc->instrument_mode));
899 
900       }
901 
902     }
903 
904     if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
905         strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
906 
907       if (!aflcc->instrument_mode ||
908           aflcc->instrument_mode == INSTRUMENT_PCGUARD)
909 
910         aflcc->instrument_mode = INSTRUMENT_PCGUARD;
911 
912       else
913         FATAL("main instrumentation mode already set with %s",
914               instrument_mode_2str(aflcc->instrument_mode));
915 
916     }
917 
918     if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
919         strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
920         strncasecmp(ptr2, "native", strlen("native")) == 0) {
921 
922       if (!aflcc->instrument_mode ||
923           aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE)
924 
925         aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
926 
927       else
928         FATAL("main instrumentation mode already set with %s",
929               instrument_mode_2str(aflcc->instrument_mode));
930 
931     }
932 
933     if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
934         strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
935 
936       if (!aflcc->instrument_mode ||
937           aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
938 
939         aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
940         aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
941 
942       } else {
943 
944         FATAL("main instrumentation mode already set with %s",
945               instrument_mode_2str(aflcc->instrument_mode));
946 
947       }
948 
949     }
950 
951     if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
952         strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
953 
954       FATAL(
955           "InsTrim instrumentation was removed. Use a modern LLVM and "
956           "PCGUARD (default in afl-cc).\n");
957 
958     }
959 
960     if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
961 
962       aflcc->lto_mode = 1;
963       if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_LTO)
964 
965         aflcc->instrument_mode = INSTRUMENT_LTO;
966 
967       else
968         FATAL("main instrumentation mode already set with %s",
969               instrument_mode_2str(aflcc->instrument_mode));
970 
971     }
972 
973     if (strcasecmp(ptr2, "gcc") == 0) {
974 
975       if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_GCC)
976 
977         aflcc->instrument_mode = INSTRUMENT_GCC;
978 
979       else if (aflcc->instrument_mode != INSTRUMENT_GCC)
980         FATAL("main instrumentation mode already set with %s",
981               instrument_mode_2str(aflcc->instrument_mode));
982 
983       aflcc->compiler_mode = GCC;
984 
985     }
986 
987     if (strcasecmp(ptr2, "clang") == 0) {
988 
989       if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_CLANG)
990 
991         aflcc->instrument_mode = INSTRUMENT_CLANG;
992 
993       else if (aflcc->instrument_mode != INSTRUMENT_CLANG)
994         FATAL("main instrumentation mode already set with %s",
995               instrument_mode_2str(aflcc->instrument_mode));
996 
997       aflcc->compiler_mode = CLANG;
998 
999     }
1000 
1001     if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
1002         strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
1003         strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
1004 
1005       u8 *ptr3 = ptr2;
1006       while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
1007         ptr3++;
1008 
1009       if (!*ptr3) {
1010 
1011         if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
1012           FATAL(
1013               "you must set the K-CTX K with (e.g. for value 2) "
1014               "AFL_LLVM_INSTRUMENT=ctx-2");
1015 
1016       }
1017 
1018       aflcc->ctx_k = atoi(ptr3);
1019       if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
1020         FATAL(
1021             "K-CTX instrumentation option must be between 1 and CTX_MAX_K "
1022             "(%u)",
1023             CTX_MAX_K);
1024 
1025       if (aflcc->ctx_k == 1) {
1026 
1027         aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
1028         setenv("AFL_LLVM_CALLER", "1", 1);
1029         unsetenv("AFL_LLVM_CTX_K");
1030 
1031       } else {
1032 
1033         aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
1034         u8 *ptr4 = alloc_printf("%u", aflcc->ctx_k);
1035         setenv("AFL_LLVM_CTX_K", ptr4, 1);
1036 
1037       }
1038 
1039     }
1040 
1041     if (strcasecmp(ptr2, "ctx") == 0) {
1042 
1043       aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
1044       setenv("AFL_LLVM_CTX", "1", 1);
1045 
1046     }
1047 
1048     if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
1049 
1050       aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
1051       setenv("AFL_LLVM_CALLER", "1", 1);
1052 
1053     }
1054 
1055     if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
1056 
1057       u8 *ptr3 = ptr2 + strlen("ngram");
1058       while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) {
1059 
1060         ptr3++;
1061 
1062       }
1063 
1064       if (!*ptr3) {
1065 
1066         if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL)
1067           FATAL(
1068               "you must set the NGRAM size with (e.g. for value 2) "
1069               "AFL_LLVM_INSTRUMENT=ngram-2");
1070 
1071       }
1072 
1073       aflcc->ngram_size = atoi(ptr3);
1074 
1075       if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX) {
1076 
1077         FATAL(
1078             "NGRAM instrumentation option must be between 2 and "
1079             "NGRAM_SIZE_MAX (%u)",
1080             NGRAM_SIZE_MAX);
1081 
1082       }
1083 
1084       aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
1085       u8 *ptr4 = alloc_printf("%u", aflcc->ngram_size);
1086       setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1);
1087 
1088     }
1089 
1090     ptr2 = strtok(NULL, ":,;");
1091 
1092   }
1093 
1094 }
1095 
1096 /*
1097   Select instrument_mode by envs, the top wrapper. We check
1098   have_instr_env firstly, then call instrument_mode_old_environ
1099   and instrument_mode_new_environ sequentially.
1100 */
instrument_mode_by_environ(aflcc_state_t * aflcc)1101 void instrument_mode_by_environ(aflcc_state_t *aflcc) {
1102 
1103   if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
1104       getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
1105       getenv("AFL_LLVM_BLOCKLIST")) {
1106 
1107     aflcc->have_instr_env = 1;
1108 
1109   }
1110 
1111   if (aflcc->have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
1112 
1113     WARNF(
1114         "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
1115         "for file matching, only function matching!");
1116 
1117   }
1118 
1119   instrument_mode_old_environ(aflcc);
1120   instrument_mode_new_environ(aflcc);
1121 
1122 }
1123 
1124 /*
1125   Workaround to ensure CALLER, CTX, K-CTX and NGRAM
1126   instrumentation were used correctly.
1127 */
instrument_opt_mode_exclude(aflcc_state_t * aflcc)1128 static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
1129 
1130   if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
1131       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
1132 
1133     FATAL("you cannot set CTX and CALLER together");
1134 
1135   }
1136 
1137   if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
1138       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
1139 
1140     FATAL("you cannot set CTX and K-CTX together");
1141 
1142   }
1143 
1144   if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
1145       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
1146 
1147     FATAL("you cannot set CALLER and K-CTX together");
1148 
1149   }
1150 
1151   if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM)
1152     FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
1153 
1154   if (aflcc->instrument_opt_mode &&
1155       aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
1156       aflcc->instrument_mode != INSTRUMENT_CLASSIC)
1157     FATAL(
1158         "CALLER, CTX and NGRAM instrumentation options can only be used with "
1159         "the LLVM CLASSIC instrumentation mode.");
1160 
1161 }
1162 
1163 /*
1164   Last step of compiler_mode & instrument_mode selecting.
1165   We have a few of workarounds here, to check any corner cases,
1166   prepare for a series of fallbacks, and raise warnings or errors.
1167 */
mode_final_checkout(aflcc_state_t * aflcc,int argc,char ** argv)1168 void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) {
1169 
1170   if (aflcc->instrument_opt_mode &&
1171       aflcc->instrument_mode == INSTRUMENT_DEFAULT &&
1172       (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == UNSET)) {
1173 
1174     aflcc->instrument_mode = INSTRUMENT_CLASSIC;
1175     aflcc->compiler_mode = LLVM;
1176 
1177   }
1178 
1179   if (!aflcc->compiler_mode) {
1180 
1181     // lto is not a default because outside of afl-cc RANLIB and AR have to
1182     // be set to LLVM versions so this would work
1183     if (aflcc->have_llvm)
1184       aflcc->compiler_mode = LLVM;
1185     else if (aflcc->have_gcc_plugin)
1186       aflcc->compiler_mode = GCC_PLUGIN;
1187     else if (aflcc->have_gcc)
1188       aflcc->compiler_mode = GCC;
1189     else if (aflcc->have_clang)
1190       aflcc->compiler_mode = CLANG;
1191     else if (aflcc->have_lto)
1192       aflcc->compiler_mode = LTO;
1193     else
1194       FATAL("no compiler mode available");
1195 
1196   }
1197 
1198   switch (aflcc->compiler_mode) {
1199 
1200     case GCC:
1201       if (!aflcc->have_gcc) FATAL("afl-gcc is not available on your platform!");
1202       break;
1203     case CLANG:
1204       if (!aflcc->have_clang)
1205         FATAL("afl-clang is not available on your platform!");
1206       break;
1207     case LLVM:
1208       if (!aflcc->have_llvm)
1209         FATAL(
1210             "LLVM mode is not available, please install LLVM 13+ and recompile "
1211             "AFL++");
1212       break;
1213     case GCC_PLUGIN:
1214       if (!aflcc->have_gcc_plugin)
1215         FATAL(
1216             "GCC_PLUGIN mode is not available, install gcc plugin support and "
1217             "recompile AFL++");
1218       break;
1219     case LTO:
1220       if (!aflcc->have_lto)
1221         FATAL(
1222             "LTO mode is not available, please install LLVM 13+ and lld of the "
1223             "same version and recompile AFL++");
1224       break;
1225     default:
1226       FATAL("no compiler mode available");
1227 
1228   }
1229 
1230   if (aflcc->compiler_mode == GCC) { aflcc->instrument_mode = INSTRUMENT_GCC; }
1231 
1232   if (aflcc->compiler_mode == CLANG) {
1233 
1234     /* if our PCGUARD implementation is not available then silently switch to
1235      native LLVM PCGUARD. Or classic asm instrument is explicitly preferred. */
1236     if (!aflcc->have_optimized_pcguard &&
1237         (aflcc->instrument_mode == INSTRUMENT_DEFAULT ||
1238          aflcc->instrument_mode == INSTRUMENT_PCGUARD)) {
1239 
1240       aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
1241 
1242     } else {
1243 
1244       aflcc->instrument_mode = INSTRUMENT_CLANG;
1245       setenv(CLANG_ENV_VAR, "1", 1);  // used by afl-as
1246 
1247     }
1248 
1249   }
1250 
1251   if (aflcc->compiler_mode == LTO) {
1252 
1253     if (aflcc->instrument_mode == 0 ||
1254         aflcc->instrument_mode == INSTRUMENT_LTO ||
1255         aflcc->instrument_mode == INSTRUMENT_CFG ||
1256         aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
1257 
1258       aflcc->lto_mode = 1;
1259       // force CFG
1260       // if (!aflcc->instrument_mode) {
1261 
1262       aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1263 
1264       // }
1265 
1266     } else if (aflcc->instrument_mode == INSTRUMENT_CLASSIC) {
1267 
1268       aflcc->lto_mode = 1;
1269 
1270     } else {
1271 
1272       if (!be_quiet) {
1273 
1274         WARNF("afl-clang-lto called with mode %s, using that mode instead",
1275               instrument_mode_2str(aflcc->instrument_mode));
1276 
1277       }
1278 
1279     }
1280 
1281   }
1282 
1283   if (aflcc->instrument_mode == 0 && aflcc->compiler_mode < GCC_PLUGIN) {
1284 
1285 #if LLVM_MAJOR >= 7
1286   #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
1287     if (aflcc->have_instr_env) {
1288 
1289       aflcc->instrument_mode = INSTRUMENT_AFL;
1290       if (!be_quiet) {
1291 
1292         WARNF(
1293             "Switching to classic instrumentation because "
1294             "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
1295 
1296       }
1297 
1298     } else
1299 
1300   #endif
1301       aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1302 
1303 #else
1304     aflcc->instrument_mode = INSTRUMENT_AFL;
1305 #endif
1306 
1307   }
1308 
1309   if (!aflcc->instrument_opt_mode && aflcc->lto_mode &&
1310       aflcc->instrument_mode == INSTRUMENT_CFG) {
1311 
1312     aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1313 
1314   }
1315 
1316 #ifndef AFL_CLANG_FLTO
1317   if (aflcc->lto_mode)
1318     FATAL(
1319         "instrumentation mode LTO specified but LLVM support not available "
1320         "(requires LLVM 11 or higher)");
1321 #endif
1322 
1323   if (aflcc->lto_mode) {
1324 
1325     if (aflcc->lto_flag[0] != '-')
1326       FATAL(
1327           "Using afl-clang-lto is not possible because Makefile magic did not "
1328           "identify the correct -flto flag");
1329     else
1330       aflcc->compiler_mode = LTO;
1331 
1332   }
1333 
1334   if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
1335     FATAL(
1336         "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
1337         "together");
1338 
1339 #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
1340 
1341   if (aflcc->instrument_mode == INSTRUMENT_PCGUARD && aflcc->have_instr_env) {
1342 
1343     FATAL(
1344         "Instrumentation type PCGUARD does not support "
1345         "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
1346 
1347   }
1348 
1349 #endif
1350 
1351   instrument_opt_mode_exclude(aflcc);
1352 
1353   u8 *ptr2;
1354 
1355   if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
1356     FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
1357 
1358   if (getenv("AFL_LLVM_LAF_ALL")) {
1359 
1360     setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1);
1361     setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1);
1362     setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1);
1363     setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1);
1364 
1365   }
1366 
1367   aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
1368                        getenv("AFL_GCC_CMPLOG");
1369 
1370 }
1371 
1372 /*
1373   Print welcome message on screen, giving brief notes about
1374   compiler_mode and instrument_mode.
1375 */
mode_notification(aflcc_state_t * aflcc)1376 void mode_notification(aflcc_state_t *aflcc) {
1377 
1378   char *ptr2 = alloc_printf(" + NGRAM-%u", aflcc->ngram_size);
1379   char *ptr3 = alloc_printf(" + K-CTX-%u", aflcc->ctx_k);
1380 
1381   char *ptr1 = alloc_printf(
1382       "%s%s%s%s%s", instrument_mode_2str(aflcc->instrument_mode),
1383       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
1384       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
1385       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
1386       (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
1387 
1388   ck_free(ptr2);
1389   ck_free(ptr3);
1390 
1391   if ((isatty(2) && !be_quiet) || aflcc->debug) {
1392 
1393     SAYF(cCYA
1394          "afl-cc" VERSION cRST
1395          " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n",
1396          compiler_mode_2str(aflcc->compiler_mode), ptr1);
1397 
1398   }
1399 
1400   ck_free(ptr1);
1401 
1402   if (!be_quiet &&
1403       (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)) {
1404 
1405     WARNF(
1406         "You are using outdated instrumentation, install LLVM and/or "
1407         "gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast "
1408         "instead!");
1409 
1410   }
1411 
1412 }
1413 
1414 /*
1415   Set argv[0] required by execvp. It can be
1416   - specified by env AFL_CXX
1417   - g++ or clang++
1418   - CLANGPP_BIN or LLVM_BINDIR/clang++
1419   when in C++ mode, or
1420   - specified by env AFL_CC
1421   - gcc or clang
1422   - CLANG_BIN or LLVM_BINDIR/clang
1423   otherwise.
1424 */
add_real_argv0(aflcc_state_t * aflcc)1425 void add_real_argv0(aflcc_state_t *aflcc) {
1426 
1427   static u8 llvm_fullpath[PATH_MAX];
1428 
1429   if (aflcc->plusplus_mode) {
1430 
1431     u8 *alt_cxx = getenv("AFL_CXX");
1432 
1433     if (!alt_cxx) {
1434 
1435       if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
1436 
1437         alt_cxx = "g++";
1438 
1439       } else if (aflcc->compiler_mode == CLANG) {
1440 
1441         alt_cxx = "clang++";
1442 
1443       } else {
1444 
1445         if (USE_BINDIR)
1446           snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++",
1447                    LLVM_BINDIR);
1448         else
1449           snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN);
1450         alt_cxx = llvm_fullpath;
1451 
1452       }
1453 
1454     }
1455 
1456     aflcc->cc_params[0] = alt_cxx;
1457 
1458   } else {
1459 
1460     u8 *alt_cc = getenv("AFL_CC");
1461 
1462     if (!alt_cc) {
1463 
1464       if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
1465 
1466         alt_cc = "gcc";
1467 
1468       } else if (aflcc->compiler_mode == CLANG) {
1469 
1470         alt_cc = "clang";
1471 
1472       } else {
1473 
1474         if (USE_BINDIR)
1475           snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
1476                    LLVM_BINDIR);
1477         else
1478           snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
1479         alt_cc = llvm_fullpath;
1480 
1481       }
1482 
1483     }
1484 
1485     aflcc->cc_params[0] = alt_cc;
1486 
1487   }
1488 
1489 }
1490 
1491 /** compiler_mode & instrument_mode selecting -----END----- **/
1492 
1493 /** Macro defs for the preprocessor -----BEGIN----- **/
1494 
add_defs_common(aflcc_state_t * aflcc)1495 void add_defs_common(aflcc_state_t *aflcc) {
1496 
1497   insert_param(aflcc, "-D__AFL_COMPILER=1");
1498   insert_param(aflcc, "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1");
1499 
1500 }
1501 
1502 /*
1503   __afl_coverage macro defs. See
1504   instrumentation/README.instrument_list.md#
1505   2-selective-instrumentation-with-_afl_coverage-directives
1506 */
add_defs_selective_instr(aflcc_state_t * aflcc)1507 void add_defs_selective_instr(aflcc_state_t *aflcc) {
1508 
1509   if (aflcc->plusplus_mode) {
1510 
1511     insert_param(aflcc,
1512                  "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
1513                  "extern \"C\" void __afl_coverage_discard();"
1514                  "extern \"C\" void __afl_coverage_skip();"
1515                  "extern \"C\" void __afl_coverage_on();"
1516                  "extern \"C\" void __afl_coverage_off();");
1517 
1518   } else {
1519 
1520     insert_param(aflcc,
1521                  "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
1522                  "void __afl_coverage_discard();"
1523                  "void __afl_coverage_skip();"
1524                  "void __afl_coverage_on();"
1525                  "void __afl_coverage_off();");
1526 
1527   }
1528 
1529   insert_param(
1530       aflcc,
1531       "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
1532       "1;");
1533   insert_param(aflcc, "-D__AFL_COVERAGE_ON()=__afl_coverage_on()");
1534   insert_param(aflcc, "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()");
1535   insert_param(aflcc, "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()");
1536   insert_param(aflcc, "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()");
1537 
1538 }
1539 
1540 /*
1541   Macro defs for persistent mode. As documented in
1542   instrumentation/README.persistent_mode.md, deferred forkserver initialization
1543   and persistent mode are not available in afl-gcc and afl-clang.
1544 */
add_defs_persistent_mode(aflcc_state_t * aflcc)1545 void add_defs_persistent_mode(aflcc_state_t *aflcc) {
1546 
1547   if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) return;
1548 
1549   insert_param(aflcc, "-D__AFL_HAVE_MANUAL_CONTROL=1");
1550 
1551   /* When the user tries to use persistent or deferred forkserver modes by
1552       appending a single line to the program, we want to reliably inject a
1553       signature into the binary (to be picked up by afl-fuzz) and we want
1554       to call a function from the runtime .o file. This is unnecessarily
1555       painful for three reasons:
1556 
1557       1) We need to convince the compiler not to optimize out the signature.
1558         This is done with __attribute__((used)).
1559 
1560       2) We need to convince the linker, when called with -Wl,--gc-sections,
1561         not to do the same. This is done by forcing an assignment to a
1562         'volatile' pointer.
1563 
1564       3) We need to declare __afl_persistent_loop() in the global namespace,
1565         but doing this within a method in a class is hard - :: and extern "C"
1566         are forbidden and __attribute__((alias(...))) doesn't work. Hence the
1567         __asm__ aliasing trick.
1568 
1569     */
1570 
1571   insert_param(aflcc,
1572                "-D__AFL_FUZZ_INIT()="
1573                "int __afl_sharedmem_fuzzing = 1;"
1574                "extern unsigned int *__afl_fuzz_len;"
1575                "extern unsigned char *__afl_fuzz_ptr;"
1576                "unsigned char __afl_fuzz_alt[1048576];"
1577                "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;");
1578 
1579   insert_param(aflcc,
1580                "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
1581                "__afl_fuzz_alt_ptr)");
1582 
1583   insert_param(
1584       aflcc,
1585       "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
1586       "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
1587       "? 0 : *__afl_fuzz_len)");
1588 
1589   insert_param(
1590       aflcc,
1591       "-D__AFL_LOOP(_A)="
1592       "({ static volatile const char *_B __attribute__((used,unused)); "
1593       " _B = (const char*)\"" PERSIST_SIG
1594       "\"; "
1595       "extern __attribute__((visibility(\"default\"))) int __afl_connected;"
1596 #ifdef __APPLE__
1597       "__attribute__((visibility(\"default\"))) "
1598       "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
1599 #else
1600       "__attribute__((visibility(\"default\"))) "
1601       "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
1602 #endif                                                        /* ^__APPLE__ */
1603       // if afl is connected, we run _A times, else once.
1604       "_L(__afl_connected ? _A : 1); })");
1605 
1606   insert_param(
1607       aflcc,
1608       "-D__AFL_INIT()="
1609       "do { static volatile const char *_A __attribute__((used,unused)); "
1610       " _A = (const char*)\"" DEFER_SIG
1611       "\"; "
1612 #ifdef __APPLE__
1613       "__attribute__((visibility(\"default\"))) "
1614       "void _I(void) __asm__(\"___afl_manual_init\"); "
1615 #else
1616       "__attribute__((visibility(\"default\"))) "
1617       "void _I(void) __asm__(\"__afl_manual_init\"); "
1618 #endif                                                        /* ^__APPLE__ */
1619       "_I(); } while (0)");
1620 
1621 }
1622 
1623 /*
1624   Control macro def of _FORTIFY_SOURCE. It will do nothing
1625   if we detect this routine has been called previously, or
1626   the macro already here in these existing args.
1627 */
add_defs_fortify(aflcc_state_t * aflcc,u8 action)1628 void add_defs_fortify(aflcc_state_t *aflcc, u8 action) {
1629 
1630   if (aflcc->have_fortify) { return; }
1631 
1632   switch (action) {
1633 
1634     case 1:
1635       insert_param(aflcc, "-D_FORTIFY_SOURCE=1");
1636       break;
1637 
1638     case 2:
1639       insert_param(aflcc, "-D_FORTIFY_SOURCE=2");
1640       break;
1641 
1642     default:  // OFF
1643       insert_param(aflcc, "-U_FORTIFY_SOURCE");
1644       break;
1645 
1646   }
1647 
1648   aflcc->have_fortify = 1;
1649 
1650 }
1651 
1652 /* Macro defs of __AFL_LEAK_CHECK, __AFL_LSAN_ON and __AFL_LSAN_OFF */
add_defs_lsan_ctrl(aflcc_state_t * aflcc)1653 void add_defs_lsan_ctrl(aflcc_state_t *aflcc) {
1654 
1655   insert_param(aflcc, "-includesanitizer/lsan_interface.h");
1656   insert_param(
1657       aflcc,
1658       "-D__AFL_LEAK_CHECK()={if(__lsan_do_recoverable_leak_check() > 0) "
1659       "_exit(23); }");
1660   insert_param(aflcc, "-D__AFL_LSAN_OFF()=__lsan_disable();");
1661   insert_param(aflcc, "-D__AFL_LSAN_ON()=__lsan_enable();");
1662 
1663 }
1664 
1665 /** Macro defs for the preprocessor -----END----- **/
1666 
1667 /** About -fsanitize -----BEGIN----- **/
1668 
1669 /* For input "-fsanitize=...", it:
1670 
1671   1. may have various OOB traps :) if ... doesn't contain ',' or
1672     the input has bad syntax such as "-fsantiz=,"
1673   2. strips any fuzzer* in ... and writes back (may result in "-fsanitize=")
1674   3. rets 1 if exactly "fuzzer" found, otherwise rets 0
1675 */
fsanitize_fuzzer_comma(char * string)1676 static u8 fsanitize_fuzzer_comma(char *string) {
1677 
1678   u8 detect_single_fuzzer = 0;
1679 
1680   char *p, *ptr = string + strlen("-fsanitize=");
1681   // ck_alloc will check alloc failure
1682   char *new = ck_alloc(strlen(string) + 1);
1683   char *tmp = ck_alloc(strlen(ptr) + 1);
1684   u32   count = 0, len, ende = 0;
1685 
1686   strcpy(new, "-fsanitize=");
1687 
1688   do {
1689 
1690     p = strchr(ptr, ',');
1691     if (!p) {
1692 
1693       p = ptr + strlen(ptr) + 1;
1694       ende = 1;
1695 
1696     }
1697 
1698     len = p - ptr;
1699     if (len) {
1700 
1701       strncpy(tmp, ptr, len);
1702       tmp[len] = 0;
1703       // fprintf(stderr, "Found: %s\n", tmp);
1704       ptr += len + 1;
1705       if (*tmp) {
1706 
1707         u32 copy = 1;
1708         if (!strcmp(tmp, "fuzzer")) {
1709 
1710           detect_single_fuzzer = 1;
1711           copy = 0;
1712 
1713         } else if (!strncmp(tmp, "fuzzer", 6)) {
1714 
1715           copy = 0;
1716 
1717         }
1718 
1719         if (copy) {
1720 
1721           if (count) { strcat(new, ","); }
1722           strcat(new, tmp);
1723           ++count;
1724 
1725         }
1726 
1727       }
1728 
1729     } else {
1730 
1731       ptr++;
1732 
1733     }
1734 
1735   } while (!ende);
1736 
1737   strcpy(string, new);
1738 
1739   ck_free(tmp);
1740   ck_free(new);
1741 
1742   return detect_single_fuzzer;
1743 
1744 }
1745 
1746 /*
1747   Parse and process possible -fsanitize related args, return PARAM_MISS
1748   if nothing matched. We have 3 main tasks here for these args:
1749   - Check which one of those sanitizers present here.
1750   - Check if libfuzzer present. We need to block the request of enable
1751     libfuzzer, and link harness with our libAFLDriver.a later.
1752   - Check if SanCov allow/denylist options present. We need to try switching
1753     to LLVMNATIVE instead of using our optimized PCGUARD anyway. If we
1754     can't make it finally for various reasons, just drop these options.
1755 */
parse_fsanitize(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan)1756 param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
1757 
1758   param_st final_ = PARAM_MISS;
1759 
1760 // MACRO START
1761 #define HAVE_SANITIZER_SCAN_KEEP(v, k)        \
1762   do {                                        \
1763                                               \
1764     if (strstr(cur_argv, "=" STRINGIFY(k)) || \
1765         strstr(cur_argv, "," STRINGIFY(k))) { \
1766                                               \
1767       if (scan) {                             \
1768                                               \
1769         aflcc->have_##v = 1;                  \
1770         final_ = PARAM_SCAN;                  \
1771                                               \
1772       } else {                                \
1773                                               \
1774         final_ = PARAM_KEEP;                  \
1775                                               \
1776       }                                       \
1777                                               \
1778     }                                         \
1779                                               \
1780   } while (0)
1781 
1782   // MACRO END
1783 
1784   if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize="))) {
1785 
1786     HAVE_SANITIZER_SCAN_KEEP(asan, address);
1787     HAVE_SANITIZER_SCAN_KEEP(msan, memory);
1788     HAVE_SANITIZER_SCAN_KEEP(ubsan, undefined);
1789     HAVE_SANITIZER_SCAN_KEEP(tsan, thread);
1790     HAVE_SANITIZER_SCAN_KEEP(lsan, leak);
1791     HAVE_SANITIZER_SCAN_KEEP(cfisan, cfi);
1792 
1793   }
1794 
1795 #undef HAVE_SANITIZER_SCAN_KEEP
1796 
1797   // We can't use a "else if" there, because some of the following
1798   // matching rules overlap with those in the if-statement above.
1799   if (!strcmp(cur_argv, "-fsanitize=fuzzer")) {
1800 
1801     if (scan) {
1802 
1803       aflcc->need_aflpplib = 1;
1804       final_ = PARAM_SCAN;
1805 
1806     } else {
1807 
1808       final_ = PARAM_DROP;
1809 
1810     }
1811 
1812   } else if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize=")) &&
1813 
1814              strchr(cur_argv, ',') &&
1815              !strstr(cur_argv, "=,")) {  // avoid OOB errors
1816 
1817     if (scan) {
1818 
1819       u8 *cur_argv_ = ck_strdup(cur_argv);
1820 
1821       if (fsanitize_fuzzer_comma(cur_argv_)) {
1822 
1823         aflcc->need_aflpplib = 1;
1824         final_ = PARAM_SCAN;
1825 
1826       }
1827 
1828       ck_free(cur_argv_);
1829 
1830     } else {
1831 
1832       fsanitize_fuzzer_comma(cur_argv);
1833       if (!cur_argv || strlen(cur_argv) <= strlen("-fsanitize="))
1834         final_ = PARAM_DROP;  // this means it only has "fuzzer" previously.
1835 
1836     }
1837 
1838   } else if (!strncmp(cur_argv, "-fsanitize-coverage-", 20) &&
1839 
1840              strstr(cur_argv, "list=")) {
1841 
1842     if (scan) {
1843 
1844       aflcc->have_instr_list = 1;
1845       final_ = PARAM_SCAN;
1846 
1847     } else {
1848 
1849       if (aflcc->instrument_mode != INSTRUMENT_LLVMNATIVE) {
1850 
1851         if (!be_quiet) { WARNF("Found '%s' - stripping!", cur_argv); }
1852         final_ = PARAM_DROP;
1853 
1854       } else {
1855 
1856         final_ = PARAM_KEEP;
1857 
1858       }
1859 
1860     }
1861 
1862   }
1863 
1864   if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
1865 
1866   return final_;
1867 
1868 }
1869 
1870 /*
1871   Add params for sanitizers. Here we need to consider:
1872   - Use static runtime for asan, as much as possible.
1873   - ASAN, MSAN, AFL_HARDEN are mutually exclusive.
1874   - Add options if not found there, on request of AFL_USE_ASAN, AFL_USE_MSAN,
1875   etc.
1876   - Update have_* so that functions called after this can have correct context.
1877     However this also means any functions called before should NOT depend on
1878   these have_*, otherwise they may not work as expected.
1879 */
add_sanitizers(aflcc_state_t * aflcc,char ** envp)1880 void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
1881 
1882   if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
1883 
1884     if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
1885       FATAL("ASAN and MSAN are mutually exclusive");
1886 
1887     if (getenv("AFL_HARDEN"))
1888       FATAL("ASAN and AFL_HARDEN are mutually exclusive");
1889 
1890     if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
1891 
1892       insert_param(aflcc, "-static-libasan");
1893 
1894     }
1895 
1896     add_defs_fortify(aflcc, 0);
1897     if (!aflcc->have_asan) { insert_param(aflcc, "-fsanitize=address"); }
1898     aflcc->have_asan = 1;
1899 
1900   } else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
1901 
1902     if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
1903       FATAL("ASAN and MSAN are mutually exclusive");
1904 
1905     if (getenv("AFL_HARDEN"))
1906       FATAL("MSAN and AFL_HARDEN are mutually exclusive");
1907 
1908     add_defs_fortify(aflcc, 0);
1909     if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
1910     aflcc->have_msan = 1;
1911 
1912   }
1913 
1914   if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
1915 
1916     if (!aflcc->have_ubsan) {
1917 
1918       insert_param(aflcc, "-fsanitize=undefined");
1919       insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
1920       insert_param(aflcc, "-fno-sanitize-recover=all");
1921 
1922     }
1923 
1924     if (!aflcc->have_fp) {
1925 
1926       insert_param(aflcc, "-fno-omit-frame-pointer");
1927       aflcc->have_fp = 1;
1928 
1929     }
1930 
1931     aflcc->have_ubsan = 1;
1932 
1933   }
1934 
1935   if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
1936 
1937     if (!aflcc->have_fp) {
1938 
1939       insert_param(aflcc, "-fno-omit-frame-pointer");
1940       aflcc->have_fp = 1;
1941 
1942     }
1943 
1944     if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
1945     aflcc->have_tsan = 1;
1946 
1947   }
1948 
1949   if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
1950 
1951     insert_param(aflcc, "-fsanitize=leak");
1952     add_defs_lsan_ctrl(aflcc);
1953     aflcc->have_lsan = 1;
1954 
1955   }
1956 
1957   if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
1958 
1959     if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
1960 
1961       if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
1962 
1963     } else {
1964 
1965       if (!aflcc->lto_mode && !aflcc->have_flto) {
1966 
1967         uint32_t i = 0, found = 0;
1968         while (envp[i] != NULL && !found) {
1969 
1970           if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
1971 
1972         }
1973 
1974         if (!found) { insert_param(aflcc, "-flto"); }
1975         aflcc->have_flto = 1;
1976 
1977       }
1978 
1979       if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
1980 
1981       if (!aflcc->have_hidden) {
1982 
1983         insert_param(aflcc, "-fvisibility=hidden");
1984         aflcc->have_hidden = 1;
1985 
1986       }
1987 
1988       aflcc->have_cfisan = 1;
1989 
1990     }
1991 
1992   }
1993 
1994 }
1995 
1996 /* Add params to enable LLVM SanCov, the native PCGUARD */
add_native_pcguard(aflcc_state_t * aflcc)1997 void add_native_pcguard(aflcc_state_t *aflcc) {
1998 
1999   /* If there is a rust ASan runtime on the command line, it is likely we're
2000    * linking from rust and adding native flags requiring the sanitizer runtime
2001    * will trigger native clang to add yet another runtime, causing linker
2002    * errors. For now we shouldn't add instrumentation here, we're linking
2003    * anyway.
2004    */
2005   if (aflcc->have_rust_asanrt) { return; }
2006 
2007   /* If llvm-config doesn't figure out LLVM_MAJOR, just
2008    go on anyway and let compiler complain if doesn't work. */
2009 
2010 #if LLVM_MAJOR > 0 && LLVM_MAJOR < 6
2011   FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
2012 #else
2013   #if LLVM_MAJOR == 0
2014   WARNF(
2015       "pcguard instrumentation with pc-table requires LLVM 6.0.1+"
2016       " otherwise the compiler will fail");
2017   #endif
2018   if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
2019 
2020     insert_param(aflcc,
2021                  "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
2022 
2023   } else {
2024 
2025     insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard,pc-table");
2026 
2027   }
2028 
2029 #endif
2030 
2031 }
2032 
2033 /*
2034   Add params to launch our optimized PCGUARD on request.
2035   It will fallback to use the native PCGUARD in some cases. If so, plz
2036   bear in mind that instrument_mode will be set to INSTRUMENT_LLVMNATIVE.
2037 */
add_optimized_pcguard(aflcc_state_t * aflcc)2038 void add_optimized_pcguard(aflcc_state_t *aflcc) {
2039 
2040 #if LLVM_MAJOR >= 13
2041   #if defined __ANDROID__ || ANDROID
2042 
2043   insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2044   aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2045 
2046   #else
2047 
2048   if (aflcc->have_instr_list) {
2049 
2050     if (!be_quiet)
2051       SAYF(
2052           "Using unoptimized trace-pc-guard, due usage of "
2053           "-fsanitize-coverage-allow/denylist, you can use "
2054           "AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST instead.\n");
2055 
2056     insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2057     aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2058 
2059   } else {
2060 
2061     /* Since LLVM_MAJOR >= 13 we use new pass manager */
2062     #if LLVM_MAJOR < 16
2063     insert_param(aflcc, "-fexperimental-new-pass-manager");
2064     #endif
2065     insert_object(aflcc, "SanitizerCoveragePCGUARD.so", "-fpass-plugin=%s", 0);
2066 
2067   }
2068 
2069   #endif  // defined __ANDROID__ || ANDROID
2070 #else     // LLVM_MAJOR < 13
2071   #if LLVM_MAJOR >= 4
2072 
2073   if (!be_quiet)
2074     SAYF(
2075         "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
2076         "enhanced version.\n");
2077   insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2078   aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2079 
2080   #else
2081 
2082   FATAL("pcguard instrumentation requires LLVM 4.0.1+");
2083 
2084   #endif
2085 #endif
2086 
2087 }
2088 
2089 /** About -fsanitize -----END----- **/
2090 
2091 /** Linking behaviors -----BEGIN----- **/
2092 
2093 /*
2094   Parse and process possible linking stage related args,
2095   return PARAM_MISS if nothing matched.
2096 */
parse_linking_params(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan,u8 * skip_next,char ** argv)2097 param_st parse_linking_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan,
2098                               u8 *skip_next, char **argv) {
2099 
2100   if (aflcc->lto_mode && !strncmp(cur_argv, "-flto=thin", 10)) {
2101 
2102     FATAL(
2103         "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
2104         "use afl-clang-fast!");
2105 
2106   }
2107 
2108   param_st final_ = PARAM_MISS;
2109 
2110   if (!strcmp(cur_argv, "-shared") || !strcmp(cur_argv, "-dynamiclib")) {
2111 
2112     if (scan) {
2113 
2114       aflcc->shared_linking = 1;
2115       final_ = PARAM_SCAN;
2116 
2117     } else {
2118 
2119       final_ = PARAM_KEEP;
2120 
2121     }
2122 
2123   } else if (!strcmp(cur_argv, "-Wl,-r") || !strcmp(cur_argv, "-Wl,-i") ||
2124 
2125              !strcmp(cur_argv, "-Wl,--relocatable") ||
2126              !strcmp(cur_argv, "-r") || !strcmp(cur_argv, "--relocatable")) {
2127 
2128     if (scan) {
2129 
2130       aflcc->partial_linking = 1;
2131       final_ = PARAM_SCAN;
2132 
2133     } else {
2134 
2135       final_ = PARAM_KEEP;
2136 
2137     }
2138 
2139   } else if (!strncmp(cur_argv, "-fuse-ld=", 9) ||
2140 
2141              !strncmp(cur_argv, "--ld-path=", 10)) {
2142 
2143     if (scan) {
2144 
2145       final_ = PARAM_SCAN;
2146 
2147     } else {
2148 
2149       if (aflcc->lto_mode)
2150         final_ = PARAM_DROP;
2151       else
2152         final_ = PARAM_KEEP;
2153 
2154     }
2155 
2156   } else if (!strcmp(cur_argv, "-Wl,-z,defs") ||
2157 
2158              !strcmp(cur_argv, "-Wl,--no-undefined") ||
2159              !strcmp(cur_argv, "-Wl,-no-undefined") ||
2160              !strcmp(cur_argv, "--no-undefined") ||
2161              strstr(cur_argv, "afl-compiler-rt") ||
2162              strstr(cur_argv, "afl-llvm-rt")) {
2163 
2164     if (scan) {
2165 
2166       final_ = PARAM_SCAN;
2167 
2168     } else {
2169 
2170       final_ = PARAM_DROP;
2171 
2172     }
2173 
2174   } else if (!strcmp(cur_argv, "-z") || !strcmp(cur_argv, "-Wl,-z")) {
2175 
2176     u8 *param = *(argv + 1);
2177     if (param && (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs"))) {
2178 
2179       *skip_next = 1;
2180 
2181       if (scan) {
2182 
2183         final_ = PARAM_SCAN;
2184 
2185       } else {
2186 
2187         final_ = PARAM_DROP;
2188 
2189       }
2190 
2191     }
2192 
2193   }
2194 
2195   // Try to warn user for some unsupported cases
2196   if (scan && final_ == PARAM_MISS) {
2197 
2198     u8 *ptr_ = NULL;
2199 
2200     if (!strcmp(cur_argv, "-Xlinker") && (ptr_ = *(argv + 1))) {
2201 
2202       if (!strcmp(ptr_, "defs")) {
2203 
2204         WARNF("'-Xlinker' 'defs' detected. This may result in a bad link.");
2205 
2206       } else if (strstr(ptr_, "-no-undefined")) {
2207 
2208         WARNF(
2209             "'-Xlinker' '%s' detected. The latter option may be dropped and "
2210             "result in a bad link.",
2211             ptr_);
2212 
2213       }
2214 
2215     } else if (!strncmp(cur_argv, "-Wl,", 4) &&
2216 
2217                (u8 *)strrchr(cur_argv, ',') != (cur_argv + 3)) {
2218 
2219       ptr_ = cur_argv + 4;
2220 
2221       if (strstr(ptr_, "-shared") || strstr(ptr_, "-dynamiclib")) {
2222 
2223         WARNF(
2224             "'%s': multiple link options after '-Wl,' may break shared "
2225             "linking.",
2226             ptr_);
2227 
2228       }
2229 
2230       if (strstr(ptr_, "-r,") || strstr(ptr_, "-i,") || strstr(ptr_, ",-r") ||
2231           strstr(ptr_, ",-i") || strstr(ptr_, "--relocatable")) {
2232 
2233         WARNF(
2234             "'%s': multiple link options after '-Wl,' may break partial "
2235             "linking.",
2236             ptr_);
2237 
2238       }
2239 
2240       if (strstr(ptr_, "defs") || strstr(ptr_, "no-undefined")) {
2241 
2242         WARNF(
2243             "'%s': multiple link options after '-Wl,' may enable report "
2244             "unresolved symbol references and result in a bad link.",
2245             ptr_);
2246 
2247       }
2248 
2249     }
2250 
2251   }
2252 
2253   if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
2254 
2255   return final_;
2256 
2257 }
2258 
2259 /* Add params to specify the linker used in LTO */
add_lto_linker(aflcc_state_t * aflcc)2260 void add_lto_linker(aflcc_state_t *aflcc) {
2261 
2262   unsetenv("AFL_LD");
2263   unsetenv("AFL_LD_CALLER");
2264 
2265   u8 *ld_path = NULL;
2266   if (getenv("AFL_REAL_LD")) {
2267 
2268     ld_path = strdup(getenv("AFL_REAL_LD"));
2269 
2270   } else {
2271 
2272     ld_path = strdup(AFL_REAL_LD);
2273 
2274   }
2275 
2276   if (!ld_path || !*ld_path) {
2277 
2278     if (ld_path) {
2279 
2280       // Freeing empty string
2281       free(ld_path);
2282 
2283     }
2284 
2285     ld_path = strdup("ld.lld");
2286 
2287   }
2288 
2289   if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
2290 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
2291   insert_param(aflcc, alloc_printf("--ld-path=%s", ld_path));
2292 #else
2293   insert_param(aflcc, alloc_printf("-fuse-ld=%s", ld_path));
2294 #endif
2295   free(ld_path);
2296 
2297 }
2298 
2299 /* Add params to launch SanitizerCoverageLTO.so when linking  */
add_lto_passes(aflcc_state_t * aflcc)2300 void add_lto_passes(aflcc_state_t *aflcc) {
2301 
2302 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 15
2303   // The NewPM implementation only works fully since LLVM 15.
2304   insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,--load-pass-plugin=%s",
2305                 0);
2306 #elif defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
2307   insert_param(aflcc, "-Wl,--lto-legacy-pass-manager");
2308   insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
2309 #else
2310   insert_param(aflcc, "-fno-experimental-new-pass-manager");
2311   insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
2312 #endif
2313 
2314   insert_param(aflcc, "-Wl,--allow-multiple-definition");
2315 
2316 }
2317 
2318 /* Add params to link with libAFLDriver.a on request */
add_aflpplib(aflcc_state_t * aflcc)2319 static void add_aflpplib(aflcc_state_t *aflcc) {
2320 
2321   if (!aflcc->need_aflpplib) return;
2322 
2323   u8 *afllib = find_object(aflcc, "libAFLDriver.a");
2324 
2325   if (!be_quiet) {
2326 
2327     OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
2328 
2329   }
2330 
2331   if (!afllib) {
2332 
2333     if (!be_quiet) {
2334 
2335       WARNF(
2336           "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
2337           "the flags - this will fail!");
2338 
2339     }
2340 
2341   } else {
2342 
2343     insert_param(aflcc, afllib);
2344 
2345 #ifdef __APPLE__
2346     insert_param(aflcc, "-Wl,-undefined");
2347     insert_param(aflcc, "dynamic_lookup");
2348 #endif
2349 
2350   }
2351 
2352 }
2353 
2354 /* Add params to link with runtimes depended by our instrumentation */
add_runtime(aflcc_state_t * aflcc)2355 void add_runtime(aflcc_state_t *aflcc) {
2356 
2357   if (aflcc->preprocessor_only || aflcc->have_c || !aflcc->non_dash) {
2358 
2359     /* In the preprocessor_only case (-E), we are not actually compiling at
2360        all but requesting the compiler to output preprocessed sources only.
2361        We must not add the runtime in this case because the compiler will
2362        simply output its binary content back on stdout, breaking any build
2363        systems that rely on a separate source preprocessing step. */
2364     return;
2365 
2366   }
2367 
2368   if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC &&
2369       !getenv("AFL_LLVM_NO_RPATH")) {
2370 
2371     // in case LLVM is installed not via a package manager or "make install"
2372     // e.g. compiled download or compiled from github then its ./lib directory
2373     // might not be in the search path. Add it if so.
2374     const char *libdir = LLVM_LIBDIR;
2375     if (aflcc->plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
2376         strncmp(libdir, "/lib", 4)) {
2377 
2378       u8 *libdir_opt = strdup("-Wl,-rpath=" LLVM_LIBDIR);
2379       insert_param(aflcc, libdir_opt);
2380 
2381     }
2382 
2383   }
2384 
2385 #ifndef __ANDROID__
2386 
2387   #define M32_ERR_MSG "-m32 is not supported by your compiler"
2388   #define M64_ERR_MSG "-m64 is not supported by your compiler"
2389 
2390   if (aflcc->compiler_mode != GCC && aflcc->compiler_mode != CLANG) {
2391 
2392     switch (aflcc->bit_mode) {
2393 
2394       case 0:
2395         if (!aflcc->shared_linking && !aflcc->partial_linking)
2396           insert_object(aflcc, "afl-compiler-rt.o", 0, 0);
2397         if (aflcc->lto_mode) insert_object(aflcc, "afl-llvm-rt-lto.o", 0, 0);
2398         break;
2399 
2400       case 32:
2401         if (!aflcc->shared_linking && !aflcc->partial_linking)
2402           insert_object(aflcc, "afl-compiler-rt-32.o", 0, M32_ERR_MSG);
2403         if (aflcc->lto_mode)
2404           insert_object(aflcc, "afl-llvm-rt-lto-32.o", 0, M32_ERR_MSG);
2405         break;
2406 
2407       case 64:
2408         if (!aflcc->shared_linking && !aflcc->partial_linking)
2409           insert_object(aflcc, "afl-compiler-rt-64.o", 0, M64_ERR_MSG);
2410         if (aflcc->lto_mode)
2411           insert_object(aflcc, "afl-llvm-rt-lto-64.o", 0, M64_ERR_MSG);
2412         break;
2413 
2414     }
2415 
2416   #if __AFL_CODE_COVERAGE
2417     // Required for dladdr used in afl-compiler-rt.o
2418     insert_param(aflcc, "-ldl");
2419   #endif
2420 
2421   #if !defined(__APPLE__) && !defined(__sun)
2422     if (!aflcc->shared_linking && !aflcc->partial_linking)
2423       insert_object(aflcc, "dynamic_list.txt", "-Wl,--dynamic-list=%s", 0);
2424   #endif
2425 
2426   #if defined(__APPLE__)
2427     if (aflcc->shared_linking || aflcc->partial_linking) {
2428 
2429       insert_param(aflcc, "-Wl,-U");
2430       insert_param(aflcc, "-Wl,___afl_area_ptr");
2431       insert_param(aflcc, "-Wl,-U");
2432       insert_param(aflcc, "-Wl,___sanitizer_cov_trace_pc_guard_init");
2433 
2434     }
2435 
2436   #endif
2437 
2438   }
2439 
2440 #endif
2441 
2442   add_aflpplib(aflcc);
2443 
2444 #if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
2445   insert_param(aflcc, "-Wl,-lrt");
2446 #endif
2447 
2448 }
2449 
2450 /** Linking behaviors -----END----- **/
2451 
2452 /** Miscellaneous routines -----BEGIN----- **/
2453 
2454 /*
2455   Add params to make compiler driver use our afl-as
2456   as assembler, required by the vanilla instrumentation.
2457 */
add_assembler(aflcc_state_t * aflcc)2458 void add_assembler(aflcc_state_t *aflcc) {
2459 
2460   u8 *afl_as = find_object(aflcc, "as");
2461 
2462   if (!afl_as) FATAL("Cannot find 'as' (symlink to 'afl-as').");
2463 
2464   u8 *slash = strrchr(afl_as, '/');
2465   if (slash) *slash = 0;
2466 
2467   insert_param(aflcc, "-B");
2468   insert_param(aflcc, afl_as);
2469 
2470   if (aflcc->compiler_mode == CLANG) insert_param(aflcc, "-no-integrated-as");
2471 
2472 }
2473 
2474 /* Add params to launch the gcc plugins for instrumentation. */
add_gcc_plugin(aflcc_state_t * aflcc)2475 void add_gcc_plugin(aflcc_state_t *aflcc) {
2476 
2477   if (aflcc->cmplog_mode) {
2478 
2479     insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
2480     insert_object(aflcc, "afl-gcc-cmptrs-pass.so", "-fplugin=%s", 0);
2481 
2482   }
2483 
2484   insert_object(aflcc, "afl-gcc-pass.so", "-fplugin=%s", 0);
2485 
2486   insert_param(aflcc, "-fno-if-conversion");
2487   insert_param(aflcc, "-fno-if-conversion2");
2488 
2489 }
2490 
2491 /* Add some miscellaneous params required by our instrumentation. */
add_misc_params(aflcc_state_t * aflcc)2492 void add_misc_params(aflcc_state_t *aflcc) {
2493 
2494   if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
2495       getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
2496       aflcc->lto_mode) {
2497 
2498     insert_param(aflcc, "-fno-builtin-strcmp");
2499     insert_param(aflcc, "-fno-builtin-strncmp");
2500     insert_param(aflcc, "-fno-builtin-strcasecmp");
2501     insert_param(aflcc, "-fno-builtin-strncasecmp");
2502     insert_param(aflcc, "-fno-builtin-memcmp");
2503     insert_param(aflcc, "-fno-builtin-bcmp");
2504     insert_param(aflcc, "-fno-builtin-strstr");
2505     insert_param(aflcc, "-fno-builtin-strcasestr");
2506 
2507   }
2508 
2509   if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
2510 
2511   if (getenv("AFL_HARDEN")) {
2512 
2513     insert_param(aflcc, "-fstack-protector-all");
2514 
2515     if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
2516 
2517   }
2518 
2519   if (!getenv("AFL_DONT_OPTIMIZE")) {
2520 
2521     insert_param(aflcc, "-g");
2522     if (!aflcc->have_o) insert_param(aflcc, "-O3");
2523     if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
2524     // if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
2525     //     insert_param(aflcc, aflcc->march_opt);
2526 
2527   }
2528 
2529   if (aflcc->x_set) {
2530 
2531     insert_param(aflcc, "-x");
2532     insert_param(aflcc, "none");
2533 
2534   }
2535 
2536 }
2537 
2538 /*
2539   Parse and process a variety of args under our matching rules,
2540   return PARAM_MISS if nothing matched.
2541 */
parse_misc_params(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan)2542 param_st parse_misc_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
2543 
2544   param_st final_ = PARAM_MISS;
2545 
2546 // MACRO START
2547 #define SCAN_KEEP(dst, src) \
2548   do {                      \
2549                             \
2550     if (scan) {             \
2551                             \
2552       dst = src;            \
2553       final_ = PARAM_SCAN;  \
2554                             \
2555     } else {                \
2556                             \
2557       final_ = PARAM_KEEP;  \
2558                             \
2559     }                       \
2560                             \
2561   } while (0)
2562 
2563   // MACRO END
2564 
2565   if (!strncasecmp(cur_argv, "-fpic", 5)) {
2566 
2567     SCAN_KEEP(aflcc->have_pic, 1);
2568 
2569   } else if (!strcmp(cur_argv, "-m32") ||
2570 
2571              !strcmp(cur_argv, "armv7a-linux-androideabi")) {
2572 
2573     SCAN_KEEP(aflcc->bit_mode, 32);
2574 
2575   } else if (!strcmp(cur_argv, "-m64")) {
2576 
2577     SCAN_KEEP(aflcc->bit_mode, 64);
2578 
2579   } else if (strstr(cur_argv, "FORTIFY_SOURCE")) {
2580 
2581     SCAN_KEEP(aflcc->fortify_set, 1);
2582 
2583   } else if (!strcmp(cur_argv, "-x")) {
2584 
2585     SCAN_KEEP(aflcc->x_set, 1);
2586 
2587   } else if (!strcmp(cur_argv, "-E")) {
2588 
2589     SCAN_KEEP(aflcc->preprocessor_only, 1);
2590 
2591   } else if (!strcmp(cur_argv, "--target=wasm32-wasi")) {
2592 
2593     SCAN_KEEP(aflcc->passthrough, 1);
2594 
2595   } else if (!strcmp(cur_argv, "-c")) {
2596 
2597     SCAN_KEEP(aflcc->have_c, 1);
2598 
2599   } else if (!strcmp(cur_argv, "-static-libasan")) {
2600 
2601     SCAN_KEEP(aflcc->have_staticasan, 1);
2602 
2603   } else if (strstr(cur_argv, "librustc") && strstr(cur_argv, "_rt.asan.a")) {
2604 
2605     SCAN_KEEP(aflcc->have_rust_asanrt, 1);
2606 
2607   } else if (!strcmp(cur_argv, "-fno-omit-frame-pointer")) {
2608 
2609     SCAN_KEEP(aflcc->have_fp, 1);
2610 
2611   } else if (!strcmp(cur_argv, "-fvisibility=hidden")) {
2612 
2613     SCAN_KEEP(aflcc->have_hidden, 1);
2614 
2615   } else if (!strcmp(cur_argv, "-flto") || !strcmp(cur_argv, "-flto=full")) {
2616 
2617     SCAN_KEEP(aflcc->have_flto, 1);
2618 
2619   } else if (!strncmp(cur_argv, "-D_FORTIFY_SOURCE",
2620 
2621                       strlen("-D_FORTIFY_SOURCE"))) {
2622 
2623     SCAN_KEEP(aflcc->have_fortify, 1);
2624 
2625   } else if (!strncmp(cur_argv, "-fcf-protection", strlen("-fcf-protection"))) {
2626 
2627     SCAN_KEEP(aflcc->have_cfisan, 1);
2628 
2629   } else if (!strncmp(cur_argv, "-O", 2)) {
2630 
2631     SCAN_KEEP(aflcc->have_o, 1);
2632 
2633   } else if (!strncmp(cur_argv, "-funroll-loop", 13)) {
2634 
2635     SCAN_KEEP(aflcc->have_unroll, 1);
2636 
2637   } else if (!strncmp(cur_argv, "--afl", 5)) {
2638 
2639     if (scan)
2640       final_ = PARAM_SCAN;
2641     else
2642       final_ = PARAM_DROP;
2643 
2644   } else if (!strncmp(cur_argv, "-fno-unroll", 11)) {
2645 
2646     if (scan)
2647       final_ = PARAM_SCAN;
2648     else
2649       final_ = PARAM_DROP;
2650 
2651   } else if (!strcmp(cur_argv, "-pipe") && aflcc->compiler_mode == GCC_PLUGIN) {
2652 
2653     if (scan)
2654       final_ = PARAM_SCAN;
2655     else
2656       final_ = PARAM_DROP;
2657 
2658   } else if (!strncmp(cur_argv, "-stdlib=", 8) &&
2659 
2660              (aflcc->compiler_mode == GCC ||
2661               aflcc->compiler_mode == GCC_PLUGIN)) {
2662 
2663     if (scan) {
2664 
2665       final_ = PARAM_SCAN;
2666 
2667     } else {
2668 
2669       if (!be_quiet) WARNF("Found '%s' - stripping!", cur_argv);
2670       final_ = PARAM_DROP;
2671 
2672     }
2673 
2674   } else if (cur_argv[0] != '-') {
2675 
2676     /* It's a weak, loose pattern, with very different purpose
2677      than others. We handle it at last, cautiously and robustly. */
2678 
2679     if (scan && cur_argv[0] != '@')  // response file support
2680       aflcc->non_dash = 1;
2681 
2682   }
2683 
2684 #undef SCAN_KEEP
2685 
2686   if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
2687 
2688   return final_;
2689 
2690 }
2691 
2692 /** Miscellaneous routines -----END----- **/
2693 
2694 /* Print help message on request */
maybe_usage(aflcc_state_t * aflcc,int argc,char ** argv)2695 static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
2696 
2697   if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
2698 
2699     printf("afl-cc" VERSION
2700            " by Michal Zalewski, Laszlo Szekeres, Marc Heuse\n");
2701 
2702     SAYF(
2703         "\n"
2704         "afl-cc/afl-c++ [options]\n"
2705         "\n"
2706         "This is a helper application for afl-fuzz. It serves as a drop-in "
2707         "replacement\n"
2708         "for gcc and clang, letting you recompile third-party code with the "
2709         "required\n"
2710         "runtime instrumentation. A common use pattern would be one of the "
2711         "following:\n\n"
2712 
2713         "  CC=afl-cc CXX=afl-c++ ./configure --disable-shared\n"
2714         "  cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ .\n"
2715         "  CC=afl-cc CXX=afl-c++ meson\n\n");
2716 
2717     SAYF(
2718         "                                       |------------- FEATURES "
2719         "-------------|\n"
2720         "MODES:                                  NCC PERSIST DICT   LAF "
2721         "CMPLOG SELECT\n"
2722         "  [LLVM] LLVM:             %s%s\n"
2723         "      PCGUARD              %s    yes yes     module yes yes    "
2724         "yes\n"
2725         "      NATIVE               AVAILABLE    no  yes     no     no  "
2726         "part.  yes\n"
2727         "      CLASSIC              %s    no  yes     module yes yes    "
2728         "yes\n"
2729         "        - NORMAL\n"
2730         "        - CALLER\n"
2731         "        - CTX\n"
2732         "        - NGRAM-{2-16}\n"
2733         "  [LTO] LLVM LTO:          %s%s\n"
2734         "      PCGUARD              DEFAULT      yes yes     yes    yes yes "
2735         "   yes\n"
2736         "      CLASSIC                           yes yes     yes    yes yes "
2737         "   yes\n"
2738         "  [GCC_PLUGIN] gcc plugin: %s%s\n"
2739         "      CLASSIC              DEFAULT      no  yes     no     no  no     "
2740         "yes\n"
2741         "  [GCC/CLANG] simple gcc/clang: %s%s\n"
2742         "      CLASSIC              DEFAULT      no  no      no     no  no     "
2743         "no\n\n",
2744         aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2745         aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
2746         aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2747         aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2748         aflcc->have_lto ? "AVAILABLE" : "unavailable!",
2749         aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
2750         aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
2751         aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "",
2752         aflcc->have_gcc && aflcc->have_clang
2753             ? "AVAILABLE"
2754             : (aflcc->have_gcc
2755                    ? "GCC ONLY "
2756                    : (aflcc->have_clang ? "CLANG ONLY" : "unavailable!")),
2757         (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)
2758             ? " [SELECTED]"
2759             : "");
2760 
2761     SAYF(
2762         "Modes:\n"
2763         "  To select the compiler mode use a symlink version (e.g. "
2764         "afl-clang-fast), set\n"
2765         "  the environment variable AFL_CC_COMPILER to a mode (e.g. LLVM) or "
2766         "use the\n"
2767         "  command line parameter --afl-MODE (e.g. --afl-llvm). If none is "
2768         "selected,\n"
2769         "  afl-cc will select the best available (LLVM -> GCC_PLUGIN -> GCC).\n"
2770         "  The best is LTO but it often needs RANLIB and AR settings outside "
2771         "of afl-cc.\n\n");
2772 
2773 #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
2774   #define NATIVE_MSG                                                   \
2775     "  LLVM-NATIVE:  use llvm's native PCGUARD instrumentation (less " \
2776     "performant)\n"
2777 #else
2778   #define NATIVE_MSG ""
2779 #endif
2780 
2781     SAYF(
2782         "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best "
2783         "available)\n"
2784         "  PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n"
2785 
2786         NATIVE_MSG
2787 
2788         "  CLASSIC: decision target instrumentation (README.llvm.md)\n"
2789         "  CALLER:  CLASSIC + single callee context "
2790         "(instrumentation/README.ctx.md)\n"
2791         "  CTX:     CLASSIC + full callee context "
2792         "(instrumentation/README.ctx.md)\n"
2793         "  NGRAM-x: CLASSIC + previous path "
2794         "((instrumentation/README.ngram.md)\n\n");
2795 
2796 #undef NATIVE_MSG
2797 
2798     SAYF(
2799         "Features: (see documentation links)\n"
2800         "  NCC:    non-colliding coverage [automatic] (that is an amazing "
2801         "thing!)\n"
2802         "          (instrumentation/README.lto.md)\n"
2803         "  PERSIST: persistent mode support [code] (huge speed increase!)\n"
2804         "          (instrumentation/README.persistent_mode.md)\n"
2805         "  DICT:   dictionary in the target [yes=automatic or LLVM module "
2806         "pass]\n"
2807         "          (instrumentation/README.lto.md + "
2808         "instrumentation/README.llvm.md)\n"
2809         "  LAF:    comparison splitting [env] "
2810         "(instrumentation/README.laf-intel.md)\n"
2811         "  CMPLOG: input2state exploration [env] "
2812         "(instrumentation/README.cmplog.md)\n"
2813         "  SELECT: selective instrumentation (allow/deny) on filename or "
2814         "function [env]\n"
2815         "          (instrumentation/README.instrument_list.md)\n\n");
2816 
2817     if (argc < 2 || strncmp(argv[1], "-hh", 3)) {
2818 
2819       SAYF(
2820           "To see all environment variables for the configuration of afl-cc "
2821           "use \"-hh\".\n");
2822 
2823     } else {
2824 
2825       SAYF(
2826           "Environment variables used:\n"
2827           "  AFL_CC: path to the C compiler to use\n"
2828           "  AFL_CXX: path to the C++ compiler to use\n"
2829           "  AFL_DEBUG: enable developer debugging output\n"
2830           "  AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
2831           "  AFL_NO_BUILTIN: no builtins for string compare functions (for "
2832           "libtokencap.so)\n"
2833           "  AFL_NOOPT: behave like a normal compiler (to pass configure "
2834           "tests)\n"
2835           "  AFL_PATH: path to instrumenting pass and runtime  "
2836           "(afl-compiler-rt.*o)\n"
2837           "  AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
2838           "  AFL_INST_RATIO: percentage of branches to instrument\n"
2839           "  AFL_QUIET: suppress verbose output\n"
2840           "  AFL_HARDEN: adds code hardening to catch memory bugs\n"
2841           "  AFL_USE_ASAN: activate address sanitizer\n"
2842           "  AFL_USE_CFISAN: activate control flow sanitizer\n"
2843           "  AFL_USE_MSAN: activate memory sanitizer\n"
2844           "  AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
2845           "  AFL_USE_TSAN: activate thread sanitizer\n"
2846           "  AFL_USE_LSAN: activate leak-checker sanitizer\n");
2847 
2848       if (aflcc->have_gcc_plugin)
2849         SAYF(
2850             "\nGCC Plugin-specific environment variables:\n"
2851             "  AFL_GCC_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
2852             "  AFL_GCC_OUT_OF_LINE: disable inlined instrumentation\n"
2853             "  AFL_GCC_SKIP_NEVERZERO: do not skip zero on trace counters\n"
2854             "  AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
2855             "filename\n");
2856 
2857 #if LLVM_MAJOR >= 9
2858   #define COUNTER_BEHAVIOUR \
2859     "  AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
2860 #else
2861   #define COUNTER_BEHAVIOUR \
2862     "  AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
2863 #endif
2864       if (aflcc->have_llvm)
2865         SAYF(
2866             "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
2867             "variables:\n"
2868             "  AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, "
2869             "disables neverzero\n"
2870 
2871             COUNTER_BEHAVIOUR
2872 
2873             "  AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
2874             "comparisons\n"
2875             "  AFL_LLVM_DICT2FILE_NO_MAIN: skip parsing main() for the "
2876             "dictionary\n"
2877             "  AFL_LLVM_INJECTIONS_ALL: enables all injections hooking\n"
2878             "  AFL_LLVM_INJECTIONS_SQL: enables SQL injections hooking\n"
2879             "  AFL_LLVM_INJECTIONS_LDAP: enables LDAP injections hooking\n"
2880             "  AFL_LLVM_INJECTIONS_XSS: enables XSS injections hooking\n"
2881             "  AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
2882             "  AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
2883             "  AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
2884             "  AFL_LLVM_LAF_SPLIT_SWITCHES: cascaded comparisons on switches\n"
2885             "  AFL_LLVM_LAF_SPLIT_FLOATS: cascaded comparisons on floats\n"
2886             "  AFL_LLVM_LAF_TRANSFORM_COMPARES: cascade comparisons for string "
2887             "functions\n"
2888             "  AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST: enable "
2889             "instrument allow/\n"
2890             "    deny listing (selective instrumentation)\n");
2891 
2892       if (aflcc->have_llvm)
2893         SAYF(
2894             "  AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
2895             "mutator)\n"
2896             "  AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
2897             "    CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 "
2898             "..-16\n"
2899             " You can also use the old environment variables instead:\n"
2900             "  AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
2901             "  AFL_LLVM_CALLER: use single context sensitive coverage (for "
2902             "CLASSIC)\n"
2903             "  AFL_LLVM_CTX: use full context sensitive coverage (for "
2904             "CLASSIC)\n"
2905             "  AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
2906             "CLASSIC)\n"
2907             "  AFL_LLVM_NO_RPATH: disable rpath setting for custom LLVM "
2908             "locations\n");
2909 
2910 #ifdef AFL_CLANG_FLTO
2911       if (aflcc->have_lto)
2912         SAYF(
2913             "\nLTO/afl-clang-lto specific environment variables:\n"
2914             "  AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), "
2915             "e.g. "
2916             "0x10000\n"
2917             "  AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
2918             "functions\n"
2919             "    into this file (LTO mode)\n"
2920             "  AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
2921             "global var\n"
2922             "  AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
2923             "a "
2924             "bb\n"
2925             "  AFL_REAL_LD: use this lld linker instead of the compiled in "
2926             "path\n"
2927             "  AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
2928             "(used in WAFL mode)\n"
2929             "If anything fails - be sure to read README.lto.md!\n");
2930 #endif
2931 
2932       SAYF(
2933           "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. "
2934           "(this is helpful\n"
2935           "in some build systems if you do not want to instrument "
2936           "everything.\n");
2937 
2938     }
2939 
2940     SAYF(
2941         "\nFor any information on the available instrumentations and options "
2942         "please \n"
2943         "consult the README.md, especially section 3.1 about instrumenting "
2944         "targets.\n\n");
2945 
2946 #if (LLVM_MAJOR >= 3)
2947     if (aflcc->have_lto)
2948       SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO);
2949     if (aflcc->have_llvm)
2950       SAYF("afl-cc LLVM version %d using the binary path \"%s\".\n", LLVM_MAJOR,
2951            LLVM_BINDIR);
2952 #endif
2953 
2954 #ifdef USEMMAP
2955   #if !defined(__HAIKU__)
2956     SAYF("Compiled with shm_open support.\n");
2957   #else
2958     SAYF("Compiled with shm_open support (adds -lrt when linking).\n");
2959   #endif
2960 #else
2961     SAYF("Compiled with shmat support.\n");
2962 #endif
2963     SAYF("\n");
2964 
2965     SAYF(
2966         "Do not be overwhelmed :) afl-cc uses good defaults if no options are "
2967         "selected.\n"
2968         "Read the documentation for FEATURES though, all are good but few are "
2969         "defaults.\n"
2970         "Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast "
2971         "with\n"
2972         "AFL_LLVM_CMPLOG and "
2973         "AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
2974 
2975     if (LLVM_MAJOR < 13) {
2976 
2977       SAYF(
2978           "Warning: It is highly recommended to use at least LLVM version 13 "
2979           "(or better, higher) rather than %d!\n\n",
2980           LLVM_MAJOR);
2981 
2982     }
2983 
2984     exit(1);
2985 
2986   }
2987 
2988 }
2989 
2990 /*
2991   Process params passed to afl-cc.
2992 
2993   We have two working modes, *scan* and *non-scan*. In scan mode,
2994   the main task is to set some variables in aflcc according to current argv[i],
2995   while in non-scan mode, is to choose keep or drop current argv[i].
2996 
2997   We have several matching routines being called sequentially in the while-loop,
2998   and each of them try to parse and match current argv[i] according to their own
2999   rules. If one miss match, the next will then take over. In non-scan mode, each
3000   argv[i] mis-matched by all the routines will be kept.
3001 
3002   These routines are:
3003   1. parse_misc_params
3004   2. parse_fsanitize
3005   3. parse_linking_params
3006   4. `if (*cur == '@') {...}`, i.e., parse response files
3007 */
process_params(aflcc_state_t * aflcc,u8 scan,u32 argc,char ** argv)3008 static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
3009                            char **argv) {
3010 
3011   // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
3012 
3013   /* Process the argument list. */
3014 
3015   u8 skip_next = 0;
3016   while (--argc) {
3017 
3018     u8 *cur = *(++argv);
3019 
3020     if (skip_next > 0) {
3021 
3022       skip_next--;
3023       continue;
3024 
3025     }
3026 
3027     if (PARAM_MISS != parse_misc_params(aflcc, cur, scan)) continue;
3028 
3029     if (PARAM_MISS != parse_fsanitize(aflcc, cur, scan)) continue;
3030 
3031     if (PARAM_MISS != parse_linking_params(aflcc, cur, scan, &skip_next, argv))
3032       continue;
3033 
3034     /* Response file support -----BEGIN-----
3035       We have two choices - move everything to the command line or
3036       rewrite the response files to temporary files and delete them
3037       afterwards. We choose the first for easiness.
3038       For clang, llvm::cl::ExpandResponseFiles does this, however it
3039       only has C++ interface. And for gcc there is expandargv in libiberty,
3040       written in C, but we can't simply copy-paste since its LGPL licensed.
3041       So here we use an equivalent FSM as alternative, and try to be compatible
3042       with the two above. See:
3043         - https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
3044         - driver::expand_at_files in gcc.git/gcc/gcc.c
3045         - expandargv in gcc.git/libiberty/argv.c
3046         - llvm-project.git/clang/tools/driver/driver.cpp
3047         - ExpandResponseFiles in
3048           llvm-project.git/llvm/lib/Support/CommandLine.cpp
3049     */
3050     if (*cur == '@') {
3051 
3052       u8 *filename = cur + 1;
3053       if (aflcc->debug) { DEBUGF("response file=%s\n", filename); }
3054 
3055       // Check not found or empty? let the compiler complain if so.
3056       FILE *f = fopen(filename, "r");
3057       if (!f) {
3058 
3059         if (!scan) insert_param(aflcc, cur);
3060         continue;
3061 
3062       }
3063 
3064       struct stat st;
3065       if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode) || st.st_size < 1) {
3066 
3067         fclose(f);
3068         if (!scan) insert_param(aflcc, cur);
3069         continue;
3070 
3071       }
3072 
3073       // Limit the number of response files, the max value
3074       // just keep consistent with expandargv. Only do this in
3075       // scan mode, and not touch rsp_count anymore in the next.
3076       static u32 rsp_count = 2000;
3077       if (scan) {
3078 
3079         if (rsp_count == 0) FATAL("Too many response files provided!");
3080 
3081         --rsp_count;
3082 
3083       }
3084 
3085       // argc, argv acquired from this rsp file. Note that
3086       // process_params ignores argv[0], we need to put a const "" here.
3087       u32    argc_read = 1;
3088       char **argv_read = ck_alloc(sizeof(char *));
3089       argv_read[0] = "";
3090 
3091       char *arg_buf = NULL;
3092       u64   arg_len = 0;
3093 
3094       enum fsm_state {
3095 
3096         fsm_whitespace,    // whitespace seen so far
3097         fsm_double_quote,  // have unpaired double quote
3098         fsm_single_quote,  // have unpaired single quote
3099         fsm_backslash,     // a backslash is seen with no unpaired quote
3100         fsm_normal         // a normal char is seen
3101 
3102       };
3103 
3104       // Workaround to append c to arg buffer, and append the buffer to argv
3105 #define ARG_ALLOC(c)                                             \
3106   do {                                                           \
3107                                                                  \
3108     ++arg_len;                                                   \
3109     arg_buf = ck_realloc(arg_buf, (arg_len + 1) * sizeof(char)); \
3110     arg_buf[arg_len] = '\0';                                     \
3111     arg_buf[arg_len - 1] = (char)c;                              \
3112                                                                  \
3113   } while (0)
3114 
3115 #define ARG_STORE()                                                \
3116   do {                                                             \
3117                                                                    \
3118     ++argc_read;                                                   \
3119     argv_read = ck_realloc(argv_read, argc_read * sizeof(char *)); \
3120     argv_read[argc_read - 1] = arg_buf;                            \
3121     arg_buf = NULL;                                                \
3122     arg_len = 0;                                                   \
3123                                                                    \
3124   } while (0)
3125 
3126       int cur_chr = (int)' ';  // init as whitespace, as a good start :)
3127       enum fsm_state state_ = fsm_whitespace;
3128 
3129       while (cur_chr != EOF) {
3130 
3131         switch (state_) {
3132 
3133           case fsm_whitespace:
3134 
3135             if (arg_buf) {
3136 
3137               ARG_STORE();
3138               break;
3139 
3140             }
3141 
3142             if (isspace(cur_chr)) {
3143 
3144               cur_chr = fgetc(f);
3145 
3146             } else if (cur_chr == (int)'\'') {
3147 
3148               state_ = fsm_single_quote;
3149               cur_chr = fgetc(f);
3150 
3151             } else if (cur_chr == (int)'"') {
3152 
3153               state_ = fsm_double_quote;
3154               cur_chr = fgetc(f);
3155 
3156             } else if (cur_chr == (int)'\\') {
3157 
3158               state_ = fsm_backslash;
3159               cur_chr = fgetc(f);
3160 
3161             } else {
3162 
3163               state_ = fsm_normal;
3164 
3165             }
3166 
3167             break;
3168 
3169           case fsm_normal:
3170 
3171             if (isspace(cur_chr)) {
3172 
3173               state_ = fsm_whitespace;
3174 
3175             } else if (cur_chr == (int)'\'') {
3176 
3177               state_ = fsm_single_quote;
3178               cur_chr = fgetc(f);
3179 
3180             } else if (cur_chr == (int)'\"') {
3181 
3182               state_ = fsm_double_quote;
3183               cur_chr = fgetc(f);
3184 
3185             } else if (cur_chr == (int)'\\') {
3186 
3187               state_ = fsm_backslash;
3188               cur_chr = fgetc(f);
3189 
3190             } else {
3191 
3192               ARG_ALLOC(cur_chr);
3193               cur_chr = fgetc(f);
3194 
3195             }
3196 
3197             break;
3198 
3199           case fsm_backslash:
3200 
3201             ARG_ALLOC(cur_chr);
3202             cur_chr = fgetc(f);
3203             state_ = fsm_normal;
3204 
3205             break;
3206 
3207           case fsm_single_quote:
3208 
3209             if (cur_chr == (int)'\\') {
3210 
3211               cur_chr = fgetc(f);
3212               if (cur_chr == EOF) break;
3213               ARG_ALLOC(cur_chr);
3214 
3215             } else if (cur_chr == (int)'\'') {
3216 
3217               state_ = fsm_normal;
3218 
3219             } else {
3220 
3221               ARG_ALLOC(cur_chr);
3222 
3223             }
3224 
3225             cur_chr = fgetc(f);
3226             break;
3227 
3228           case fsm_double_quote:
3229 
3230             if (cur_chr == (int)'\\') {
3231 
3232               cur_chr = fgetc(f);
3233               if (cur_chr == EOF) break;
3234               ARG_ALLOC(cur_chr);
3235 
3236             } else if (cur_chr == (int)'"') {
3237 
3238               state_ = fsm_normal;
3239 
3240             } else {
3241 
3242               ARG_ALLOC(cur_chr);
3243 
3244             }
3245 
3246             cur_chr = fgetc(f);
3247             break;
3248 
3249           default:
3250             break;
3251 
3252         }
3253 
3254       }
3255 
3256       if (arg_buf) { ARG_STORE(); }  // save the pending arg after EOF
3257 
3258 #undef ARG_ALLOC
3259 #undef ARG_STORE
3260 
3261       if (argc_read > 1) { process_params(aflcc, scan, argc_read, argv_read); }
3262 
3263       // We cannot free argv_read[] unless we don't need to keep any
3264       // reference in cc_params. Never free argv[0], the const "".
3265       if (scan) {
3266 
3267         while (argc_read > 1)
3268           ck_free(argv_read[--argc_read]);
3269 
3270         ck_free(argv_read);
3271 
3272       }
3273 
3274       continue;
3275 
3276     }                                /* Response file support -----END----- */
3277 
3278     if (!scan) insert_param(aflcc, cur);
3279 
3280   }
3281 
3282 }
3283 
3284 /* Process each of the existing argv, also add a few new args. */
edit_params(aflcc_state_t * aflcc,u32 argc,char ** argv,char ** envp)3285 static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
3286                         char **envp) {
3287 
3288   add_real_argv0(aflcc);
3289 
3290   // prevent unnecessary build errors
3291   if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC) {
3292 
3293     insert_param(aflcc, "-Wno-unused-command-line-argument");
3294 
3295   }
3296 
3297   if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) {
3298 
3299     add_assembler(aflcc);
3300 
3301   }
3302 
3303   if (aflcc->compiler_mode == GCC_PLUGIN) { add_gcc_plugin(aflcc); }
3304 
3305   if (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == LTO) {
3306 
3307     if (aflcc->lto_mode && aflcc->have_instr_env) {
3308 
3309       load_llvm_pass(aflcc, "afl-llvm-lto-instrumentlist.so");
3310 
3311     }
3312 
3313     if (getenv("AFL_LLVM_DICT2FILE")) {
3314 
3315       load_llvm_pass(aflcc, "afl-llvm-dict2file.so");
3316 
3317     }
3318 
3319     // laf
3320     if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
3321 
3322       load_llvm_pass(aflcc, "split-switches-pass.so");
3323 
3324     }
3325 
3326     if (getenv("LAF_TRANSFORM_COMPARES") ||
3327         getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
3328 
3329       load_llvm_pass(aflcc, "compare-transform-pass.so");
3330 
3331     }
3332 
3333     if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
3334         getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
3335 
3336       load_llvm_pass(aflcc, "split-compares-pass.so");
3337 
3338     }
3339 
3340     // /laf
3341 
3342     if (aflcc->cmplog_mode) {
3343 
3344       insert_param(aflcc, "-fno-inline");
3345 
3346       load_llvm_pass(aflcc, "cmplog-switches-pass.so");
3347       // reuse split switches from laf
3348       load_llvm_pass(aflcc, "split-switches-pass.so");
3349 
3350     }
3351 
3352     // #if LLVM_MAJOR >= 13
3353     //     // Use the old pass manager in LLVM 14 which the AFL++ passes still
3354     //     use. insert_param(aflcc, "-flegacy-pass-manager");
3355     // #endif
3356 
3357     if (aflcc->lto_mode) {
3358 
3359       insert_param(aflcc, aflcc->lto_flag);
3360 
3361       if (!aflcc->have_c) {
3362 
3363         add_lto_linker(aflcc);
3364         add_lto_passes(aflcc);
3365 
3366       }
3367 
3368     } else {
3369 
3370       if (aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
3371 
3372         add_optimized_pcguard(aflcc);
3373 
3374       } else if (aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
3375 
3376         add_native_pcguard(aflcc);
3377 
3378       } else {
3379 
3380         load_llvm_pass(aflcc, "afl-llvm-pass.so");
3381 
3382       }
3383 
3384     }
3385 
3386     if (aflcc->cmplog_mode) {
3387 
3388       load_llvm_pass(aflcc, "cmplog-instructions-pass.so");
3389       load_llvm_pass(aflcc, "cmplog-routines-pass.so");
3390 
3391     }
3392 
3393     if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
3394         getenv("AFL_LLVM_INJECTIONS_SQL") ||
3395         getenv("AFL_LLVM_INJECTIONS_LDAP") ||
3396         getenv("AFL_LLVM_INJECTIONS_XSS")) {
3397 
3398       load_llvm_pass(aflcc, "injection-pass.so");
3399 
3400     }
3401 
3402     // insert_param(aflcc, "-Qunused-arguments");
3403 
3404   }
3405 
3406   /* Inspect the command line parameters. */
3407 
3408   process_params(aflcc, 0, argc, argv);
3409 
3410   add_sanitizers(aflcc, envp);
3411 
3412   add_misc_params(aflcc);
3413 
3414   add_defs_common(aflcc);
3415   add_defs_selective_instr(aflcc);
3416   add_defs_persistent_mode(aflcc);
3417 
3418   add_runtime(aflcc);
3419 
3420   insert_param(aflcc, NULL);
3421 
3422 }
3423 
3424 /* Main entry point */
main(int argc,char ** argv,char ** envp)3425 int main(int argc, char **argv, char **envp) {
3426 
3427   aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
3428   aflcc_state_init(aflcc, (u8 *)argv[0]);
3429 
3430   check_environment_vars(envp);
3431 
3432   find_built_deps(aflcc);
3433 
3434   compiler_mode_by_callname(aflcc);
3435   compiler_mode_by_environ(aflcc);
3436   compiler_mode_by_cmdline(aflcc, argc, argv);
3437 
3438   instrument_mode_by_environ(aflcc);
3439 
3440   mode_final_checkout(aflcc, argc, argv);
3441 
3442   process_params(aflcc, 1, argc, argv);
3443 
3444   maybe_usage(aflcc, argc, argv);
3445 
3446   mode_notification(aflcc);
3447 
3448   if (aflcc->debug) debugf_args(argc, argv);
3449 
3450   edit_params(aflcc, argc, argv, envp);
3451 
3452   if (aflcc->debug)
3453     debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
3454 
3455   if (aflcc->passthrough) {
3456 
3457     argv[0] = aflcc->cc_params[0];
3458     execvp(aflcc->cc_params[0], (char **)argv);
3459 
3460   } else {
3461 
3462     execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
3463 
3464   }
3465 
3466   FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
3467 
3468   return 0;
3469 
3470 }
3471 
3472