xref: /llvm-project/mlir/lib/Debug/DebuggerExecutionContextHook.cpp (revision d5746d73cedcf7a593dc4b4f2ce2465e2d45750b)
11020150eSMehdi Amini //===- DebuggerExecutionContextHook.cpp - Debugger Support ----------------===//
21020150eSMehdi Amini //
31020150eSMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41020150eSMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
51020150eSMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61020150eSMehdi Amini //
71020150eSMehdi Amini //===----------------------------------------------------------------------===//
81020150eSMehdi Amini 
91020150eSMehdi Amini #include "mlir/Debug/DebuggerExecutionContextHook.h"
101020150eSMehdi Amini 
111020150eSMehdi Amini #include "mlir/Debug/BreakpointManagers/FileLineColLocBreakpointManager.h"
121020150eSMehdi Amini #include "mlir/Debug/BreakpointManagers/TagBreakpointManager.h"
131020150eSMehdi Amini 
141020150eSMehdi Amini using namespace mlir;
151020150eSMehdi Amini using namespace mlir::tracing;
161020150eSMehdi Amini 
171020150eSMehdi Amini namespace {
181020150eSMehdi Amini /// This structure tracks the state of the interactive debugger.
191020150eSMehdi Amini struct DebuggerState {
201020150eSMehdi Amini   /// This variable keeps track of the current control option. This is set by
211020150eSMehdi Amini   /// the debugger when control is handed over to it.
221020150eSMehdi Amini   ExecutionContext::Control debuggerControl = ExecutionContext::Apply;
231020150eSMehdi Amini 
241020150eSMehdi Amini   /// The breakpoint manager that allows the debugger to set breakpoints on
251020150eSMehdi Amini   /// action tags.
261020150eSMehdi Amini   TagBreakpointManager tagBreakpointManager;
271020150eSMehdi Amini 
281020150eSMehdi Amini   /// The breakpoint manager that allows the debugger to set breakpoints on
291020150eSMehdi Amini   /// FileLineColLoc locations.
301020150eSMehdi Amini   FileLineColLocBreakpointManager fileLineColLocBreakpointManager;
311020150eSMehdi Amini 
321020150eSMehdi Amini   /// Map of breakpoint IDs to breakpoint objects.
331020150eSMehdi Amini   DenseMap<unsigned, Breakpoint *> breakpointIdsMap;
341020150eSMehdi Amini 
351020150eSMehdi Amini   /// The current stack of actiive actions.
361020150eSMehdi Amini   const tracing::ActionActiveStack *actionActiveStack;
371020150eSMehdi Amini 
381020150eSMehdi Amini   /// This is a "cursor" in the IR, it is used for the debugger to navigate the
391020150eSMehdi Amini   /// IR associated to the actions.
401020150eSMehdi Amini   IRUnit cursor;
411020150eSMehdi Amini };
421020150eSMehdi Amini } // namespace
431020150eSMehdi Amini 
441020150eSMehdi Amini static DebuggerState &getGlobalDebuggerState() {
451020150eSMehdi Amini   static LLVM_THREAD_LOCAL DebuggerState debuggerState;
461020150eSMehdi Amini   return debuggerState;
471020150eSMehdi Amini }
481020150eSMehdi Amini 
491020150eSMehdi Amini extern "C" {
501020150eSMehdi Amini void mlirDebuggerSetControl(int controlOption) {
511020150eSMehdi Amini   getGlobalDebuggerState().debuggerControl =
521020150eSMehdi Amini       static_cast<ExecutionContext::Control>(controlOption);
531020150eSMehdi Amini }
541020150eSMehdi Amini 
551020150eSMehdi Amini void mlirDebuggerPrintContext() {
561020150eSMehdi Amini   DebuggerState &state = getGlobalDebuggerState();
571020150eSMehdi Amini   if (!state.actionActiveStack) {
581020150eSMehdi Amini     llvm::outs() << "No active action.\n";
591020150eSMehdi Amini     return;
601020150eSMehdi Amini   }
611020150eSMehdi Amini   const ArrayRef<IRUnit> &units =
621020150eSMehdi Amini       state.actionActiveStack->getAction().getContextIRUnits();
631020150eSMehdi Amini   llvm::outs() << units.size() << " available IRUnits:\n";
641020150eSMehdi Amini   for (const IRUnit &unit : units) {
651020150eSMehdi Amini     llvm::outs() << "  - ";
661020150eSMehdi Amini     unit.print(
671020150eSMehdi Amini         llvm::outs(),
681020150eSMehdi Amini         OpPrintingFlags().useLocalScope().skipRegions().enableDebugInfo());
691020150eSMehdi Amini     llvm::outs() << "\n";
701020150eSMehdi Amini   }
711020150eSMehdi Amini }
721020150eSMehdi Amini 
731020150eSMehdi Amini void mlirDebuggerPrintActionBacktrace(bool withContext) {
741020150eSMehdi Amini   DebuggerState &state = getGlobalDebuggerState();
751020150eSMehdi Amini   if (!state.actionActiveStack) {
761020150eSMehdi Amini     llvm::outs() << "No active action.\n";
771020150eSMehdi Amini     return;
781020150eSMehdi Amini   }
791020150eSMehdi Amini   state.actionActiveStack->print(llvm::outs(), withContext);
801020150eSMehdi Amini }
811020150eSMehdi Amini 
821020150eSMehdi Amini //===----------------------------------------------------------------------===//
831020150eSMehdi Amini // Cursor Management
841020150eSMehdi Amini //===----------------------------------------------------------------------===//
851020150eSMehdi Amini 
861020150eSMehdi Amini void mlirDebuggerCursorPrint(bool withRegion) {
871020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
881020150eSMehdi Amini   if (!state.cursor) {
891020150eSMehdi Amini     llvm::outs() << "No active MLIR cursor, select from the context first\n";
901020150eSMehdi Amini     return;
911020150eSMehdi Amini   }
921020150eSMehdi Amini   state.cursor.print(llvm::outs(), OpPrintingFlags()
931020150eSMehdi Amini                                        .skipRegions(!withRegion)
941020150eSMehdi Amini                                        .useLocalScope()
951020150eSMehdi Amini                                        .enableDebugInfo());
961020150eSMehdi Amini   llvm::outs() << "\n";
971020150eSMehdi Amini }
981020150eSMehdi Amini 
991020150eSMehdi Amini void mlirDebuggerCursorSelectIRUnitFromContext(int index) {
1001020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
1011020150eSMehdi Amini   if (!state.actionActiveStack) {
1021020150eSMehdi Amini     llvm::outs() << "No active MLIR Action stack\n";
1031020150eSMehdi Amini     return;
1041020150eSMehdi Amini   }
1051020150eSMehdi Amini   ArrayRef<IRUnit> units =
1061020150eSMehdi Amini       state.actionActiveStack->getAction().getContextIRUnits();
1071020150eSMehdi Amini   if (index < 0 || index >= static_cast<int>(units.size())) {
1081020150eSMehdi Amini     llvm::outs() << "Index invalid, bounds: [0, " << units.size()
1091020150eSMehdi Amini                  << "] but got " << index << "\n";
1101020150eSMehdi Amini     return;
1111020150eSMehdi Amini   }
1121020150eSMehdi Amini   state.cursor = units[index];
1131020150eSMehdi Amini   state.cursor.print(llvm::outs());
1141020150eSMehdi Amini   llvm::outs() << "\n";
1151020150eSMehdi Amini }
1161020150eSMehdi Amini 
1171020150eSMehdi Amini void mlirDebuggerCursorSelectParentIRUnit() {
1181020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
1191020150eSMehdi Amini   if (!state.cursor) {
1201020150eSMehdi Amini     llvm::outs() << "No active MLIR cursor, select from the context first\n";
1211020150eSMehdi Amini     return;
1221020150eSMehdi Amini   }
1231020150eSMehdi Amini   IRUnit *unit = &state.cursor;
12468f58812STres Popp   if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
1251020150eSMehdi Amini     state.cursor = op->getBlock();
12668f58812STres Popp   } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
1271020150eSMehdi Amini     state.cursor = region->getParentOp();
12868f58812STres Popp   } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
1291020150eSMehdi Amini     state.cursor = block->getParent();
1301020150eSMehdi Amini   } else {
1311020150eSMehdi Amini     llvm::outs() << "Current cursor is not a valid IRUnit";
1321020150eSMehdi Amini     return;
1331020150eSMehdi Amini   }
1341020150eSMehdi Amini   state.cursor.print(llvm::outs());
1351020150eSMehdi Amini   llvm::outs() << "\n";
1361020150eSMehdi Amini }
1371020150eSMehdi Amini 
1381020150eSMehdi Amini void mlirDebuggerCursorSelectChildIRUnit(int index) {
1391020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
1401020150eSMehdi Amini   if (!state.cursor) {
1411020150eSMehdi Amini     llvm::outs() << "No active MLIR cursor, select from the context first\n";
1421020150eSMehdi Amini     return;
1431020150eSMehdi Amini   }
1441020150eSMehdi Amini   IRUnit *unit = &state.cursor;
14568f58812STres Popp   if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
1461020150eSMehdi Amini     if (index < 0 || index >= static_cast<int>(op->getNumRegions())) {
1471020150eSMehdi Amini       llvm::outs() << "Index invalid, op has " << op->getNumRegions()
1481020150eSMehdi Amini                    << " but got " << index << "\n";
1491020150eSMehdi Amini       return;
1501020150eSMehdi Amini     }
1511020150eSMehdi Amini     state.cursor = &op->getRegion(index);
15268f58812STres Popp   } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
1531020150eSMehdi Amini     auto block = region->begin();
1541020150eSMehdi Amini     int count = 0;
1551020150eSMehdi Amini     while (block != region->end() && count != index) {
1561020150eSMehdi Amini       ++block;
1571020150eSMehdi Amini       ++count;
1581020150eSMehdi Amini     }
1591020150eSMehdi Amini 
1601020150eSMehdi Amini     if (block == region->end()) {
1611020150eSMehdi Amini       llvm::outs() << "Index invalid, region has " << count << " block but got "
1621020150eSMehdi Amini                    << index << "\n";
1631020150eSMehdi Amini       return;
1641020150eSMehdi Amini     }
1651020150eSMehdi Amini     state.cursor = &*block;
16668f58812STres Popp   } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
1671020150eSMehdi Amini     auto op = block->begin();
1681020150eSMehdi Amini     int count = 0;
1691020150eSMehdi Amini     while (op != block->end() && count != index) {
1701020150eSMehdi Amini       ++op;
1711020150eSMehdi Amini       ++count;
1721020150eSMehdi Amini     }
1731020150eSMehdi Amini 
1741020150eSMehdi Amini     if (op == block->end()) {
1751020150eSMehdi Amini       llvm::outs() << "Index invalid, block has " << count
1761020150eSMehdi Amini                    << "operations but got " << index << "\n";
1771020150eSMehdi Amini       return;
1781020150eSMehdi Amini     }
1791020150eSMehdi Amini     state.cursor = &*op;
1801020150eSMehdi Amini   } else {
1811020150eSMehdi Amini     llvm::outs() << "Current cursor is not a valid IRUnit";
1821020150eSMehdi Amini     return;
1831020150eSMehdi Amini   }
1841020150eSMehdi Amini   state.cursor.print(llvm::outs());
1851020150eSMehdi Amini   llvm::outs() << "\n";
1861020150eSMehdi Amini }
1871020150eSMehdi Amini 
1881020150eSMehdi Amini void mlirDebuggerCursorSelectPreviousIRUnit() {
1891020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
1901020150eSMehdi Amini   if (!state.cursor) {
1911020150eSMehdi Amini     llvm::outs() << "No active MLIR cursor, select from the context first\n";
1921020150eSMehdi Amini     return;
1931020150eSMehdi Amini   }
1941020150eSMehdi Amini   IRUnit *unit = &state.cursor;
19568f58812STres Popp   if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
1961020150eSMehdi Amini     Operation *previous = op->getPrevNode();
1971020150eSMehdi Amini     if (!previous) {
1981020150eSMehdi Amini       llvm::outs() << "No previous operation in the current block\n";
1991020150eSMehdi Amini       return;
2001020150eSMehdi Amini     }
2011020150eSMehdi Amini     state.cursor = previous;
20268f58812STres Popp   } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
2031020150eSMehdi Amini     llvm::outs() << "Has region\n";
2041020150eSMehdi Amini     Operation *parent = region->getParentOp();
2051020150eSMehdi Amini     if (!parent) {
2061020150eSMehdi Amini       llvm::outs() << "No parent operation for the current region\n";
2071020150eSMehdi Amini       return;
2081020150eSMehdi Amini     }
2091020150eSMehdi Amini     if (region->getRegionNumber() == 0) {
2101020150eSMehdi Amini       llvm::outs() << "No previous region in the current operation\n";
2111020150eSMehdi Amini       return;
2121020150eSMehdi Amini     }
2131020150eSMehdi Amini     state.cursor =
2141020150eSMehdi Amini         &region->getParentOp()->getRegion(region->getRegionNumber() - 1);
21568f58812STres Popp   } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
2161020150eSMehdi Amini     Block *previous = block->getPrevNode();
2171020150eSMehdi Amini     if (!previous) {
2181020150eSMehdi Amini       llvm::outs() << "No previous block in the current region\n";
2191020150eSMehdi Amini       return;
2201020150eSMehdi Amini     }
2211020150eSMehdi Amini     state.cursor = previous;
2221020150eSMehdi Amini   } else {
2231020150eSMehdi Amini     llvm::outs() << "Current cursor is not a valid IRUnit";
2241020150eSMehdi Amini     return;
2251020150eSMehdi Amini   }
2261020150eSMehdi Amini   state.cursor.print(llvm::outs());
2271020150eSMehdi Amini   llvm::outs() << "\n";
2281020150eSMehdi Amini }
2291020150eSMehdi Amini 
2301020150eSMehdi Amini void mlirDebuggerCursorSelectNextIRUnit() {
2311020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
2321020150eSMehdi Amini   if (!state.cursor) {
2331020150eSMehdi Amini     llvm::outs() << "No active MLIR cursor, select from the context first\n";
2341020150eSMehdi Amini     return;
2351020150eSMehdi Amini   }
2361020150eSMehdi Amini   IRUnit *unit = &state.cursor;
23768f58812STres Popp   if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
2381020150eSMehdi Amini     Operation *next = op->getNextNode();
2391020150eSMehdi Amini     if (!next) {
2401020150eSMehdi Amini       llvm::outs() << "No next operation in the current block\n";
2411020150eSMehdi Amini       return;
2421020150eSMehdi Amini     }
2431020150eSMehdi Amini     state.cursor = next;
24468f58812STres Popp   } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
2451020150eSMehdi Amini     Operation *parent = region->getParentOp();
2461020150eSMehdi Amini     if (!parent) {
2471020150eSMehdi Amini       llvm::outs() << "No parent operation for the current region\n";
2481020150eSMehdi Amini       return;
2491020150eSMehdi Amini     }
2501020150eSMehdi Amini     if (region->getRegionNumber() == parent->getNumRegions() - 1) {
2511020150eSMehdi Amini       llvm::outs() << "No next region in the current operation\n";
2521020150eSMehdi Amini       return;
2531020150eSMehdi Amini     }
2541020150eSMehdi Amini     state.cursor =
2551020150eSMehdi Amini         &region->getParentOp()->getRegion(region->getRegionNumber() + 1);
25668f58812STres Popp   } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
2571020150eSMehdi Amini     Block *next = block->getNextNode();
2581020150eSMehdi Amini     if (!next) {
2591020150eSMehdi Amini       llvm::outs() << "No next block in the current region\n";
2601020150eSMehdi Amini       return;
2611020150eSMehdi Amini     }
2621020150eSMehdi Amini     state.cursor = next;
2631020150eSMehdi Amini   } else {
2641020150eSMehdi Amini     llvm::outs() << "Current cursor is not a valid IRUnit";
2651020150eSMehdi Amini     return;
2661020150eSMehdi Amini   }
2671020150eSMehdi Amini   state.cursor.print(llvm::outs());
2681020150eSMehdi Amini   llvm::outs() << "\n";
2691020150eSMehdi Amini }
2701020150eSMehdi Amini 
2711020150eSMehdi Amini //===----------------------------------------------------------------------===//
2721020150eSMehdi Amini // Breakpoint Management
2731020150eSMehdi Amini //===----------------------------------------------------------------------===//
2741020150eSMehdi Amini 
2751020150eSMehdi Amini void mlirDebuggerEnableBreakpoint(BreakpointHandle breakpoint) {
2761020150eSMehdi Amini   reinterpret_cast<Breakpoint *>(breakpoint)->enable();
2771020150eSMehdi Amini }
2781020150eSMehdi Amini 
2791020150eSMehdi Amini void mlirDebuggerDisableBreakpoint(BreakpointHandle breakpoint) {
2801020150eSMehdi Amini   reinterpret_cast<Breakpoint *>(breakpoint)->disable();
2811020150eSMehdi Amini }
2821020150eSMehdi Amini 
2831020150eSMehdi Amini BreakpointHandle mlirDebuggerAddTagBreakpoint(const char *tag) {
2841020150eSMehdi Amini   DebuggerState &state = getGlobalDebuggerState();
2851020150eSMehdi Amini   Breakpoint *breakpoint =
2861020150eSMehdi Amini       state.tagBreakpointManager.addBreakpoint(StringRef(tag, strlen(tag)));
2871020150eSMehdi Amini   int breakpointId = state.breakpointIdsMap.size() + 1;
2881020150eSMehdi Amini   state.breakpointIdsMap[breakpointId] = breakpoint;
2891020150eSMehdi Amini   return reinterpret_cast<BreakpointHandle>(breakpoint);
2901020150eSMehdi Amini }
2911020150eSMehdi Amini 
2921020150eSMehdi Amini void mlirDebuggerAddRewritePatternBreakpoint(const char *patternNameInfo) {}
2931020150eSMehdi Amini 
2941020150eSMehdi Amini void mlirDebuggerAddFileLineColLocBreakpoint(const char *file, int line,
2951020150eSMehdi Amini                                              int col) {
2961020150eSMehdi Amini   getGlobalDebuggerState().fileLineColLocBreakpointManager.addBreakpoint(
2971020150eSMehdi Amini       StringRef(file, strlen(file)), line, col);
2981020150eSMehdi Amini }
2991020150eSMehdi Amini 
3001020150eSMehdi Amini } // extern "C"
3011020150eSMehdi Amini 
3021020150eSMehdi Amini LLVM_ATTRIBUTE_NOINLINE void mlirDebuggerBreakpointHook() {
3031020150eSMehdi Amini   static LLVM_THREAD_LOCAL void *volatile sink;
304*d5746d73SFrank Schlimbach   sink = static_cast<void *>(const_cast<void **>(&sink));
3051020150eSMehdi Amini }
3061020150eSMehdi Amini 
3071020150eSMehdi Amini static void preventLinkerDeadCodeElim() {
3081020150eSMehdi Amini   static void *volatile sink;
3091020150eSMehdi Amini   static bool initialized = [&]() {
3101020150eSMehdi Amini     sink = (void *)mlirDebuggerSetControl;
3111020150eSMehdi Amini     sink = (void *)mlirDebuggerEnableBreakpoint;
3121020150eSMehdi Amini     sink = (void *)mlirDebuggerDisableBreakpoint;
3131020150eSMehdi Amini     sink = (void *)mlirDebuggerPrintContext;
3141020150eSMehdi Amini     sink = (void *)mlirDebuggerPrintActionBacktrace;
3151020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorPrint;
3161020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorSelectIRUnitFromContext;
3171020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorSelectParentIRUnit;
3181020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorSelectChildIRUnit;
3191020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorSelectPreviousIRUnit;
3201020150eSMehdi Amini     sink = (void *)mlirDebuggerCursorSelectNextIRUnit;
3211020150eSMehdi Amini     sink = (void *)mlirDebuggerAddTagBreakpoint;
3221020150eSMehdi Amini     sink = (void *)mlirDebuggerAddRewritePatternBreakpoint;
3231020150eSMehdi Amini     sink = (void *)mlirDebuggerAddFileLineColLocBreakpoint;
324*d5746d73SFrank Schlimbach     sink = static_cast<void *>(const_cast<void **>(&sink));
3251020150eSMehdi Amini     return true;
3261020150eSMehdi Amini   }();
3271020150eSMehdi Amini   (void)initialized;
3281020150eSMehdi Amini }
3291020150eSMehdi Amini 
3301020150eSMehdi Amini static tracing::ExecutionContext::Control
3311020150eSMehdi Amini debuggerCallBackFunction(const tracing::ActionActiveStack *actionStack) {
3321020150eSMehdi Amini   preventLinkerDeadCodeElim();
3331020150eSMehdi Amini   // Invoke the breakpoint hook, the debugger is supposed to trap this.
3341020150eSMehdi Amini   // The debugger controls the execution from there by invoking
3351020150eSMehdi Amini   // `mlirDebuggerSetControl()`.
3361020150eSMehdi Amini   auto &state = getGlobalDebuggerState();
3371020150eSMehdi Amini   state.actionActiveStack = actionStack;
3381020150eSMehdi Amini   getGlobalDebuggerState().debuggerControl = ExecutionContext::Apply;
3391020150eSMehdi Amini   actionStack->getAction().print(llvm::outs());
3401020150eSMehdi Amini   llvm::outs() << "\n";
3411020150eSMehdi Amini   mlirDebuggerBreakpointHook();
3421020150eSMehdi Amini   return getGlobalDebuggerState().debuggerControl;
3431020150eSMehdi Amini }
3441020150eSMehdi Amini 
3451020150eSMehdi Amini namespace {
3461020150eSMehdi Amini /// Manage the stack of actions that are currently active.
3471020150eSMehdi Amini class DebuggerObserver : public ExecutionContext::Observer {
3481020150eSMehdi Amini   void beforeExecute(const ActionActiveStack *action, Breakpoint *breakpoint,
3491020150eSMehdi Amini                      bool willExecute) override {
3501020150eSMehdi Amini     auto &state = getGlobalDebuggerState();
3511020150eSMehdi Amini     state.actionActiveStack = action;
3521020150eSMehdi Amini   }
3531020150eSMehdi Amini   void afterExecute(const ActionActiveStack *action) override {
3541020150eSMehdi Amini     auto &state = getGlobalDebuggerState();
3551020150eSMehdi Amini     state.actionActiveStack = action->getParent();
3561020150eSMehdi Amini     state.cursor = nullptr;
3571020150eSMehdi Amini   }
3581020150eSMehdi Amini };
3591020150eSMehdi Amini } // namespace
3601020150eSMehdi Amini 
3611020150eSMehdi Amini void mlir::setupDebuggerExecutionContextHook(
3621020150eSMehdi Amini     tracing::ExecutionContext &executionContext) {
3631020150eSMehdi Amini   executionContext.setCallback(debuggerCallBackFunction);
3641020150eSMehdi Amini   DebuggerState &state = getGlobalDebuggerState();
3651020150eSMehdi Amini   static DebuggerObserver observer;
3661020150eSMehdi Amini   executionContext.registerObserver(&observer);
3671020150eSMehdi Amini   executionContext.addBreakpointManager(&state.fileLineColLocBreakpointManager);
3681020150eSMehdi Amini   executionContext.addBreakpointManager(&state.tagBreakpointManager);
3691020150eSMehdi Amini }
370