Commit 1a227336 authored by Luc Michel's avatar Luc Michel Committed by Peter Maydell
Browse files

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: default avatarLuc Michel <luc.michel@greensocs.com>
Acked-by: default avatarAlistair Francis <alistair.francis@wdc.com>
Reviewed-by: default avatarEdgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 20181207090135.7651-4-luc.michel@greensocs.com
[PMM: fixed checkpatch blockquote style nit]
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 8f468636
Loading
Loading
Loading
Loading
+64 −2
Original line number Diff line number Diff line
@@ -640,6 +640,54 @@ static int memtox(char *buf, const char *mem, int len)
    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,
                                   CPUClass *cc)
{
@@ -909,6 +957,19 @@ static CPUState *find_cpu(uint32_t thread_id)
    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)
{
    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;
    uint8_t mem_buf[MAX_PACKET_LENGTH];
    char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
    char thread_id[16];
    uint8_t *registers;
    target_ulong addr, len;

@@ -1030,8 +1092,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
    switch(ch) {
    case '?':
        /* TODO: Make this return the correct value for user-mode.  */
        snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
                 cpu_gdb_index(s->c_cpu));
        snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
                 gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
        put_packet(s, buf);
        /* Remove all the breakpoints when this query is issued,
         * because gdb is doing and initial connect and the state