Add command "exec_progbuf" (#795)

* Add command "exec_progbuf"

Command "exec_progbuf" allows to execute a user-specified sequence
of instructions using the program buffer.

Change-Id: If3b9614129d0b6fcbc33fade29d3d60b35e52f98
Signed-off-by: Jan Matyas <jan.matyas@codasip.com>

* Updated the doc:

- Minor reword and reorder of the sentences.
- Added information about C-instructions in progbuf.
- Fixed a typo (per the review).
- Added examples.

Change-Id: I88c9a3ff3c6b60614be7eafd3a6f21be722a77b7
Signed-off-by: Jan Matyas <jan.matyas@codasip.com>

* Cosmetic changes

Change-Id: I7135c9f435f640e189c7d7922a2702814dfd595f
Signed-off-by: Jan Matyas <jan.matyas@codasip.com>

---------

Signed-off-by: Jan Matyas <jan.matyas@codasip.com>
Co-authored-by: Jan Matyas <jan.matyas@codasip.com>
This commit is contained in:
Jan Matyas 2023-02-15 18:53:03 +01:00 committed by GitHub
parent 9cafc75678
commit 872ebb14ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 9 deletions

View File

@ -10753,6 +10753,39 @@ For details on this trigger type, see the RISC-V Debug Specification.
Clear the type 4 trigger that was set using @command{riscv itrigger set}. Clear the type 4 trigger that was set using @command{riscv itrigger set}.
@end deffn @end deffn
@subsection RISC-V Program Buffer Commands
Program Buffer is an optional feature of RISC-V targets - it is a mechanism that debuggers
can use to execute sequences of arbitrary instructions (small programs) on the target.
For details on the Program Buffer, please refer to the RISC-V Debug Specification.
@deffn {Command} {riscv exec_progbuf} inst1 [inst2 [... inst16]]
Execute the given sequence of instructions on the target using the Program Buffer.
The command can only be used on halted targets.
The instructions @var{inst1} .. @var{inst16} shall be specified in their binary form
(as 32-bit integers). In case a pair of compressed (16-bit) instructions is used,
the first instruction should be placed to the lower 16-bits of the 32-bit value.
The terminating @var{ebreak} instruction needs not be specified - it is added
automatically if needed.
@end deffn
Examples:
@example
# Execute 32-bit instructions "fence rw,rw" (0x0330000f)
# and "fence.i" (0x0000100f) using the Program Buffer,
# in this order:
riscv exec_progbuf 0x0330000f 0x0000100f
# Execute 16-bit instructions "c.addi s0,s0,1" (0x0405)
# and "c.add s1,s1,s0" (0x94a2) using the Program Buffer,
# in this order:
riscv exec_progbuf 0x94a20405
@end example
@section ARC Architecture @section ARC Architecture
@cindex ARC @cindex ARC

View File

@ -32,7 +32,8 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
int riscv_program_write(struct riscv_program *program) int riscv_program_write(struct riscv_program *program)
{ {
for (unsigned i = 0; i < program->instruction_count; ++i) { for (unsigned i = 0; i < program->instruction_count; ++i) {
LOG_DEBUG("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]); LOG_TARGET_DEBUG(program->target, "debug_buffer[%02x] = DASM(0x%08x)",
i, program->debug_buffer[i]);
if (riscv_write_debug_buffer(program->target, i, if (riscv_write_debug_buffer(program->target, i,
program->debug_buffer[i]) != ERROR_OK) program->debug_buffer[i]) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
@ -48,7 +49,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) {
if (p->writes_xreg[i]) { if (p->writes_xreg[i]) {
LOG_DEBUG("Saving register %d as used by program", (int)i); LOG_TARGET_DEBUG(t, "Saving register %d as used by program", (int)i);
int result = riscv_get_register(t, &saved_registers[i], i); int result = riscv_get_register(t, &saved_registers[i], i);
if (result != ERROR_OK) if (result != ERROR_OK)
return result; return result;
@ -56,9 +57,9 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
} }
if (riscv_program_ebreak(p) != ERROR_OK) { if (riscv_program_ebreak(p) != ERROR_OK) {
LOG_ERROR("Unable to write ebreak"); LOG_TARGET_ERROR(t, "Unable to insert ebreak into program buffer");
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", LOG_TARGET_ERROR(t, "ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]",
(int)i, p->debug_buffer[i], p->debug_buffer[i]); (int)i, p->debug_buffer[i], p->debug_buffer[i]);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -67,7 +68,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
return ERROR_FAIL; return ERROR_FAIL;
if (riscv_execute_debug_buffer(t) != ERROR_OK) { if (riscv_execute_debug_buffer(t) != ERROR_OK) {
LOG_DEBUG("Unable to execute program %p", p); LOG_TARGET_DEBUG(t, "Unable to execute program %p", p);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -175,9 +176,9 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
{ {
if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { if (p->instruction_count >= riscv_debug_buffer_size(p->target)) {
LOG_ERROR("Unable to insert instruction:"); LOG_TARGET_ERROR(p->target, "Unable to insert program into progbuf, "
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); "capacity would be exceeded (progbufsize=%d).",
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); (int)riscv_debug_buffer_size(p->target));
return ERROR_FAIL; return ERROR_FAIL;
} }

View File

@ -1700,7 +1700,7 @@ static int examine(struct target *target)
} }
/* Without knowing anything else we can at least mess with the /* Without knowing anything else we can at least mess with the
* program buffer. */ * program buffer. */
r->debug_buffer_size = info->progbufsize; r->debug_buffer_size = info->progbufsize;
int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64);

View File

@ -20,6 +20,7 @@
#include "helper/base64.h" #include "helper/base64.h"
#include "helper/time_support.h" #include "helper/time_support.h"
#include "riscv.h" #include "riscv.h"
#include "program.h"
#include "gdb_regs.h" #include "gdb_regs.h"
#include "rtos/rtos.h" #include "rtos/rtos.h"
#include "debug_defines.h" #include "debug_defines.h"
@ -3589,6 +3590,52 @@ COMMAND_HANDLER(handle_info)
return 0; return 0;
} }
COMMAND_HANDLER(riscv_exec_progbuf)
{
if (CMD_ARGC < 1 || CMD_ARGC > 16) {
LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct target *target = get_current_target(CMD_CTX);
RISCV_INFO(r);
if (r->dtm_version != 1) {
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is "
"only supported on v0.13 or v1.0 targets.");
return ERROR_FAIL;
}
if (target->state != TARGET_HALTED) {
LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute "
"program buffer, target not halted.");
return ERROR_FAIL;
}
if (riscv_debug_buffer_size(target) == 0) {
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer not implemented "
"in the target.");
return ERROR_FAIL;
}
struct riscv_program prog;
riscv_program_init(&prog, target);
for (unsigned int i = 0; i < CMD_ARGC; i++) {
riscv_insn_t instr;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], instr);
if (riscv_program_insert(&prog, instr) != ERROR_OK)
return ERROR_FAIL;
}
if (riscv_program_exec(&prog, target) == ERROR_OK)
LOG_TARGET_DEBUG(target, "exec_progbuf: Program buffer execution successful.");
else
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed.");
return ERROR_OK;
}
static const struct command_registration riscv_exec_command_handlers[] = { static const struct command_registration riscv_exec_command_handlers[] = {
{ {
.name = "dump_sample_buf", .name = "dump_sample_buf",
@ -3804,6 +3851,14 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear", .usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear",
.help = "Set or clear a single interrupt trigger." .help = "Set or clear a single interrupt trigger."
}, },
{
.name = "exec_progbuf",
.handler = riscv_exec_progbuf,
.mode = COMMAND_EXEC,
.usage = "instr1 [instr2 [... instr16]]",
.help = "Execute a sequence of 32-bit instructions using the program buffer. "
"The final ebreak instruction is added automatically, if needed."
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };