Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- IRDynamicChecks.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
#include "llvm/IR/Constants.h"
10
#include "llvm/IR/DataLayout.h"
11
#include "llvm/IR/Function.h"
12
#include "llvm/IR/Instructions.h"
13
#include "llvm/IR/Module.h"
14
#include "llvm/IR/Value.h"
15
#include "llvm/Support/raw_ostream.h"
16
17
#include "IRDynamicChecks.h"
18
19
#include "lldb/Expression/UtilityFunction.h"
20
#include "lldb/Target/ExecutionContext.h"
21
#include "lldb/Target/Process.h"
22
#include "lldb/Target/StackFrame.h"
23
#include "lldb/Target/Target.h"
24
#include "lldb/Utility/ConstString.h"
25
#include "lldb/Utility/LLDBLog.h"
26
#include "lldb/Utility/Log.h"
27
28
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
29
30
using namespace llvm;
31
using namespace lldb_private;
32
33
static char ID;
34
35
370
#define VALID_POINTER_CHECK_NAME "_$__lldb_valid_pointer_check"
36
370
#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
37
38
static const char g_valid_pointer_check_text[] =
39
    "extern \"C\" void\n"
40
    "_$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
41
    "{\n"
42
    "    unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"
43
    "}";
44
45
ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions()
46
370
    : DynamicCheckerFunctions(DCF_Clang) {}
47
48
370
ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default;
49
50
llvm::Error ClangDynamicCheckerFunctions::Install(
51
370
    DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
52
370
  Expected<std::unique_ptr<UtilityFunction>> utility_fn =
53
370
      exe_ctx.GetTargetRef().CreateUtilityFunction(
54
370
          g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME,
55
370
          lldb::eLanguageTypeC, exe_ctx);
56
370
  if (!utility_fn)
57
0
    return utility_fn.takeError();
58
370
  m_valid_pointer_check = std::move(*utility_fn);
59
60
370
  if (Process *process = exe_ctx.GetProcessPtr()) {
61
370
    ObjCLanguageRuntime *objc_language_runtime =
62
370
        ObjCLanguageRuntime::Get(*process);
63
64
370
    if (objc_language_runtime) {
65
370
      Expected<std::unique_ptr<UtilityFunction>> checker_fn =
66
370
          objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx);
67
370
      if (!checker_fn)
68
0
        return checker_fn.takeError();
69
370
      m_objc_object_check = std::move(*checker_fn);
70
370
    }
71
370
  }
72
73
370
  return Error::success();
74
370
}
75
76
bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr,
77
24
                                                         Stream &message) {
78
  // FIXME: We have to get the checkers to know why they scotched the call in
79
  // more detail,
80
  // so we can print a better message here.
81
24
  if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) {
82
0
    message.Printf("Attempted to dereference an invalid pointer.");
83
0
    return true;
84
24
  } else if (m_objc_object_check &&
85
24
             m_objc_object_check->ContainsAddress(addr)) {
86
1
    message.Printf("Attempted to dereference an invalid ObjC Object or send it "
87
1
                   "an unrecognized selector");
88
1
    return true;
89
1
  }
90
23
  return false;
