xref: /openbsd-src/gnu/llvm/lldb/tools/lldb-fuzzer/lldb-expression-fuzzer/lldb-expression-fuzzer.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1*f6aab3d8Srobert //===-- lldb-expression-fuzzer.cpp ---------------------------------------===//
2*f6aab3d8Srobert //
3*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information.
5*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*f6aab3d8Srobert //
7*f6aab3d8Srobert //===---------------------------------------------------------------------===//
8*f6aab3d8Srobert //
9*f6aab3d8Srobert // \file
10*f6aab3d8Srobert // This file is a fuzzer for LLDB's expression evaluator. It uses protobufs
11*f6aab3d8Srobert // and the libprotobuf-mutator to create valid C-like inputs for the
12*f6aab3d8Srobert // expression evaluator.
13*f6aab3d8Srobert //
14*f6aab3d8Srobert //===---------------------------------------------------------------------===//
15*f6aab3d8Srobert 
16*f6aab3d8Srobert #include <string>
17*f6aab3d8Srobert 
18*f6aab3d8Srobert #include "cxx_proto.pb.h"
19*f6aab3d8Srobert #include "handle-cxx/handle_cxx.h"
20*f6aab3d8Srobert #include "lldb/API/SBBreakpoint.h"
21*f6aab3d8Srobert #include "lldb/API/SBDebugger.h"
22*f6aab3d8Srobert #include "lldb/API/SBError.h"
23*f6aab3d8Srobert #include "lldb/API/SBLaunchInfo.h"
24*f6aab3d8Srobert #include "lldb/API/SBProcess.h"
25*f6aab3d8Srobert #include "lldb/API/SBTarget.h"
26*f6aab3d8Srobert #include "proto-to-cxx/proto_to_cxx.h"
27*f6aab3d8Srobert #include "src/libfuzzer/libfuzzer_macro.h"
28*f6aab3d8Srobert #include "llvm/ADT/StringRef.h"
29*f6aab3d8Srobert #include "llvm/Support/Error.h"
30*f6aab3d8Srobert #include "llvm/Support/FileSystem.h"
31*f6aab3d8Srobert #include "llvm/Support/FormatVariadic.h"
32*f6aab3d8Srobert #include "llvm/Support/WithColor.h"
33*f6aab3d8Srobert 
34*f6aab3d8Srobert using namespace lldb;
35*f6aab3d8Srobert using namespace llvm;
36*f6aab3d8Srobert using namespace clang_fuzzer;
37*f6aab3d8Srobert 
38*f6aab3d8Srobert const char *target_path = nullptr;
39*f6aab3d8Srobert 
ReportError(llvm::StringRef message)40*f6aab3d8Srobert void ReportError(llvm::StringRef message) {
41*f6aab3d8Srobert   WithColor::error() << message << '\n';
42*f6aab3d8Srobert   exit(1);
43*f6aab3d8Srobert }
44*f6aab3d8Srobert 
LLVMFuzzerInitialize(int * argc,char *** argv)45*f6aab3d8Srobert extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
46*f6aab3d8Srobert #if !defined(_WIN32)
47*f6aab3d8Srobert   signal(SIGPIPE, SIG_IGN);
48*f6aab3d8Srobert #endif
49*f6aab3d8Srobert 
50*f6aab3d8Srobert   // `target_path` can be set by either the "--lldb_fuzzer_target" commandline
51*f6aab3d8Srobert   // flag or the "LLDB_FUZZER_TARGET" environment variable. Arbitrarily, we
52*f6aab3d8Srobert   // always do flag parsing and only check the environment variable if the
53*f6aab3d8Srobert   // commandline flag is not set.
54*f6aab3d8Srobert   for (int i = 1; i < *argc; ++i) {
55*f6aab3d8Srobert     auto this_arg = llvm::StringRef((*argv)[i]);
56*f6aab3d8Srobert     WithColor::note() << "argv[" << i << "] = " << this_arg << "\n";
57*f6aab3d8Srobert     if (this_arg.consume_front("--lldb_fuzzer_target="))
58*f6aab3d8Srobert       target_path = this_arg.data();
59*f6aab3d8Srobert   }
60*f6aab3d8Srobert 
61*f6aab3d8Srobert   if (!target_path)
62*f6aab3d8Srobert     target_path = ::getenv("LLDB_FUZZER_TARGET");
63*f6aab3d8Srobert 
64*f6aab3d8Srobert   if (!target_path)
65*f6aab3d8Srobert     ReportError("No target path specified. Set one either as an environment "
66*f6aab3d8Srobert                 "variable (i.e. LLDB_FUZZER_TARGET=target_path) or pass as a "
67*f6aab3d8Srobert                 "command line flag (i.e. --lldb_fuzzer_target=target_path).");
68*f6aab3d8Srobert 
69*f6aab3d8Srobert   if (!sys::fs::exists(target_path))
70*f6aab3d8Srobert     ReportError(formatv("target path '{0}' does not exist", target_path).str());
71*f6aab3d8Srobert 
72*f6aab3d8Srobert   SBDebugger::Initialize();
73*f6aab3d8Srobert 
74*f6aab3d8Srobert   return 0;
75*f6aab3d8Srobert }
76*f6aab3d8Srobert 
DEFINE_BINARY_PROTO_FUZZER(const clang_fuzzer::Function & input)77*f6aab3d8Srobert DEFINE_BINARY_PROTO_FUZZER(const clang_fuzzer::Function &input) {
78*f6aab3d8Srobert   std::string expression = clang_fuzzer::FunctionToString(input);
79*f6aab3d8Srobert 
80*f6aab3d8Srobert   // Create a debugger and a target
81*f6aab3d8Srobert   SBDebugger debugger = SBDebugger::Create(false);
82*f6aab3d8Srobert   if (!debugger.IsValid())
83*f6aab3d8Srobert     ReportError("Couldn't create debugger");
84*f6aab3d8Srobert 
85*f6aab3d8Srobert   SBTarget target = debugger.CreateTarget(target_path);
86*f6aab3d8Srobert   if (!target.IsValid())
87*f6aab3d8Srobert     ReportError(formatv("Couldn't create target '{0}'", target_path).str());
88*f6aab3d8Srobert 
89*f6aab3d8Srobert   // Create a breakpoint on the only line in the program
90*f6aab3d8Srobert   SBBreakpoint breakpoint = target.BreakpointCreateByName("main", target_path);
91*f6aab3d8Srobert   if (!breakpoint.IsValid())
92*f6aab3d8Srobert     ReportError("Couldn't create breakpoint");
93*f6aab3d8Srobert 
94*f6aab3d8Srobert   // Create launch info and error for launching the process
95*f6aab3d8Srobert   SBLaunchInfo launch_info = target.GetLaunchInfo();
96*f6aab3d8Srobert   SBError error;
97*f6aab3d8Srobert 
98*f6aab3d8Srobert   // Launch the process and evaluate the fuzzer's input data
99*f6aab3d8Srobert   // as an expression
100*f6aab3d8Srobert   SBProcess process = target.Launch(launch_info, error);
101*f6aab3d8Srobert   if (!process.IsValid() || error.Fail())
102*f6aab3d8Srobert     ReportError("Couldn't launch process");
103*f6aab3d8Srobert 
104*f6aab3d8Srobert   SBValue value = target.EvaluateExpression(expression.c_str());
105*f6aab3d8Srobert 
106*f6aab3d8Srobert   debugger.DeleteTarget(target);
107*f6aab3d8Srobert   SBDebugger::Destroy(debugger);
108*f6aab3d8Srobert   SBModule::GarbageCollectAllocatedModules();
109*f6aab3d8Srobert }
110