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