91
24
}
92
93
0
static std::string PrintValue(llvm::Value *V, bool truncate = false) {
94
0
  std::string s;
95
0
  raw_string_ostream rso(s);
96
0
  V->print(rso);
97
0
  rso.flush();
98
0
  if (truncate)
99
0
    s.resize(s.length() - 1);
100
0
  return s;
101
0
}
102
103
/// \class Instrumenter IRDynamicChecks.cpp
104
/// Finds and instruments individual LLVM IR instructions
105
///
106
/// When instrumenting LLVM IR, it is frequently desirable to first search for
107
/// instructions, and then later modify them.  This way iterators remain
108
/// intact, and multiple passes can look at the same code base without
109
/// treading on each other's toes.
110
///
111
/// The Instrumenter class implements this functionality.  A client first
112
/// calls Inspect on a function, which populates a list of instructions to be
113
/// instrumented.  Then, later, when all passes' Inspect functions have been
114
/// called, the client calls Instrument, which adds the desired
115
/// instrumentation.
116
///
117
/// A subclass of Instrumenter must override InstrumentInstruction, which
118
/// is responsible for adding whatever instrumentation is necessary.
119
///
120
/// A subclass of Instrumenter may override:
121
///
122
/// - InspectInstruction [default: does nothing]
123
///
124
/// - InspectBasicBlock [default: iterates through the instructions in a
125
///   basic block calling InspectInstruction]
126
///
127
/// - InspectFunction [default: iterates through the basic blocks in a
128
///   function calling InspectBasicBlock]
129
class Instrumenter {
130
public:
131
  /// Constructor
132
  ///
133
  /// \param[in] module
134
  ///     The module being instrumented.
135
  Instrumenter(llvm::Module &module,
136
               std::shared_ptr<UtilityFunction> checker_function)
137
2.37k
      : m_module(module), m_checker_function(checker_function) {}
138
139
2.37k
  virtual ~Instrumenter() = default;
140
141
  /// Inspect a function to find instructions to instrument
142
  ///
143
  /// \param[in] function
144
  ///     The function to inspect.
145
  ///
146
  /// \return
147
  ///     True on success; false on error.
148
2.37k
  bool Inspect(llvm::Function &function) { return InspectFunction(function); }
149
150
  /// Instrument all the instructions found by Inspect()
151
  ///
152
  /// \return
153
  ///     True on success; false on error.
154
2.37k
  bool Instrument() {
155
2.37k
    for (InstIterator ii = m_to_instrument.begin(),
156
2.37k
                      last_ii = m_to_instrument.end();
157
8.29k
         ii != last_ii; 
++ii5.91k
) {
158
5.91k
      if (!InstrumentInstruction(*ii))
159
0
        return false;
160
5.91k
    }
161
162
2.37k
    return true;
163
2.37k
  }
164
165
protected:
166
  /// Add instrumentation to a single instruction
167
  ///
168
  /// \param[in] inst
169
  ///     The instruction to be instrumented.
170
  ///
171
  /// \return
172
  ///     True on success; false otherwise.
173
  virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
174
175
  /// Register a single instruction to be instrumented
176
  ///
177
  /// \param[in] inst
178
  ///     The instruction to be instrumented.
179
5.91k
  void RegisterInstruction(llvm::Instruction &inst) {
180
5.91k
    m_to_instrument.push_back(&inst);
181
5.91k
  }
182
183
  /// Determine whether a single instruction is interesting to instrument,
184
  /// and, if so, call RegisterInstruction
185
  ///
186
  /// \param[in] i
187
  ///     The instruction to be inspected.
188
  ///
189
  /// \return
190
  ///     False if there was an error scanning; true otherwise.
191
0
  virtual bool InspectInstruction(llvm::Instruction &i) { return true; }
192
193
  /// Scan a basic block to see if any instructions are interesting
194
  ///
195
  /// \param[in] bb
196
  ///     The basic block to be inspected.
197
  ///
198
  /// \return
199
  ///     False if there was an error scanning; true otherwise.
200
6.95k
  virtual bool InspectBasicBlock(llvm::BasicBlock &bb) {
201
6.95k
    for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
202
47.1k
         ii != last_ii; 
++ii40.1k
) {
203
40.1k
      if (!InspectInstruction(*ii))
204
0
        return false;
205
40.1k
    }
206
207
6.95k
    return true;
208
6.95k
  }
209
210
  /// Scan a function to see if any instructions are interesting
211
  ///
212
  /// \param[in] f
213
  ///     The function to be inspected.
214
  ///
215
  /// \return
216
  ///     False if there was an error scanning; true otherwise.
217
2.37k
  virtual bool InspectFunction(llvm::Function &f) {
218
2.37k
    for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
219
9.33k
         bbi != last_bbi; 
++bbi6.95k
) {
220
6.95k
      if (!InspectBasicBlock(*bbi))
221
0
        return false;
222
6.95k
    }
223
224
2.37k
    return true;
225
2.37k
  }
226
227
  /// Build a function pointer for a function with signature void
228
  /// (*)(uint8_t*) with a given address
229
  ///
230
  /// \param[in] start_address
231
  ///     The address of the function.
232
  ///
233
  /// \return
234
  ///     The function pointer, for use in a CallInst.
