110ab2aceSGeorge Karpenkov //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Misc utils.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov 
1110ab2aceSGeorge Karpenkov #include "FuzzerUtil.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1410ab2aceSGeorge Karpenkov #include <cassert>
1510ab2aceSGeorge Karpenkov #include <chrono>
1610ab2aceSGeorge Karpenkov #include <cstring>
1710ab2aceSGeorge Karpenkov #include <errno.h>
1814cf71a3SMatt Morehouse #include <mutex>
1910ab2aceSGeorge Karpenkov #include <signal.h>
2010ab2aceSGeorge Karpenkov #include <sstream>
2110ab2aceSGeorge Karpenkov #include <stdio.h>
2210ab2aceSGeorge Karpenkov #include <sys/types.h>
2310ab2aceSGeorge Karpenkov #include <thread>
2410ab2aceSGeorge Karpenkov 
2510ab2aceSGeorge Karpenkov namespace fuzzer {
2610ab2aceSGeorge Karpenkov 
PrintHexArray(const uint8_t * Data,size_t Size,const char * PrintAfter)2710ab2aceSGeorge Karpenkov void PrintHexArray(const uint8_t *Data, size_t Size,
2810ab2aceSGeorge Karpenkov                    const char *PrintAfter) {
2910ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Size; i++)
3010ab2aceSGeorge Karpenkov     Printf("0x%x,", (unsigned)Data[i]);
3110ab2aceSGeorge Karpenkov   Printf("%s", PrintAfter);
3210ab2aceSGeorge Karpenkov }
3310ab2aceSGeorge Karpenkov 
Print(const Unit & v,const char * PrintAfter)3410ab2aceSGeorge Karpenkov void Print(const Unit &v, const char *PrintAfter) {
3510ab2aceSGeorge Karpenkov   PrintHexArray(v.data(), v.size(), PrintAfter);
3610ab2aceSGeorge Karpenkov }
3710ab2aceSGeorge Karpenkov 
PrintASCIIByte(uint8_t Byte)3810ab2aceSGeorge Karpenkov void PrintASCIIByte(uint8_t Byte) {
3910ab2aceSGeorge Karpenkov   if (Byte == '\\')
4010ab2aceSGeorge Karpenkov     Printf("\\\\");
4110ab2aceSGeorge Karpenkov   else if (Byte == '"')
4210ab2aceSGeorge Karpenkov     Printf("\\\"");
4310ab2aceSGeorge Karpenkov   else if (Byte >= 32 && Byte < 127)
4410ab2aceSGeorge Karpenkov     Printf("%c", Byte);
4510ab2aceSGeorge Karpenkov   else
46*c7bd6435SHans Wennborg     Printf("\\%03o", Byte);
4710ab2aceSGeorge Karpenkov }
4810ab2aceSGeorge Karpenkov 
PrintASCII(const uint8_t * Data,size_t Size,const char * PrintAfter)4910ab2aceSGeorge Karpenkov void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
5010ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Size; i++)
5110ab2aceSGeorge Karpenkov     PrintASCIIByte(Data[i]);
5210ab2aceSGeorge Karpenkov   Printf("%s", PrintAfter);
5310ab2aceSGeorge Karpenkov }
5410ab2aceSGeorge Karpenkov 
PrintASCII(const Unit & U,const char * PrintAfter)5510ab2aceSGeorge Karpenkov void PrintASCII(const Unit &U, const char *PrintAfter) {
5610ab2aceSGeorge Karpenkov   PrintASCII(U.data(), U.size(), PrintAfter);
5710ab2aceSGeorge Karpenkov }
5810ab2aceSGeorge Karpenkov 
ToASCII(uint8_t * Data,size_t Size)5910ab2aceSGeorge Karpenkov bool ToASCII(uint8_t *Data, size_t Size) {
6010ab2aceSGeorge Karpenkov   bool Changed = false;
6110ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Size; i++) {
6210ab2aceSGeorge Karpenkov     uint8_t &X = Data[i];
6310ab2aceSGeorge Karpenkov     auto NewX = X;
6410ab2aceSGeorge Karpenkov     NewX &= 127;
6510ab2aceSGeorge Karpenkov     if (!isspace(NewX) && !isprint(NewX))
6610ab2aceSGeorge Karpenkov       NewX = ' ';
6710ab2aceSGeorge Karpenkov     Changed |= NewX != X;
6810ab2aceSGeorge Karpenkov     X = NewX;
6910ab2aceSGeorge Karpenkov   }
7010ab2aceSGeorge Karpenkov   return Changed;
7110ab2aceSGeorge Karpenkov }
7210ab2aceSGeorge Karpenkov 
IsASCII(const Unit & U)7310ab2aceSGeorge Karpenkov bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
7410ab2aceSGeorge Karpenkov 
IsASCII(const uint8_t * Data,size_t Size)7510ab2aceSGeorge Karpenkov bool IsASCII(const uint8_t *Data, size_t Size) {
7610ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Size; i++)
7710ab2aceSGeorge Karpenkov     if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
7810ab2aceSGeorge Karpenkov   return true;
7910ab2aceSGeorge Karpenkov }
8010ab2aceSGeorge Karpenkov 
ParseOneDictionaryEntry(const std::string & Str,Unit * U)8110ab2aceSGeorge Karpenkov bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
8210ab2aceSGeorge Karpenkov   U->clear();
8310ab2aceSGeorge Karpenkov   if (Str.empty()) return false;
8410ab2aceSGeorge Karpenkov   size_t L = 0, R = Str.size() - 1;  // We are parsing the range [L,R].
8510ab2aceSGeorge Karpenkov   // Skip spaces from both sides.
8610ab2aceSGeorge Karpenkov   while (L < R && isspace(Str[L])) L++;
8710ab2aceSGeorge Karpenkov   while (R > L && isspace(Str[R])) R--;
8810ab2aceSGeorge Karpenkov   if (R - L < 2) return false;
8910ab2aceSGeorge Karpenkov   // Check the closing "
9010ab2aceSGeorge Karpenkov   if (Str[R] != '"') return false;
9110ab2aceSGeorge Karpenkov   R--;
9210ab2aceSGeorge Karpenkov   // Find the opening "
9310ab2aceSGeorge Karpenkov   while (L < R && Str[L] != '"') L++;
9410ab2aceSGeorge Karpenkov   if (L >= R) return false;
9510ab2aceSGeorge Karpenkov   assert(Str[L] == '\"');
9610ab2aceSGeorge Karpenkov   L++;
9710ab2aceSGeorge Karpenkov   assert(L <= R);
9810ab2aceSGeorge Karpenkov   for (size_t Pos = L; Pos <= R; Pos++) {
9910ab2aceSGeorge Karpenkov     uint8_t V = (uint8_t)Str[Pos];
10010ab2aceSGeorge Karpenkov     if (!isprint(V) && !isspace(V)) return false;
10110ab2aceSGeorge Karpenkov     if (V =='\\') {
10210ab2aceSGeorge Karpenkov       // Handle '\\'
10310ab2aceSGeorge Karpenkov       if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
10410ab2aceSGeorge Karpenkov         U->push_back(Str[Pos + 1]);
10510ab2aceSGeorge Karpenkov         Pos++;
10610ab2aceSGeorge Karpenkov         continue;
10710ab2aceSGeorge Karpenkov       }
10810ab2aceSGeorge Karpenkov       // Handle '\xAB'
10910ab2aceSGeorge Karpenkov       if (Pos + 3 <= R && Str[Pos + 1] == 'x'
11010ab2aceSGeorge Karpenkov            && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
11110ab2aceSGeorge Karpenkov         char Hex[] = "0xAA";
11210ab2aceSGeorge Karpenkov         Hex[2] = Str[Pos + 2];
11310ab2aceSGeorge Karpenkov         Hex[3] = Str[Pos + 3];
1146708186cSAaron Green         U->push_back(static_cast<uint8_t>(strtol(Hex, nullptr, 16)));
11510ab2aceSGeorge Karpenkov         Pos += 3;
11610ab2aceSGeorge Karpenkov         continue;
11710ab2aceSGeorge Karpenkov       }
11810ab2aceSGeorge Karpenkov       return false;  // Invalid escape.
11910ab2aceSGeorge Karpenkov     } else {
12010ab2aceSGeorge Karpenkov       // Any other character.
12110ab2aceSGeorge Karpenkov       U->push_back(V);
12210ab2aceSGeorge Karpenkov     }
12310ab2aceSGeorge Karpenkov   }
12410ab2aceSGeorge Karpenkov   return true;
12510ab2aceSGeorge Karpenkov }
12610ab2aceSGeorge Karpenkov 
ParseDictionaryFile(const std::string & Text,std::vector<Unit> * Units)1277c921753SKostya Serebryany bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
12810ab2aceSGeorge Karpenkov   if (Text.empty()) {
12910ab2aceSGeorge Karpenkov     Printf("ParseDictionaryFile: file does not exist or is empty\n");
13010ab2aceSGeorge Karpenkov     return false;
13110ab2aceSGeorge Karpenkov   }
13210ab2aceSGeorge Karpenkov   std::istringstream ISS(Text);
13310ab2aceSGeorge Karpenkov   Units->clear();
13410ab2aceSGeorge Karpenkov   Unit U;
13510ab2aceSGeorge Karpenkov   int LineNo = 0;
13610ab2aceSGeorge Karpenkov   std::string S;
13710ab2aceSGeorge Karpenkov   while (std::getline(ISS, S, '\n')) {
13810ab2aceSGeorge Karpenkov     LineNo++;
13910ab2aceSGeorge Karpenkov     size_t Pos = 0;
14010ab2aceSGeorge Karpenkov     while (Pos < S.size() && isspace(S[Pos])) Pos++;  // Skip spaces.
14110ab2aceSGeorge Karpenkov     if (Pos == S.size()) continue;  // Empty line.
14210ab2aceSGeorge Karpenkov     if (S[Pos] == '#') continue;  // Comment line.
14310ab2aceSGeorge Karpenkov     if (ParseOneDictionaryEntry(S, &U)) {
14410ab2aceSGeorge Karpenkov       Units->push_back(U);
14510ab2aceSGeorge Karpenkov     } else {
14610ab2aceSGeorge Karpenkov       Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
14710ab2aceSGeorge Karpenkov              S.c_str());
14810ab2aceSGeorge Karpenkov       return false;
14910ab2aceSGeorge Karpenkov     }
15010ab2aceSGeorge Karpenkov   }
15110ab2aceSGeorge Karpenkov   return true;
15210ab2aceSGeorge Karpenkov }
15310ab2aceSGeorge Karpenkov 
1541454c27bSserge-sans-paille // Code duplicated (and tested) in llvm/include/llvm/Support/Base64.h
Base64(const Unit & U)15510ab2aceSGeorge Karpenkov std::string Base64(const Unit &U) {
15610ab2aceSGeorge Karpenkov   static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15710ab2aceSGeorge Karpenkov                               "abcdefghijklmnopqrstuvwxyz"
15810ab2aceSGeorge Karpenkov                               "0123456789+/";
1591454c27bSserge-sans-paille   std::string Buffer;
1601454c27bSserge-sans-paille   Buffer.resize(((U.size() + 2) / 3) * 4);
1611454c27bSserge-sans-paille 
1621454c27bSserge-sans-paille   size_t i = 0, j = 0;
1631454c27bSserge-sans-paille   for (size_t n = U.size() / 3 * 3; i < n; i += 3, j += 4) {
164292ab49dSserge-sans-paille     uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8) |
165292ab49dSserge-sans-paille                  (unsigned char)U[i + 2];
1661454c27bSserge-sans-paille     Buffer[j + 0] = Table[(x >> 18) & 63];
1671454c27bSserge-sans-paille     Buffer[j + 1] = Table[(x >> 12) & 63];
1681454c27bSserge-sans-paille     Buffer[j + 2] = Table[(x >> 6) & 63];
1691454c27bSserge-sans-paille     Buffer[j + 3] = Table[x & 63];
17010ab2aceSGeorge Karpenkov   }
17110ab2aceSGeorge Karpenkov   if (i + 1 == U.size()) {
172292ab49dSserge-sans-paille     uint32_t x = ((unsigned char)U[i] << 16);
1731454c27bSserge-sans-paille     Buffer[j + 0] = Table[(x >> 18) & 63];
1741454c27bSserge-sans-paille     Buffer[j + 1] = Table[(x >> 12) & 63];
1751454c27bSserge-sans-paille     Buffer[j + 2] = '=';
1761454c27bSserge-sans-paille     Buffer[j + 3] = '=';
17710ab2aceSGeorge Karpenkov   } else if (i + 2 == U.size()) {
178292ab49dSserge-sans-paille     uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8);
1791454c27bSserge-sans-paille     Buffer[j + 0] = Table[(x >> 18) & 63];
1801454c27bSserge-sans-paille     Buffer[j + 1] = Table[(x >> 12) & 63];
1811454c27bSserge-sans-paille     Buffer[j + 2] = Table[(x >> 6) & 63];
1821454c27bSserge-sans-paille     Buffer[j + 3] = '=';
18310ab2aceSGeorge Karpenkov   }
1841454c27bSserge-sans-paille   return Buffer;
18510ab2aceSGeorge Karpenkov }
18610ab2aceSGeorge Karpenkov 
18714cf71a3SMatt Morehouse static std::mutex SymbolizeMutex;
18814cf71a3SMatt Morehouse 
DescribePC(const char * SymbolizedFMT,uintptr_t PC)18910ab2aceSGeorge Karpenkov std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
19014cf71a3SMatt Morehouse   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
19114cf71a3SMatt Morehouse   if (!EF->__sanitizer_symbolize_pc || !l.owns_lock())
19214cf71a3SMatt Morehouse     return "<can not symbolize>";
193065421f0SVitaly Buka   char PcDescr[1024] = {};
19410ab2aceSGeorge Karpenkov   EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
19510ab2aceSGeorge Karpenkov                                SymbolizedFMT, PcDescr, sizeof(PcDescr));
19610ab2aceSGeorge Karpenkov   PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
19710ab2aceSGeorge Karpenkov   return PcDescr;
19810ab2aceSGeorge Karpenkov }
19910ab2aceSGeorge Karpenkov 
PrintPC(const char * SymbolizedFMT,const char * FallbackFMT,uintptr_t PC)20010ab2aceSGeorge Karpenkov void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
20110ab2aceSGeorge Karpenkov   if (EF->__sanitizer_symbolize_pc)
20210ab2aceSGeorge Karpenkov     Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
20310ab2aceSGeorge Karpenkov   else
20410ab2aceSGeorge Karpenkov     Printf(FallbackFMT, PC);
20510ab2aceSGeorge Karpenkov }
20610ab2aceSGeorge Karpenkov 
PrintStackTrace()20714cf71a3SMatt Morehouse void PrintStackTrace() {
20814cf71a3SMatt Morehouse   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
20914cf71a3SMatt Morehouse   if (EF->__sanitizer_print_stack_trace && l.owns_lock())
21014cf71a3SMatt Morehouse     EF->__sanitizer_print_stack_trace();
21114cf71a3SMatt Morehouse }
21214cf71a3SMatt Morehouse 
PrintMemoryProfile()21314cf71a3SMatt Morehouse void PrintMemoryProfile() {
21414cf71a3SMatt Morehouse   std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
21514cf71a3SMatt Morehouse   if (EF->__sanitizer_print_memory_profile && l.owns_lock())
21614cf71a3SMatt Morehouse     EF->__sanitizer_print_memory_profile(95, 8);
21714cf71a3SMatt Morehouse }
21814cf71a3SMatt Morehouse 
NumberOfCpuCores()21910ab2aceSGeorge Karpenkov unsigned NumberOfCpuCores() {
22010ab2aceSGeorge Karpenkov   unsigned N = std::thread::hardware_concurrency();
22110ab2aceSGeorge Karpenkov   if (!N) {
22210ab2aceSGeorge Karpenkov     Printf("WARNING: std::thread::hardware_concurrency not well defined for "
22310ab2aceSGeorge Karpenkov            "your platform. Assuming CPU count of 1.\n");
22410ab2aceSGeorge Karpenkov     N = 1;
22510ab2aceSGeorge Karpenkov   }
22610ab2aceSGeorge Karpenkov   return N;
22710ab2aceSGeorge Karpenkov }
22810ab2aceSGeorge Karpenkov 
SimpleFastHash(const void * Data,size_t Size,uint64_t Initial)22908891816SAaron Green uint64_t SimpleFastHash(const void *Data, size_t Size, uint64_t Initial) {
23008891816SAaron Green   uint64_t Res = Initial;
23108891816SAaron Green   const uint8_t *Bytes = static_cast<const uint8_t *>(Data);
23210ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Size; i++)
23308891816SAaron Green     Res = Res * 11 + Bytes[i];
23410ab2aceSGeorge Karpenkov   return Res;
23510ab2aceSGeorge Karpenkov }
23610ab2aceSGeorge Karpenkov 
23710ab2aceSGeorge Karpenkov }  // namespace fuzzer
238