rtos support to write registers on current thread
I don't understand how it was ever possible to change the registers on a thread that's not the current active one when a halt happened. Really instead of the RTOS tracking what the currently selected thread is, it would make more sense to have gdb_server do that and simply pass it along in every call to the RTOS layer. Now MulticoreRegTest passes. Change-Id: I399b9b2b05a147aa6b41463714ed3a39534b1fc8log_output
parent
02ece46105
commit
c84d56debc
|
@ -35,6 +35,7 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
|||
struct rtos_reg **reg_list, int *num_regs);
|
||||
static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
|
||||
static int hwthread_smp_init(struct target *target);
|
||||
int hwthread_set_reg(struct rtos *rtos, int reg_num, uint8_t *reg_value);
|
||||
|
||||
#define HW_THREAD_NAME_STR_SIZE (32)
|
||||
|
||||
|
@ -53,6 +54,7 @@ const struct rtos_type hwthread_rtos = {
|
|||
.get_thread_reg_list = hwthread_get_thread_reg_list,
|
||||
.get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
|
||||
.smp_init = hwthread_smp_init,
|
||||
.set_reg = hwthread_set_reg,
|
||||
};
|
||||
|
||||
struct hwthread_params {
|
||||
|
@ -201,44 +203,33 @@ static int hwthread_smp_init(struct target *target)
|
|||
return hwthread_update_threads(target->rtos);
|
||||
}
|
||||
|
||||
static inline int gdb_reg_pos(struct target *target, int pos, int len)
|
||||
static struct target *find_thread(struct target *target, int64_t thread_id)
|
||||
{
|
||||
if (target->endianness == TARGET_LITTLE_ENDIAN)
|
||||
return pos;
|
||||
else
|
||||
return len - 1 - pos;
|
||||
/* Find the thread with that thread_id */
|
||||
if (target == NULL)
|
||||
return NULL;
|
||||
if (target->smp) {
|
||||
for (struct target_list *head = target->head; head != NULL; head = head->next) {
|
||||
if (thread_id == threadid_from_target(head->target))
|
||||
return head->target;
|
||||
}
|
||||
} else if (thread_id == threadid_from_target(target)) {
|
||||
return target;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
||||
struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
|
||||
{
|
||||
struct target_list *head;
|
||||
struct target *target;
|
||||
struct target *curr;
|
||||
|
||||
if (rtos == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
target = rtos->target;
|
||||
struct target *target = rtos->target;
|
||||
|
||||
/* Find the thread with that thread_id */
|
||||
if (target->smp) {
|
||||
curr = NULL;
|
||||
for (head = target->head; head != NULL; head = head->next) {
|
||||
curr = head->target;
|
||||
|
||||
if (thread_id == threadid_from_target(curr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (head == NULL)
|
||||
return ERROR_FAIL;
|
||||
} else {
|
||||
curr = target;
|
||||
if (thread_id != threadid_from_target(curr))
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
struct target *curr = find_thread(target, thread_id);
|
||||
if (curr == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (!target_was_examined(curr))
|
||||
return ERROR_FAIL;
|
||||
|
@ -266,6 +257,32 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int hwthread_set_reg(struct rtos *rtos, int reg_num, uint8_t *reg_value)
|
||||
{
|
||||
if (rtos == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
struct target *target = rtos->target;
|
||||
|
||||
struct target *curr = find_thread(target, rtos->current_thread);
|
||||
LOG_DEBUG(">>> found %ld: %p", rtos->current_thread, curr);
|
||||
if (curr == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
struct reg **reg_list;
|
||||
int reg_list_size;
|
||||
if (target_get_gdb_reg_list(curr, ®_list, ®_list_size,
|
||||
REG_CLASS_ALL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (reg_list_size <= reg_num) {
|
||||
LOG_ERROR("Register %d requested, but only %d registers exist.",
|
||||
reg_num, reg_list_size);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return reg_list[reg_num]->type->set(reg_list[reg_num], reg_value);
|
||||
}
|
||||
|
||||
static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
|
||||
{
|
||||
/* return an empty list, we don't have any symbols to look up */
|
||||
|
@ -277,26 +294,10 @@ static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]
|
|||
static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
struct target_list *head;
|
||||
struct target *curr;
|
||||
|
||||
if (target->smp) {
|
||||
/* Find the thread with that thread_id */
|
||||
curr = NULL;
|
||||
for (head = target->head; head != NULL; head = head->next) {
|
||||
curr = head->target;
|
||||
|
||||
if (thread_id == threadid_from_target(curr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (head == NULL)
|
||||
return ERROR_FAIL;
|
||||
} else {
|
||||
curr = target;
|
||||
if (thread_id != threadid_from_target(curr))
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
struct target *curr = find_thread(target, thread_id);
|
||||
if (curr == NULL)
|
||||
return ERROR_FAIL;
|
||||
|
||||
*p_target = curr;
|
||||
|
||||
|
@ -331,6 +332,7 @@ static int hwthread_thread_packet(struct connection *connection, const char *pac
|
|||
target->rtos->current_thread = threadid_from_target(target);
|
||||
|
||||
target->rtos->current_threadid = current_threadid;
|
||||
LOG_DEBUG(">>> current_threadid=%ld", current_threadid);
|
||||
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
return ERROR_OK;
|
||||
|
|
|
@ -535,6 +535,21 @@ int rtos_get_gdb_reg_list(struct connection *connection)
|
|||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int rtos_set_reg(struct connection *connection, int reg_num,
|
||||
uint8_t *reg_value)
|
||||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
int64_t current_threadid = target->rtos->current_threadid;
|
||||
LOG_DEBUG(">>> reg_num=%d", reg_num);
|
||||
if ((target->rtos != NULL) &&
|
||||
(target->rtos->type->set_reg != NULL) &&
|
||||
(current_threadid != -1) &&
|
||||
(current_threadid != 0)) {
|
||||
return target->rtos->type->set_reg(target->rtos, reg_num, reg_value);
|
||||
}
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int rtos_generic_stack_read(struct target *target,
|
||||
const struct rtos_register_stacking *stacking,
|
||||
int64_t stack_ptr,
|
||||
|
|
|
@ -76,6 +76,7 @@ struct rtos_type {
|
|||
int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]);
|
||||
int (*clean)(struct target *target);
|
||||
char * (*ps_command)(struct target *target);
|
||||
int (*set_reg)(struct rtos *rtos, int reg_num, uint8_t *reg_value);
|
||||
};
|
||||
|
||||
struct stack_register_offset {
|
||||
|
@ -105,6 +106,8 @@ struct rtos_register_stacking {
|
|||
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40)
|
||||
|
||||
int rtos_create(Jim_GetOptInfo *goi, struct target *target);
|
||||
int rtos_set_reg(struct connection *connection, int reg_num,
|
||||
uint8_t *reg_value);
|
||||
int rtos_generic_stack_read(struct target *target,
|
||||
const struct rtos_register_stacking *stacking,
|
||||
int64_t stack_ptr,
|
||||
|
|
|
@ -1340,37 +1340,49 @@ static int gdb_set_register_packet(struct connection *connection,
|
|||
{
|
||||
struct target *target = get_target_from_connection(connection);
|
||||
char *separator;
|
||||
uint8_t *bin_buf;
|
||||
int reg_num = strtoul(packet + 1, &separator, 16);
|
||||
struct reg **reg_list;
|
||||
int reg_list_size;
|
||||
int retval;
|
||||
|
||||
#ifdef _DEBUG_GDB_IO_
|
||||
LOG_DEBUG("-");
|
||||
|
||||
retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
|
||||
REG_CLASS_ALL);
|
||||
if (retval != ERROR_OK)
|
||||
return gdb_error(connection, retval);
|
||||
|
||||
if (reg_list_size <= reg_num) {
|
||||
LOG_ERROR("gdb requested a non-existing register");
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*separator != '=') {
|
||||
LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
}
|
||||
size_t chars = strlen(separator + 1);
|
||||
uint8_t *bin_buf = malloc(chars / 2);
|
||||
gdb_target_to_reg(target, separator + 1, chars, bin_buf);
|
||||
|
||||
/* convert from GDB-string (target-endian) to hex-string (big-endian) */
|
||||
bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8));
|
||||
int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
|
||||
|
||||
if ((unsigned int)chars != strlen(separator + 1)) {
|
||||
LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)",
|
||||
strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name);
|
||||
if ((target->rtos != NULL) &&
|
||||
(ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) {
|
||||
free(bin_buf);
|
||||
gdb_put_packet(connection, "OK", 2);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
|
||||
REG_CLASS_ALL);
|
||||
if (retval != ERROR_OK) {
|
||||
free(bin_buf);
|
||||
return gdb_error(connection, retval);
|
||||
}
|
||||
|
||||
if (reg_list_size <= reg_num) {
|
||||
LOG_ERROR("gdb requested a non-existing register");
|
||||
free(bin_buf);
|
||||
free(reg_list);
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
}
|
||||
|
||||
if (chars != (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2)) {
|
||||
LOG_ERROR("gdb sent %d bits for a %d-bit register (%s)",
|
||||
(int) chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name);
|
||||
free(bin_buf);
|
||||
free(reg_list);
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue