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