Modified CoreAccess to allow for loaders being available after initial setup.

This changes the loader member from an Elf loader pointer, to a function
that returns an Elf loader pointer.

PiperOrigin-RevId: 639096497
Change-Id: Ia629d958b155d4e78660afb651116c36bbe35461
diff --git a/cheriot/cheriot_instrumentation_control.cc b/cheriot/cheriot_instrumentation_control.cc
index 51cb100..203285f 100644
--- a/cheriot/cheriot_instrumentation_control.cc
+++ b/cheriot/cheriot_instrumentation_control.cc
@@ -114,11 +114,12 @@
       return true;
     }
     // Let's see if it is a symbol.
-    if (core_access.loader == nullptr) {
+    auto *loader = core_access.loader_getter();
+    if (loader == nullptr) {
       output = "Error: cannot perform symbol lookup";
       return true;
     }
-    auto result = core_access.loader->GetSymbol(where);
+    auto result = loader->GetSymbol(where);
     if (!result.ok()) {
       output = absl::StrCat("Error: symbol ", where, " not found");
       return true;
diff --git a/cheriot/cheriot_renode.cc b/cheriot/cheriot_renode.cc
index be0c484..ad96a65 100644
--- a/cheriot/cheriot_renode.cc
+++ b/cheriot/cheriot_renode.cc
@@ -462,7 +462,7 @@
         cmd_shell_, cheriot_top_, mem_profiler_);
     cmd_shell_->AddCore(
         {static_cast<CheriotDebugInterface *>(cheriot_cli_forwarder_),
-         program_loader_});
+         [this]() { return program_loader_; }});
     cmd_shell_->AddCommand(
         instrumentation_control_->Usage(),
         absl::bind_front(&CheriotInstrumentationControl::PerformShellCommand,
diff --git a/cheriot/cheriot_top.cc b/cheriot/cheriot_top.cc
index b75b5b3..5beda12 100644
--- a/cheriot/cheriot_top.cc
+++ b/cheriot/cheriot_top.cc
@@ -314,6 +314,9 @@
   if (num <= 0) {
     return absl::InvalidArgumentError("Step count must be > 0");
   }
+  if (halt_reason_ == *HaltReason::kProgramDone) {
+    return absl::FailedPreconditionError("Step: Program has completed.");
+  }
   // If the simulator is running, return with an error.
   if (run_status_ != RunStatus::kHalted) {
     return absl::FailedPreconditionError(
@@ -411,6 +414,9 @@
 }
 
 absl::Status CheriotTop::Run() {
+  if (halt_reason_ == *HaltReason::kProgramDone) {
+    return absl::FailedPreconditionError("Run: Program has completed.");
+  }
   // Verify that the core isn't running already.
   if (run_status_ == RunStatus::kRunning) {
     return absl::FailedPreconditionError(
diff --git a/cheriot/debug_command_shell.cc b/cheriot/debug_command_shell.cc
index cdde439..46ad147 100644
--- a/cheriot/debug_command_shell.cc
+++ b/cheriot/debug_command_shell.cc
@@ -84,7 +84,7 @@
       clear_watch_re_{R"(\s*watch\s+clear\s+(\w+)(\s+r|\s+w|\s+rw)?\s*)"},
       clear_watch_n_re_{R"(\s*watch\s+clear\s+\#(\d+)\s*)"},
       clear_all_watch_re_{R"(\s*watch\s+clear-all\s*)"},
-      list_action_re_{R"(\s*action\*)"},
+      list_action_re_{R"(\s*action\s*)"},
       enable_action_n_re_{R"(\s*action\s+enable\s+\*(\d+)\s*)"},
       disable_action_n_re_{R"(\s*action\s+disable\s+\*(\d+)\s*)"},
       clear_action_n_re_{R"(\s*action\s+clear\s+\*(\d+)\s*)"},
@@ -205,10 +205,10 @@
     std::string prompt;
     if (halt_reason) {
       halt_reason = false;
-      auto halt_reason =
+      auto result =
           core_access_[current_core_].debug_interface->GetLastHaltReason();
-      if (halt_reason.ok()) {
-        switch (halt_reason.value()) {
+      if (result.ok()) {
+        switch (result.value()) {
           case *HaltReason::kSoftwareBreakpoint:
             absl::StrAppend(&prompt, "Stopped at software breakpoint\n");
             break;
@@ -222,8 +222,8 @@
             absl::StrAppend(&prompt, "Program done\n");
             break;
           default:
-            if ((halt_reason.value() >= *HaltReason::kUserSpecifiedMin) &&
-                (halt_reason.value() <= *HaltReason::kUserSpecifiedMax)) {
+            if ((result.value() >= *HaltReason::kUserSpecifiedMin) &&
+                (result.value() <= *HaltReason::kUserSpecifiedMax)) {
               absl::StrAppend(&prompt, "Stopped for custom halt reason\n");
             }
             break;
@@ -231,10 +231,9 @@
       }
     }
     if (pcc_result.ok()) {
-      if (core_access_[current_core_].loader != nullptr) {
-        auto symbol_result =
-            core_access_[current_core_].loader->GetFcnSymbolName(
-                pcc_result.value());
+      auto *loader = core_access_[current_core_].loader_getter();
+      if (loader != nullptr) {
+        auto symbol_result = loader->GetFcnSymbolName(pcc_result.value());
         if (symbol_result.ok()) {
           absl::StrAppend(&prompt, symbol_result.value(), ":\n");
         }
@@ -262,6 +261,8 @@
       } while ((is_file && RE2::FullMatch(line, *empty_re_)) &&
                !current_is.bad() && !current_is.eof());
 
+      if (command_streams_.empty()) return;
+
       // If the current is at eof or gone bad, pop the stream and try the next.
       if (current_is.bad() || current_is.eof()) {
         // If it's not the only stream, delete the stream since it was allocated
@@ -384,6 +385,7 @@
       if (result.value() != count) {
         os << result.value() << " instructions executed" << std::endl;
         os.flush();
+        halt_reason = true;
       }
       continue;
     }
@@ -590,9 +592,9 @@
         bool active =
             core_access_[current_core_].debug_interface->HasBreakpoint(address);
         std::string symbol;
-        if (core_access_[current_core_].loader != nullptr) {
-          auto res =
-              core_access_[current_core_].loader->GetFcnSymbolName(address);
+        auto *loader = core_access_[current_core_].loader_getter();
+        if (loader != nullptr) {
+          auto res = loader->GetFcnSymbolName(address);
           if (res.ok()) symbol = std::move(res.value());
         }
         absl::StrAppend(&bp_list,
@@ -891,9 +893,9 @@
       for (auto const &[index, info] :
            core_access_[current_core_].watchpoint_map) {
         std::string symbol;
-        if (core_access_[current_core_].loader != nullptr) {
-          auto res = core_access_[current_core_].loader->GetFcnSymbolName(
-              info.address);
+        auto *loader = core_access_[current_core_].loader_getter();
+        if (loader != nullptr) {
+          auto res = loader->GetFcnSymbolName(info.address);
           if (res.ok()) symbol = std::move(res.value());
         }
         std::string access_type;
@@ -1398,9 +1400,10 @@
     return convert_result.status();
   }
   // If all else fails, let's see if it's a symbol.
-  if (core_access_[current_core_].loader == nullptr)
-    return absl::NotFoundError("Symbol not found");
-  auto result = core_access_[current_core_].loader->GetSymbol(str_value);
+  auto *loader = core_access_[core].loader_getter();
+  if (loader == nullptr)
+    return absl::NotFoundError("No symbol table available");
+  auto result = loader->GetSymbol(str_value);
   if (!result.ok()) return result.status();
   return result.value().first;
 }
diff --git a/cheriot/mpact_cheriot.cc b/cheriot/mpact_cheriot.cc
index 51673c2..81b7a7f 100644
--- a/cheriot/mpact_cheriot.cc
+++ b/cheriot/mpact_cheriot.cc
@@ -434,7 +434,7 @@
   CheriotInstrumentationControl *cheriot_instrumentation_control = nullptr;
   if (interactive) {
     mpact::sim::cheriot::DebugCommandShell cmd_shell;
-    cmd_shell.AddCore({&cheriot_top, &elf_loader});
+    cmd_shell.AddCore({&cheriot_top, [&elf_loader]() { return &elf_loader; }});
     cheriot_instrumentation_control = new CheriotInstrumentationControl(
         &cmd_shell, &cheriot_top, memory_use_profiler);
     // Add custom command to interactive debug command shell.