mib updated this revision to Diff 216747.
mib marked 16 inline comments as done.
mib added a comment.

Add doxygen documentation.

Move `ArgumentMetadata` struct inside `BreakpointInjectedSite`.

Change string format for logging.

Make `$__lldb_create_args_struct` generation architecture-independent.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66249/new/

https://reviews.llvm.org/D66249

Files:
  lldb/include/lldb/API/SBBreakpoint.h
  lldb/include/lldb/API/SBBreakpointLocation.h
  lldb/include/lldb/Breakpoint/Breakpoint.h
  lldb/include/lldb/Breakpoint/BreakpointInjectedSite.h
  lldb/include/lldb/Breakpoint/BreakpointLocation.h
  lldb/include/lldb/Breakpoint/BreakpointOptions.h
  lldb/include/lldb/Breakpoint/BreakpointSite.h
  lldb/include/lldb/Core/Disassembler.h
  lldb/include/lldb/Core/Opcode.h
  lldb/include/lldb/Expression/Expression.h
  lldb/include/lldb/Expression/ExpressionVariable.h
  lldb/include/lldb/Expression/LLVMUserExpression.h
  lldb/include/lldb/Symbol/VariableList.h
  lldb/include/lldb/Target/ABI.h
  lldb/include/lldb/Target/ExecutionContextScope.h
  lldb/include/lldb/Target/Process.h
  lldb/include/lldb/Target/Target.h
  lldb/include/lldb/lldb-enumerations.h
  lldb/include/lldb/lldb-forward.h
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/Makefile
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/TestFastConditionalBreakpoints.py
  
lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/main.c
  lldb/scripts/interface/SBBreakpoint.i
  lldb/scripts/interface/SBBreakpointLocation.i
  lldb/source/API/SBBreakpoint.cpp
  lldb/source/API/SBBreakpointLocation.cpp
  lldb/source/Breakpoint/Breakpoint.cpp
  lldb/source/Breakpoint/BreakpointInjectedSite.cpp
  lldb/source/Breakpoint/BreakpointLocation.cpp
  lldb/source/Breakpoint/BreakpointOptions.cpp
  lldb/source/Breakpoint/BreakpointSite.cpp
  lldb/source/Breakpoint/CMakeLists.txt
  lldb/source/Commands/CommandObjectBreakpoint.cpp
  lldb/source/Commands/Options.td
  lldb/source/Expression/LLVMUserExpression.cpp
  lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
  lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
  lldb/source/Symbol/ClangASTContext.cpp
  lldb/source/Target/Process.cpp

Index: lldb/source/Target/Process.cpp
===================================================================
--- lldb/source/Target/Process.cpp
+++ lldb/source/Target/Process.cpp
@@ -1612,9 +1612,22 @@
   return error;
 }
 
+lldb::break_id_t
+Process::FallbackToRegularBreakpointSite(const BreakpointLocationSP &owner,
+                                         bool use_hardware, Log *log,
+                                         const char *error) {
+  LLDB_LOG(log, error);
+  LLDB_LOG(log, "Disabling JIT-ed condition and falling back to regular "
+                "conditional breakpoint");
+  owner->SetInjectCondition(false);
+  return CreateBreakpointSite(owner, use_hardware);
+}
+
 lldb::break_id_t
 Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
                               bool use_hardware) {
+  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+
   addr_t load_addr = LLDB_INVALID_ADDRESS;
 
   bool show_error = true;
@@ -1675,11 +1688,72 @@
 
     if (bp_site_sp) {
       bp_site_sp->AddOwner(owner);
+
+      if (owner->GetInjectCondition()) {
+        BreakpointSite *bp_site = bp_site_sp.get();
+
+        BreakpointInjectedSite *bp_jitted_site_sp =
+            llvm::dyn_cast<BreakpointInjectedSite>(bp_site);
+        bp_jitted_site_sp->BuildConditionExpression();
+      }
+
       owner->SetBreakpointSite(bp_site_sp);
       return bp_site_sp->GetID();
     } else {
-      bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
-                                          load_addr, use_hardware));
+      if (owner->GetInjectCondition() && GetABI()->ImplementsJIT()) {
+        // Build user expression's IR from condition
+        BreakpointInjectedSite *bp_injected_site = new BreakpointInjectedSite(
+            &m_breakpoint_site_list, owner, load_addr);
+
+        std::string error;
+        // Setup a call before the copied instructions
+        if (!bp_injected_site->BuildConditionExpression()) {
+          error = "FCB: Couldn't build the condition expression";
+          return FallbackToRegularBreakpointSite(owner, use_hardware, log,
+                                                 error.c_str());
+        }
+
+        size_t instrs_size = SaveInstructions(owner->GetAddress());
+
+        if (!instrs_size) {
+          error = "FCB: Couldn't save instructions";
+
+          return FallbackToRegularBreakpointSite(owner, use_hardware, log,
+                                                 error.c_str());
+        }
+
+        const lldb::addr_t cond_expr_addr =
+            bp_injected_site->GetConditionExpressionAddress();
+        const lldb::addr_t util_func_addr =
+            bp_injected_site->GetUtilityFunctionAddress();
+
+        if (!GetABI()->SetupFastConditionalBreakpointTrampoline(
+                instrs_size, m_overriden_instructions, load_addr,
+                util_func_addr, cond_expr_addr)) {
+          error = "FCB: Couldn't setup trampoline";
+
+          return FallbackToRegularBreakpointSite(owner, use_hardware, log,
+                                                 error.c_str());
+        }
+
+        addr_t trap_addr = bp_injected_site->GetTrapAddress();
+
+        if (trap_addr == LLDB_INVALID_ADDRESS) {
+          error = "FCB: Couldn't get trap address";
+          return FallbackToRegularBreakpointSite(owner, use_hardware, log,
+                                                 error.c_str());
+        }
+
+        // bp_site_sp.reset(bp_jitted_site);
+        bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
+                                            trap_addr, use_hardware));
+
+        bp_site_sp->AddOwner(owner);
+      } else {
+
+        bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
+                                            load_addr, use_hardware));
+      }
       if (bp_site_sp) {
         Status error = EnableBreakpointSite(bp_site_sp.get());
         if (error.Success()) {
@@ -1702,6 +1776,84 @@
   return LLDB_INVALID_BREAK_ID;
 }
 
+size_t Process::SaveInstructions(Address &address) {
+  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+
+  TargetSP target_sp = m_target_wp.lock();
+  const char *plugin_name = nullptr;
+  const char *flavor = nullptr;
+  const bool prefer_file_cache = true;
+
+  Function *function = address.CalculateSymbolContextFunction();
+
+  if (!function) {
+    LLDB_LOG(log, "JIT: No function in the SymbolContext");
+    return 0;
+  }
+
+  lldb::addr_t addr = address.GetCallableLoadAddress(target_sp.get());
+
+  const AddressRange disasm_range(addr,
+                                  function->GetAddressRange().GetByteSize());
+
+  DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+      target_sp->GetArchitecture(), plugin_name, flavor, this, disasm_range,
+      prefer_file_cache);
+
+  if (!disassembler_sp) {
+    LLDB_LOG(log, "JIT: Couldn't disassemble '{}' function",
+             function->GetName());
+    return 0;
+  }
+
+  InstructionList *instructions = &disassembler_sp->GetInstructionList();
+
+  DataExtractor data;
+
+  size_t instructions_count = 0;
+  size_t instructions_size = 0;
+
+  for (size_t i = 0; i < instructions->GetSize(); i++) {
+    InstructionSP instruction = instructions->GetInstructionAtIndex(i);
+
+    instruction->GetData(data);
+    uint32_t size = instruction->Decode(*disassembler_sp.get(), data, 0);
+
+    if (instructions_size < GetABI()->GetJumpSize()) {
+      instructions_size += size;
+      instructions_count++;
+    }
+
+    const ExecutionContext exe_ctx(this);
+
+    LLDB_LOGV(log, "%#llx <+%llu>: %s, %s\t\t(%u)",
+              instruction->GetAddress().GetLoadAddress(target_sp.get()),
+              instruction->GetAddress().GetOffset(),
+              instruction->GetMnemonic(&exe_ctx),
+              instruction->GetOperands(&exe_ctx), size);
+  }
+
+  LLDB_LOGV(log, "JIT: Instruction count: {}", instructions_count);
+
+  Status error;
+  m_overriden_instructions = std::calloc(instructions_size, sizeof(uint8_t));
+
+  if (!m_overriden_instructions) {
+    LLDB_LOG(log, "JIT: Couldn't allocate instruction buffer");
+    return 0;
+  }
+
+  size_t memory_read =
+      ReadMemory(addr, m_overriden_instructions, instructions_size, error);
+
+  if (memory_read != instructions_size || error.Fail()) {
+    LLDB_LOG(log, "JIT: Couldn't copy instruction to buffer");
+    return 0;
+  }
+
+  return memory_read;
+}
+
 void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id,
                                             lldb::user_id_t owner_loc_id,
                                             BreakpointSiteSP &bp_site_sp) {
Index: lldb/source/Symbol/ClangASTContext.cpp
===================================================================
--- lldb/source/Symbol/ClangASTContext.cpp
+++ lldb/source/Symbol/ClangASTContext.cpp
@@ -250,7 +250,7 @@
   // We have an object already read from process memory,
   // so just extract VTable pointer from it
 
-  DataExtractor data;
+  lldb_private::DataExtractor data;
   Status err;
   auto size = valobj.GetData(data, err);
   if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size)
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -324,7 +324,7 @@
 
   bool ParsePythonTargetDefinition(const FileSpec &target_definition_fspec);
 
-  DataExtractor GetAuxvData() override;
+  lldb_private::DataExtractor GetAuxvData() override;
 
   StructuredData::ObjectSP GetExtendedInfoForThread(lldb::tid_t tid);
 
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4041,7 +4041,7 @@
   return error;
 }
 
-DataExtractor ProcessGDBRemote::GetAuxvData() {
+lldb_private::DataExtractor ProcessGDBRemote::GetAuxvData() {
   DataBufferSP buf;
   if (m_gdb_comm.GetQXferAuxvReadSupported()) {
     std::string response_string;
@@ -4051,7 +4051,7 @@
       buf = std::make_shared<DataBufferHeap>(response_string.c_str(),
                                              response_string.length());
   }
-  return DataExtractor(buf, GetByteOrder(), GetAddressByteSize());
+  return lldb_private::DataExtractor(buf, GetByteOrder(), GetAddressByteSize());
 }
 
 StructuredData::ObjectSP
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -549,6 +549,8 @@
   ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
 
   auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });
+  if (m_options.GetInjectCondition())
+    on_exit.release();
 
   if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
     diagnostic_manager.PutString(
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -76,7 +76,7 @@
 
   bool RewriteExpression(DiagnosticManager &diagnostic_manager) override;
 
-  /// Ready an already-parsed expression for execution, possibly evaluating it
+  /// Read an already-parsed expression for execution, possibly evaluating it
   /// statically.
   ///
   /// \param[out] func_addr
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -304,6 +304,8 @@
                                 CompilerDeclContext &namespace_decl,
                                 unsigned int current_id);
 
+  ExpressionVariableList &GetStructMembers(void) { return m_struct_members; }
+
 private:
   ExpressionVariableList
       m_found_entities; ///< All entities that were looked up for the parser.
Index: lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
===================================================================
--- lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -9,6 +9,53 @@
 #ifndef liblldb_ABISysV_x86_64_h_
 #define liblldb_ABISysV_x86_64_h_
 
+#define X64_JMP_OPCODE    (0xE9)
+#define X64_JMP_SIZE      (5)
+#define X64_CALL_OPCODE   (0xE8)
+#define X64_CALL_SIZE     (5)
+
+#define X64_PUSH_OPCODE   (0x50)
+#define X64_POP_OPCODE    (0x58)
+
+#define X64_MOV_OPCODE    (0x89)
+#define X64_MOV_SIZE      (3)
+
+#define X64_REXB_OPCODE   (0x41)
+#define X64_REXW_OPCODE   (0x48)
+
+#define X64_SAVED_REGS    (16)
+#define X64_VOLATILE_REGS (8)
+
+#define X64_REGS_CTX_STR  "typedef struct {\n" \
+                          "  intptr_t r15;\n"  \
+                          "  intptr_t r14;\n"  \
+                          "  intptr_t r13;\n"  \
+                          "  intptr_t r12;\n"  \
+                          "  intptr_t r11;\n"  \
+                          "  intptr_t r10;\n"  \
+                          "  intptr_t r9;\n"   \
+                          "  intptr_t r8;\n"   \
+                          "  intptr_t rdi;\n"  \
+                          "  intptr_t rsi;\n"  \
+                          "  intptr_t rbp;\n"  \
+                          "  intptr_t rsp;\n"  \
+                          "  intptr_t rbx;\n"  \
+                          "  intptr_t rdx;\n"  \
+                          "  intptr_t rcx;\n"  \
+                          "  intptr_t rax;\n"  \
+                          "} register_context;\n\n"
+
+#define X64_MACH_TYPES    "  typedef unsigned int       uint32_t;\n"           \
+                          "  typedef unsigned long long uint64_t ;\n"          \
+                          "  typedef unsigned long      uintptr_t;\n"          \
+                          "  typedef uint32_t           mach_port_t;\n"        \
+                          "  typedef mach_port_t        vm_map_t;\n"           \
+                          "  typedef int                kern_return_t;\n"      \
+                          "  typedef uintptr_t          vm_offset_t;\n"        \
+                          "  typedef uint64_t           mach_vm_address_t;\n"  \
+                          "  typedef vm_offset_t        vm_address_t;\n"       \
+                          "  typedef uint64_t           mach_vm_size_t;\n"
+
 #include "lldb/Target/ABI.h"
 #include "lldb/lldb-private.h"
 
@@ -72,6 +119,45 @@
 
   bool GetPointerReturnRegister(const char *&name) override;
 
+  /// Allocate a memory stub for the fast condition breakpoint trampoline, and
+  /// build it by saving the register context, calling the argument structure
+  /// builder, passing the resulting structure to the condition checker,
+  /// restoring the register context, running the copied instructions and]
+  /// jumping back to the user source code.
+  ///
+  /// \param[in] instrs_size
+  ///    The size in bytes of the copied instructions.
+  ///
+  /// \param[in] data
+  ///    The copied instructions buffer.
+  ///
+  /// \param[in] jmp_addr
+  ///    The address of the source .
+  ///
+  /// \param[in] util_func_addr
+  ///    The address of the JIT-ed argument structure builder.
+  ///
+  /// \param[in] cond_expr_addr
+  ///    The address of the JIT-ed condition checker.
+  ///
+  bool SetupFastConditionalBreakpointTrampoline(
+      size_t instrs_size, void *data, lldb::addr_t &jmp_addr,
+      lldb::addr_t util_func_addr, lldb::addr_t cond_expr_addr) override;
+
+  llvm::ArrayRef<uint8_t> GetJumpOpcode() override { return X64_JMP_OPCODE; }
+
+  size_t GetJumpSize() override { return X64_JMP_SIZE; }
+
+  llvm::ArrayRef<uint8_t> GetCallOpcode() override { return X64_JMP_OPCODE; }
+
+  size_t GetCallSize() override { return X64_JMP_SIZE; }
+
+  llvm::StringRef GetRegisterContextAsString() { return X64_REGS_CTX_STR; }
+
+  llvm::StringRef GetMachTypesAsString() { return X64_MACH_TYPES; }
+
+  bool ImplementsJIT() override { return true; }
+
   // Static Functions
 
   static void Initialize();
Index: lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
===================================================================
--- lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -18,6 +18,7 @@
 #include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Core/ValueObjectMemory.h"
 #include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Expression/IRMemoryMap.h"
 #include "lldb/Symbol/UnwindPlan.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
@@ -214,6 +215,148 @@
   return true;
 }
 
+bool ABISysV_x86_64::SetupFastConditionalBreakpointTrampoline(
+    size_t instrs_size, void *data, addr_t &jmp_addr, addr_t util_func_addr,
+    addr_t cond_expr_addr) {
+  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER));
+
+  ProcessSP process_sp = m_process_wp.lock();
+
+  // Copy saved instructions to the inferior memory buffer.
+  Status error;
+  uint8_t alignment = 8;
+  uint32_t permission =
+      ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable;
+  IRMemoryMap::AllocationPolicy policy = IRMemoryMap::eAllocationPolicyMirror;
+
+  IRMemoryMap memory_map(process_sp->GetTarget().shared_from_this());
+
+  size_t context_size = X64_SAVED_REGS + X64_VOLATILE_REGS;
+
+  size_t expected_trampoline_size = context_size; // Save registers
+  expected_trampoline_size += X64_MOV_SIZE;       // Pass register addr as arg
+  expected_trampoline_size += X64_CALL_SIZE;      // Create arg struct
+  expected_trampoline_size += X64_MOV_SIZE;       // Pass arg struct to jit expr
+  expected_trampoline_size += X64_CALL_SIZE;      // Call jit expr
+  expected_trampoline_size += context_size;       // Restore registers
+  expected_trampoline_size += instrs_size;        // Run copied instrs
+  expected_trampoline_size += X64_JMP_SIZE;       // Return to user code
+
+  addr_t trampoline_addr = memory_map.Malloc(
+      expected_trampoline_size, alignment, permission, policy, true, error);
+
+  if (trampoline_addr == LLDB_INVALID_ADDRESS) {
+    LLDB_LOG(log, "JIT: Couldn't allocate trampoline buffer");
+    return false;
+  }
+
+  size_t trampoline_size = 0;
+
+  uint8_t trampoline_buffer[expected_trampoline_size];
+
+  uint8_t regs_ctx[context_size];
+  // Save registers
+  for (size_t i = 0; i < 8; i++)
+    regs_ctx[i] = X64_PUSH_OPCODE + i;
+  for (size_t i = 0; i < 8; i++) {
+    size_t offset = X64_VOLATILE_REGS + 2 * i;
+    regs_ctx[offset] = X64_REXB_OPCODE;
+    regs_ctx[offset + 1] = X64_PUSH_OPCODE + i;
+  }
+  std::memcpy(trampoline_buffer, &regs_ctx, context_size);
+  trampoline_size += context_size;
+
+  // Pass the register address as an argument.
+  uint8_t mov_buffer[X64_MOV_SIZE];
+  mov_buffer[0] = X64_REXW_OPCODE;
+  mov_buffer[1] = X64_MOV_OPCODE;
+  // %rsp SIB Bytes
+  mov_buffer[2] = 0xE7;
+  std::memcpy(&trampoline_buffer[trampoline_size], &mov_buffer, X64_MOV_SIZE);
+  trampoline_size += X64_MOV_SIZE;
+
+  // Call to create_arg_struct.
+  uint8_t call_buffer[X64_CALL_SIZE];
+  uint32_t call_offset =
+      -X64_CALL_SIZE - trampoline_size - trampoline_addr + util_func_addr;
+  call_buffer[0] = X64_CALL_OPCODE;
+  std::memcpy(&call_buffer[1], &call_offset, sizeof(uint32_t));
+  std::memcpy(&trampoline_buffer[trampoline_size], call_buffer, X64_CALL_SIZE);
+  trampoline_size += X64_CALL_SIZE;
+
+  // Pass the argument structure to condition checker.
+  // %rdi SIB Bytes
+  mov_buffer[2] = 0xC7;
+  std::memcpy(&trampoline_buffer[trampoline_size], &mov_buffer, X64_MOV_SIZE);
+  trampoline_size += X64_MOV_SIZE;
+
+  // Copy condition checker call in trampoline buffer.
+  call_offset =
+      -X64_CALL_SIZE - trampoline_size - trampoline_addr + cond_expr_addr;
+  call_buffer[0] = X64_CALL_OPCODE;
+  std::memcpy(&call_buffer[1], &call_offset, sizeof(uint32_t));
+  std::memcpy(&trampoline_buffer[trampoline_size], call_buffer, X64_CALL_SIZE);
+  trampoline_size += X64_CALL_SIZE;
+
+  // Restore registers.
+  for (size_t i = 0; i < 8; i++) {
+    regs_ctx[2 * i] = X64_REXB_OPCODE;
+    regs_ctx[2 * i + 1] = X64_POP_OPCODE + X64_VOLATILE_REGS - i - 1;
+  }
+  for (size_t i = 0; i < 8; i++)
+    regs_ctx[X64_SAVED_REGS + i] = X64_POP_OPCODE + X64_VOLATILE_REGS - i - 1;
+  std::memcpy(&trampoline_buffer[trampoline_size], &regs_ctx, context_size);
+  trampoline_size += context_size;
+
+  // Copy saved instruction in trampoline buffer.
+  std::memcpy(&trampoline_buffer[trampoline_size], data, instrs_size);
+  trampoline_size += instrs_size;
+
+  // Copy jump back instruction in trampoline buffer.
+  uint8_t jmp_buffer[X64_JMP_SIZE];
+  uint32_t jmp_offset = jmp_addr - trampoline_addr - trampoline_size;
+
+  jmp_buffer[0] = X64_JMP_OPCODE;
+  std::memcpy(&jmp_buffer[1], &jmp_offset, sizeof(uint32_t));
+  std::memcpy(&trampoline_buffer[trampoline_size], jmp_buffer, X64_JMP_SIZE);
+  trampoline_size += X64_JMP_SIZE;
+
+  if (trampoline_size != expected_trampoline_size) {
+    LLDB_LOG(log, "JIT: Trampoline size ({}) is not the one expected ({})",
+             trampoline_size, expected_trampoline_size);
+    return false;
+  }
+
+  size_t written_bytes = process_sp->WriteMemory(
+      trampoline_addr, &trampoline_buffer, trampoline_size, error);
+
+  if (written_bytes != trampoline_size || error.Fail()) {
+    LLDB_LOG(log, "JIT: Couldn't write trampoline buffer to inferior");
+    return false;
+  }
+
+  // Overwrite current instruction with JMP.
+  jmp_offset = trampoline_addr - jmp_addr - X64_JMP_SIZE;
+
+  jmp_buffer[0] = X64_JMP_OPCODE;
+  std::memcpy(&jmp_buffer[1], &jmp_offset, sizeof(uint32_t));
+
+  for (size_t i = 0; i < X64_JMP_SIZE; i++)
+    LLDB_LOGV(log, "0x{:x}", jmp_buffer[i]);
+
+  written_bytes =
+      process_sp->WriteMemory(jmp_addr, jmp_buffer, X64_JMP_SIZE, error);
+
+  if (written_bytes != X64_JMP_SIZE || error.Fail()) {
+    LLDB_LOG(log, "JIT: Couldn't override instruction with branching");
+    return false;
+  }
+
+  jmp_addr = trampoline_addr;
+
+  return true;
+}
+
 size_t ABISysV_x86_64::GetRedZoneSize() const { return 128; }
 
 // Static Functions
