gdbstub: add multiprocess support to '?' packets
The gdb_get_cpu_pid() function does the PID lookup for the given CPU. It checks if the CPU is a direct child of a CPU cluster. If it is, the returned PID is the cluster ID plus one (cluster IDs start at 0, GDB PIDs at 1). When the CPU is not a child of such a container, the PID of the default process is returned. The gdb_fmt_thread_id() function generates the string to be used to identify a given thread, in a response packet for the peer. This function supports generating thread IDs when multiprocess mode is enabled (in the form `p<pid>.<tid>'). Use them in the reply to a '?' request. Signed-off-by: Luc Michel <luc.michel@greensocs.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 20181207090135.7651-4-luc.michel@greensocs.com [PMM: fixed checkpatch blockquote style nit] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
8f46863618
commit
1a22733697
66
gdbstub.c
66
gdbstub.c
|
@ -640,6 +640,54 @@ static int memtox(char *buf, const char *mem, int len)
|
||||||
return p - buf;
|
return p - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
|
||||||
|
{
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
gchar *path, *name = NULL;
|
||||||
|
Object *obj;
|
||||||
|
CPUClusterState *cluster;
|
||||||
|
uint32_t ret;
|
||||||
|
|
||||||
|
path = object_get_canonical_path(OBJECT(cpu));
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
/* Return the default process' PID */
|
||||||
|
ret = s->processes[s->process_num - 1].pid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = object_get_canonical_path_component(OBJECT(cpu));
|
||||||
|
assert(name != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the CPU parent path by removing the last '/' and the CPU name
|
||||||
|
* from the CPU canonical path.
|
||||||
|
*/
|
||||||
|
path[strlen(path) - strlen(name) - 1] = '\0';
|
||||||
|
|
||||||
|
obj = object_resolve_path_type(path, TYPE_CPU_CLUSTER, NULL);
|
||||||
|
|
||||||
|
if (obj == NULL) {
|
||||||
|
/* Return the default process' PID */
|
||||||
|
ret = s->processes[s->process_num - 1].pid;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster = CPU_CLUSTER(obj);
|
||||||
|
ret = cluster->cluster_id + 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free(name);
|
||||||
|
g_free(path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* TODO: In user mode, we should use the task state PID */
|
||||||
|
return s->processes[s->process_num - 1].pid;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static const char *get_feature_xml(const char *p, const char **newp,
|
static const char *get_feature_xml(const char *p, const char **newp,
|
||||||
CPUClass *cc)
|
CPUClass *cc)
|
||||||
{
|
{
|
||||||
|
@ -909,6 +957,19 @@ static CPUState *find_cpu(uint32_t thread_id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
|
||||||
|
char *buf, size_t buf_size)
|
||||||
|
{
|
||||||
|
if (s->multiprocess) {
|
||||||
|
snprintf(buf, buf_size, "p%02x.%02x",
|
||||||
|
gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
static int is_query_packet(const char *p, const char *query, char separator)
|
static int is_query_packet(const char *p, const char *query, char separator)
|
||||||
{
|
{
|
||||||
unsigned int query_len = strlen(query);
|
unsigned int query_len = strlen(query);
|
||||||
|
@ -1020,6 +1081,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||||
int ch, reg_size, type, res;
|
int ch, reg_size, type, res;
|
||||||
uint8_t mem_buf[MAX_PACKET_LENGTH];
|
uint8_t mem_buf[MAX_PACKET_LENGTH];
|
||||||
char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
|
char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
|
||||||
|
char thread_id[16];
|
||||||
uint8_t *registers;
|
uint8_t *registers;
|
||||||
target_ulong addr, len;
|
target_ulong addr, len;
|
||||||
|
|
||||||
|
@ -1030,8 +1092,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case '?':
|
case '?':
|
||||||
/* TODO: Make this return the correct value for user-mode. */
|
/* TODO: Make this return the correct value for user-mode. */
|
||||||
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
|
snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
|
||||||
cpu_gdb_index(s->c_cpu));
|
gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
|
||||||
put_packet(s, buf);
|
put_packet(s, buf);
|
||||||
/* Remove all the breakpoints when this query is issued,
|
/* Remove all the breakpoints when this query is issued,
|
||||||
* because gdb is doing and initial connect and the state
|
* because gdb is doing and initial connect and the state
|
||||||
|
|
Loading…
Reference in New Issue