xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
10b57cec5SDimitry Andric //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // Misc utils.
90b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "FuzzerUtil.h"
120b57cec5SDimitry Andric #include "FuzzerIO.h"
130b57cec5SDimitry Andric #include "FuzzerInternal.h"
140b57cec5SDimitry Andric #include <cassert>
150b57cec5SDimitry Andric #include <chrono>
160b57cec5SDimitry Andric #include <cstring>
170b57cec5SDimitry Andric #include <errno.h>
180b57cec5SDimitry Andric #include <mutex>
190b57cec5SDimitry Andric #include <signal.h>
200b57cec5SDimitry Andric #include <sstream>
210b57cec5SDimitry Andric #include <stdio.h>
220b57cec5SDimitry Andric #include <sys/types.h>
230b57cec5SDimitry Andric #include <thread>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace fuzzer {
260b57cec5SDimitry Andric 
PrintHexArray(const uint8_t * Data,size_t Size,const char * PrintAfter)270b57cec5SDimitry Andric void PrintHexArray(const uint8_t *Data, size_t Size,
280b57cec5SDimitry Andric                    const char *PrintAfter) {
290b57cec5SDimitry Andric   for (size_t i = 0; i < Size; i++)
300b57cec5SDimitry Andric     Printf("0x%x,", (unsigned)Data[i]);
310b57cec5SDimitry Andric   Printf("%s", PrintAfter);
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
Print(const Unit & v,const char * PrintAfter)340b57cec5SDimitry Andric void Print(const Unit &v, const char *PrintAfter) {
350b57cec5SDimitry Andric   PrintHexArray(v.data(), v.size(), PrintAfter);
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
PrintASCIIByte(uint8_t Byte)380b57cec5SDimitry Andric void PrintASCIIByte(uint8_t Byte) {
390b57cec5SDimitry Andric   if (Byte == '\\')
400b57cec5SDimitry Andric     Printf("\\\\");
410b57cec5SDimitry Andric   else if (Byte == '"')
420b57cec5SDimitry Andric     Printf("\\\"");
430b57cec5SDimitry Andric   else if (Byte >= 32 && Byte < 127)
440b57cec5SDimitry Andric     Printf("%c", Byte);
450b57cec5SDimitry Andric   else
46*349cc55cSDimitry Andric     Printf("\\%03o", Byte);
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
PrintASCII(const uint8_t * Data,size_t Size,const char * PrintAfter)490b57cec5SDimitry Andric void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
500b57cec5SDimitry Andric   for (size_t i = 0; i < Size; i++)
510b57cec5SDimitry Andric     PrintASCIIByte(Data[i]);
520b57cec5SDimitry Andric   Printf("%s", PrintAfter);
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
PrintASCII(const Unit & U,const char * PrintAfter)550b57cec5SDimitry Andric void PrintASCII(const Unit &U, const char *PrintAfter) {
560b57cec5SDimitry Andric   PrintASCII(U.data(), U.size(), PrintAfter);
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
ToASCII(uint8_t * Data,size_t Size)590b57cec5SDimitry Andric bool ToASCII(uint8_t *Data, size_t Size) {
600b57cec5SDimitry Andric   bool Changed = false;
610b57cec5SDimitry Andric   for (size_t i = 0; i < Size; i++) {
620b57cec5SDimitry Andric     uint8_t &X = Data[i];
630b57cec5SDimitry Andric     auto NewX = X;
640b57cec5SDimitry Andric     NewX &= 127;
650b57cec5SDimitry Andric     if (!isspace(NewX) && !isprint(NewX))
660b57cec5SDimitry Andric       NewX = ' ';
670b57cec5SDimitry Andric     Changed |= NewX != X;
680b57cec5SDimitry Andric     X = NewX;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric   return Changed;
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric 
IsASCII(const Unit & U)730b57cec5SDimitry Andric bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
740b57cec5SDimitry Andric 
IsASCII(const uint8_t * Data,size_t Size)750b57cec5SDimitry Andric bool IsASCII(const uint8_t *Data, size_t Size) {
760b57cec5SDimitry Andric   for (size_t i = 0; i < Size; i++)
770b57cec5SDimitry Andric     if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
780b57cec5SDimitry Andric   return true;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
ParseOneDictionaryEntry(const std::string & Str,Unit * U)810b57cec5SDimitry Andric bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
820b57cec5SDimitry Andric   U->clear();
830b57cec5SDimitry Andric   if (Str.empty()) return false;
840b57cec5SDimitry Andric   size_t L = 0, R = Str.size() - 1;  // We are parsing the range [L,R].
850b57cec5SDimitry Andric   // Skip spaces from both sides.
860b57cec5SDimitry Andric   while (L < R && isspace(Str[L])) L++;
870b57cec5SDimitry Andric   while (R > L && isspace(Str[R])) R--;
880b57cec5SDimitry Andric   if (R - L < 2) return false;
890b57cec5SDimitry Andric   // Check the closing "
900b57cec5SDimitry Andric   if (Str[R] != '"') return false;
910b57cec5SDimitry Andric   R--;
920b57cec5SDimitry Andric   // Find the opening "
930b57cec5SDimitry Andric   while (L < R && Str[L] != '"') L++;
940b57cec5SDimitry Andric   if (L >= R) return false;
950b57cec5SDimitry Andric   assert(Str[L] == '\"');
960b57cec5SDimitry Andric   L++;
970b57cec5SDimitry Andric   assert(L <= R);
980b57cec5SDimitry Andric   for (size_t Pos = L; Pos <= R; Pos++) {
990b57cec5SDimitry Andric     uint8_t V = (uint8_t)Str[Pos];
1000b57cec5SDimitry Andric     if (!isprint(V) && !isspace(V)) return false;
1010b57cec5SDimitry Andric     if (V =='\\') {
1020b57cec5SDimitry Andric       // Handle '\\'
1030b57cec5SDimitry Andric       if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
1040b57cec5SDimitry Andric         U->push_back(Str[Pos + 1]);
1050b57cec5SDimitry Andric         Pos++;
1060b57cec5SDimitry Andric         continue;
1070b57cec5SDimitry Andric       }
1080b57cec5SDimitry Andric       // Handle '\xAB'
1090b57cec5SDimitry Andric       if (Pos + 3 <= R && Str[Pos + 1] == 'x'
1100b57cec5SDimitry Andric            && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
1110b57cec5SDimitry Andric         char Hex[] = "0xAA";
1120b57cec5SDimitry Andric         Hex[2] = Str[Pos + 2];
1130b57cec5SDimitry Andric         Hex[3] = Str[Pos + 3];
114fe6060f1SDimitry Andric         U->push_back(static_cast<uint8_t>(strtol(Hex, nullptr, 16)));
1150b57cec5SDimitry Andric         Pos += 3;
1160b57cec5SDimitry Andric         continue;
1170b57cec5SDimitry Andric       }
1180b57cec5SDimitry Andric       return false;  // Invalid escape.
1190b57cec5SDimitry Andric     } else {
1200b57cec5SDimitry Andric       // Any other character.
1210b57cec5SDimitry Andric       U->push_back(V);
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric   return true;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
ParseDictionaryFile(const std::string & Text,std::vector<Unit> * Units)127*349cc55cSDimitry Andric bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
1280b57cec5SDimitry Andric   if (Text.empty()) {
1290b57cec5SDimitry Andric     Printf("ParseDictionaryFile: file does not exist or is empty\n");
1300b57cec5SDimitry Andric     return false;
1310b57cec5SDimitry Andric   }
1320b57cec5SDimitry Andric   std::istringstream ISS(Text);
1330b57cec5SDimitry Andric   Units->clear();
1340b57cec5SDimitry Andric   Unit U;
1350b57cec5SDimitry Andric   int LineNo = 0;
1360b57cec5SDimitry Andric   std::string S;
1370b57cec5SDimitry Andric   while (std::getline(ISS, S, '\n')) {
1380b57cec5SDimitry Andric     LineNo++;
1390b57cec5SDimitry Andric     size_t Pos = 0;
1400b57cec5SDimitry Andric     while (Pos < S.size() && isspace(S[Pos])) Pos++;  // Skip spaces.
1410b57cec5SDimitry Andric     if (Pos == S.size()) continue;  // Empty line.
1420b57cec5SDimitry Andric     if (S[Pos] == '#') continue;  // Comment line.
1430b57cec5SDimitry Andric     if (ParseOneDictionaryEntry(S, &U)) {
1440b57cec5SDimitry Andric       Units->push_back(U);
1450b57cec5SDimitry Andric     } else {
1460b57cec5SDimitry Andric       Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
1470b57cec5SDimitry Andric              S.c_str());
1480b57cec5SDimitry Andric       return false;
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric   return true;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
1545ffd83dbSDimitry Andric // Code duplicated (and tested) in llvm/include/llvm/Support/Base64.h
Base64(const Unit & U)1550b57cec5SDimitry Andric std::string Base64(const Unit &U) {
1560b57cec5SDimitry Andric   static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1570b57cec5SDimitry Andric                               "abcdefghijklmnopqrstuvwxyz"
1580b57cec5SDimitry Andric                               "0123456789+/";
1595ffd83dbSDimitry Andric   std::string Buffer;
1605ffd83dbSDimitry Andric   Buffer.resize(((U.size() + 2) / 3) * 4);
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric   size_t i = 0, j = 0;
1635ffd83dbSDimitry Andric   for (size_t n = U.size() / 3 * 3; i < n; i += 3, j += 4) {
1645ffd83dbSDimitry Andric     uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8) |
1655ffd83dbSDimitry Andric                  (unsigned char)U[i + 2];
1665ffd83dbSDimitry Andric     Buffer[j + 0] = Table[(x >> 18) & 63];
1675ffd83dbSDimitry Andric     Buffer[j + 1] = Table[(x >> 12) & 63];
1685ffd83dbSDimitry Andric     Buffer[j + 2] = Table[(x >> 6) & 63];
1695ffd83dbSDimitry Andric     Buffer[j + 3] = Table[x & 63];
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric   if (i + 1 == U.size()) {
1725ffd83dbSDimitry Andric     uint32_t x = ((unsigned char)U[i] << 16);
1735ffd83dbSDimitry Andric     Buffer[j + 0] = Table[(x >> 18) & 63];
1745ffd83dbSDimitry Andric     Buffer[j + 1] = Table[(x >> 12) & 63];
1755ffd83dbSDimitry Andric     Buffer[j + 2] = '=';
1765ffd83dbSDimitry Andric     Buffer[j + 3] = '=';
1770b57cec5SDimitry Andric   } else if (i + 2 == U.size()) {
1785ffd83dbSDimitry Andric     uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8);
1795ffd83dbSDimitry Andric     Buffer[j + 0] = Table[(x >> 18) & 63];
1805ffd83dbSDimitry Andric     Buffer[j + 1] = Table[(x >> 12) & 63];
1815ffd83dbSDimitry Andric     Buffer[j + 2] = Table[(x >> 6) & 63];
1825ffd83dbSDimitry Andric     Buffer[j + 3] = '=';
1830b57cec5SDimitry Andric   }
1845ffd83dbSDimitry Andric   return Buffer;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric static std::mutex SymbolizeMutex;
1880b57cec5SDimitry Andric 
DescribePC(const char * SymbolizedFMT,uintptr_t PC)1890b57cec5SDimitry Andric std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
1900b57cec5SDimitry Andric   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
1910b57cec5SDimitry Andric   if (!EF->__sanitizer_symbolize_pc || !l.owns_lock())
1920b57cec5SDimitry Andric     return "<can not symbolize>";
1930b57cec5SDimitry Andric   char PcDescr[1024] = {};
1940b57cec5SDimitry Andric   EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
1950b57cec5SDimitry Andric                                SymbolizedFMT, PcDescr, sizeof(PcDescr));
1960b57cec5SDimitry Andric   PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
1970b57cec5SDimitry Andric   return PcDescr;
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
PrintPC(const char * SymbolizedFMT,const char * FallbackFMT,uintptr_t PC)2000b57cec5SDimitry Andric void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
2010b57cec5SDimitry Andric   if (EF->__sanitizer_symbolize_pc)
2020b57cec5SDimitry Andric     Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
2030b57cec5SDimitry Andric   else
2040b57cec5SDimitry Andric     Printf(FallbackFMT, PC);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
PrintStackTrace()2070b57cec5SDimitry Andric void PrintStackTrace() {
2080b57cec5SDimitry Andric   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
2090b57cec5SDimitry Andric   if (EF->__sanitizer_print_stack_trace && l.owns_lock())
2100b57cec5SDimitry Andric     EF->__sanitizer_print_stack_trace();
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
PrintMemoryProfile()2130b57cec5SDimitry Andric void PrintMemoryProfile() {
2140b57cec5SDimitry Andric   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
2150b57cec5SDimitry Andric   if (EF->__sanitizer_print_memory_profile && l.owns_lock())
2160b57cec5SDimitry Andric     EF->__sanitizer_print_memory_profile(95, 8);
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
NumberOfCpuCores()2190b57cec5SDimitry Andric unsigned NumberOfCpuCores() {
2200b57cec5SDimitry Andric   unsigned N = std::thread::hardware_concurrency();
2210b57cec5SDimitry Andric   if (!N) {
2220b57cec5SDimitry Andric     Printf("WARNING: std::thread::hardware_concurrency not well defined for "
2230b57cec5SDimitry Andric            "your platform. Assuming CPU count of 1.\n");
2240b57cec5SDimitry Andric     N = 1;
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   return N;
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
SimpleFastHash(const void * Data,size_t Size,uint64_t Initial)229fe6060f1SDimitry Andric uint64_t SimpleFastHash(const void *Data, size_t Size, uint64_t Initial) {
230fe6060f1SDimitry Andric   uint64_t Res = Initial;
231fe6060f1SDimitry Andric   const uint8_t *Bytes = static_cast<const uint8_t *>(Data);
2320b57cec5SDimitry Andric   for (size_t i = 0; i < Size; i++)
233fe6060f1SDimitry Andric     Res = Res * 11 + Bytes[i];
2340b57cec5SDimitry Andric   return Res;
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric }  // namespace fuzzer
238