feat(sdb): support sdb
This commit is contained in:
parent
8500df8a6e
commit
e828e140cd
22 changed files with 985 additions and 44 deletions
145
npc/utils/sdb/include/console.hpp
Normal file
145
npc/utils/sdb/include/console.hpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
// cpp-readline library
|
||||
//
|
||||
// @author zmij
|
||||
// @date Nov 30, 2015
|
||||
|
||||
#ifndef CONSOLE_CONSOLE_HEADER_FILE
|
||||
#define CONSOLE_CONSOLE_HEADER_FILE
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace CppReadline {
|
||||
class Console {
|
||||
public:
|
||||
/**
|
||||
* @brief This is the function type that is used to interface with the Console class.
|
||||
*
|
||||
* These are the functions that are going to get called by Console
|
||||
* when the user types in a message. The vector will hold the
|
||||
* command elements, and the function needs to return its result.
|
||||
* The result can either be Quit (-1), OK (0), or an arbitrary
|
||||
* error (>=1).
|
||||
*/
|
||||
using Arguments = std::vector<std::string>;
|
||||
using CommandFunction = std::function<int(const Arguments &)>;
|
||||
|
||||
enum ReturnCode {
|
||||
Quit = -1,
|
||||
Ok = 0,
|
||||
Error = 1 // Or greater!
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Basic constructor.
|
||||
*
|
||||
* The Console comes with two predefined commands: "quit" and
|
||||
* "exit", which both terminate the console, "help" which prints a
|
||||
* list of all registered commands, and "run" which executes script
|
||||
* files.
|
||||
*
|
||||
* These commands can be overridden or unregistered - but remember
|
||||
* to leave at least one to quit ;).
|
||||
*
|
||||
* @param greeting This represents the prompt of the Console.
|
||||
*/
|
||||
explicit Console(std::string const &greeting);
|
||||
|
||||
/**
|
||||
* @brief Basic destructor.
|
||||
*
|
||||
* Frees the history which is been produced by GNU readline.
|
||||
*/
|
||||
~Console();
|
||||
|
||||
/**
|
||||
* @brief This function registers a new command within the Console.
|
||||
*
|
||||
* If the command already existed, it overwrites the previous entry.
|
||||
*
|
||||
* @param s The name of the command as inserted by the user.
|
||||
* @param f The function that will be called once the user writes the command.
|
||||
*/
|
||||
void registerCommand(const std::string &s, CommandFunction f);
|
||||
|
||||
/**
|
||||
* @brief This function returns a list with the currently available commands.
|
||||
*
|
||||
* @return A vector containing all registered commands names.
|
||||
*/
|
||||
std::vector<std::string> getRegisteredCommands() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the prompt for this Console.
|
||||
*
|
||||
* @param greeting The new greeting.
|
||||
*/
|
||||
void setGreeting(const std::string &greeting);
|
||||
|
||||
/**
|
||||
* @brief Gets the current prompt of this Console.
|
||||
*
|
||||
* @return The currently set greeting.
|
||||
*/
|
||||
std::string getGreeting() const;
|
||||
|
||||
/**
|
||||
* @brief This function executes an arbitrary string as if it was inserted via stdin.
|
||||
*
|
||||
* @param command The command that needs to be executed.
|
||||
*
|
||||
* @return The result of the operation.
|
||||
*/
|
||||
int executeCommand(const std::string &command);
|
||||
|
||||
/**
|
||||
* @brief This function calls an external script and executes all commands inside.
|
||||
*
|
||||
* This function stops execution as soon as any single command returns something
|
||||
* different from 0, be it a quit code or an error code.
|
||||
*
|
||||
* @param filename The pathname of the script.
|
||||
*
|
||||
* @return What the last command executed returned.
|
||||
*/
|
||||
int executeFile(const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief This function executes a single command from the user via stdin.
|
||||
*
|
||||
* @return The result of the operation.
|
||||
*/
|
||||
int readLine();
|
||||
|
||||
private:
|
||||
Console(const Console &) = delete;
|
||||
Console(Console &&) = delete;
|
||||
Console &operator=(Console const &) = delete;
|
||||
Console &operator=(Console &&) = delete;
|
||||
|
||||
struct Impl;
|
||||
using PImpl = ::std::unique_ptr<Impl>;
|
||||
PImpl pimpl_;
|
||||
|
||||
/**
|
||||
* @brief This function saves the current state so that some other Console can make use of the GNU readline facilities.
|
||||
*/
|
||||
void saveState();
|
||||
/**
|
||||
* @brief This function reserves the use of the GNU readline facilities to the calling Console instance.
|
||||
*/
|
||||
void reserveConsole();
|
||||
|
||||
// GNU newline interface to our commands.
|
||||
using commandCompleterFunction = char **(const char *text, int start,
|
||||
int end);
|
||||
using commandIteratorFunction = char *(const char *text, int state);
|
||||
|
||||
static commandCompleterFunction getCommandCompletions;
|
||||
static commandIteratorFunction commandIterator;
|
||||
};
|
||||
} // namespace CppReadline
|
||||
|
||||
#endif
|
149
npc/utils/sdb/include/sdb.hpp
Normal file
149
npc/utils/sdb/include/sdb.hpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#ifndef _SDB_SDB_HEADER_FILE_
|
||||
#define _SDB_SDB_HEADER_FILE_
|
||||
|
||||
#include <components.hpp>
|
||||
#include <console.hpp>
|
||||
#include <difftest.hpp>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <types.h>
|
||||
|
||||
namespace cr = CppReadline;
|
||||
using ret = cr::Console::ReturnCode;
|
||||
|
||||
namespace SDB {
|
||||
|
||||
enum SDBStatus {
|
||||
SDB_SUCCESS,
|
||||
SDB_WRONG_ARGUMENT,
|
||||
};
|
||||
|
||||
struct Handler {
|
||||
const std::vector<const char *> names;
|
||||
cr::Console::CommandFunction f;
|
||||
};
|
||||
|
||||
template <const DifftestInterface &funcs> class _SDBHandlers {
|
||||
using CPUState = CPUStateBase<uint32_t, 32>;
|
||||
|
||||
private:
|
||||
std::vector<Handler> all_handlers;
|
||||
|
||||
public:
|
||||
static CPUState cpu;
|
||||
|
||||
private:
|
||||
static _SDBHandlers<funcs> *instance;
|
||||
static int cmd_continue(const cr::Console::Arguments &input);
|
||||
static int cmd_step(const std::vector<std::string> &input);
|
||||
static int cmd_info_registers(const std::vector<std::string> &input);
|
||||
static int cmd_print(const std::vector<std::string> &input);
|
||||
_SDBHandlers<funcs>(std::vector<Handler> all_handlers)
|
||||
: all_handlers(all_handlers){};
|
||||
|
||||
public:
|
||||
_SDBHandlers<funcs>(const _SDBHandlers<funcs> &) = delete;
|
||||
_SDBHandlers<funcs> operator=(const _SDBHandlers<funcs> &) = delete;
|
||||
|
||||
static _SDBHandlers<funcs> *getInstance() {
|
||||
if (instance == nullptr) {
|
||||
std::vector<Handler> all_handlers{
|
||||
Handler{{"c", "continue"}, &_SDBHandlers::cmd_continue},
|
||||
Handler{{"si", "step-instruction"}, &_SDBHandlers::cmd_step},
|
||||
};
|
||||
instance = new _SDBHandlers<funcs>(all_handlers);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void registerHandlers(cr::Console *c);
|
||||
};
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
_SDBHandlers<funcs> *_SDBHandlers<funcs>::instance = nullptr;
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
CPUState _SDBHandlers<funcs>::cpu = CPUState();
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_continue(const cr::Console::Arguments &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
funcs.exec(-1);
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_step(const std::vector<std::string> &input) {
|
||||
if (input.size() > 2) {
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
}
|
||||
uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1;
|
||||
funcs.exec(step_count);
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_info_registers(
|
||||
const std::vector<std::string> &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
std::cout << _SDBHandlers<funcs>::getInstance()->cpu << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_print(const std::vector<std::string> &input) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
void _SDBHandlers<funcs>::registerHandlers(cr::Console *c) {
|
||||
for (auto &h : this->all_handlers) {
|
||||
for (auto &name : h.names) {
|
||||
c->registerCommand(name, h.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs> class SDB {
|
||||
private:
|
||||
std::unique_ptr<CppReadline::Console> c;
|
||||
using SDBHandlers = _SDBHandlers<funcs>;
|
||||
|
||||
public:
|
||||
SDB(std::string const &greeting = "\033[1;34m(npc)\033[0m ") {
|
||||
c = std::make_unique<CppReadline::Console>(greeting);
|
||||
SDBHandlers::getInstance()->registerHandlers(c.get());
|
||||
};
|
||||
|
||||
word_t reg_str2val(const char *name, bool *success) {
|
||||
try {
|
||||
*success = true;
|
||||
return SDBHandlers::getInstance()->cpu.at(name);
|
||||
} catch (std::runtime_error) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main_loop() {
|
||||
int retCode;
|
||||
do {
|
||||
retCode = c->readLine();
|
||||
// We can also change the prompt based on last return value:
|
||||
if (retCode == ret::Ok)
|
||||
c->setGreeting("\033[1;34m(npc)\033[0m ");
|
||||
else
|
||||
c->setGreeting("\033[1;31m(npc)\033[0m ");
|
||||
|
||||
if (retCode == SDB_WRONG_ARGUMENT) {
|
||||
std::cout << "Wrong argument give to command\n";
|
||||
}
|
||||
} while (retCode != ret::Quit);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // namespace SDB
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue