Added color and history to cheriot debug cli PiperOrigin-RevId: 903386333 Change-Id: I1a059cfbde451479c43f14206adf4fc8abbf5e9a
diff --git a/MODULE.bazel b/MODULE.bazel index 4655aa1..dfbae2f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -57,6 +57,10 @@ name = "rules_cc", version = "0.1.3", ) +bazel_dep( + name = "linenoise", + version = "2.0.0", +) sim_deps = use_extension( "@mpact-sim//:extensions.bzl",
diff --git a/cheriot/BUILD b/cheriot/BUILD index b05d113..e430887 100644 --- a/cheriot/BUILD +++ b/cheriot/BUILD
@@ -556,6 +556,7 @@ "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", "@com_googlesource_code_re2//:re2", + "@linenoise", "@mpact-riscv//riscv:stoull_wrapper", "@mpact-sim//mpact/sim/generic:core", "@mpact-sim//mpact/sim/generic:core_debug_interface",
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc index d1dff0f..801c793 100644 --- a/cheriot/cheriot_state.cc +++ b/cheriot/cheriot_state.cc
@@ -195,7 +195,7 @@ // minstret/minstreth auto* minstret = CreateCsr<RiscVCounterCsr<T, CheriotState>>( - state, csr_vec, "minstret", RiscVCsrEnum ::kMInstret, state); + state, csr_vec, "minstret", RiscVCsrEnum::kMInstret, state); CHECK_NE(minstret, nullptr); auto minstreth = CreateCsr<RiscVCounterCsrHigh<CheriotState>>( state, csr_vec, "minstreth", RiscVCsrEnum::kMInstretH, state, @@ -237,7 +237,7 @@ // User level CSRs // instret/instreth CHECK_NE(CreateCsr<RiscVShadowCsr<T>>( - state, csr_vec, "instret", RiscVCsrEnum ::kInstret, + state, csr_vec, "instret", RiscVCsrEnum::kInstret, std::numeric_limits<T>::max(), 0, state, minstret), nullptr); CHECK_NE(CreateCsr<RiscVShadowCsr<T>>(
diff --git a/cheriot/debug_command_shell.cc b/cheriot/debug_command_shell.cc index 613834d..fb1db03 100644 --- a/cheriot/debug_command_shell.cc +++ b/cheriot/debug_command_shell.cc
@@ -15,6 +15,7 @@ #include "cheriot/debug_command_shell.h" #include <cstdint> +#include <cstdlib> #include <cstring> #include <fstream> #include <functional> @@ -39,6 +40,7 @@ #include "cheriot/cheriot_top.h" #include "cheriot/riscv_cheriot_enums.h" #include "cheriot/riscv_cheriot_register_aliases.h" +#include "linenoise.h" #include "mpact/sim/generic/core_debug_interface.h" #include "mpact/sim/generic/data_buffer.h" #include "mpact/sim/generic/instruction.h" @@ -261,11 +263,12 @@ absl::string_view line_view; bool halt_reason = false; int last_info_list_size = 0; + linenoiseHistorySetMaxLen(1000); while (true) { // Prompt and read in the next command. auto pcc_result = core_access_[current_core_].debug_interface->ReadRegister("pcc"); - std::string prompt; + std::string pre_prompt; if (halt_reason) { halt_reason = false; auto result = @@ -273,49 +276,53 @@ if (result.ok()) { switch (result.value()) { case *HaltReason::kSoftwareBreakpoint: - absl::StrAppend(&prompt, "Stopped at software breakpoint\n"); + absl::StrAppend(&pre_prompt, "Stopped at software breakpoint\n"); break; case *HaltReason::kUserRequest: - absl::StrAppend(&prompt, "Stopped at user request\n"); + absl::StrAppend(&pre_prompt, "Stopped at user request\n"); break; case *HaltReason::kDataWatchPoint: - absl::StrAppend(&prompt, "Stopped at data watchpoint\n"); + absl::StrAppend(&pre_prompt, "Stopped at data watchpoint\n"); break; case InterruptListener::kInterruptTaken: - absl::StrAppend(&prompt, "Stopped at taken interrupt\n"); + absl::StrAppend(&pre_prompt, "Stopped at taken interrupt\n"); break; case InterruptListener::kInterruptReturn: - absl::StrAppend(&prompt, + absl::StrAppend(&pre_prompt, "Stopped at return from interrupt handler\n"); break; case InterruptListener::kExceptionTaken: - absl::StrAppend(&prompt, "Stopped at exception\n"); + absl::StrAppend(&pre_prompt, "Stopped at exception\n"); break; case InterruptListener::kExceptionReturn: - absl::StrAppend(&prompt, "Stopped at return exception handler\n"); + absl::StrAppend(&pre_prompt, + "Stopped at return exception handler\n"); break; case *HaltReason::kProgramDone: - absl::StrAppend(&prompt, "Program done\n"); + absl::StrAppend(&pre_prompt, "Program done\n"); break; default: if ((result.value() >= *HaltReason::kUserSpecifiedMin) && (result.value() <= *HaltReason::kUserSpecifiedMax)) { - absl::StrAppend(&prompt, "Stopped for custom halt reason\n"); + absl::StrAppend(&pre_prompt, "Stopped for custom halt reason\n"); } break; } } } + std::string prompt; if (pcc_result.ok()) { auto* loader = core_access_[current_core_].loader_getter(); if (loader != nullptr) { auto fcn_result = loader->GetFunctionName(pcc_result.value()); if (fcn_result.ok()) { - absl::StrAppend(&prompt, "[", fcn_result.value(), "]:\n"); + absl::StrAppend(&pre_prompt, kSymbolColor, "[", fcn_result.value(), + "]:\n", kDefaultColor); } auto symbol_result = loader->GetFcnSymbolName(pcc_result.value()); if (symbol_result.ok()) { - absl::StrAppend(&prompt, symbol_result.value(), ":\n"); + absl::StrAppend(&pre_prompt, kSymbolColor, symbol_result.value(), + ":\n", kDefaultColor); } } absl::StrAppend(&prompt, @@ -324,9 +331,10 @@ core_access_[current_core_].debug_interface->GetDisassembly( pcc_result.value()); if (disasm_result.ok()) { - absl::StrAppend(&prompt, " ", disasm_result.value()); + absl::StrAppend(&pre_prompt, " ", kTextColor, disasm_result.value(), + kDefaultColor); } - absl::StrAppend(&prompt, "\n"); + absl::StrAppend(&pre_prompt, "\n"); } auto cheriot_state = static_cast<CheriotState*>(core_access_[current_core_].state); @@ -334,12 +342,15 @@ // Check if there is a new interrupt, if so print the info. if (info_list.size() > last_info_list_size) { auto const& info = *info_list.rbegin(); - absl::StrAppend(&prompt, info.is_interrupt ? "interrupt " : "exception ", + absl::StrAppend(&pre_prompt, + info.is_interrupt ? "interrupt " : "exception ", info.is_interrupt ? GetInterruptDescription(info) : GetExceptionDescription(info)); } last_info_list_size = info_list.size(); - absl::StrAppend(&prompt, "[", current_core_, "] > "); + + if (!pre_prompt.empty()) absl::StrAppend(&pre_prompt, "\n"); + absl::StrAppend(&prompt, " [", current_core_, "] > "); while (!command_streams_.empty()) { auto& current_is = *command_streams_.back(); // Ignore comments or empty lines. @@ -347,8 +358,18 @@ // Read a command from the input stream. If it's from a file, then ignore // empty lines and comments. do { - if (command_streams_.size() == 1) os << prompt; - current_is.getline(line, kLineSize); + if (command_streams_.size() == 1) { + os << pre_prompt; + char* line_c = linenoise(prompt.c_str()); + if (line_c != nullptr) { + absl::SNPrintF(line, kLineSize, "%s", line_c); + free(line_c); + } else { + line[0] = '\0'; + } + } else { + current_is.getline(line, kLineSize); + } } while ((is_file && RE2::FullMatch(line, *empty_re_)) && !current_is.bad() && !current_is.eof()); @@ -378,6 +399,7 @@ if (line[0] != '\0') { previous_line = line; + linenoiseHistoryAdd(line); } line_view = absl::string_view(previous_line); @@ -1638,11 +1660,12 @@ values[6] & PB::kPermitUnseal ? "U" : "-", values[6] & PB::kUserPerm0 ? "0" : "-"); absl::StrAppend( - &output, + &output, kValueColor, absl::StrFormat( "%-5s = 0x%08x (v: %1x 0x%08x-0x%09x l: 0x%09x o: 0x%x p: %s)", reg_name, values[0], values[1], values[2], values[3], values[4], - obj_type, permissions)); + obj_type, permissions), + kDefaultColor); return output; } @@ -1660,7 +1683,8 @@ auto result = core_access_[current_core_].debug_interface->ReadRegister(reg_name); if (result.ok()) { - absl::StrAppend(&output, reg_name, " = ", absl::Hex(result.value())); + absl::StrAppend(&output, kValueColor, reg_name, " = ", + absl::Hex(result.value()), kDefaultColor); } else { absl::StrAppend(&output, "Error reading '", reg_name, "': ", result.status().message());
diff --git a/cheriot/debug_command_shell.h b/cheriot/debug_command_shell.h index 36d52d1..bf5a108 100644 --- a/cheriot/debug_command_shell.h +++ b/cheriot/debug_command_shell.h
@@ -251,6 +251,11 @@ std::vector<absl::btree_map<int, ActionPointInfo>> core_action_point_info_; std::vector<int> core_action_point_id_; std::vector<InterruptListener*> interrupt_listeners_; + + static constexpr absl::string_view kTextColor = "\033[38;5;58m"; + static constexpr absl::string_view kSymbolColor = "\033[38;5;21m"; + static constexpr absl::string_view kValueColor = "\033[38;5;27m"; + static constexpr absl::string_view kDefaultColor = "\033[0m"; }; } // namespace cheriot