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: I399b9b2b05a147aa6b41463714ed3a39534b1fc8
This commit is contained in:
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);
|
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_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
|
||||||
static int hwthread_smp_init(struct target *target);
|
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)
|
#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_thread_reg_list = hwthread_get_thread_reg_list,
|
||||||
.get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
|
.get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
|
||||||
.smp_init = hwthread_smp_init,
|
.smp_init = hwthread_smp_init,
|
||||||
|
.set_reg = hwthread_set_reg,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hwthread_params {
|
struct hwthread_params {
|
||||||
|
@ -201,44 +203,33 @@ static int hwthread_smp_init(struct target *target)
|
||||||
return hwthread_update_threads(target->rtos);
|
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)
|
/* Find the thread with that thread_id */
|
||||||
return pos;
|
if (target == NULL)
|
||||||
else
|
return NULL;
|
||||||
return len - 1 - pos;
|
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,
|
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 rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
|
||||||
{
|
{
|
||||||
struct target_list *head;
|
|
||||||
struct target *target;
|
|
||||||
struct target *curr;
|
|
||||||
|
|
||||||
if (rtos == NULL)
|
if (rtos == NULL)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
target = rtos->target;
|
struct target *target = rtos->target;
|
||||||
|
|
||||||
/* Find the thread with that thread_id */
|
struct target *curr = find_thread(target, thread_id);
|
||||||
if (target->smp) {
|
if (curr == NULL)
|
||||||
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;
|
return ERROR_FAIL;
|
||||||
} else {
|
|
||||||
curr = target;
|
|
||||||
if (thread_id != threadid_from_target(curr))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!target_was_examined(curr))
|
if (!target_was_examined(curr))
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -266,6 +257,32 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
||||||
return ERROR_OK;
|
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[])
|
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 */
|
/* 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)
|
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 *target = get_target_from_connection(connection);
|
||||||
struct target_list *head;
|
|
||||||
struct target *curr;
|
|
||||||
|
|
||||||
if (target->smp) {
|
struct target *curr = find_thread(target, thread_id);
|
||||||
/* Find the thread with that thread_id */
|
if (curr == NULL)
|
||||||
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;
|
return ERROR_FAIL;
|
||||||
} else {
|
|
||||||
curr = target;
|
|
||||||
if (thread_id != threadid_from_target(curr))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p_target = curr;
|
*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_thread = threadid_from_target(target);
|
||||||
|
|
||||||
target->rtos->current_threadid = current_threadid;
|
target->rtos->current_threadid = current_threadid;
|
||||||
|
LOG_DEBUG(">>> current_threadid=%ld", current_threadid);
|
||||||
|
|
||||||
gdb_put_packet(connection, "OK", 2);
|
gdb_put_packet(connection, "OK", 2);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
|
@ -535,6 +535,21 @@ int rtos_get_gdb_reg_list(struct connection *connection)
|
||||||
return ERROR_FAIL;
|
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,
|
int rtos_generic_stack_read(struct target *target,
|
||||||
const struct rtos_register_stacking *stacking,
|
const struct rtos_register_stacking *stacking,
|
||||||
int64_t stack_ptr,
|
int64_t stack_ptr,
|
||||||
|
|
|
@ -76,6 +76,7 @@ struct rtos_type {
|
||||||
int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]);
|
int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]);
|
||||||
int (*clean)(struct target *target);
|
int (*clean)(struct target *target);
|
||||||
char * (*ps_command)(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 {
|
struct stack_register_offset {
|
||||||
|
@ -105,6 +106,8 @@ struct rtos_register_stacking {
|
||||||
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40)
|
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40)
|
||||||
|
|
||||||
int rtos_create(Jim_GetOptInfo *goi, struct target *target);
|
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,
|
int rtos_generic_stack_read(struct target *target,
|
||||||
const struct rtos_register_stacking *stacking,
|
const struct rtos_register_stacking *stacking,
|
||||||
int64_t stack_ptr,
|
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);
|
struct target *target = get_target_from_connection(connection);
|
||||||
char *separator;
|
char *separator;
|
||||||
uint8_t *bin_buf;
|
|
||||||
int reg_num = strtoul(packet + 1, &separator, 16);
|
int reg_num = strtoul(packet + 1, &separator, 16);
|
||||||
struct reg **reg_list;
|
struct reg **reg_list;
|
||||||
int reg_list_size;
|
int reg_list_size;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
#ifdef _DEBUG_GDB_IO_
|
||||||
LOG_DEBUG("-");
|
LOG_DEBUG("-");
|
||||||
|
#endif
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*separator != '=') {
|
if (*separator != '=') {
|
||||||
LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
|
LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
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) */
|
if ((target->rtos != NULL) &&
|
||||||
bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8));
|
(ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) {
|
||||||
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);
|
|
||||||
free(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;
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue