server/gdb_server: Add support for default thread, use by IDA debugger
Signed-off-by: Benoit Forgette <benoit.forgette@ci-yow.com> Change-Id: Ia3a29a3377be650f0ccad11a0ae4fe4da78b3ab4 Reviewed-on: https://review.openocd.org/c/openocd/+/7017 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
c271958850
commit
5f46de2e79
|
@ -3030,128 +3030,127 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
|
||||||
gdb_running_type = 's';
|
gdb_running_type = 's';
|
||||||
bool fake_step = false;
|
bool fake_step = false;
|
||||||
|
|
||||||
if (strncmp(parse, "s:", 2) == 0) {
|
struct target *ct = target;
|
||||||
struct target *ct = target;
|
int current_pc = 1;
|
||||||
int current_pc = 1;
|
int64_t thread_id;
|
||||||
int64_t thread_id;
|
parse++;
|
||||||
|
packet_size--;
|
||||||
|
if (parse[0] == ':') {
|
||||||
char *endp;
|
char *endp;
|
||||||
|
parse++;
|
||||||
parse += 2;
|
packet_size--;
|
||||||
packet_size -= 2;
|
|
||||||
|
|
||||||
thread_id = strtoll(parse, &endp, 16);
|
thread_id = strtoll(parse, &endp, 16);
|
||||||
if (endp) {
|
if (endp) {
|
||||||
packet_size -= endp - parse;
|
packet_size -= endp - parse;
|
||||||
parse = endp;
|
parse = endp;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
thread_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->rtos) {
|
if (target->rtos) {
|
||||||
/* FIXME: why is this necessary? rtos state should be up-to-date here already! */
|
/* FIXME: why is this necessary? rtos state should be up-to-date here already! */
|
||||||
rtos_update_threads(target);
|
rtos_update_threads(target);
|
||||||
|
|
||||||
target->rtos->gdb_target_for_threadid(connection, thread_id, &ct);
|
target->rtos->gdb_target_for_threadid(connection, thread_id, &ct);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check if the thread to be stepped is the current rtos thread
|
* check if the thread to be stepped is the current rtos thread
|
||||||
* if not, we must fake the step
|
* if not, we must fake the step
|
||||||
*/
|
*/
|
||||||
if (target->rtos->current_thread != thread_id)
|
if (target->rtos->current_thread != thread_id)
|
||||||
fake_step = true;
|
fake_step = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse[0] == ';') {
|
if (parse[0] == ';') {
|
||||||
++parse;
|
++parse;
|
||||||
--packet_size;
|
--packet_size;
|
||||||
|
|
||||||
if (parse[0] == 'c') {
|
if (parse[0] == 'c') {
|
||||||
|
parse += 1;
|
||||||
|
|
||||||
|
/* check if thread-id follows */
|
||||||
|
if (parse[0] == ':') {
|
||||||
|
int64_t tid;
|
||||||
parse += 1;
|
parse += 1;
|
||||||
|
|
||||||
/* check if thread-id follows */
|
tid = strtoll(parse, NULL, 16);
|
||||||
if (parse[0] == ':') {
|
if (tid == thread_id) {
|
||||||
int64_t tid;
|
/*
|
||||||
parse += 1;
|
* Special case: only step a single thread (core),
|
||||||
|
* keep the other threads halted. Currently, only
|
||||||
tid = strtoll(parse, &endp, 16);
|
* aarch64 target understands it. Other target types don't
|
||||||
if (tid == thread_id) {
|
* care (nobody checks the actual value of 'current')
|
||||||
/*
|
* and it doesn't really matter. This deserves
|
||||||
* Special case: only step a single thread (core),
|
* a symbolic constant and a formal interface documentation
|
||||||
* keep the other threads halted. Currently, only
|
* at a later time.
|
||||||
* aarch64 target understands it. Other target types don't
|
*/
|
||||||
* care (nobody checks the actual value of 'current')
|
LOG_DEBUG("request to step current core only");
|
||||||
* and it doesn't really matter. This deserves
|
/* uncomment after checking that indeed other targets are safe */
|
||||||
* a symbolic constant and a formal interface documentation
|
/*current_pc = 2;*/
|
||||||
* 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_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
|
||||||
gdb_connection->output_flag = GDB_OUTPUT_ALL;
|
gdb_connection->output_flag = GDB_OUTPUT_ALL;
|
||||||
target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
|
target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* work around an annoying gdb behaviour: when the current thread
|
* work around an annoying gdb behaviour: when the current thread
|
||||||
* is changed in gdb, it assumes that the target can follow and also
|
* is changed in gdb, it assumes that the target can follow and also
|
||||||
* make the thread current. This is an assumption that cannot hold
|
* make the thread current. This is an assumption that cannot hold
|
||||||
* for a real target running a multi-threading OS. We just fake
|
* for a real target running a multi-threading OS. We just fake
|
||||||
* the step to not trigger an internal error in gdb. See
|
* the step to not trigger an internal error in gdb. See
|
||||||
* https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details
|
||||||
*/
|
*/
|
||||||
if (fake_step) {
|
if (fake_step) {
|
||||||
int sig_reply_len;
|
int sig_reply_len;
|
||||||
char sig_reply[128];
|
char sig_reply[128];
|
||||||
|
|
||||||
LOG_DEBUG("fake step thread %"PRIx64, thread_id);
|
LOG_DEBUG("fake step thread %"PRIx64, thread_id);
|
||||||
|
|
||||||
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply),
|
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply),
|
||||||
"T05thread:%016"PRIx64";", thread_id);
|
"T05thread:%016"PRIx64";", thread_id);
|
||||||
|
|
||||||
gdb_put_packet(connection, sig_reply, sig_reply_len);
|
gdb_put_packet(connection, sig_reply, sig_reply_len);
|
||||||
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* support for gdb_sync command */
|
/* support for gdb_sync command */
|
||||||
if (gdb_connection->sync) {
|
if (gdb_connection->sync) {
|
||||||
gdb_connection->sync = false;
|
gdb_connection->sync = false;
|
||||||
if (ct->state == TARGET_HALTED) {
|
if (ct->state == TARGET_HALTED) {
|
||||||
LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
|
LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
|
||||||
"from the target.");
|
"from the target.");
|
||||||
gdb_sig_halted(connection);
|
gdb_sig_halted(connection);
|
||||||
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
|
||||||
} 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! */
|
|
||||||
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
||||||
} else
|
} else
|
||||||
gdb_connection->frontend_state = TARGET_RUNNING;
|
gdb_connection->frontend_state = TARGET_RUNNING;
|
||||||
} else {
|
return true;
|
||||||
LOG_ERROR("Unknown vCont packet");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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! */
|
||||||
|
gdb_connection->output_flag = GDB_OUTPUT_NO;
|
||||||
|
} else
|
||||||
|
gdb_connection->frontend_state = TARGET_RUNNING;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
LOG_ERROR("Unknown vCont packet");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue