rtos: support gdb_get_register_packet

This patch adds support for p packet responses by targets configured
with RTOS support. This change required moving to a rtos_reg struct,
which is similar to struct reg used by targets, which resulted in
needing to update each stacking with register numbers. This patch also
allows targets with non-linear register numbers to function with RTOSes
as well.

Change-Id: I5b189d74110d6b6f2fa851a67ab0762ae6b1832f
Signed-off-by: Steven Stallion <stallion@squareup.com>
Reviewed-on: http://openocd.zylin.com/4121
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
This commit is contained in:
Steven Stallion
2017-05-03 12:46:11 -05:00
committed by Matthias Welwarsky
parent b5964191f0
commit d92adf8abf
18 changed files with 470 additions and 471 deletions

View File

@@ -435,6 +435,68 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
return GDB_THREAD_PACKET_NOT_CONSUMED;
}
static int rtos_put_gdb_reg_list(struct connection *connection,
struct rtos_reg *reg_list, int num_regs)
{
size_t num_bytes = 1; /* NUL */
for (int i = 0; i < num_regs; ++i)
num_bytes += DIV_ROUND_UP(reg_list[i].size, 8) * 2;
char *hex = malloc(num_bytes);
char *hex_p = hex;
for (int i = 0; i < num_regs; ++i) {
size_t count = DIV_ROUND_UP(reg_list[i].size, 8);
size_t n = hexify(hex_p, reg_list[i].value, count, num_bytes);
hex_p += n;
num_bytes -= n;
}
gdb_put_packet(connection, hex, strlen(hex));
free(hex);
return ERROR_OK;
}
int rtos_get_gdb_reg(struct connection *connection, int reg_num)
{
struct target *target = get_target_from_connection(connection);
int64_t current_threadid = target->rtos->current_threadid;
if ((target->rtos != NULL) && (current_threadid != -1) &&
(current_threadid != 0) &&
((current_threadid != target->rtos->current_thread) ||
(target->smp))) { /* in smp several current thread are possible */
struct rtos_reg *reg_list;
int num_regs;
LOG_DEBUG("RTOS: getting register %d for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64 "\r\n",
reg_num,
current_threadid,
target->rtos->current_thread);
int retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid,
&reg_list,
&num_regs);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
}
for (int i = 0; i < num_regs; ++i) {
if (reg_list[i].number == (uint32_t)reg_num) {
rtos_put_gdb_reg_list(connection, reg_list + i, 1);
free(reg_list);
return ERROR_OK;
}
}
free(reg_list);
}
return ERROR_FAIL;
}
int rtos_get_gdb_reg_list(struct connection *connection)
{
struct target *target = get_target_from_connection(connection);
@@ -443,7 +505,8 @@ int rtos_get_gdb_reg_list(struct connection *connection)
(current_threadid != 0) &&
((current_threadid != target->rtos->current_thread) ||
(target->smp))) { /* in smp several current thread are possible */
char *hex_reg_list;
struct rtos_reg *reg_list;
int num_regs;
LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64 "\r\n",
@@ -452,17 +515,17 @@ int rtos_get_gdb_reg_list(struct connection *connection)
int retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid,
&hex_reg_list);
&reg_list,
&num_regs);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
}
if (hex_reg_list != NULL) {
gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
free(hex_reg_list);
return ERROR_OK;
}
rtos_put_gdb_reg_list(connection, reg_list, num_regs);
free(reg_list);
return ERROR_OK;
}
return ERROR_FAIL;
}
@@ -470,12 +533,9 @@ int rtos_get_gdb_reg_list(struct connection *connection)
int rtos_generic_stack_read(struct target *target,
const struct rtos_register_stacking *stacking,
int64_t stack_ptr,
char **hex_reg_list)
struct rtos_reg **reg_list,
int *num_regs)
{
int list_size = 0;
char *tmp_str_ptr;
int64_t new_stack_ptr;
int i;
int retval;
if (stack_ptr == 0) {
@@ -502,10 +562,8 @@ int rtos_generic_stack_read(struct target *target,
LOG_OUTPUT("%02X", stack_data[i]);
LOG_OUTPUT("\r\n");
#endif
for (i = 0; i < stacking->num_output_registers; i++)
list_size += stacking->register_offsets[i].width_bits/8;
*hex_reg_list = malloc(list_size*2 + 1);
tmp_str_ptr = *hex_reg_list;
int64_t new_stack_ptr;
if (stacking->calculate_process_stack != NULL) {
new_stack_ptr = stacking->calculate_process_stack(target,
stack_data, stacking, stack_ptr);
@@ -513,19 +571,21 @@ int rtos_generic_stack_read(struct target *target,
new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
stacking->stack_registers_size;
}
for (i = 0; i < stacking->num_output_registers; i++) {
int j;
for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
if (stacking->register_offsets[i].offset == -1)
tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
else if (stacking->register_offsets[i].offset == -2)
tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
((uint8_t *)&new_stack_ptr)[j]);
else
tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
stack_data[stacking->register_offsets[i].offset + j]);
}
*reg_list = calloc(stacking->num_output_registers, sizeof(struct rtos_reg));
*num_regs = stacking->num_output_registers;
for (int i = 0; i < stacking->num_output_registers; ++i) {
(*reg_list)[i].number = stacking->register_offsets[i].number;
(*reg_list)[i].size = stacking->register_offsets[i].width_bits;
int offset = stacking->register_offsets[i].offset;
if (offset == -2)
buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size);
else if (offset != -1)
buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size);
}
free(stack_data);
/* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
return ERROR_OK;