diff options
Diffstat (limited to 'compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp')
-rw-r--r-- | compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp | 120 |
1 files changed, 63 insertions, 57 deletions
diff --git a/compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp b/compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp index 8a5d695094d..989675e81d9 100644 --- a/compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp +++ b/compiler-rt/lib/fuzzer/dataflow/DataFlow.cpp @@ -35,8 +35,7 @@ // Run: // # Collect data flow and coverage for INPUT_FILE // # write to OUTPUT_FILE (default: stdout) -// export DFSAN_OPTIONS=fast16labels=1:warn_unimplemented=0 -// ./a.out INPUT_FILE [OUTPUT_FILE] +// ./a.out FIRST_LABEL LAST_LABEL INPUT_FILE [OUTPUT_FILE] // // # Print all instrumented functions. llvm-symbolizer must be present in PATH // ./a.out @@ -49,6 +48,8 @@ // C1 8 // =============== // "FN xxxxxxxxxx": tells what bytes of the input does the function N depend on. +// The byte string is LEN+1 bytes. The last byte is set if the function +// depends on the input length. // "CN X Y Z T": tells that a function N has basic blocks X, Y, and Z covered // in addition to the function's entry block, out of T total instrumented // blocks. @@ -71,20 +72,22 @@ __attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); } // extern "C" static size_t InputLen; -static size_t NumIterations; +static size_t InputLabelBeg; +static size_t InputLabelEnd; +static size_t InputSizeLabel; static size_t NumFuncs, NumGuards; static uint32_t *GuardsBeg, *GuardsEnd; static const uintptr_t *PCsBeg, *PCsEnd; -static __thread size_t CurrentFunc, CurrentIteration; -static dfsan_label **FuncLabels; // NumFuncs x NumIterations. +static __thread size_t CurrentFunc; +static dfsan_label *FuncLabels; // Array of NumFuncs elements. static bool *BBExecuted; // Array of NumGuards elements. +static char *PrintableStringForLabel; // InputLen + 2 bytes. +static bool LabelSeen[1 << 8 * sizeof(dfsan_label)]; enum { PCFLAG_FUNC_ENTRY = 1, }; -const int kNumLabels = 16; - static inline bool BlockIsEntry(size_t BlockIdx) { return PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY; } @@ -109,32 +112,35 @@ static int PrintFunctions() { return 0; } -static void PrintBinary(FILE *Out, dfsan_label L, size_t Len) { - char buf[kNumLabels + 1]; - assert(Len <= kNumLabels); - for (int i = 0; i < kNumLabels; i++) - buf[i] = (L & (1 << i)) ? '1' : '0'; - buf[Len] = 0; - fprintf(Out, "%s", buf); +extern "C" +void SetBytesForLabel(dfsan_label L, char *Bytes) { + if (LabelSeen[L]) + return; + LabelSeen[L] = true; + assert(L); + if (L < InputSizeLabel) { + Bytes[L + InputLabelBeg - 1] = '1'; + } else if (L == InputSizeLabel) { + Bytes[InputLen] = '1'; + } else { + auto *DLI = dfsan_get_label_info(L); + SetBytesForLabel(DLI->l1, Bytes); + SetBytesForLabel(DLI->l2, Bytes); + } +} + +static char *GetPrintableStringForLabel(dfsan_label L) { + memset(PrintableStringForLabel, '0', InputLen + 1); + PrintableStringForLabel[InputLen + 1] = 0; + memset(LabelSeen, 0, sizeof(LabelSeen)); + SetBytesForLabel(L, PrintableStringForLabel); + return PrintableStringForLabel; } static void PrintDataFlow(FILE *Out) { - for (size_t Func = 0; Func < NumFuncs; Func++) { - bool HasAny = false; - for (size_t Iter = 0; Iter < NumIterations; Iter++) - if (FuncLabels[Func][Iter]) - HasAny = true; - if (!HasAny) - continue; - fprintf(Out, "F%zd ", Func); - size_t LenOfLastIteration = kNumLabels; - if (auto Tail = InputLen % kNumLabels) - LenOfLastIteration = Tail; - for (size_t Iter = 0; Iter < NumIterations; Iter++) - PrintBinary(Out, FuncLabels[Func][Iter], - Iter == NumIterations - 1 ? LenOfLastIteration : kNumLabels); - fprintf(Out, "\n"); - } + for (size_t I = 0; I < NumFuncs; I++) + if (FuncLabels[I]) + fprintf(Out, "F%zd %s\n", I, GetPrintableStringForLabel(FuncLabels[I])); } static void PrintCoverage(FILE *Out) { @@ -163,9 +169,12 @@ int main(int argc, char **argv) { LLVMFuzzerInitialize(&argc, &argv); if (argc == 1) return PrintFunctions(); - assert(argc == 2 || argc == 3); + assert(argc == 4 || argc == 5); + InputLabelBeg = atoi(argv[1]); + InputLabelEnd = atoi(argv[2]); + assert(InputLabelBeg < InputLabelEnd); - const char *Input = argv[1]; + const char *Input = argv[3]; fprintf(stderr, "INFO: reading '%s'\n", Input); FILE *In = fopen(Input, "r"); assert(In); @@ -175,35 +184,30 @@ int main(int argc, char **argv) { unsigned char *Buf = (unsigned char*)malloc(InputLen); size_t NumBytesRead = fread(Buf, 1, InputLen, In); assert(NumBytesRead == InputLen); + PrintableStringForLabel = (char*)malloc(InputLen + 2); fclose(In); - NumIterations = (NumBytesRead + kNumLabels - 1) / kNumLabels; - FuncLabels = (dfsan_label**)calloc(NumFuncs, sizeof(dfsan_label*)); - for (size_t Func = 0; Func < NumFuncs; Func++) - FuncLabels[Func] = - (dfsan_label *)calloc(NumIterations, sizeof(dfsan_label)); - - for (CurrentIteration = 0; CurrentIteration < NumIterations; - CurrentIteration++) { - fprintf(stderr, "INFO: running '%s' %zd/%zd\n", Input, CurrentIteration, - NumIterations); - dfsan_flush(); - dfsan_set_label(0, Buf, InputLen); - - size_t BaseIdx = CurrentIteration * kNumLabels; - size_t LastIdx = BaseIdx + kNumLabels < NumBytesRead ? BaseIdx + kNumLabels - : NumBytesRead; - assert(BaseIdx < LastIdx); - for (size_t Idx = BaseIdx; Idx < LastIdx; Idx++) - dfsan_set_label(1 << (Idx - BaseIdx), Buf + Idx, 1); - LLVMFuzzerTestOneInput(Buf, InputLen); + fprintf(stderr, "INFO: running '%s'\n", Input); + for (size_t I = 1; I <= InputLen; I++) { + size_t Idx = I - 1; + if (Idx >= InputLabelBeg && Idx < InputLabelEnd) { + dfsan_label L = dfsan_create_label("", nullptr); + assert(L == I - InputLabelBeg); + dfsan_set_label(L, Buf + Idx, 1); + } } + dfsan_label SizeL = dfsan_create_label("", nullptr); + InputSizeLabel = SizeL; + assert(InputSizeLabel == InputLabelEnd - InputLabelBeg + 1); + dfsan_set_label(SizeL, &InputLen, sizeof(InputLen)); + + LLVMFuzzerTestOneInput(Buf, InputLen); free(Buf); - bool OutIsStdout = argc == 2; + bool OutIsStdout = argc == 4; fprintf(stderr, "INFO: writing dataflow to %s\n", - OutIsStdout ? "<stdout>" : argv[2]); - FILE *Out = OutIsStdout ? stdout : fopen(argv[2], "w"); + OutIsStdout ? "<stdout>" : argv[4]); + FILE *Out = OutIsStdout ? stdout : fopen(argv[4], "w"); PrintDataFlow(Out); PrintCoverage(Out); if (!OutIsStdout) fclose(Out); @@ -233,6 +237,7 @@ void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, GuardsBeg[i] = NumFuncs; } } + FuncLabels = (dfsan_label*)calloc(NumFuncs, sizeof(dfsan_label)); BBExecuted = (bool*)calloc(NumGuards, sizeof(bool)); fprintf(stderr, "INFO: %zd instrumented function(s) observed " "and %zd basic blocks\n", NumFuncs, NumGuards); @@ -253,13 +258,14 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases, dfsan_label L1, dfsan_label UnusedL) { assert(CurrentFunc < NumFuncs); - FuncLabels[CurrentFunc][CurrentIteration] |= L1; + FuncLabels[CurrentFunc] = dfsan_union(FuncLabels[CurrentFunc], L1); } #define HOOK(Name, Type) \ void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) { \ assert(CurrentFunc < NumFuncs); \ - FuncLabels[CurrentFunc][CurrentIteration] |= L1 | L2; \ + FuncLabels[CurrentFunc] = \ + dfsan_union(FuncLabels[CurrentFunc], dfsan_union(L1, L2)); \ } HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t) |