235
1.18k
  llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address) {
236
1.18k
    llvm::Type *param_array[1];
237
238
1.18k
    param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
239
240
1.18k
    ArrayRef<llvm::Type *> params(param_array, 1);
241
242
1.18k
    FunctionType *fun_ty = FunctionType::get(
243
1.18k
        llvm::Type::getVoidTy(m_module.getContext()), params, true);
244
1.18k
    PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
245
1.18k
    Constant *fun_addr_int =
246
1.18k
        ConstantInt::get(GetIntptrTy(), start_address, false);
247
1.18k
    return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
248
1.18k
  }
249
250
  /// Build a function pointer for a function with signature void
251
  /// (*)(uint8_t*, uint8_t*) with a given address
252
  ///
253
  /// \param[in] start_address
254
  ///     The address of the function.
255
  ///
256
  /// \return
257
  ///     The function pointer, for use in a CallInst.
258
159
  llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) {
259
159
    llvm::Type *param_array[2];
260
261
159
    param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
262
159
    param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy());
263
264
159
    ArrayRef<llvm::Type *> params(param_array, 2);
265
266
159
    FunctionType *fun_ty = FunctionType::get(
267
159
        llvm::Type::getVoidTy(m_module.getContext()), params, true);
268
159
    PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
269
159
    Constant *fun_addr_int =
270
159
        ConstantInt::get(GetIntptrTy(), start_address, false);
271
159
    return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
272
159
  }
273
274
1.50k
  PointerType *GetI8PtrTy() {
275
1.50k
    if (!m_i8ptr_ty)
276
1.34k
      m_i8ptr_ty = llvm::PointerType::getUnqual(m_module.getContext());
277
278
1.50k
    return m_i8ptr_ty;
279
1.50k
  }
280
281
1.34k
  IntegerType *GetIntptrTy() {
282
1.34k
    if (!m_intptr_ty) {
283
1.34k
      llvm::DataLayout data_layout(&m_module);
284
285
1.34k
      m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
286
1.34k
                                          data_layout.getPointerSizeInBits());
287
1.34k
    }
288
289
1.34k
    return m_intptr_ty;
290
1.34k
  }
291
292
  typedef std::vector<llvm::Instruction *> InstVector;
293
  typedef InstVector::iterator InstIterator;
294
295
  InstVector m_to_instrument; ///< List of instructions the inspector found
296
  llvm::Module &m_module;     ///< The module which is being instrumented
297
  std::shared_ptr<UtilityFunction>
298
      m_checker_function; ///< The dynamic checker function for the process
299
300
private:
301
  PointerType *m_i8ptr_ty = nullptr;
302
  IntegerType *m_intptr_ty = nullptr;
303
};
304
305
class ValidPointerChecker : public Instrumenter {
306
public:
307
  ValidPointerChecker(llvm::Module &module,
308
                      std::shared_ptr<UtilityFunction> checker_function)
309
1.18k
      : Instrumenter(module, checker_function),
310
1.18k
        m_valid_pointer_check_func(nullptr) {}
311
312
1.18k
  ~ValidPointerChecker() override = default;
313
314
protected:
315
5.74k
  bool InstrumentInstruction(llvm::Instruction *inst) override {
316
5.74k
    Log *log = GetLog(LLDBLog::Expressions);
317
318
5.74k
    LLDB_LOGF(log, "Instrumenting load/store instruction: %s\n",
319
5.74k
              PrintValue(inst).c_str());
320
321
5.74k
    if (!m_valid_pointer_check_func)
322
1.18k
      m_valid_pointer_check_func =
323
1.18k
          BuildPointerValidatorFunc(m_checker_function->StartAddress());
324
325
5.74k
    llvm::Value *dereferenced_ptr = nullptr;
326
327
5.74k
    if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst>(inst))
328
2.53k
      dereferenced_ptr = li->getPointerOperand();
329
3.21k
    else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst>(inst))
330
3.21k
      dereferenced_ptr = si->getPointerOperand();
331
0
    else
332
0
      return false;
333
334
    // Insert an instruction to call the helper with the result
335
5.74k
    CallInst::Create(m_valid_pointer_check_func, dereferenced_ptr, "", inst);
336
337
5.74k
    return true;
338
5.74k
  }
339
340
17.2k
  bool InspectInstruction(llvm::Instruction &i) override {
341
17.2k
    if (isa<llvm::LoadInst>(&i) || 
isa<llvm::StoreInst>(&i)14.6k
)
342
5.74k
      RegisterInstruction(i);
343
344
17.2k
    return true;
345
17.2k
  }
346
347
private:
348
  llvm::FunctionCallee m_valid_pointer_check_func;
349
};
350
351
class ObjcObjectChecker : public Instrumenter {
352
public:
353
  ObjcObjectChecker(llvm::Module &module,
354
                    std::shared_ptr<UtilityFunction> checker_function)
355
1.18k
      : Instrumenter(module, checker_function),
356
1.18k
        m_objc_object_check_func(nullptr) {}
357
358
1.18k
  ~ObjcObjectChecker() override = default;
359
360
  enum msgSend_type {
361
    eMsgSend = 0,
362
    eMsgSendSuper,
363
    eMsgSendSuper_stret,
364
    eMsgSend_fpret,
365
    eMsgSend_stret
366
  };
367
368
  std::map<llvm::Instruction *, msgSend_type> msgSend_types;
369
370
protected:
371
163
  bool InstrumentInstruction(llvm::Instruction *inst) override {
372
163
    CallInst *call_inst = dyn_cast<CallInst>(inst);
373
374
163
    if (!call_inst)
375
0
      return false; // call_inst really shouldn't be nullptr, because otherwise
376
                    // InspectInstruction wouldn't have registered it
377
378
163
    if (!m_objc_object_check_func)
379
159
      m_objc_object_check_func =
380
159
          BuildObjectCheckerFunc(m_checker_function->StartAddress());
381
382
    // id objc_msgSend(id theReceiver, SEL theSelector, ...)
383
384
163
    llvm::Value *target_object;
385
163
    llvm::Value *selector;
386
387
163
    switch (msgSend_types[inst]) {
388
162
    case eMsgSend:
389
162
    case eMsgSend_fpret:
390
      // On arm64, clang uses objc_msgSend for scalar and struct return
391
      // calls.  The call instruction will record which was used.
392
162
      if (call_inst->hasStructRetAttr()) {
393
0
        target_object = call_inst->getArgOperand(1);
394
0
        selector = call_inst->getArgOperand(2);
395
162
      } else {
396
162
        target_object = call_inst->getArgOperand(0);
397
162
        selector = call_inst->getArgOperand(1);
398
162
      }
399
162
      break;
400
1
    case eMsgSend_stret:
401
1
      target_object = call_inst->getArgOperand(1);
402
1
      selector = call_inst->getArgOperand(2);
403
1
      break;
404
0
    case eMsgSendSuper:
405
0
    case eMsgSendSuper_stret:
406
0
      return true;
407
163
    }
408
409
    // These objects should always be valid according to Sean Calannan
410
163
    assert(target_object);
411
163
    assert(selector);
412
413
    // Insert an instruction to call the helper with the result
414
415
163
    llvm::Value *arg_array[2];
416
417
163
    arg_array[0] = target_object;
418
163
    arg_array[1] = selector;
419
420
163
    ArrayRef<llvm::Value *> args(arg_array, 2);
421
422
163
    CallInst::Create(m_objc_object_check_func, args, "", inst);
423
424
163
    return true;
425
163
  }
426
427
7.29k
  static llvm::Function *GetFunction(llvm::Value *value) {
428
7.29k
    if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) {
429
1.24k
      return function;
430
1.24k
    }
431
432
6.05k
    if (llvm::ConstantExpr *const_expr =
433
6.05k
            llvm::dyn_cast<llvm::ConstantExpr>(value)) {
434
5.97k
      switch (const_expr->getOpcode()) {
435
5.97k
      default:
436
5.97k
        return nullptr;
437
0
      case llvm::Instruction::BitCast:
438
0
        return GetFunction(const_expr->getOperand(0));
439
5.97k
      }
440
5.97k
    }
441
442
87
    return nullptr;
443
6.05k
  }
444
445
7.29k
  static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {
446
7.29k
    return GetFunction(inst->getCalledOperand());
447
7.29k
  }
