/**
|
/**
|
* @file
|
* @file
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* @brief Command Executor implementation.
|
* @brief Command Executor implementation.
|
*/
|
*/
|
|
|
#include <string.h>
|
#include <string.h>
|
#include "cmdexec.h"
|
#include "cmdexec.h"
|
#include "cmd/cmd_regs.h"
|
#include "cmd/cmd_regs.h"
|
#include "cmd/cmd_reg.h"
|
#include "cmd/cmd_reg.h"
|
#include "cmd/cmd_loadelf.h"
|
#include "cmd/cmd_loadelf.h"
|
|
#include "cmd/cmd_loadsrec.h"
|
#include "cmd/cmd_log.h"
|
#include "cmd/cmd_log.h"
|
#include "cmd/cmd_isrunning.h"
|
#include "cmd/cmd_isrunning.h"
|
#include "cmd/cmd_read.h"
|
#include "cmd/cmd_read.h"
|
#include "cmd/cmd_write.h"
|
#include "cmd/cmd_write.h"
|
#include "cmd/cmd_run.h"
|
#include "cmd/cmd_run.h"
|
#include "cmd/cmd_halt.h"
|
#include "cmd/cmd_halt.h"
|
#include "cmd/cmd_csr.h"
|
#include "cmd/cmd_csr.h"
|
#include "cmd/cmd_exit.h"
|
#include "cmd/cmd_exit.h"
|
#include "cmd/cmd_memdump.h"
|
#include "cmd/cmd_memdump.h"
|
#include "cmd/cmd_br.h"
|
#include "cmd/cmd_br.h"
|
#include "cmd/cmd_cpi.h"
|
#include "cmd/cmd_cpi.h"
|
#include "cmd/cmd_status.h"
|
#include "cmd/cmd_status.h"
|
#include "cmd/cmd_reset.h"
|
#include "cmd/cmd_reset.h"
|
#include "cmd/cmd_disas.h"
|
#include "cmd/cmd_disas.h"
|
#include "cmd/cmd_busutil.h"
|
#include "cmd/cmd_busutil.h"
|
#include "cmd/cmd_symb.h"
|
#include "cmd/cmd_symb.h"
|
#include "cmd/cmd_stack.h"
|
#include "cmd/cmd_stack.h"
|
|
#include "cmd/cmd_loadbin.h"
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
/** Class registration in the Core */
|
/** Class registration in the Core */
|
REGISTER_CLASS(CmdExecutor)
|
REGISTER_CLASS(CmdExecutor)
|
|
|
CmdExecutor::CmdExecutor(const char *name)
|
CmdExecutor::CmdExecutor(const char *name)
|
: IService(name) {
|
: IService(name) {
|
registerInterface(static_cast<ICmdExecutor *>(this));
|
registerInterface(static_cast<ICmdExecutor *>(this));
|
registerAttribute("Tap", &tap_);
|
registerAttribute("Tap", &tap_);
|
registerAttribute("SocInfo", &socInfo_);
|
registerAttribute("SocInfo", &socInfo_);
|
|
|
//console_.make_list(0);
|
//console_.make_list(0);
|
tap_.make_string("");
|
tap_.make_string("");
|
socInfo_.make_string("");
|
socInfo_.make_string("");
|
cmds_.make_list(0);
|
cmds_.make_list(0);
|
|
|
RISCV_mutex_init(&mutexExec_);
|
RISCV_mutex_init(&mutexExec_);
|
|
|
tmpbuf_ = new uint8_t[tmpbuf_size_ = 4096];
|
tmpbuf_ = new uint8_t[tmpbuf_size_ = 4096];
|
outbuf_ = new char[outbuf_size_ = 4096];
|
outbuf_ = new char[outbuf_size_ = 4096];
|
}
|
}
|
|
|
CmdExecutor::~CmdExecutor() {
|
CmdExecutor::~CmdExecutor() {
|
RISCV_mutex_destroy(&mutexExec_);
|
RISCV_mutex_destroy(&mutexExec_);
|
delete [] tmpbuf_;
|
delete [] tmpbuf_;
|
delete [] outbuf_;
|
delete [] outbuf_;
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
delete cmds_[i].to_iface();
|
delete cmds_[i].to_iface();
|
}
|
}
|
}
|
}
|
|
|
void CmdExecutor::postinitService() {
|
void CmdExecutor::postinitService() {
|
itap_ = static_cast<ITap *>
|
itap_ = static_cast<ITap *>
|
(RISCV_get_service_iface(tap_.to_string(), IFACE_TAP));
|
(RISCV_get_service_iface(tap_.to_string(), IFACE_TAP));
|
info_ = static_cast<ISocInfo *>
|
info_ = static_cast<ISocInfo *>
|
(RISCV_get_service_iface(socInfo_.to_string(),
|
(RISCV_get_service_iface(socInfo_.to_string(),
|
IFACE_SOC_INFO));
|
IFACE_SOC_INFO));
|
|
|
// Core commands registration:
|
// Core commands registration:
|
registerCommand(new CmdBr(itap_, info_));
|
registerCommand(new CmdBr(itap_, info_));
|
registerCommand(new CmdBusUtil(itap_, info_));
|
registerCommand(new CmdBusUtil(itap_, info_));
|
registerCommand(new CmdCpi(itap_, info_));
|
registerCommand(new CmdCpi(itap_, info_));
|
registerCommand(new CmdCsr(itap_, info_));
|
registerCommand(new CmdCsr(itap_, info_));
|
registerCommand(new CmdDisas(itap_, info_));
|
registerCommand(new CmdDisas(itap_, info_));
|
registerCommand(new CmdExit(itap_, info_));
|
registerCommand(new CmdExit(itap_, info_));
|
registerCommand(new CmdHalt(itap_, info_));
|
registerCommand(new CmdHalt(itap_, info_));
|
registerCommand(new CmdIsRunning(itap_, info_));
|
registerCommand(new CmdIsRunning(itap_, info_));
|
|
registerCommand(new CmdLoadBin(itap_, info_));
|
registerCommand(new CmdLoadElf(itap_, info_));
|
registerCommand(new CmdLoadElf(itap_, info_));
|
|
registerCommand(new CmdLoadSrec(itap_, info_));
|
registerCommand(new CmdLog(itap_, info_));
|
registerCommand(new CmdLog(itap_, info_));
|
registerCommand(new CmdMemDump(itap_, info_));
|
registerCommand(new CmdMemDump(itap_, info_));
|
registerCommand(new CmdRead(itap_, info_));
|
registerCommand(new CmdRead(itap_, info_));
|
registerCommand(new CmdRun(itap_, info_));
|
registerCommand(new CmdRun(itap_, info_));
|
registerCommand(new CmdReg(itap_, info_));
|
registerCommand(new CmdReg(itap_, info_));
|
registerCommand(new CmdRegs(itap_, info_));
|
registerCommand(new CmdRegs(itap_, info_));
|
registerCommand(new CmdReset(itap_, info_));
|
registerCommand(new CmdReset(itap_, info_));
|
registerCommand(new CmdStack(itap_, info_));
|
registerCommand(new CmdStack(itap_, info_));
|
registerCommand(new CmdStatus(itap_, info_));
|
registerCommand(new CmdStatus(itap_, info_));
|
registerCommand(new CmdSymb(itap_, info_));
|
registerCommand(new CmdSymb(itap_, info_));
|
registerCommand(new CmdWrite(itap_, info_));
|
registerCommand(new CmdWrite(itap_, info_));
|
}
|
}
|
|
|
void CmdExecutor::registerCommand(ICommand *icmd) {
|
void CmdExecutor::registerCommand(ICommand *icmd) {
|
AttributeType t1(icmd);
|
AttributeType t1(icmd);
|
cmds_.add_to_list(&t1);
|
cmds_.add_to_list(&t1);
|
}
|
}
|
|
|
void CmdExecutor::unregisterCommand(ICommand *icmd) {
|
void CmdExecutor::unregisterCommand(ICommand *icmd) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
if (cmds_[i].to_iface() == icmd) {
|
if (cmds_[i].to_iface() == icmd) {
|
cmds_.remove_from_list(i);
|
cmds_.remove_from_list(i);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
void CmdExecutor::exec(const char *line, AttributeType *res, bool silent) {
|
void CmdExecutor::exec(const char *line, AttributeType *res, bool silent) {
|
RISCV_mutex_lock(&mutexExec_);
|
RISCV_mutex_lock(&mutexExec_);
|
res->make_nil();
|
res->make_nil();
|
|
|
AttributeType cmd;
|
AttributeType cmd;
|
if (line[0] == '[' || line[0] == '}') {
|
if (line[0] == '[' || line[0] == '}') {
|
cmd.from_config(line);
|
cmd.from_config(line);
|
} else {
|
} else {
|
cmd.make_string(line);
|
cmd.make_string(line);
|
}
|
}
|
|
|
AttributeType listArgs(Attr_List), *cmd_parsed;
|
AttributeType listArgs(Attr_List), *cmd_parsed;
|
if (cmd.is_string()) {
|
if (cmd.is_string()) {
|
splitLine(const_cast<char *>(cmd.to_string()), &listArgs);
|
splitLine(const_cast<char *>(cmd.to_string()), &listArgs);
|
cmd_parsed = &listArgs;
|
cmd_parsed = &listArgs;
|
} else {
|
} else {
|
cmd_parsed = &cmd;
|
cmd_parsed = &cmd;
|
}
|
}
|
processSimple(cmd_parsed, res);
|
processSimple(cmd_parsed, res);
|
|
|
RISCV_mutex_unlock(&mutexExec_);
|
RISCV_mutex_unlock(&mutexExec_);
|
|
|
/** Do not output any information into console in silent mode: */
|
/** Do not output any information into console in silent mode: */
|
if (silent) {
|
if (silent) {
|
return;
|
return;
|
}
|
}
|
//RISCV_printf0("%s", outbuf_);
|
//RISCV_printf0("%s", outbuf_);
|
}
|
}
|
|
|
void CmdExecutor::commands(const char *substr, AttributeType *res) {
|
void CmdExecutor::commands(const char *substr, AttributeType *res) {
|
if (!res->is_list()) {
|
if (!res->is_list()) {
|
res->make_list(0);
|
res->make_list(0);
|
}
|
}
|
AttributeType item;
|
AttributeType item;
|
item.make_list(3);
|
item.make_list(3);
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
ICommand *icmd = static_cast<ICommand *>(cmds_[i].to_iface());
|
ICommand *icmd = static_cast<ICommand *>(cmds_[i].to_iface());
|
if (strstr(icmd->cmdName(), substr)) {
|
if (strstr(icmd->cmdName(), substr)) {
|
item[0u].make_string(icmd->cmdName());
|
item[0u].make_string(icmd->cmdName());
|
item[1].make_string(icmd->briefDescr());
|
item[1].make_string(icmd->briefDescr());
|
item[2].make_string(icmd->detailedDescr());
|
item[2].make_string(icmd->detailedDescr());
|
res->add_to_list(&item);
|
res->add_to_list(&item);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
void CmdExecutor::processSimple(AttributeType *cmd, AttributeType *res) {
|
void CmdExecutor::processSimple(AttributeType *cmd, AttributeType *res) {
|
outbuf_[outbuf_cnt_ = 0] = '\0';
|
outbuf_[outbuf_cnt_ = 0] = '\0';
|
if (cmd->size() == 0) {
|
if (cmd->size() == 0) {
|
return;
|
return;
|
}
|
}
|
|
|
ICommand *icmd;
|
ICommand *icmd;
|
if (!(*cmd)[0u].is_string()) {
|
if (!(*cmd)[0u].is_string()) {
|
RISCV_error("Wrong command format", NULL);
|
RISCV_error("Wrong command format", NULL);
|
return;
|
return;
|
}
|
}
|
|
|
if ((*cmd)[0u].is_equal("help")) {
|
if ((*cmd)[0u].is_equal("help")) {
|
if (cmd->size() == 1) {
|
if (cmd->size() == 1) {
|
RISCV_printf0("** List of supported commands: **", NULL);
|
RISCV_printf0("** List of supported commands: **", NULL);
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
icmd = static_cast<ICommand *>(cmds_[i].to_iface());
|
icmd = static_cast<ICommand *>(cmds_[i].to_iface());
|
RISCV_printf0("%13s - %s",
|
RISCV_printf0("%13s - %s",
|
icmd->cmdName(), icmd->briefDescr());
|
icmd->cmdName(), icmd->briefDescr());
|
}
|
}
|
} else {
|
} else {
|
const char *helpcmd = (*cmd)[1].to_string();
|
const char *helpcmd = (*cmd)[1].to_string();
|
icmd = getICommand(helpcmd);
|
icmd = getICommand(helpcmd);
|
if (icmd) {
|
if (icmd) {
|
RISCV_printf0("\n%s", icmd->detailedDescr());
|
RISCV_printf0("\n%s", icmd->detailedDescr());
|
} else {
|
} else {
|
RISCV_error("Command '%s' not found", helpcmd);
|
RISCV_error("Command \\'%s\\' not found", helpcmd);
|
}
|
}
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
AttributeType u;
|
AttributeType u;
|
icmd = getICommand(cmd);
|
icmd = getICommand(cmd);
|
if (!icmd) {
|
if (!icmd) {
|
RISCV_error("Command '%s' not found. Use 'help' to list commands",
|
RISCV_error("Command \\'%s\\' not found. "
|
(*cmd)[0u].to_string());
|
"Use \\'help\\' to list commands", (*cmd)[0u].to_string());
|
return;
|
return;
|
}
|
}
|
icmd->exec(cmd, res);
|
icmd->exec(cmd, res);
|
|
|
if (cmdIsError(res)) {
|
if (cmdIsError(res)) {
|
RISCV_error("Command '%s' error: '%s'",
|
RISCV_error("Command \\'%s\\' error: \\'%s\\'",
|
(*res)[1].to_string(), (*res)[2].to_string());
|
(*res)[1].to_string(), (*res)[2].to_string());
|
}
|
}
|
}
|
}
|
|
|
bool CmdExecutor::cmdIsError(AttributeType *res) {
|
bool CmdExecutor::cmdIsError(AttributeType *res) {
|
if (!res->is_list() || res->size() != 3) {
|
if (!res->is_list() || res->size() != 3) {
|
return false;
|
return false;
|
}
|
}
|
if (!(*res)[0u].is_string()) {
|
if (!(*res)[0u].is_string()) {
|
return false;
|
return false;
|
}
|
}
|
return (*res)[0u].is_equal("ERROR");
|
return (*res)[0u].is_equal("ERROR");
|
}
|
}
|
|
|
ICommand *CmdExecutor::getICommand(AttributeType *args) {
|
ICommand *CmdExecutor::getICommand(AttributeType *args) {
|
ICommand *ret = 0;
|
ICommand *ret = 0;
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
ret = static_cast<ICommand *>(cmds_[i].to_iface());
|
ret = static_cast<ICommand *>(cmds_[i].to_iface());
|
if (ret && (ret->isValid(args) == CMD_VALID)) {
|
if (ret && (ret->isValid(args) == CMD_VALID)) {
|
return ret;
|
return ret;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
ICommand *CmdExecutor::getICommand(const char *name) {
|
ICommand *CmdExecutor::getICommand(const char *name) {
|
ICommand *ret = 0;
|
ICommand *ret = 0;
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
for (unsigned i = 0; i < cmds_.size(); i++) {
|
ret = static_cast<ICommand *>(cmds_[i].to_iface());
|
ret = static_cast<ICommand *>(cmds_[i].to_iface());
|
if (ret && strcmp(ret->cmdName(), name) == 0) {
|
if (ret && strcmp(ret->cmdName(), name) == 0) {
|
return ret;
|
return ret;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void CmdExecutor::splitLine(char *str, AttributeType *listArgs) {
|
void CmdExecutor::splitLine(char *str, AttributeType *listArgs) {
|
char *end = str;
|
char *end = str;
|
bool last = false;
|
bool last = false;
|
bool inside_string = false;
|
bool inside_string = false;
|
char string_marker;
|
char string_marker;
|
while (*str) {
|
while (*str) {
|
if (*end == '\0') {
|
if (*end == '\0') {
|
last = true;
|
last = true;
|
} else if (*end == ' ' && !inside_string) {
|
} else if (*end == ' ' && !inside_string) {
|
*end = '\0';
|
*end = '\0';
|
while (*(end + 1) == ' ') {
|
while (*(end + 1) == ' ') {
|
*(++end) = '\0';
|
*(++end) = '\0';
|
}
|
}
|
} else if (!inside_string && (*end == '"' || *end == '\'')) {
|
} else if (!inside_string && (*end == '"' || *end == '\'')) {
|
inside_string = true;
|
inside_string = true;
|
string_marker = *end;
|
string_marker = *end;
|
} else if (inside_string && string_marker == *end) {
|
} else if (inside_string && string_marker == *end) {
|
inside_string = false;
|
inside_string = false;
|
}
|
}
|
|
|
if (*end == '\0') {
|
if (*end == '\0') {
|
AttributeType item;
|
AttributeType item;
|
if ((str[0] >= '0' && str[0] <= '9')
|
if ((str[0] >= '0' && str[0] <= '9')
|
|| (str[0] == '[') || (str[0] == '"') || (str[0] == '\'')
|
|| (str[0] == '[') || (str[0] == '"') || (str[0] == '\'')
|
|| (str[0] == '{') || (str[0] == '(')) {
|
|| (str[0] == '{') || (str[0] == '(')) {
|
item.from_config(str);
|
item.from_config(str);
|
} else {
|
} else {
|
item.make_string(str);
|
item.make_string(str);
|
}
|
}
|
listArgs->add_to_list(&item);
|
listArgs->add_to_list(&item);
|
if (!last) {
|
if (!last) {
|
splitLine(end + 1, listArgs);
|
splitLine(end + 1, listArgs);
|
}
|
}
|
break;
|
break;
|
}
|
}
|
++end;
|
++end;
|
}
|
}
|
}
|
}
|
|
|
int CmdExecutor::outf(const char *fmt, ...) {
|
int CmdExecutor::outf(const char *fmt, ...) {
|
if (outbuf_cnt_ > (outbuf_size_ - 128)) {
|
if (outbuf_cnt_ > (outbuf_size_ - 128)) {
|
char *t = new char [2*outbuf_size_];
|
char *t = new char [2*outbuf_size_];
|
memcpy(t, outbuf_, outbuf_size_);
|
memcpy(t, outbuf_, outbuf_size_);
|
delete [] outbuf_;
|
delete [] outbuf_;
|
outbuf_size_ *= 2;
|
outbuf_size_ *= 2;
|
outbuf_ = t;
|
outbuf_ = t;
|
}
|
}
|
va_list arg;
|
va_list arg;
|
va_start(arg, fmt);
|
va_start(arg, fmt);
|
outbuf_cnt_ += vsprintf(&outbuf_[outbuf_cnt_], fmt, arg);
|
outbuf_cnt_ += vsprintf(&outbuf_[outbuf_cnt_], fmt, arg);
|
va_end(arg);
|
va_end(arg);
|
return outbuf_cnt_;
|
return outbuf_cnt_;
|
}
|
}
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|