Merge branch 'master' into from_upstream

Conflicts:
	src/rtos/rtos.c
	src/rtos/rtos.h
	src/server/gdb_server.c

Change-Id: Icd5a8165fe111f699542530c9cb034faf30e09b2
This commit is contained in:
Tim Newsome
2018-04-09 12:17:08 -07:00
212 changed files with 8395 additions and 1608 deletions
+311 -17
View File
@@ -41,6 +41,8 @@
#include <target/breakpoints.h>
#include <target/target_request.h>
#include <target/register.h>
#include <target/target.h>
#include <target/target_type.h>
#include "server.h"
#include <flash/nor/core.h>
#include "gdb_server.h"
@@ -110,6 +112,8 @@ static char *gdb_port_next;
static void gdb_log_callback(void *priv, const char *file, unsigned line,
const char *function, const char *string);
static void gdb_sig_halted(struct connection *connection);
/* number of gdb connections, mainly to suppress gdb related debugging spam
* in helper/log.c when no gdb connections are actually active */
int gdb_actual_connections;
@@ -731,7 +735,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
} else {
if (gdb_connection->ctrl_c) {
signal_var = 0x2;
gdb_connection->ctrl_c = 0;
} else
signal_var = gdb_last_signal(target);
@@ -763,12 +766,19 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
current_thread[0] = '\0';
if (target->rtos != NULL) {
snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread);
struct target *ct;
snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";",
target->rtos->current_thread);
target->rtos->current_threadid = target->rtos->current_thread;
target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
if (!gdb_connection->ctrl_c)
signal_var = gdb_last_signal(ct);
}
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
signal_var, stop_reason, current_thread);
gdb_connection->ctrl_c = 0;
}
gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -956,9 +966,14 @@ static int gdb_new_connection(struct connection *connection)
breakpoint_clear_target(target);
watchpoint_clear_target(target);
/* clean previous rtos session if supported*/
if ((target->rtos) && (target->rtos->type->clean))
target->rtos->type->clean(target);
if (target->rtos) {
/* clean previous rtos session if supported*/
if (target->rtos->type->clean)
target->rtos->type->clean(target);
/* update threads */
rtos_update_threads(target);
}
/* remove the initial ACK from the incoming buffer */
retval = gdb_get_char(connection, &initial_ack);
@@ -1922,6 +1937,8 @@ static int gdb_memory_map(struct connection *connection,
static const char *gdb_get_reg_type_name(enum reg_type type)
{
switch (type) {
case REG_TYPE_BOOL:
return "bool";
case REG_TYPE_INT:
return "int";
case REG_TYPE_INT8:
@@ -1934,6 +1951,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
return "int64";
case REG_TYPE_INT128:
return "int128";
case REG_TYPE_UINT:
return "uint";
case REG_TYPE_UINT8:
return "uint8";
case REG_TYPE_UINT16:
@@ -1961,12 +1980,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
return "int"; /* "int" as default value */
}
static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id,
int *num_arch_defined_types)
{
int tbl_sz = *num_arch_defined_types;
if (type_id != NULL && (strcmp(type_id, ""))) {
for (int j = 0; j < (tbl_sz + 1); j++) {
if (!((*arch_defined_types_list)[j])) {
(*arch_defined_types_list)[tbl_sz++] = type_id;
*arch_defined_types_list = realloc(*arch_defined_types_list,
sizeof(char *) * (tbl_sz + 1));
(*arch_defined_types_list)[tbl_sz] = NULL;
*num_arch_defined_types = tbl_sz;
return 1;
} else {
if (!strcmp((*arch_defined_types_list)[j], type_id))
return 0;
}
}
}
return -1;
}
static int gdb_generate_reg_type_description(struct target *target,
char **tdesc, int *pos, int *size, struct reg_data_type *type)
char **tdesc, int *pos, int *size, struct reg_data_type *type,
char const **arch_defined_types_list[], int * num_arch_defined_types)
{
int retval = ERROR_OK;
if (type->type_class == REG_TYPE_CLASS_VECTOR) {
struct reg_data_type *data_type = type->reg_type_vector->type;
if (data_type->type == REG_TYPE_ARCH_DEFINED) {
if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
num_arch_defined_types))
gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
arch_defined_types_list,
num_arch_defined_types);
}
/* <vector id="id" type="type" count="count"/> */
xml_printf(&retval, tdesc, pos, size,
"<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
@@ -1974,6 +2026,20 @@ static int gdb_generate_reg_type_description(struct target *target,
type->reg_type_vector->count);
} else if (type->type_class == REG_TYPE_CLASS_UNION) {
struct reg_data_type_union_field *field;
field = type->reg_type_union->fields;
while (field != NULL) {
struct reg_data_type *data_type = field->type;
if (data_type->type == REG_TYPE_ARCH_DEFINED) {
if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
num_arch_defined_types))
gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
arch_defined_types_list,
num_arch_defined_types);
}
field = field->next;
}
/* <union id="id">
* <field name="name" type="type"/> ...
* </union> */
@@ -1981,7 +2047,6 @@ static int gdb_generate_reg_type_description(struct target *target,
"<union id=\"%s\">\n",
type->id);
struct reg_data_type_union_field *field;
field = type->reg_type_union->fields;
while (field != NULL) {
xml_printf(&retval, tdesc, pos, size,
@@ -2007,13 +2072,24 @@ static int gdb_generate_reg_type_description(struct target *target,
type->id, type->reg_type_struct->size);
while (field != NULL) {
xml_printf(&retval, tdesc, pos, size,
"<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
field->name, field->bitfield->start,
field->bitfield->end);
"<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
field->name, field->bitfield->start, field->bitfield->end,
gdb_get_reg_type_name(field->bitfield->type));
field = field->next;
}
} else {
while (field != NULL) {
struct reg_data_type *data_type = field->type;
if (data_type->type == REG_TYPE_ARCH_DEFINED) {
if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
num_arch_defined_types))
gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
arch_defined_types_list,
num_arch_defined_types);
}
}
/* <struct id="id">
* <field name="name" type="type"/> ...
* </struct> */
@@ -2044,8 +2120,9 @@ static int gdb_generate_reg_type_description(struct target *target,
field = type->reg_type_flags->fields;
while (field != NULL) {
xml_printf(&retval, tdesc, pos, size,
"<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
field->name, field->bitfield->start, field->bitfield->end);
"<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
field->name, field->bitfield->start, field->bitfield->end,
gdb_get_reg_type_name(field->bitfield->type));
field = field->next;
}
@@ -2106,11 +2183,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
struct reg **reg_list = NULL;
int reg_list_size;
char const **features = NULL;
char const **arch_defined_types = NULL;
int feature_list_size = 0;
int num_arch_defined_types = 0;
char *tdesc = NULL;
int pos = 0;
int size = 0;
arch_defined_types = calloc(1, sizeof(char *));
retval = target_get_gdb_reg_list(target, &reg_list,
&reg_list_size, REG_CLASS_ALL);
@@ -2163,8 +2244,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
if (reg_list[i]->reg_data_type != NULL) {
if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
/* generate <type... first, if there are architecture-defined types. */
gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
reg_list[i]->reg_data_type);
if (lookup_add_arch_defined_types(&arch_defined_types,
reg_list[i]->reg_data_type->id,
&num_arch_defined_types))
gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
reg_list[i]->reg_data_type,
&arch_defined_types,
&num_arch_defined_types);
type_str = reg_list[i]->reg_data_type->id;
} else {
@@ -2214,6 +2300,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
error:
free(features);
free(reg_list);
free(arch_defined_types);
if (retval == ERROR_OK)
*tdesc_out = tdesc;
@@ -2390,7 +2477,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
else
transfer_type = 'l';
*chunk = malloc(length + 2);
*chunk = malloc(length + 2 + 3);
/* Allocating extra 3 bytes prevents false positive valgrind report
* of strlen(chunk) word access:
* Invalid read of size 4
* Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */
if (*chunk == NULL) {
LOG_ERROR("Unable to allocate memory");
return ERROR_FAIL;
@@ -2498,7 +2589,7 @@ static int gdb_query_packet(struct connection *connection,
&buffer,
&pos,
&size,
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+",
"PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+",
(GDB_BUFFER_SIZE - 1),
((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
(gdb_target_desc_supported == 1) ? '+' : '-');
@@ -2587,6 +2678,185 @@ static int gdb_query_packet(struct connection *connection,
return ERROR_OK;
}
static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size)
{
struct gdb_connection *gdb_connection = connection->priv;
struct target *target = get_target_from_connection(connection);
const char *parse = packet;
int retval;
/* query for vCont supported */
if (parse[0] == '?') {
if (target->type->step != NULL) {
/* gdb doesn't accept c without C and s without S */
gdb_put_packet(connection, "vCont;c;C;s;S", 13);
return true;
}
return false;
}
if (parse[0] == ';') {
++parse;
--packet_size;
}
/* simple case, a continue packet */
if (parse[0] == 'c') {
LOG_DEBUG("target %s continue", target_name(target));
log_add_callback(gdb_log_callback, connection);
retval = target_resume(target, 1, 0, 0, 0);
if (retval == ERROR_TARGET_NOT_HALTED)
LOG_INFO("target %s was not halted when resume was requested", target_name(target));
/* poll target in an attempt to make its internal state consistent */
if (retval != ERROR_OK) {
retval = target_poll(target);
if (retval != ERROR_OK)
LOG_DEBUG("error polling target %s after failed resume", target_name(target));
}
/*
* We don't report errors to gdb here, move frontend_state to
* TARGET_RUNNING to stay in sync with gdb's expectation of the
* target state
*/
gdb_connection->frontend_state = TARGET_RUNNING;
target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
return true;
}
/* single-step or step-over-breakpoint */
if (parse[0] == 's') {
bool fake_step = false;
if (strncmp(parse, "s:", 2) == 0) {
struct target *ct = target;
int current_pc = 1;
int64_t thread_id;
char *endp;
parse += 2;
packet_size -= 2;
thread_id = strtoll(parse, &endp, 16);
if (endp != NULL) {
packet_size -= endp - parse;
parse = endp;
}
if (target->rtos != NULL) {
/* FIXME: why is this necessary? rtos state should be up-to-date here already! */
rtos_update_threads(target);
target->rtos->gdb_target_for_threadid(connection, thread_id, &ct);
/*
* check if the thread to be stepped is the current rtos thread
* if not, we must fake the step
*/
if (target->rtos->current_thread != thread_id)
fake_step = true;
}
if (parse[0] == ';') {
++parse;
--packet_size;
if (parse[0] == 'c') {
parse += 1;
packet_size -= 1;
/* check if thread-id follows */
if (parse[0] == ':') {
int64_t tid;
parse += 1;
packet_size -= 1;
tid = strtoll(parse, &endp, 16);
if (tid == thread_id) {
/*
* Special case: only step a single thread (core),
* keep the other threads halted. Currently, only
* aarch64 target understands it. Other target types don't
* care (nobody checks the actual value of 'current')
* and it doesn't really matter. This deserves
* a symbolic constant and a formal interface documentation
* at a later time.
*/
LOG_DEBUG("request to step current core only");
/* uncomment after checking that indeed other targets are safe */
/*current_pc = 2;*/
}
}
}
}
LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
log_add_callback(gdb_log_callback, connection);
target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
/*
* work around an annoying gdb behaviour: when the current thread
* is changed in gdb, it assumes that the target can follow and also
* make the thread current. This is an assumption that cannot hold
* for a real target running a multi-threading OS. We just fake
* the step to not trigger an internal error in gdb. See
* https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details
*/
if (fake_step) {
int sig_reply_len;
char sig_reply[128];
LOG_DEBUG("fake step thread %"PRIx64, thread_id);
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply),
"T05thread:%016"PRIx64";", thread_id);
gdb_put_packet(connection, sig_reply, sig_reply_len);
log_remove_callback(gdb_log_callback, connection);
return true;
}
/* support for gdb_sync command */
if (gdb_connection->sync) {
gdb_connection->sync = false;
if (ct->state == TARGET_HALTED) {
LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
"from the target.");
gdb_sig_halted(connection);
log_remove_callback(gdb_log_callback, connection);
} else
gdb_connection->frontend_state = TARGET_RUNNING;
return true;
}
retval = target_step(ct, current_pc, 0, 0);
if (retval == ERROR_TARGET_NOT_HALTED)
LOG_INFO("target %s was not halted when step was requested", target_name(ct));
/* if step was successful send a reply back to gdb */
if (retval == ERROR_OK) {
retval = target_poll(ct);
if (retval != ERROR_OK)
LOG_DEBUG("error polling target %s after successful step", target_name(ct));
/* send back signal information */
gdb_signal_reply(ct, connection);
/* stop forwarding log packets! */
log_remove_callback(gdb_log_callback, connection);
} else
gdb_connection->frontend_state = TARGET_RUNNING;
} else {
LOG_ERROR("Unknown vCont packet");
return false;
}
return true;
}
return false;
}
static int gdb_v_packet(struct connection *connection,
char const *packet, int packet_size)
{
@@ -2600,6 +2870,19 @@ static int gdb_v_packet(struct connection *connection,
return out;
}
if (strncmp(packet, "vCont", 5) == 0) {
bool handled;
packet += 5;
packet_size -= 5;
handled = gdb_handle_vcont_packet(connection, packet, packet_size);
if (!handled)
gdb_put_packet(connection, "", 0);
return ERROR_OK;
}
/* if flash programming disabled - send a empty reply */
if (gdb_flash_program == 0) {
@@ -3039,7 +3322,12 @@ static int gdb_input_inner(struct connection *connection)
if (gdb_con->ctrl_c) {
if (target->state == TARGET_RUNNING) {
retval = target_halt(target);
struct target *t = target;
if (target->rtos)
target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t);
retval = target_halt(t);
if (retval == ERROR_OK)
retval = target_poll(t);
if (retval != ERROR_OK)
target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
gdb_con->ctrl_c = 0;
@@ -3385,3 +3673,9 @@ void gdb_set_frontend_state_running(struct connection *connection)
struct gdb_connection *gdb_con = connection->priv;
gdb_con->frontend_state = TARGET_RUNNING;
}
void gdb_service_free(void)
{
free(gdb_port);
free(gdb_port_next);
}
+1
View File
@@ -36,6 +36,7 @@ struct reg;
int gdb_target_add_all(struct target *target);
int gdb_register_commands(struct command_context *command_context);
void gdb_service_free(void);
int gdb_put_packet(struct connection *connection, char *buffer, int len);
+25 -1
View File
@@ -259,7 +259,7 @@ int add_service(char *name,
c->sin.sin_family = AF_INET;
if (bindto_name == NULL)
c->sin.sin_addr.s_addr = INADDR_ANY;
c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else {
hp = gethostbyname(bindto_name);
if (hp == NULL) {
@@ -345,6 +345,21 @@ int add_service(char *name,
return ERROR_OK;
}
static void remove_connections(struct service *service)
{
struct connection *connection;
connection = service->connections;
while (connection) {
struct connection *tmp;
tmp = connection->next;
remove_connection(service, connection);
connection = tmp;
}
}
static int remove_services(void)
{
struct service *c = services;
@@ -353,6 +368,8 @@ static int remove_services(void)
while (c) {
struct service *next = c->next;
remove_connections(c);
if (c->name)
free(c->name);
@@ -624,6 +641,13 @@ int server_quit(void)
return last_signal;
}
void server_free(void)
{
tcl_service_free();
telnet_service_free();
jsp_service_free();
}
void exit_on_signal(int sig)
{
#ifndef _WIN32
+5
View File
@@ -25,6 +25,10 @@
#ifndef OPENOCD_SERVER_SERVER_H
#define OPENOCD_SERVER_SERVER_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/log.h>
#ifdef HAVE_NETINET_IN_H
@@ -78,6 +82,7 @@ int add_service(char *name, const char *port,
int server_preinit(void);
int server_init(struct command_context *cmd_ctx);
int server_quit(void);
void server_free(void);
void exit_on_signal(int);
int server_loop(struct command_context *command_context);
+6 -1
View File
@@ -157,7 +157,7 @@ static int tcl_new_connection(struct connection *connection)
connection->priv = tclc;
struct target *target = get_target_by_num(connection->cmd_ctx->current_target);
struct target *target = get_current_target(connection->cmd_ctx);
if (target != NULL)
tclc->tc_laststate = target->state;
@@ -359,3 +359,8 @@ int tcl_register_commands(struct command_context *cmd_ctx)
tcl_port = strdup("6666");
return register_commands(cmd_ctx, NULL, tcl_command_handlers);
}
void tcl_service_free(void)
{
free(tcl_port);
}
+1
View File
@@ -22,5 +22,6 @@
int tcl_init(void);
int tcl_register_commands(struct command_context *cmd_ctx);
void tcl_service_free(void);
#endif /* OPENOCD_SERVER_TCL_SERVER_H */
+5
View File
@@ -719,3 +719,8 @@ int telnet_register_commands(struct command_context *cmd_ctx)
telnet_port = strdup("4444");
return register_commands(cmd_ctx, NULL, telnet_command_handlers);
}
void telnet_service_free(void)
{
free(telnet_port);
}
+1
View File
@@ -64,5 +64,6 @@ struct telnet_service {
int telnet_init(char *banner);
int telnet_register_commands(struct command_context *command_context);
void telnet_service_free(void);
#endif /* OPENOCD_SERVER_TELNET_SERVER_H */