448
449
22.9k
  bool InspectInstruction(llvm::Instruction &i) override {
450
22.9k
    Log *log = GetLog(LLDBLog::Expressions);
451
452
22.9k
    CallInst *call_inst = dyn_cast<CallInst>(&i);
453
454
22.9k
    if (call_inst) {
455
7.29k
      const llvm::Function *called_function = GetCalledFunction(call_inst);
456
457
7.29k
      if (!called_function)
458
6.05k
        return true;
459
460
1.24k
      std::string name_str = called_function->getName().str();
461
1.24k
      const char *name_cstr = name_str.c_str();
462
463
1.24k
      LLDB_LOGF(log, "Found call to %s: %s\n", name_cstr,
464
1.24k
                PrintValue(call_inst).c_str());
465
466
1.24k
      if (name_str.find("objc_msgSend") == std::string::npos)
467
1.07k
        return true;
468
469
165
      if (!strcmp(name_cstr, "objc_msgSend")) {
470
162
        RegisterInstruction(i);
471
162
        msgSend_types[&i] = eMsgSend;
472
162
        return true;
473
162
      }
474
475
3
      if (!strcmp(name_cstr, "objc_msgSend_stret")) {
476
1
        RegisterInstruction(i);
477
1
        msgSend_types[&i] = eMsgSend_stret;
478
1
        return true;
479
1
      }
480
481
2
      if (!strcmp(name_cstr, "objc_msgSend_fpret")) {
482
0
        RegisterInstruction(i);
483
0
        msgSend_types[&i] = eMsgSend_fpret;
484
0
        return true;
485
0
      }
486
487
2
      if (!strcmp(name_cstr, "objc_msgSendSuper")) {
488
0
        RegisterInstruction(i);
489
0
        msgSend_types[&i] = eMsgSendSuper;
490
0
        return true;
491
0
      }
492
493
2
      if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) {
494
0
        RegisterInstruction(i);
495
0
        msgSend_types[&i] = eMsgSendSuper_stret;
496
0
        return true;
497
0
      }
498
499
2
      LLDB_LOGF(log,
500
2
                "Function name '%s' contains 'objc_msgSend' but is not handled",
501
2
                name_str.c_str());
502
503
2
      return true;
504
2
    }
505
506
15.6k
    return true;
507
22.9k
  }
508
509
private:
510
  llvm::FunctionCallee m_objc_object_check_func;
511
};
512
513
IRDynamicChecks::IRDynamicChecks(
514
    ClangDynamicCheckerFunctions &checker_functions, const char *func_name)
515
1.18k
    : ModulePass(ID), m_func_name(func_name),
516
1.18k
      m_checker_functions(checker_functions) {}
517
518
1.18k
IRDynamicChecks::~IRDynamicChecks() = default;
519
520
1.18k
bool IRDynamicChecks::runOnModule(llvm::Module &M) {
521
1.18k
  Log *log = GetLog(LLDBLog::Expressions);
522
523
1.18k
  llvm::Function *function = M.getFunction(StringRef(m_func_name));
524
525
1.18k
  if (!function) {
526
0
    LLDB_LOGF(log, "Couldn't find %s() in the module", m_func_name.c_str());
527
528
0
    return false;
529
0
  }
530
531
1.18k
  if (m_checker_functions.m_valid_pointer_check) {
532
1.18k
    ValidPointerChecker vpc(M, m_checker_functions.m_valid_pointer_check);
533
534
1.18k
    if (!vpc.Inspect(*function))
535
0
      return false;
536
537
1.18k
    if (!vpc.Instrument())
538
0
      return false;
539
1.18k
  }
540
541
1.18k
  if (m_checker_functions.m_objc_object_check) {
542
1.18k
    ObjcObjectChecker ooc(M, m_checker_functions.m_objc_object_check);
543
544
1.18k
    if (!ooc.Inspect(*function))
545
0
      return false;
546
547
1.18k
    if (!ooc.Instrument())
548
0
      return false;
549
1.18k
  }
550
551
1.18k
  if (log && 
log->GetVerbose()0
) {
552
0
    std::string s;
553
0
    raw_string_ostream oss(s);
554
555
0
    M.print(oss, nullptr);
556
557
0
    oss.flush();
558
559
0
    LLDB_LOGF(log, "Module after dynamic checks: \n%s", s.c_str());
560
0
  }
561
562
1.18k
  return true;
563
1.18k
}
564
565
0
void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}
566
567
0
PassManagerType IRDynamicChecks::getPotentialPassManagerType() const {
568
0
  return PMT_ModulePassManager;
569
0
}