Index: lldb/source/Expression/LLVMUserExpression.cpp
===================================================================
--- lldb/source/Expression/LLVMUserExpression.cpp
+++ lldb/source/Expression/LLVMUserExpression.cpp
@@ -77,7 +77,7 @@
     lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
 
     if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx,
-                                       struct_address)) {
+                                       struct_address, options)) {
       diagnostic_manager.Printf(
           eDiagnosticSeverityError,
           "errored out in %s, couldn't PrepareToExecuteJITExpression",
@@ -88,7 +88,7 @@
     lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
     lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
 
-    if (m_can_interpret) {
+    if (m_can_interpret && !options.GetInjectCondition()) {
       llvm::Module *module = m_execution_unit_sp->GetModule();
       llvm::Function *function = m_execution_unit_sp->GetFunction();
 
@@ -285,7 +285,7 @@
 
 bool LLVMUserExpression::PrepareToExecuteJITExpression(
     DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
-    lldb::addr_t &struct_address) {
+    lldb::addr_t &struct_address, const EvaluateExpressionOptions options) {
   lldb::TargetSP target;
   lldb::ProcessSP process;
   lldb::StackFrameSP frame;
@@ -302,8 +302,9 @@
       Status alloc_error;
 
       IRMemoryMap::AllocationPolicy policy =
-          m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly
-                          : IRMemoryMap::eAllocationPolicyMirror;
+          m_can_interpret && !options.GetInjectCondition()
+              ? IRMemoryMap::eAllocationPolicyHostOnly
+              : IRMemoryMap::eAllocationPolicyMirror;
 
       const bool zero_memory = false;
 
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -87,6 +87,9 @@
     Arg<"Command">,
     Desc<"A command to run when the breakpoint is hit, can be provided more "
     "than once, the commands will get run in order left to right.">;
+  def breakpoint_modify_inject_condition : Option<"inject-condition", "I">,
+      Desc<"The breakpoint injects the condition expression into the process "
+      "machine code. Enables Fast Conditional Breakpoints.">;
 }
 
 let Command = "breakpoint dummy" in {
Index: lldb/source/Commands/CommandObjectBreakpoint.cpp
===================================================================
--- lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -102,6 +102,13 @@
         m_bp_opts.SetIgnoreCount(ignore_count);
     }
     break;
+    case 'I': {
+      if (!m_bp_opts.IsOptionSet(BreakpointOptions::eCondition))
+        error.SetErrorString("inject-condition option only available for "
+                             "conditional breakpoints");
+      else
+        m_bp_opts.SetInjectCondition(true);
+    } break;
     case 'o': {
       bool value, success;
       value = OptionArgParser::ToBoolean(option_arg, false, &success);
Index: lldb/source/Breakpoint/CMakeLists.txt
===================================================================
--- lldb/source/Breakpoint/CMakeLists.txt
+++ lldb/source/Breakpoint/CMakeLists.txt
@@ -2,6 +2,7 @@
   Breakpoint.cpp
   BreakpointID.cpp
   BreakpointIDList.cpp
+  BreakpointInjectedSite.cpp
   BreakpointList.cpp
   BreakpointLocation.cpp
   BreakpointLocationCollection.cpp
Index: lldb/source/Breakpoint/BreakpointSite.cpp
===================================================================
--- lldb/source/Breakpoint/BreakpointSite.cpp
+++ lldb/source/Breakpoint/BreakpointSite.cpp
@@ -20,14 +20,15 @@
 
 BreakpointSite::BreakpointSite(BreakpointSiteList *list,
                                const BreakpointLocationSP &owner,
-                               lldb::addr_t addr, bool use_hardware)
+                               lldb::addr_t addr, bool use_hardware,
+                               BreakpointSiteKind kind)
     : StoppointLocation(GetNextID(), addr, 0, use_hardware),
       m_type(eSoftware), // Process subclasses need to set this correctly using
                          // SetType()
       m_saved_opcode(), m_trap_opcode(),
       m_enabled(false), // Need to create it disabled, so the first enable turns
                         // it on.
-      m_owners(), m_owners_mutex() {
+      m_owners(), m_owners_mutex(), m_kind(kind) {
   m_owners.Add(owner);
 }
 
Index: lldb/source/Breakpoint/BreakpointOptions.cpp
===================================================================
--- lldb/source/Breakpoint/BreakpointOptions.cpp
+++ lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -109,8 +109,8 @@
 
 const char *BreakpointOptions::g_option_names[(
     size_t)BreakpointOptions::OptionNames::LastOptionName]{
-    "ConditionText", "IgnoreCount", 
-    "EnabledState", "OneShotState", "AutoContinue"};
+    "ConditionText", "IgnoreCount",  "EnabledState",
+    "OneShotState",  "AutoContinue", "JITCondition"};
 
 bool BreakpointOptions::NullCallback(void *baton,
                                      StoppointCallbackContext *context,
@@ -124,25 +124,23 @@
     : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(),
       m_baton_is_command_baton(false), m_callback_is_synchronous(false),
       m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_up(),
-      m_condition_text(), m_condition_text_hash(0), m_auto_continue(false),
-      m_set_flags(0) {
+      m_condition_text(), m_condition_text_hash(0), m_inject_condition(false),
+      m_auto_continue(false), m_set_flags(0) {
   if (all_flags_set)
     m_set_flags.Set(~((Flags::ValueType)0));
 }
 
 BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
-                                     int32_t ignore, bool one_shot, 
-                                     bool auto_continue)
+                                     int32_t ignore, bool one_shot,
+                                     bool auto_continue, bool inject_condition)
     : m_callback(nullptr), m_baton_is_command_baton(false),
       m_callback_is_synchronous(false), m_enabled(enabled),
-      m_one_shot(one_shot), m_ignore_count(ignore),
-      m_condition_text_hash(0), m_auto_continue(auto_continue)
-{
-    m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot 
-                   | eAutoContinue);
-    if (condition && *condition != '\0') {
-      SetCondition(condition);
-    }
+      m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text_hash(0),
+      m_inject_condition(inject_condition), m_auto_continue(auto_continue) {
+  m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eAutoContinue);
+  if (condition && *condition != '\0') {
+    SetCondition(condition);
+  }
 }
 
 // BreakpointOptions copy constructor
@@ -152,6 +150,7 @@
       m_callback_is_synchronous(rhs.m_callback_is_synchronous),
       m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
       m_ignore_count(rhs.m_ignore_count), m_thread_spec_up(),
+      m_inject_condition(rhs.m_inject_condition),
       m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
   if (rhs.m_thread_spec_up != nullptr)
     m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up));
@@ -175,6 +174,7 @@
   m_condition_text_hash = rhs.m_condition_text_hash;
   m_auto_continue = rhs.m_auto_continue;
   m_set_flags = rhs.m_set_flags;
+  m_inject_condition = rhs.m_inject_condition;
   return *this;
 }
 
@@ -210,12 +210,18 @@
       m_condition_text.clear();
       m_condition_text_hash = 0;
       m_set_flags.Clear(eCondition);
+      m_inject_condition = false;
     } else {
       m_condition_text = incoming.m_condition_text;
       m_condition_text_hash = incoming.m_condition_text_hash;
       m_set_flags.Set(eCondition);
+      m_inject_condition = incoming.m_inject_condition;
     }
   }
+  if (incoming.m_set_flags.Test(eInjectCondition)) {
+    m_inject_condition = incoming.m_inject_condition;
+    m_set_flags.Set(eInjectCondition);
+  }
   if (incoming.m_set_flags.Test(eAutoContinue))
   {
     m_auto_continue = incoming.m_auto_continue;
@@ -374,10 +380,14 @@
   if (m_set_flags.Test(eIgnoreCount))
     options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
                                     m_ignore_count);
-  if (m_set_flags.Test(eCondition))
+  if (m_set_flags.Test(eCondition)) {
     options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
                                    m_condition_text);
-         
+    if (m_set_flags.Test(eInjectCondition))
+      options_dict_sp->AddBooleanItem(GetKey(OptionNames::InjectCondition),
+                                      m_inject_condition);
+  }
+
   if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
     auto cmd_baton =
         std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
@@ -464,6 +474,10 @@
   return m_callback != BreakpointOptions::NullCallback;
 }
 
+bool BreakpointOptions::GetInjectCondition() const {
+  return m_inject_condition;
+}
+
 bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
   if (!HasCallback())
     return false;
@@ -482,6 +496,7 @@
   if (!condition || condition[0] == '\0') {
     condition = "";
     m_set_flags.Clear(eCondition);
+    m_set_flags.Clear(eInjectCondition);
   }
   else
     m_set_flags.Set(eCondition);
@@ -571,8 +586,9 @@
   }
   if (!m_condition_text.empty()) {
     if (level != eDescriptionLevelBrief) {
+      std::string fast = (m_inject_condition) ? " (FAST)" : "";
       s->EOL();
-      s->Printf("Condition: %s\n", m_condition_text.c_str());
+      s->Printf("Condition: %s%s\n", m_condition_text.c_str(), fast.c_str());
     }
   }
 }
@@ -671,4 +687,5 @@
   m_callback_is_synchronous = false;
   m_enabled = false;
   m_condition_text.clear();
+  m_inject_condition = false;
 }
Index: lldb/source/Breakpoint/BreakpointLocation.cpp
===================================================================
--- lldb/source/Breakpoint/BreakpointLocation.cpp
+++ lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -226,6 +226,19 @@
       ->GetConditionText(hash);
 }
 
+bool BreakpointLocation::GetInjectCondition() const {
+  if (m_options_up &&
+      m_options_up->IsOptionSet(BreakpointOptions::eInjectCondition))
+    return m_options_up->GetInjectCondition();
+  return m_owner.GetInjectCondition();
+}
+
+void BreakpointLocation::SetInjectCondition(bool inject_condition) {
+  m_owner.SetInjectCondition(inject_condition);
+  GetLocationOptions()->SetInjectCondition(inject_condition);
+  SendBreakpointLocationChangedEvent(eBreakpointEventTypeInjectedCondition);
+}
+
 bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
                                            Status &error) {
   Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
@@ -240,6 +253,14 @@
     return false;
   }
 
+  bool inject_condition = GetInjectCondition();
+
+  if (inject_condition) {
+    // TODO: Evalutates condition is case of multi-condition
+    // BreakpointInjectSite
+    return true;
+  }
+
   error.Clear();
 
   DiagnosticManager diagnostics;
@@ -263,9 +284,12 @@
       return true;
     }
 
-    if (!m_user_expression_sp->Parse(diagnostics, exe_ctx,
-                                     eExecutionPolicyOnlyWhenNeeded, true,
-                                     false)) {
+    ExecutionPolicy execution_policy = inject_condition
+                                           ? eExecutionPolicyAlways
+                                           : eExecutionPolicyOnlyWhenNeeded;
+
+    if (!m_user_expression_sp->Parse(diagnostics, exe_ctx, execution_policy,
+                                     true, false)) {
       error.SetErrorStringWithFormat(
           "Couldn't parse conditional expression:\n%s",
           diagnostics.GetString().c_str());
@@ -287,6 +311,7 @@
   options.SetTryAllThreads(true);
   options.SetResultIsInternal(
       true); // Don't generate a user variable for condition expressions.
+  options.SetInjectCondition(inject_condition);
 
   Status expr_error;
 
Index: lldb/source/Breakpoint/BreakpointInjectedSite.cpp
===================================================================
--- /dev/null
+++ lldb/source/Breakpoint/BreakpointInjectedSite.cpp
@@ -0,0 +1,449 @@
+//===-- BreakpointInjectedSite.cpp ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointInjectedSite.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
+#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Target/Language.h"
+
+#include "lldb/Target/ABI.h"
+
+#include "llvm/Support/DataExtractor.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointInjectedSite::BreakpointInjectedSite(
+    BreakpointSiteList *list, const BreakpointLocationSP &owner,
+    lldb::addr_t addr)
+    : BreakpointSite(list, owner, addr, false, eKindBreakpointInjectedSite),
+      m_target_sp(owner->GetTarget().shared_from_this()),
+      m_real_addr(owner->GetAddress()), m_trap_addr(LLDB_INVALID_ADDRESS) {}
+
+BreakpointInjectedSite::~BreakpointInjectedSite() {}
+
+bool BreakpointInjectedSite::BuildConditionExpression(void) {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_JIT_LOADER);
+
+  Status error;
+
+  std::string trap;
+  std::string condition_text;
+  bool single_condition = true;
+
+  LanguageType language = eLanguageTypeUnknown;
+
+  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+
+    // Stop building the expression if a location condition is not JIT-ed
+    if (!loc_sp->GetInjectCondition()) {
+      LLDB_LOG(log, "FCB: BreakpointLocation ({}) condition is not JIT-ed",
+               loc_sp->GetConditionText());
+      return false;
+    }
+
+    std::string condition = loc_sp->GetConditionText();
+    // See if we can figure out the language from the frame, otherwise use the
+    // default language:
+    CompileUnit *comp_unit =
+        loc_sp->GetAddress().CalculateSymbolContextCompileUnit();
+    if (comp_unit)
+      language = comp_unit->GetLanguage();
+
+    if (language == eLanguageTypeSwift) {
+      trap += "Builtin.int_trap()";
+    } else if (Language::LanguageIsCFamily(language)) {
+      trap = "__builtin_debugtrap()";
+    } else {
+      LLDB_LOG(log, "FCB: Language {} not supported",
+               Language::GetNameForLanguageType(language));
+      m_condition_expression_sp.reset();
+      return false;
+    }
+
+    condition_text += "static int hit_count = 0;\n\thit_count++;\n\t";
+    condition_text += (single_condition) ? "if (" : " || ";
+    condition_text += condition;
+
+    single_condition = false;
+  }
+
+  condition_text += ") {\n\t";
+
+  condition_text += trap + ";\n}";
+
+  LLDB_LOGV(log, "Injected Condition:\n{}\n", condition_text.c_str());
+
+  DiagnosticManager diagnostics;
+
+  EvaluateExpressionOptions options;
+  options.SetInjectCondition(true);
+  options.SetKeepInMemory(true);
+  options.SetGenerateDebugInfo(true);
+
+  m_condition_expression_sp.reset(m_target_sp->GetUserExpressionForLanguage(
+      condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
+      EvaluateExpressionOptions(options), nullptr, error));
+
+  if (error.Fail()) {
+    if (log)
+      log->Printf("Error getting condition expression: %s.", error.AsCString());
+    m_condition_expression_sp.reset();
+    return false;
+  }
+
+  diagnostics.Clear();
+
+  ThreadSP thread_sp = m_target_sp->GetProcessSP()
+                           ->GetThreadList()
+                           .GetExpressionExecutionThread();
+
+  user_id_t frame_idx = -1;
+  user_id_t concrete_frame_idx = -1;
+  addr_t cfa = LLDB_INVALID_ADDRESS;
+  bool cfa_is_valid = false;
+  addr_t pc = LLDB_INVALID_ADDRESS;
+  StackFrame::Kind frame_kind = StackFrame::Kind::Regular;
+  bool zeroth_frame = false;
+  SymbolContext sc;
+  m_real_addr.CalculateSymbolContext(&sc);
+
+  StackFrameSP frame_sp =
+      make_shared<StackFrame>(thread_sp, frame_idx, concrete_frame_idx, cfa,
+                              cfa_is_valid, pc, frame_kind, zeroth_frame, &sc);
+
+  m_owner_exe_ctx = ExecutionContext(frame_sp);
+  ExecutionPolicy execution_policy = eExecutionPolicyAlways;
+  bool keep_result_in_memory = true;
+  bool generate_debug_info = true;
+
+  if (!m_condition_expression_sp->Parse(diagnostics, m_owner_exe_ctx,
+                                        execution_policy, keep_result_in_memory,
+                                        generate_debug_info)) {
+    LLDB_LOG(log, "Couldn't parse conditional expression:\n{}",
+             diagnostics.GetString().c_str());
+    m_condition_expression_sp.reset();
+    return false;
+  }
+
+  const AddressRange &jit_addr_range =
+      m_condition_expression_sp->GetJITAddressRange();
+
+  error.Clear();
+
+  void *buffer = std::calloc(jit_addr_range.GetByteSize(), sizeof(uint8_t));
+
+  lldb::addr_t jit_addr =
+      jit_addr_range.GetBaseAddress().GetCallableLoadAddress(m_target_sp.get());
+
+  size_t memory_read = m_target_sp->GetProcessSP()->ReadMemory(
+      jit_addr, buffer, jit_addr_range.GetByteSize(), error);
+
+  if (memory_read != jit_addr_range.GetByteSize() || error.Fail()) {
+    m_condition_expression_sp.reset();
+    error.SetErrorString("Couldn't read jit memory");
+    return false;
+  }
+
+  PlatformSP platform_sp = m_target_sp->GetPlatform();
+
+  if (!platform_sp) {
+    error.SetErrorString("Couldn't get running platform");
+    return false;
+  }
+
+  if (!platform_sp->GetSoftwareBreakpointTrapOpcode(*m_target_sp.get(), this)) {
+    error.SetErrorString("Couldn't get current architecture trap opcode");
+    return false;
+  }
+
+  if (!ResolveTrapAddress(buffer, memory_read)) {
+    error.SetErrorString("Couldn't find trap in jitter expression");
+    return false;
+  }
+
+  if (!GatherArgumentsMetadata()) {
+    LLDB_LOG(log, "FCB: Couldn't gather argument metadata");
+    return false;
+  }
+
+  if (!CreateArgumentsStructure()) {
+    LLDB_LOG(log, "FCB: Couldn't create argument structure");
+    return false;
+  }
+
+  return true;
+}
+
+bool BreakpointInjectedSite::ResolveTrapAddress(void *jit, size_t size) {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_JIT_LOADER);
+
+  const ArchSpec &arch = m_target_sp->GetArchitecture();
+  const char *plugin_name = nullptr;
+  const char *flavor = nullptr;
+  const ExecutionContext exe_ctx(m_target_sp, true);
+  const bool prefer_file_cache = true;
+
+  m_disassembler_sp = Disassembler::DisassembleRange(
+      arch, plugin_name, flavor, exe_ctx,
+      m_condition_expression_sp->GetJITAddressRange(), prefer_file_cache);
+
+  if (!m_disassembler_sp) {
+    LLDB_LOG(log, "FCB: Couldn't disassemble JIT-ed expression");
+    return false;
+  }
+
+  InstructionList &instructions = m_disassembler_sp->GetInstructionList();
+
+  if (!instructions.GetSize()) {
+    LLDB_LOG(log, "FCB: No instructions found for JIT-ed expression");
+    return false;
+  }
+
+  for (size_t i = 0; i < instructions.GetSize(); i++) {
+    InstructionSP instr = instructions.GetInstructionAtIndex(i);
+    const void *instr_opcode = instr->GetOpcode().GetOpcodeDataBytes();
+
+    DataExtractor data;
+    instr->GetData(data);
+
+    const size_t trap_size = instr->Decode(*m_disassembler_sp.get(), data, 0);
+
+    if (!instr_opcode) {
+      return false;
+    }
+
+    if (!memcmp(instr_opcode, m_trap_opcode, trap_size)) {
+      addr_t addr = instr->GetAddress().GetOpcodeLoadAddress(m_target_sp.get());
+      m_trap_addr = addr;
+      LLDB_LOGV(log, "Injected trap address: {0:X+}", addr);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool BreakpointInjectedSite::GatherArgumentsMetadata() {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_JIT_LOADER);
+
+  LanguageType native_language = m_condition_expression_sp->Language();
+
+  if (!Language::LanguageIsCFamily(native_language)) {
+    LLDB_LOG(log, "FCB: {} language does not support Injected Conditional \
+             Breapoint",
+             Language::GetNameForLanguageType(native_language));
+    return false;
+  }
+
+  ClangUserExpression *clang_expr =
+      llvm::dyn_cast<ClangUserExpression>(m_condition_expression_sp.get());
+
+  ClangExpressionDeclMap *decl_map = clang_expr->DeclMap();
+  if (!decl_map) {
+    LLDB_LOG(log, "FCB: Couldn't find DeclMap for JIT-ed expression");
+    return false;
+  }
+
+  uint32_t num_elements;
+  size_t size;
+  offset_t alignment;
+
+  if (!decl_map->GetStructInfo(num_elements, size, alignment)) {
+    LLDB_LOG(log, "FCB: Couldn't fetch arguments info from DeclMap");
+    return false;
+  }
+
+  for (uint32_t i = 0; i < num_elements; ++i) {
+    const clang::NamedDecl *decl = nullptr;
+    llvm::Value *value = nullptr;
+    lldb::offset_t offset;
+    lldb_private::ConstString name;
+
+    if (!decl_map->GetStructElement(decl, value, offset, name, i)) {
+      LLDB_LOG(log, "FCB: Couldn't fetch element from DeclMap");
+      return false;
+    }
+    if (!value) {
+      LLDB_LOG(log, "FCB: Couldn't find value for element {}/{}", i,
+               num_elements);
+      return false;
+    }
+  }
+
+  ExpressionVariableList &members = decl_map->GetStructMembers();
+
+  for (ExpressionVariableSP expr_var : members.Variables()) {
+    ValueObjectSP val_obj_sp = expr_var->GetValueObject();
+
+    if (!val_obj_sp->GetVariable()) {
+      // if Expression Variable does not have ValueObject, skip it
+      continue;
+    }
+
+    VariableSP var_sp = val_obj_sp->GetVariable();
+
+    DWARFExpression lldb_dwarf_expr = var_sp->LocationExpression();
+    DataExtractor lldb_data;
+    if (!lldb_dwarf_expr.GetExpressionData(lldb_data)) {
+      return false;
+    }
+
+    llvm::StringRef data(lldb_data.PeekCStr(0));
+    bool is_le = (lldb_data.GetByteOrder() == lldb::eByteOrderLittle);
+    uint32_t data_addr_size = lldb_data.GetAddressByteSize();
+    llvm::DataExtractor llvm_data =
+        llvm::DataExtractor(data, is_le, data_addr_size);
+
+    llvm::DWARFExpression::Operation::DwarfVersion version =
+        llvm::DWARFExpression::Operation::Dwarf5;
+    uint8_t addr_size = m_target_sp->GetArchitecture().GetAddressByteSize();
+
+    auto size = var_sp->GetType()->GetByteSize();
+    if (!size) {
+      LLDB_LOG(log, "FCB: Variable {} has invalid size",
+               var_sp->GetName().GetCString());
+      return false;
+    }
+
+    VariableMetadata metadata(expr_var->GetName().GetStringRef(),
+                              size.getValue(), llvm_data, version, addr_size);
+
+    m_metadatas.push_back(metadata);
+  }
+
+  clang_expr->ResetDeclMap();
+
+  return true;
+}
+
+bool BreakpointInjectedSite::CreateArgumentsStructure() {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_JIT_LOADER);
+
+  Status error;
+  std::string expr;
+  expr.reserve(2048);
+  std::string name = "$__lldb_create_args_struct";
+
+  ABISP abi_sp = m_owner_exe_ctx.GetProcessSP()->GetABI();
+
+  expr += "extern unsigned int        mach_task_self_;\n";
+
+  expr += "extern \"C\"\n"
+          "{\n"
+          "   /*\n"
+          "   * mach defines\n"
+          "   */\n"
+          "\n";
+
+  expr += abi_sp->GetMachTypesAsString();
+
+  expr += "\n"
+          "   void* memcpy (void *dest, const void *src, size_t count);\n"
+          "   kern_return_t mach_vm_allocate (vm_map_t target, "
+          "mach_vm_address_t *address, mach_vm_size_t size, int flags);\n"
+          "   kern_return_t mach_vm_deallocate (vm_map_t target, "
+          "mach_vm_address_t address, mach_vm_size_t size);\n"
+          "}\n\n";
+
+  expr += "#define KERN_SUCCESS               0\n"
+          "#define KERN_INVALID_ADDRESS       1\n\n";
+
+  // Get structure size
+  std::size_t size = m_metadatas.size() * 8;
+  expr += "static mach_vm_size_t size = " + std::to_string(size) + ";\n\n";
+
+  expr += abi_sp->GetRegisterContextAsString();
+
+  expr +=
+      "mach_vm_address_t $__lldb_create_args_struct(register_context* regs) {\n"
+      "   mach_vm_address_t address = (vm_address_t) NULL;\n"
+      "   int flags = 1;\n"
+      "   \n"
+      "   kern_return_t kr = mach_vm_allocate(mach_task_self_, &address, "
+      "size, flags);\n"
+      "   if (kr != KERN_SUCCESS) {\n"
+      "     return KERN_INVALID_ADDRESS;\n"
+      "   }\n\n"
+      "   void *src_addr = NULL;\n"
+      "   void *dst_addr = NULL;\n"
+      "   size_t count = sizeof(void*);\n\n"
+      "\n";
+
+  for (size_t index = 0; index < m_metadatas.size(); index++) {
+    expr += ParseDWARFExpression(index, error);
+    if (error.Fail()) {
+      LLDB_LOG(log, "FCB: Couldn't parse DWARFExpression ({}/{})", index,
+               m_metadatas.size());
+      return false;
+    }
+  }
+
+  expr += "   return address;\n"
+          "}\n";
+
+  m_create_args_struct_function_sp.reset(
+      m_target_sp->GetUtilityFunctionForLanguage(expr.c_str(), eLanguageTypeC,
+                                                 name.c_str(), error));
+
+  if (error.Fail()) {
+    LLDB_LOG(log, "Error getting utility function: {1}.", error);
+    m_create_args_struct_function_sp.reset();
+    return false;
+  }
+
+  DiagnosticManager diagnostics;
+  ExecutionContext exe_ctx(m_target_sp->GetProcessSP());
+
+  if (!m_create_args_struct_function_sp->Install(diagnostics, exe_ctx)) {
+    error.SetErrorStringWithFormat("Couldn't install utility function:\n%s",
+                                   diagnostics.GetString().c_str());
+    m_create_args_struct_function_sp.reset();
+    return false;
+  }
+
+  return true;
+}
+
+std::string BreakpointInjectedSite::ParseDWARFExpression(size_t index,
+                                                         Status &error) {
+  std::string expr;
+
+  for (auto op : m_metadatas[index].dwarf) {
+    switch (op.getCode()) {
+    case DW_OP_addr: {
+      int64_t operand = op.getRawOperand(0);
+      expr += "   src_addr = " + std::to_string(operand) +
+              ";\n"
+              "   dst_addr = (void*) (address + " +
+              std::to_string(index * 8) +
+              ");\n"
+              "   memcpy(dst_addr, &src_addr, count);\n";
+      break;
+    }
+    case DW_OP_fbreg: {
+      int64_t operand = op.getRawOperand(0);
+      expr += "   src_addr = (void*) (regs->rbp + " + std::to_string(operand) +
+              ");\n"
+              "   dst_addr = (void*) (address + " +
+              std::to_string(index * 8) +
+              ");\n"
+              "   memcpy(dst_addr, &src_addr, count);\n";
+      break;
+    }
+    default: {
+      error.Clear();
+      error.SetErrorToErrno();
+      break;
+    }
+    }
+  }
+
+  return expr;
+}
Index: lldb/source/Breakpoint/Breakpoint.cpp
===================================================================
--- lldb/source/Breakpoint/Breakpoint.cpp
+++ lldb/source/Breakpoint/Breakpoint.cpp
@@ -418,6 +418,14 @@
   return m_options_up->GetConditionText();
 }
 
+void Breakpoint::SetInjectCondition(bool inject_condition) {
+  m_options_up->SetInjectCondition(inject_condition);
+}
+
+bool Breakpoint::GetInjectCondition() const {
+  return m_options_up->GetInjectCondition();
+}
+
 // This function is used when "baton" doesn't need to be freed
 void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton,
                              bool is_synchronous) {
Index: lldb/source/API/SBBreakpointLocation.cpp
===================================================================
--- lldb/source/API/SBBreakpointLocation.cpp
+++ lldb/source/API/SBBreakpointLocation.cpp
@@ -206,6 +206,32 @@
   return false;
 }
 
+void SBBreakpointLocation::SetInjectCondition(bool inject_condition) {
+  LLDB_RECORD_METHOD(void, SBBreakpointLocation, SetInjectCondition, (bool),
+                     inject_condition);
+
+  BreakpointLocationSP loc_sp = GetSP();
+  if (!loc_sp)
+    return;
+  
+  std::lock_guard<std::recursive_mutex> guard(
+      loc_sp->GetTarget().GetAPIMutex());
+  loc_sp->SetInjectCondition(inject_condition);
+  loc_sp->GetBreakpoint().SetInjectCondition(inject_condition);
+}
+
+bool SBBreakpointLocation::GetInjectCondition() {
+  LLDB_RECORD_METHOD_NO_ARGS(bool, SBBreakpointLocation, GetInjectCondition);
+
+  BreakpointLocationSP loc_sp = GetSP();
+  if (!loc_sp)
+    return false;
+  
+  std::lock_guard<std::recursive_mutex> guard(
+      loc_sp->GetTarget().GetAPIMutex());
+  return loc_sp->GetInjectCondition();
+}
+
 void SBBreakpointLocation::SetScriptCallbackFunction(
     const char *callback_function_name) {
   LLDB_RECORD_METHOD(void, SBBreakpointLocation, SetScriptCallbackFunction,
@@ -480,6 +506,8 @@
   LLDB_REGISTER_METHOD(const char *, SBBreakpointLocation, GetCondition, ());
   LLDB_REGISTER_METHOD(void, SBBreakpointLocation, SetAutoContinue, (bool));
   LLDB_REGISTER_METHOD(bool, SBBreakpointLocation, GetAutoContinue, ());
+  LLDB_REGISTER_METHOD(void, SBBreakpointLocation, SetInjectCondition, (bool));
+  LLDB_REGISTER_METHOD(bool, SBBreakpointLocation, GetInjectCondition, ());
   LLDB_REGISTER_METHOD(void, SBBreakpointLocation, SetScriptCallbackFunction,
                        (const char *));
   LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpointLocation,
Index: lldb/source/API/SBBreakpoint.cpp
===================================================================
--- lldb/source/API/SBBreakpoint.cpp
+++ lldb/source/API/SBBreakpoint.cpp
@@ -312,6 +312,31 @@
   return false;
 }
 
+void SBBreakpoint::SetInjectCondition(bool inject_condition) {
+  LLDB_RECORD_METHOD(void, SBBreakpoint, SetInjectCondition, (bool),
+                     inject_condition);
+
+  BreakpointSP bkpt_sp = GetSP();
+  if (!bkpt_sp)
+    return;
+
+  std::lock_guard<std::recursive_mutex> guard(
+      bkpt_sp->GetTarget().GetAPIMutex());
+  bkpt_sp->SetInjectCondition(inject_condition);
+}
+
+bool SBBreakpoint::GetInjectCondition() {
+  LLDB_RECORD_METHOD_NO_ARGS(bool, SBBreakpoint, GetInjectCondition);
+
+  BreakpointSP bkpt_sp = GetSP();
+  if (!bkpt_sp)
+    return false;
+
+  std::lock_guard<std::recursive_mutex> guard(
+      bkpt_sp->GetTarget().GetAPIMutex());
+  return bkpt_sp->GetInjectCondition();
+}
+
 uint32_t SBBreakpoint::GetHitCount() const {
   LLDB_RECORD_METHOD_CONST_NO_ARGS(uint32_t, SBBreakpoint, GetHitCount);
 
@@ -967,6 +992,8 @@
   LLDB_REGISTER_METHOD(const char *, SBBreakpoint, GetCondition, ());
   LLDB_REGISTER_METHOD(void, SBBreakpoint, SetAutoContinue, (bool));
   LLDB_REGISTER_METHOD(bool, SBBreakpoint, GetAutoContinue, ());
+  LLDB_REGISTER_METHOD(void, SBBreakpoint, SetInjectCondition, (bool));
+  LLDB_REGISTER_METHOD(bool, SBBreakpoint, GetInjectCondition, ());
   LLDB_REGISTER_METHOD_CONST(uint32_t, SBBreakpoint, GetHitCount, ());
   LLDB_REGISTER_METHOD_CONST(uint32_t, SBBreakpoint, GetIgnoreCount, ());
   LLDB_REGISTER_METHOD(void, SBBreakpoint, SetThreadID, (lldb::tid_t));
Index: lldb/scripts/interface/SBBreakpointLocation.i
===================================================================
--- lldb/scripts/interface/SBBreakpointLocation.i
+++ lldb/scripts/interface/SBBreakpointLocation.i
@@ -72,6 +72,15 @@
 
     void SetAutoContinue(bool auto_continue);
 
+    %feature("docstring", "
+    *EXPERIMENTAL* Check if the condition expression is injected and checked in-process.") GetInjectCondition;
+    bool GetInjectCondition();
+
+    %feature("docstring", "
+    *EXPERIMENTAL* The condition expression in injected and checked in-process.
+    Enables Fast Conditional Breakpoint.") SetInjectCondition;
+    void SetInjectCondition(bool inject_condition);
+
     %feature("docstring", "
     Set the callback to the given Python function name.") SetScriptCallbackFunction;
     void
Index: lldb/scripts/interface/SBBreakpoint.i
===================================================================
--- lldb/scripts/interface/SBBreakpoint.i
+++ lldb/scripts/interface/SBBreakpoint.i
@@ -150,6 +150,15 @@
 
     bool GetAutoContinue();
 
+    %feature("docstring", "
+    *EXPERIMENTAL* Check if the condition expression is injected and checked in-process.") GetInjectCondition;
+    bool GetInjectCondition();
+
+    %feature("docstring", "
+    *EXPERIMENTAL* The condition expression in injected and checked in-process.
+    Toggles Fast Conditional Breakpoint.") SetInjectCondition;
+    void SetInjectCondition(bool inject_condition);
+
     void
     SetThreadID (lldb::tid_t sb_thread_id);
 
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/main.c
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/main.c
@@ -0,0 +1,24 @@
+// This simple program is to demonstrate the capability of the lldb command
+// "breakpoint set -c "condition() == 999999" -f main.c -l 29 -I" or
+// "breakpoint set -c "local_count == 999999" -f main.c -l 29 -I" to break
+// the condition for an inject breakpoint evaluate to true.
+
+#include <stdio.h>
+
+static int global_count = 0;
+
+int condition(void) {
+  printf("global_count = %d\n", global_count);
+  return global_count++;
+}
+
+int main(int argc, char *argv[])
+{
+  int local_count = 0;
+  for (int i = 0; i < 10000000; i++) {
+    printf("local_count = %d\n", local_count++);  // Find the line number of condition breakpoint for local_count
+  }
+
+  return 0;
+}
+
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/TestFastConditionalBreakpoints.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/TestFastConditionalBreakpoints.py
@@ -0,0 +1,191 @@
+"""
+Test Fast Conditional Breakpoints.
+"""
+
+from __future__ import print_function
+
+import os
+import time
+import re
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class FastConditionalBreakpoitsTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        self.file = lldb.SBFileSpec("main.c")
+        self.comment = "Find the line number of condition breakpoint for local_count"
+        self.condition = '"local_count == 9"'
+        self.extra_options = "-c " + self.condition + " -I"
+        self.binary = "a.out"
+
+    @skipIfWindows
+    def test_fast_conditional_breakpoint_flag_interpreter(self):
+        """Enable fast conditional breakpoints with 'breakpoint modify -c <expr> id -I'."""
+        self.build()
+        self.enable_fast_conditional_breakpoint(use_interpreter=True)
+
+    @skipIfWindows
+    @add_test_categories(["pyapi"])
+    def test_fast_conditional_breakpoint_flag_api(self):
+        """Exercise fast conditional breakpoints with SB API"""
+        self.build()
+        self.enable_fast_conditional_breakpoint(use_interpreter=False)
+
+    @skipIfWindows
+    @add_test_categories(["pyapi"])
+    def test_fast_conditional_breakpoint(self):
+        """Exercice injected breakpoint conditions"""
+        self.build()
+        self.inject_fast_conditional_breakpoint()
+
+    @skipIfWindows
+    @add_test_categories(["pyapi"])
+    def test_invalid_fast_conditional_breakpoint(self):
+        """Exercice invalid injected breakpoint conditions"""
+        self.build()
+        self.inject_invalid_fast_conditional_breakpoint()
+
+    def enable_fast_conditional_breakpoint(self, use_interpreter):
+        exe = self.getBuildArtifact(self.binary)
+        self.target = self.dbg.CreateTarget(exe)
+        self.assertTrue(self.target, VALID_TARGET)
+
+        if use_interpreter:
+            lldbutil.run_break_set_by_source_regexp(
+                self, self.comment, self.extra_options
+            )
+
+            self.runCmd("breakpoint modify " + self.condition + " 1")
+
+            self.expect("breakpoint list -f", substrs=["(FAST)"])
+        else:
+            # Now create a breakpoint on main.c by source regex'.
+            breakpoint = self.target.BreakpointCreateBySourceRegex(
+                self.comment, self.file
+            )
+            self.assertTrue(
+                breakpoint and breakpoint.GetNumLocations() == 1,
+                VALID_BREAKPOINT)
+
+            # We didn't associate a thread index with the breakpoint, so it should
+            # be invalid.
+            self.assertTrue(
+                breakpoint.GetThreadIndex() == lldb.UINT32_MAX,
+                "the thread index should be invalid",
+            )
+            # The thread name should be invalid, too.
+            self.assertTrue(
+                breakpoint.GetThreadName() is None,
+                "the thread name should be invalid")
+
+            # Let's set the thread index for this breakpoint and verify that it is,
+            # indeed, being set correctly and there's only one thread for the
+            # process.
+            breakpoint.SetThreadIndex(1)
+            self.assertTrue(
+                breakpoint.GetThreadIndex() == 1,
+                "the thread index has been set correctly",
+            )
+
+            # Get the breakpoint location from breakpoint after we verified that,
+            # indeed, it has one location.
+            location = breakpoint.GetLocationAtIndex(0)
+            self.assertTrue(
+                location and location.IsEnabled(), VALID_BREAKPOINT_LOCATION
+            )
+
+            # Set the condition on the breakpoint.
+            location.SetCondition(self.condition)
+            self.expect(
+                location.GetCondition(),
+                exe=False,
+                startstr=self.condition)
+
+            # Set condition on the breakpoint to be injected in-process.
+            location.SetInjectCondition(True)
+            self.assertTrue(
+                location.GetInjectCondition(),
+                VALID_BREAKPOINT_LOCATION)
+
+        return self.target.GetBreakpointAtIndex(0)
+
+    def inject_fast_conditional_breakpoint(self):
+        # now launch the process, and do not stop at entry point.
+        breakpoint = self.enable_fast_conditional_breakpoint(
+            use_interpreter=False)
+        process = self.target.LaunchSimple(
+            None, None, self.get_process_working_directory()
+        )
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # frame #0 should be on self.line and the break condition should hold.
+        from lldbsuite.test.lldbutil import get_stopped_thread
+
+        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        self.assertTrue(
+            thread and thread.IsValid(),
+            "there should be a thread stopped due to breakpoint condition",
+        )
+
+        frame0 = thread.GetFrameAtIndex(0)
+        expected_fn_name = "$__lldb_expr(void*)"
+        self.assertTrue(frame0 and frame0.GetFunctionName()
+                        == expected_fn_name)
+
+        # the hit count for the breakpoint should be 1.
+        self.assertTrue(breakpoint.GetHitCount() == 1)
+
+    def inject_invalid_fast_conditional_breakpoint(self):
+        # now create a breakpoint on main.c by source regex'.
+        exe = self.getBuildArtifact(self.binary)
+        self.target = self.dbg.CreateTarget(exe)
+        self.assertTrue(self.target, VALID_TARGET)
+        breakpoint = self.target.BreakpointCreateBySourceRegex(
+            self.comment, self.file)
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
+        )
+
+        # set the condition on the breakpoint.
+        breakpoint.SetCondition("no_such_variable == not_this_one_either")
+        self.expect(
+            breakpoint.GetCondition(),
+            exe=False,
+            startstr="no_such_variable == not_this_one_either",
+        )
+        # get the breakpoint location from breakpoint after we verified that,
+        # indeed, it has one location.
+        location = breakpoint.GetLocationAtIndex(0)
+        self.assertTrue(
+            location and location.IsEnabled(),
+            VALID_BREAKPOINT_LOCATION)
+
+        # set condition on the breakpoint to be injected.
+        location.SetInjectCondition(True)
+        self.assertTrue(
+            location.GetInjectCondition(),
+            VALID_BREAKPOINT_LOCATION)
+
+        # now launch the process, and do not stop at entry point.
+        process = self.target.LaunchSimple(
+            None, None, self.get_process_working_directory()
+        )
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # frame #0 should be on self.line1 and the break condition should hold.
+        from lldbsuite.test.lldbutil import get_stopped_thread
+
+        # FCB is disabled because the condition is not valid.
+        self.assertFalse(
+            location.GetInjectCondition(),
+            VALID_BREAKPOINT_LOCATION)
+        # FCB falls back to regular conditional breakpoint that get hit once.
+        self.assertTrue(breakpoint.GetHitCount() == 1)
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/fast_conditional_breakpoints/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+CFLAGS_EXTRAS += -std=c99
+
+include $(LEVEL)/Makefile.rules
Index: lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
+++ lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py
@@ -15,30 +15,22 @@
 
     mydir = TestBase.compute_mydir(__file__)
 
-    # Requires EE to support COFF on Windows (http://llvm.org/pr22232)
-    @skipIfWindows
     def test_breakpoint_condition_and_run_command(self):
         """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
         self.build()
         self.breakpoint_conditions()
 
-    # Requires EE to support COFF on Windows (http://llvm.org/pr22232)
-    @skipIfWindows
     def test_breakpoint_condition_inline_and_run_command(self):
         """Exercise breakpoint condition inline with 'breakpoint set'."""
         self.build()
         self.breakpoint_conditions(inline=True)
 
-    # Requires EE to support COFF on Windows (http://llvm.org/pr22232)
-    @skipIfWindows
     @add_test_categories(['pyapi'])
     def test_breakpoint_condition_and_python_api(self):
         """Use Python APIs to set breakpoint conditions."""
         self.build()
         self.breakpoint_conditions_python()
 
-    # Requires EE to support COFF on Windows (http://llvm.org/pr22232)
-    @skipIfWindows
     @add_test_categories(['pyapi'])
     def test_breakpoint_invalid_condition_and_python_api(self):
         """Use Python APIs to set breakpoint conditions."""
Index: lldb/include/lldb/lldb-forward.h
===================================================================
--- lldb/include/lldb/lldb-forward.h
+++ lldb/include/lldb/lldb-forward.h
@@ -40,6 +40,7 @@
 class BreakpointPrecondition;
 class BreakpointResolver;
 class BreakpointSite;
+class BreakpointInjectedSite;
 class BreakpointSiteList;
 class BroadcastEventSpec;
 class Broadcaster;
@@ -297,6 +298,10 @@
 typedef std::weak_ptr<lldb_private::Breakpoint> BreakpointWP;
 typedef std::shared_ptr<lldb_private::BreakpointSite> BreakpointSiteSP;
 typedef std::weak_ptr<lldb_private::BreakpointSite> BreakpointSiteWP;
+typedef std::shared_ptr<lldb_private::BreakpointInjectedSite>
+    BreakpointInjectedSiteSP;
+typedef std::weak_ptr<lldb_private::BreakpointInjectedSite>
+    BreakpointInjectedSiteWP;
 typedef std::shared_ptr<lldb_private::BreakpointLocation> BreakpointLocationSP;
 typedef std::weak_ptr<lldb_private::BreakpointLocation> BreakpointLocationWP;
 typedef std::shared_ptr<lldb_private::BreakpointPrecondition> BreakpointPreconditionSP;
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -402,7 +402,8 @@
     eBreakpointEventTypeConditionChanged = (1u << 9),
     eBreakpointEventTypeIgnoreChanged = (1u << 10),
     eBreakpointEventTypeThreadChanged = (1u << 11),
-    eBreakpointEventTypeAutoContinueChanged = (1u << 12)};
+    eBreakpointEventTypeAutoContinueChanged = (1u << 12),
+    eBreakpointEventTypeInjectedCondition = (1u << 13)};
 
 FLAGS_ENUM(WatchpointEventType){
     eWatchpointEventTypeInvalidType = (1u << 0),
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -290,6 +290,12 @@
     m_ignore_breakpoints = ignore;
   }
 
+  void SetInjectCondition(bool inject_condition) {
+    m_inject_condition = inject_condition;
+  }
+
+  bool GetInjectCondition() const { return m_inject_condition; }
+
   bool DoesKeepInMemory() const { return m_keep_in_memory; }
 
   void SetKeepInMemory(bool keep = true) { m_keep_in_memory = keep; }
@@ -403,6 +409,7 @@
   bool m_ansi_color_errors = false;
   bool m_result_is_internal = false;
   bool m_auto_apply_fixits = true;
+  bool m_inject_condition = false;
   /// True if the executed code should be treated as utility code that is only
   /// used by LLDB internally.
   bool m_running_utility_expression = false;
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -21,8 +21,10 @@
 #include <unordered_set>
 #include <vector>
 
+#include "lldb/Breakpoint/BreakpointInjectedSite.h"
 #include "lldb/Breakpoint/BreakpointSiteList.h"
 #include "lldb/Core/Communication.h"
+#include "lldb/Core/Disassembler.h"
 #include "lldb/Core/LoadedModuleInfoList.h"
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/Core/ThreadSafeValue.h"
@@ -2030,6 +2032,13 @@
   lldb::break_id_t CreateBreakpointSite(const lldb::BreakpointLocationSP &owner,
                                         bool use_hardware);
 
+  lldb::break_id_t
+  FallbackToRegularBreakpointSite(const lldb::BreakpointLocationSP &owner,
+                                  bool use_hardware, Log *log,
+                                  const char *error);
+
+  size_t SaveInstructions(Address &address);
+
   Status DisableBreakpointSiteByID(lldb::user_id_t break_id);
 
   Status EnableBreakpointSiteByID(lldb::user_id_t break_id);
@@ -2743,6 +2752,8 @@
   std::unique_ptr<UtilityFunction> m_dlopen_utility_func_up;
   std::once_flag m_dlopen_utility_func_flag_once;
 
+  void *m_overriden_instructions = nullptr;
+
   size_t RemoveBreakpointOpcodesFromBuffer(lldb::addr_t addr, size_t size,
                                            uint8_t *buf) const;
 
Index: lldb/include/lldb/Target/ExecutionContextScope.h
===================================================================
--- lldb/include/lldb/Target/ExecutionContextScope.h
+++ lldb/include/lldb/Target/ExecutionContextScope.h
@@ -13,7 +13,7 @@
 
 namespace lldb_private {
 
-/// @class ExecutionContextScope ExecutionContextScope.h
+/// \class ExecutionContextScope ExecutionContextScope.h
 /// "lldb/Target/ExecutionContextScope.h" Inherit from this if your object can
 /// reconstruct its
 ///        execution context.
Index: lldb/include/lldb/Target/ABI.h
===================================================================
--- lldb/include/lldb/Target/ABI.h
+++ lldb/include/lldb/Target/ABI.h
@@ -133,6 +133,47 @@
 
   virtual bool GetPointerReturnRegister(const char *&name) { return false; }
 
+  /// Allocate a memory stub for the fast condition breakpoint trampoline, and
+  /// build it by saving the register context, calling the argument structure
+  /// builder, passing the resulting structure to the condition checker,
+  /// restoring the register context, running the copied instructions and]
+  /// jumping back to the user source code.
+  ///
+  /// \param[in] instrs_size
+  ///    The size in bytes of the copied instructions.
+  ///
+  /// \param[in] data
+  ///    The copied instructions buffer.
+  ///
+  /// \param[in] jmp_addr
+  ///    The address of the source .
+  ///
+  /// \param[in] util_func_addr
+  ///    The address of the JIT-ed argument structure builder.
+  ///
+  /// \param[in] cond_expr_addr
+  ///    The address of the JIT-ed condition checker.
+  ///
+  virtual bool SetupFastConditionalBreakpointTrampoline(
+      size_t instrs_size, void *data, lldb::addr_t &jmp_addr,
+      lldb::addr_t util_func_addr, lldb::addr_t cond_expr_addr) {
+    return false;
+  }
+
+  virtual llvm::ArrayRef<uint8_t> GetJumpOpcode() { return 0; }
+
+  virtual size_t GetJumpSize() { return 0; }
+
+  virtual llvm::ArrayRef<uint8_t> GetCallOpcode() { return 0; }
+
+  virtual size_t GetCallSize() { return 0; }
+
+  virtual llvm::StringRef GetRegisterContextAsString() { return ""; }
+
+  virtual llvm::StringRef GetMachTypesAsString() { return ""; }
+
+  virtual bool ImplementsJIT() { return false; }
+
   static lldb::ABISP FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch);
 
 protected:
Index: lldb/include/lldb/Symbol/VariableList.h
===================================================================
--- lldb/include/lldb/Symbol/VariableList.h
+++ lldb/include/lldb/Symbol/VariableList.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Symbol/Variable.h"
+#include "lldb/Utility/Iterable.h"
 #include "lldb/lldb-private.h"
 
 namespace lldb_private {
@@ -75,6 +76,13 @@
 private:
   // For VariableList only
   DISALLOW_COPY_AND_ASSIGN(VariableList);
+
+public:
+  typedef AdaptedIterable<collection, lldb::VariableSP, vector_adapter>
+      VariableListCollectionIterable;
+  VariableListCollectionIterable Variables() {
+    return VariableListCollectionIterable(m_variables);
+  }
 };
 
 } // namespace lldb_private
Index: lldb/include/lldb/Expression/LLVMUserExpression.h
===================================================================
--- lldb/include/lldb/Expression/LLVMUserExpression.h
+++ lldb/include/lldb/Expression/LLVMUserExpression.h
@@ -81,7 +81,8 @@
 
   bool PrepareToExecuteJITExpression(DiagnosticManager &diagnostic_manager,
                                      ExecutionContext &exe_ctx,
-                                     lldb::addr_t &struct_address);
+                                     lldb::addr_t &struct_address,
+                                     const EvaluateExpressionOptions options);
 
   virtual bool AddArguments(ExecutionContext &exe_ctx,
                             std::vector<lldb::addr_t> &args,
Index: lldb/include/lldb/Expression/ExpressionVariable.h
===================================================================
--- lldb/include/lldb/Expression/ExpressionVariable.h
+++ lldb/include/lldb/Expression/ExpressionVariable.h
@@ -16,6 +16,7 @@
 
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Iterable.h"
 #include "lldb/lldb-public.h"
 
 namespace lldb_private {
@@ -199,7 +200,19 @@
   void Clear() { m_variables.clear(); }
 
 private:
-  std::vector<lldb::ExpressionVariableSP> m_variables;
+  typedef std::vector<lldb::ExpressionVariableSP> collection;
+  typedef collection::iterator iterator;
+  typedef collection::const_iterator const_iterator;
+
+  collection m_variables;
+
+public:
+  typedef AdaptedIterable<collection, lldb::ExpressionVariableSP,
+                          vector_adapter>
+      ExpressionVariableListCollectionIterable;
+  ExpressionVariableListCollectionIterable Variables() {
+    return ExpressionVariableListCollectionIterable(m_variables);
+  }
 };
 
 class PersistentExpressionState : public ExpressionVariableList {
Index: lldb/include/lldb/Expression/Expression.h
===================================================================
--- lldb/include/lldb/Expression/Expression.h
+++ lldb/include/lldb/Expression/Expression.h
@@ -13,7 +13,7 @@
 #include <string>
 #include <vector>
 
-
+#include "lldb/Core/AddressRange.h"
 #include "lldb/Expression/ExpressionTypeSystemHelper.h"
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-private.h"
@@ -92,7 +92,11 @@
 
   /// LLVM-style RTTI support.
   ExpressionKind getKind() const { return m_kind; }
-  
+
+  const AddressRange GetJITAddressRange(void) const {
+    return AddressRange(m_jit_start_addr, m_jit_end_addr - m_jit_start_addr);
+  }
+
 private:
   /// LLVM-style RTTI support.
   const ExpressionKind m_kind;
Index: lldb/include/lldb/Core/Opcode.h
===================================================================
--- lldb/include/lldb/Core/Opcode.h
+++ lldb/include/lldb/Core/Opcode.h
@@ -221,9 +221,6 @@
   // Get the opcode exactly as it would be laid out in memory.
   uint32_t GetData(DataExtractor &data) const;
 
-protected:
-  friend class lldb::SBInstruction;
-
   const void *GetOpcodeDataBytes() const {
     switch (m_type) {
     case Opcode::eTypeInvalid:
@@ -243,6 +240,9 @@
     return nullptr;
   }
 
+protected:
+  friend class lldb::SBInstruction;
+
   lldb::ByteOrder GetDataByteOrder() const;
 
   bool GetEndianSwap() const {
Index: lldb/include/lldb/Core/Disassembler.h
===================================================================
--- lldb/include/lldb/Core/Disassembler.h
+++ lldb/include/lldb/Core/Disassembler.h
@@ -20,6 +20,7 @@
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Iterable.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-private-enumerations.h"
@@ -311,10 +312,16 @@
 
 private:
   typedef std::vector<lldb::InstructionSP> collection;
+  collection m_instructions;
+
+public:
   typedef collection::iterator iterator;
   typedef collection::const_iterator const_iterator;
-
-  collection m_instructions;
+  typedef AdaptedIterable<collection, lldb::InstructionSP, vector_adapter>
+      InstructionListCollectionIterable;
+  InstructionListCollectionIterable Instructions() {
+    return InstructionListCollectionIterable(m_instructions);
+  }
 };
 
 class PseudoInstruction : public Instruction {
Index: lldb/include/lldb/Breakpoint/BreakpointSite.h
===================================================================
--- lldb/include/lldb/Breakpoint/BreakpointSite.h
+++ lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -45,6 +45,16 @@
                // display any breakpoint opcodes.
   };
 
+  /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
+  enum BreakpointSiteKind {
+    eKindBreakpointSite,
+    eKindBreakpointInjectedSite,
+  };
+
+  static bool classof(const BreakpointSite *bp_site) {
+    return bp_site->getKind() == eKindBreakpointSite;
+  }
+
   ~BreakpointSite() override;
 
   // This section manages the breakpoint traps
@@ -147,7 +157,7 @@
   /// \param[in] thread
   ///     The thread against which to test.
   ///
-  /// return
+  /// \return
   ///     \b true if the collection contains at least one location that
   ///     would be valid for this thread, false otherwise.
   bool ValidForThisThread(Thread *thread);
@@ -187,6 +197,9 @@
 
   BreakpointSite::Type GetType() const { return m_type; }
 
+  /// LLVM-style RTTI support.
+  BreakpointSiteKind getKind() const { return m_kind; }
+
   void SetType(BreakpointSite::Type type) { m_type = type; }
 
 private:
@@ -196,6 +209,7 @@
   // a site, so let it be the one to manage setting the location hit count once
   // and only once.
   friend class StopInfoBreakpoint;
+  friend class BreakpointInjectedSite;
 
   void BumpHitCounts();
 
@@ -221,13 +235,16 @@
   std::recursive_mutex
       m_owners_mutex; ///< This mutex protects the owners collection.
 
+  const BreakpointSiteKind m_kind;
+
   static lldb::break_id_t GetNextID();
 
   // Only the Process can create breakpoint sites in
   // Process::CreateBreakpointSite (lldb::BreakpointLocationSP &, bool).
   BreakpointSite(BreakpointSiteList *list,
                  const lldb::BreakpointLocationSP &owner, lldb::addr_t m_addr,
-                 bool use_hardware);
+                 bool use_hardware,
+                 BreakpointSiteKind kind = eKindBreakpointSite);
 
   DISALLOW_COPY_AND_ASSIGN(BreakpointSite);
 };
Index: lldb/include/lldb/Breakpoint/BreakpointOptions.h
===================================================================
--- lldb/include/lldb/Breakpoint/BreakpointOptions.h
+++ lldb/include/lldb/Breakpoint/BreakpointOptions.h
@@ -32,15 +32,16 @@
 
 public:
   enum OptionKind {
-    eCallback     = 1 << 0,
-    eEnabled      = 1 << 1,
-    eOneShot      = 1 << 2,
-    eIgnoreCount  = 1 << 3,
-    eThreadSpec   = 1 << 4,
-    eCondition    = 1 << 5,
-    eAutoContinue = 1 << 6,
-    eAllOptions   = (eCallback | eEnabled | eOneShot | eIgnoreCount | eThreadSpec
-                     | eCondition | eAutoContinue)
+    eCallback        = 1 << 0,
+    eEnabled         = 1 << 1,
+    eOneShot         = 1 << 2,
+    eIgnoreCount     = 1 << 3,
+    eThreadSpec      = 1 << 4,
+    eCondition       = 1 << 5,
+    eAutoContinue    = 1 << 6,
+    eInjectCondition = 1 << 7,
+    eAllOptions      = (eCallback | eEnabled | eOneShot | eIgnoreCount |
+                   eThreadSpec | eCondition | eAutoContinue | eInjectCondition)
   };
   struct CommandData {
     CommandData()
@@ -113,9 +114,12 @@
   /// \param[in] auto_continue
   ///    Should this breakpoint auto-continue after running its commands.
   ///
+  /// \param[in] inject_condition
+  ///    Should the condition be injected and checked in-process.
+  ///
   BreakpointOptions(const char *condition, bool enabled = true,
                     int32_t ignore = 0, bool one_shot = false,
-                    bool auto_continue = false);
+                    bool auto_continue = false, bool inject_condition = false);
 
   /// Breakpoints make options with all flags set.  Locations and Names make
   /// options with no flags set.
@@ -347,7 +351,20 @@
   bool AnySet() const {
     return m_set_flags.AnySet(eAllOptions);
   }
-  
+
+  /// Check if the breakpoint condition should be injected
+  ///
+  /// \return
+  ///    If condition is injected \b true, \b false otherwise.
+  bool GetInjectCondition() const;
+
+  /// If \a inject_condition is \b true, inject the breakpoint condition in the
+  /// process.
+  void SetInjectCondition(bool inject_condition) {
+    m_inject_condition = inject_condition;
+    m_set_flags.Set(eInjectCondition);
+  }
+
 protected:
   // Classes that inherit from BreakpointOptions can see and modify these
   bool IsOptionSet(OptionKind kind)
@@ -361,6 +378,7 @@
     EnabledState,
     OneShotState,
     AutoContinue,
+    InjectCondition,
     LastOptionName
   };
   static const char *g_option_names[(size_t)OptionNames::LastOptionName];
Index: lldb/include/lldb/Breakpoint/BreakpointLocation.h
===================================================================
--- lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -131,6 +131,16 @@
   //     condition has been set.
   const char *GetConditionText(size_t *hash = nullptr) const;
 
+  /// Check if the breakpoint condition should be injected
+  ///
+  /// \return
+  ///    If condition is injected \b true, \b false otherwise.
+  bool GetInjectCondition() const;
+
+  /// If \a inject_condition is \b true, inject the breakpoint condition in the
+  /// process.
+  void SetInjectCondition(bool inject_condition);
+
   bool ConditionSaysStop(ExecutionContext &exe_ctx, Status &error);
 
   /// Set the valid thread to be checked when the breakpoint is hit.
@@ -273,6 +283,7 @@
 
 protected:
   friend class BreakpointSite;
+  friend class BreakpointInjectedSite;
   friend class BreakpointLocationList;
   friend class Process;
   friend class StopInfoBreakpoint;
Index: lldb/include/lldb/Breakpoint/BreakpointInjectedSite.h
===================================================================
--- /dev/null
+++ lldb/include/lldb/Breakpoint/BreakpointInjectedSite.h
@@ -0,0 +1,198 @@
+//===-- BreakpointInjectedSite.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_BreakpointInjectedSite_h_
+#define liblldb_BreakpointInjectedSite_h_
+
+#include "lldb/lldb-forward.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/DataEncoder.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+
+namespace lldb_private {
+
+/// \class BreakpointInjectedSite BreakpointInjectedSite.h
+/// Class that setup fast conditional breakpoints.
+///
+/// Fast conditional breakpoints have a different way of evaluating the
+/// condition expression by doing the check in-process, which saves the cost
+/// of doing several context switches between the inferior and LLDB.
+///
+///
+class BreakpointInjectedSite : public BreakpointSite {
+public:
+  /// LLVM-style RTTI support.
+  static bool classof(const BreakpointSite *bp_site) {
+    return bp_site->getKind() == eKindBreakpointInjectedSite;
+  }
+
+  // Destructor
+  ~BreakpointInjectedSite() override;
+
+  /// Fetch each breakpoint location's condition and build the JIT-ed condition
+  /// checker with the injected trap.
+  ///
+  /// \return
+  ///     \b true if building the condition checker succeeded,
+  ///     \b false otherwise.
+  bool BuildConditionExpression();
+
+  lldb_private::ExecutionContext GetOwnerExecutionContext() {
+    return m_owner_exe_ctx;
+  }
+
+  lldb::addr_t GetConditionExpressionAddress() {
+    return m_condition_expression_sp->StartAddress();
+  }
+
+  lldb::addr_t GetUtilityFunctionAddress() {
+    return m_create_args_struct_function_sp->StartAddress();
+  }
+
+  lldb::addr_t GetTrapAddress() {
+    return m_trap_addr.GetLoadAddress(m_target_sp.get());
+  }
+
+  /// \struct ArgumentMetadata BreakpointInjectedSite.h
+  /// "lldb/Breakpoint/BreakpointInjectedSite.h" Struct that contains debugging
+  /// information for the variable used in the condition expression.
+  struct VariableMetadata {
+
+    // Constructor
+
+    /// This constructor stores the variable name and type size and create a
+    /// DWARF Expression from the DataExtractor containing the DWARF Operation
+    /// and its operands.
+    ///
+    /// \param[in] name
+    ///    The name of the variable.
+    ///
+    /// \param[in] size
+    ///    The type size of the variable.
+    ///
+    /// \param[in] data
+    ///    The buffer containing the variable DWARF Expression data.
+    ///
+    /// \param[in] version
+    ///    The version of DWARF that is used for the DWARF Expression.
+    ///
+    /// \param[in] address_size
+    ///    The size in bytes for the address of the current architecture.
+    ///
+    VariableMetadata(std::string name, size_t size, llvm::DataExtractor data,
+                     uint16_t version, uint8_t address_size)
+        : name(std::move(name)), size(size),
+          dwarf(data, version, address_size) {}
+
+    /// The variable name.
+    std::string name;
+    /// The variable size.
+    size_t size;
+    /// The variable DWARF Expression.
+    llvm::DWARFExpression dwarf;
+  };
+
+private:
+  friend class Process;
+
+  // Constructor
+
+  /// This constructor stores the variable name and type size and create a
+  /// DWARF Expression from the DataExtractor containing the DWARF Operation
+  /// and its operands.
+  ///
+  /// \param[in] list
+  ///    The list of the breakpoint sites already set.
+  ///
+  /// \param[in] owner
+  ///    The breakpoint location holding this breakpoint site.
+  ///
+  /// \param[in] addr
+  ///    The breakpoint site load address.
+  ///
+  BreakpointInjectedSite(BreakpointSiteList *list,
+                         const lldb::BreakpointLocationSP &owner,
+                         lldb::addr_t addr);
+
+  /// Scan the JIT-ed condition expression instructions and look for the
+  /// injected trap instruction.
+  ///
+  /// \param[in] jit
+  ///     The buffer containing the JIT-ed condition expression.
+  ///
+  /// \param[in] size
+  ///     The size of the JIT-ed condition expression in memory.
+  ///
+  /// \return
+  ///     \b true if the injected trap instruction is found, \b false otherwise.
+  bool ResolveTrapAddress(void *jit, size_t size);
+
+  /// Iterate over the JIT-ed condition expression variable and build a metadata
+  /// vector used to resolve variables when checking the condition.
+  ///
+  /// \return
+  ///     \b true if the metadata gathering succeeded, \b false otherwise.
+  bool GatherArgumentsMetadata();
+
+  /// Build the argument structure used by the JIT-ed condition expression.
+  /// Allocate dynamically the structure and using the variable metadata vector,
+  /// write the variable address in the argument structure.
+  ///
+  /// \return
+  ///     \b true if building the argument structure succeeded,
+  ///     \b false otherwise.
+  bool CreateArgumentsStructure();
+
+  /// Parse the variable's DWARF Expression and return the proper source code,
+  /// according to the DWARF Operation.
+  ///
+  /// \param[in] index
+  ///     The index of the variable in the metadata vector.
+  ///
+  /// \param[in] error
+  ///     The thread against which to test.
+  ///
+  /// \return
+  ///     The source code needed to copy the variable in the argument structure.
+  std::string ParseDWARFExpression(size_t index, Status &error);
+
+private:
+  /// The target that hold the breakpoint.
+  lldb::TargetSP m_target_sp;
+  /// The breakpoint location load address.
+  Address m_real_addr;
+  /// The injected trap instruction address.
+  Address m_trap_addr;
+  /// The breakpoint location execution context.
+  lldb_private::ExecutionContext m_owner_exe_ctx;
+  /// The disassembler used to resolve the injected trap address.
+  lldb::DisassemblerSP m_disassembler_sp;
+  /// The JIT-ed condition checker.
+  lldb::UserExpressionSP m_condition_expression_sp;
+  /// The JIT-ed argument structure builder.
+  lldb::UtilityFunctionSP m_create_args_struct_function_sp;
+  /// The variable metadata vector.
+  std::vector<VariableMetadata> m_metadatas;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointInjectedSite_h_
Index: lldb/include/lldb/Breakpoint/Breakpoint.h
===================================================================
--- lldb/include/lldb/Breakpoint/Breakpoint.h
+++ lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -63,6 +63,7 @@
 ///    \b Ignore Count
 ///    \b Callback
 ///    \b Condition
+///    \b Inject Condition
 /// Note, these options can be set on the breakpoint, and they can also be set
 /// on the individual locations.  The options set on the breakpoint take
 /// precedence over the options set on the individual location. So for
@@ -399,6 +400,16 @@
   //     condition has been set.
   const char *GetConditionText() const;
 
+  /// If \a inject_condition is \b true, inject the breakpoint condition in the
+  /// process.
+  void SetInjectCondition(bool inject_condition);
+
+  /// Check if the breakpoint condition should be injected
+  ///
+  /// \return
+  ///    If condition is injected \b true, \b false otherwise.
+  bool GetInjectCondition() const;
+
   // The next section are various utility functions.
 
   /// Return the number of breakpoint locations that have resolved to actual
Index: lldb/include/lldb/API/SBBreakpointLocation.h
===================================================================
--- lldb/include/lldb/API/SBBreakpointLocation.h
+++ lldb/include/lldb/API/SBBreakpointLocation.h
@@ -53,6 +53,10 @@
 
   bool GetAutoContinue();
 
+  void SetInjectCondition(bool inject_condition);
+
+  bool GetInjectCondition();
+
   void SetScriptCallbackFunction(const char *callback_function_name);
 
   SBError SetScriptCallbackBody(const char *script_body_text);
Index: lldb/include/lldb/API/SBBreakpoint.h
===================================================================
--- lldb/include/lldb/API/SBBreakpoint.h
+++ lldb/include/lldb/API/SBBreakpoint.h
@@ -74,6 +74,10 @@
 
   bool GetAutoContinue();
 
+  void SetInjectCondition(bool inject_condition);
+
+  bool GetInjectCondition();
+
   void SetThreadID(lldb::tid_t sb_thread_id);
 
   lldb::tid_t GetThreadID();
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to