qemu/gdbstub/user-target.c
<<
>>
Prefs
   1/*
   2 * Target specific user-mode handling
   3 *
   4 * Copyright (c) 2003-2005 Fabrice Bellard
   5 * Copyright (c) 2022 Linaro Ltd
   6 *
   7 * SPDX-License-Identifier: LGPL-2.0+
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "exec/gdbstub.h"
  12#include "qemu.h"
  13#include "internals.h"
  14#ifdef CONFIG_LINUX
  15#include "linux-user/loader.h"
  16#include "linux-user/qemu.h"
  17#endif
  18
  19/*
  20 * Map target signal numbers to GDB protocol signal numbers and vice
  21 * versa.  For user emulation's currently supported systems, we can
  22 * assume most signals are defined.
  23 */
  24
  25static int gdb_signal_table[] = {
  26    0,
  27    TARGET_SIGHUP,
  28    TARGET_SIGINT,
  29    TARGET_SIGQUIT,
  30    TARGET_SIGILL,
  31    TARGET_SIGTRAP,
  32    TARGET_SIGABRT,
  33    -1, /* SIGEMT */
  34    TARGET_SIGFPE,
  35    TARGET_SIGKILL,
  36    TARGET_SIGBUS,
  37    TARGET_SIGSEGV,
  38    TARGET_SIGSYS,
  39    TARGET_SIGPIPE,
  40    TARGET_SIGALRM,
  41    TARGET_SIGTERM,
  42    TARGET_SIGURG,
  43    TARGET_SIGSTOP,
  44    TARGET_SIGTSTP,
  45    TARGET_SIGCONT,
  46    TARGET_SIGCHLD,
  47    TARGET_SIGTTIN,
  48    TARGET_SIGTTOU,
  49    TARGET_SIGIO,
  50    TARGET_SIGXCPU,
  51    TARGET_SIGXFSZ,
  52    TARGET_SIGVTALRM,
  53    TARGET_SIGPROF,
  54    TARGET_SIGWINCH,
  55    -1, /* SIGLOST */
  56    TARGET_SIGUSR1,
  57    TARGET_SIGUSR2,
  58#ifdef TARGET_SIGPWR
  59    TARGET_SIGPWR,
  60#else
  61    -1,
  62#endif
  63    -1, /* SIGPOLL */
  64    -1,
  65    -1,
  66    -1,
  67    -1,
  68    -1,
  69    -1,
  70    -1,
  71    -1,
  72    -1,
  73    -1,
  74    -1,
  75#ifdef __SIGRTMIN
  76    __SIGRTMIN + 1,
  77    __SIGRTMIN + 2,
  78    __SIGRTMIN + 3,
  79    __SIGRTMIN + 4,
  80    __SIGRTMIN + 5,
  81    __SIGRTMIN + 6,
  82    __SIGRTMIN + 7,
  83    __SIGRTMIN + 8,
  84    __SIGRTMIN + 9,
  85    __SIGRTMIN + 10,
  86    __SIGRTMIN + 11,
  87    __SIGRTMIN + 12,
  88    __SIGRTMIN + 13,
  89    __SIGRTMIN + 14,
  90    __SIGRTMIN + 15,
  91    __SIGRTMIN + 16,
  92    __SIGRTMIN + 17,
  93    __SIGRTMIN + 18,
  94    __SIGRTMIN + 19,
  95    __SIGRTMIN + 20,
  96    __SIGRTMIN + 21,
  97    __SIGRTMIN + 22,
  98    __SIGRTMIN + 23,
  99    __SIGRTMIN + 24,
 100    __SIGRTMIN + 25,
 101    __SIGRTMIN + 26,
 102    __SIGRTMIN + 27,
 103    __SIGRTMIN + 28,
 104    __SIGRTMIN + 29,
 105    __SIGRTMIN + 30,
 106    __SIGRTMIN + 31,
 107    -1, /* SIGCANCEL */
 108    __SIGRTMIN,
 109    __SIGRTMIN + 32,
 110    __SIGRTMIN + 33,
 111    __SIGRTMIN + 34,
 112    __SIGRTMIN + 35,
 113    __SIGRTMIN + 36,
 114    __SIGRTMIN + 37,
 115    __SIGRTMIN + 38,
 116    __SIGRTMIN + 39,
 117    __SIGRTMIN + 40,
 118    __SIGRTMIN + 41,
 119    __SIGRTMIN + 42,
 120    __SIGRTMIN + 43,
 121    __SIGRTMIN + 44,
 122    __SIGRTMIN + 45,
 123    __SIGRTMIN + 46,
 124    __SIGRTMIN + 47,
 125    __SIGRTMIN + 48,
 126    __SIGRTMIN + 49,
 127    __SIGRTMIN + 50,
 128    __SIGRTMIN + 51,
 129    __SIGRTMIN + 52,
 130    __SIGRTMIN + 53,
 131    __SIGRTMIN + 54,
 132    __SIGRTMIN + 55,
 133    __SIGRTMIN + 56,
 134    __SIGRTMIN + 57,
 135    __SIGRTMIN + 58,
 136    __SIGRTMIN + 59,
 137    __SIGRTMIN + 60,
 138    __SIGRTMIN + 61,
 139    __SIGRTMIN + 62,
 140    __SIGRTMIN + 63,
 141    __SIGRTMIN + 64,
 142    __SIGRTMIN + 65,
 143    __SIGRTMIN + 66,
 144    __SIGRTMIN + 67,
 145    __SIGRTMIN + 68,
 146    __SIGRTMIN + 69,
 147    __SIGRTMIN + 70,
 148    __SIGRTMIN + 71,
 149    __SIGRTMIN + 72,
 150    __SIGRTMIN + 73,
 151    __SIGRTMIN + 74,
 152    __SIGRTMIN + 75,
 153    __SIGRTMIN + 76,
 154    __SIGRTMIN + 77,
 155    __SIGRTMIN + 78,
 156    __SIGRTMIN + 79,
 157    __SIGRTMIN + 80,
 158    __SIGRTMIN + 81,
 159    __SIGRTMIN + 82,
 160    __SIGRTMIN + 83,
 161    __SIGRTMIN + 84,
 162    __SIGRTMIN + 85,
 163    __SIGRTMIN + 86,
 164    __SIGRTMIN + 87,
 165    __SIGRTMIN + 88,
 166    __SIGRTMIN + 89,
 167    __SIGRTMIN + 90,
 168    __SIGRTMIN + 91,
 169    __SIGRTMIN + 92,
 170    __SIGRTMIN + 93,
 171    __SIGRTMIN + 94,
 172    __SIGRTMIN + 95,
 173    -1, /* SIGINFO */
 174    -1, /* UNKNOWN */
 175    -1, /* DEFAULT */
 176    -1,
 177    -1,
 178    -1,
 179    -1,
 180    -1,
 181    -1
 182#endif
 183};
 184
 185int gdb_signal_to_target(int sig)
 186{
 187    if (sig < ARRAY_SIZE(gdb_signal_table)) {
 188        return gdb_signal_table[sig];
 189    } else {
 190        return -1;
 191    }
 192}
 193
 194int gdb_target_signal_to_gdb(int sig)
 195{
 196    int i;
 197    for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
 198        if (gdb_signal_table[i] == sig) {
 199            return i;
 200        }
 201    }
 202    return GDB_SIGNAL_UNKNOWN;
 203}
 204
 205int gdb_get_cpu_index(CPUState *cpu)
 206{
 207    TaskState *ts = (TaskState *) cpu->opaque;
 208    return ts ? ts->ts_tid : -1;
 209}
 210
 211/*
 212 * User-mode specific command helpers
 213 */
 214
 215void gdb_handle_query_offsets(GArray *params, void *user_ctx)
 216{
 217    TaskState *ts;
 218
 219    ts = gdbserver_state.c_cpu->opaque;
 220    g_string_printf(gdbserver_state.str_buf,
 221                    "Text=" TARGET_ABI_FMT_lx
 222                    ";Data=" TARGET_ABI_FMT_lx
 223                    ";Bss=" TARGET_ABI_FMT_lx,
 224                    ts->info->code_offset,
 225                    ts->info->data_offset,
 226                    ts->info->data_offset);
 227    gdb_put_strbuf();
 228}
 229
 230#if defined(CONFIG_LINUX)
 231/* Partial user only duplicate of helper in gdbstub.c */
 232static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
 233                                         uint8_t *buf, int len, bool is_write)
 234{
 235    CPUClass *cc;
 236    cc = CPU_GET_CLASS(cpu);
 237    if (cc->memory_rw_debug) {
 238        return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
 239    }
 240    return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
 241}
 242
 243void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
 244{
 245    TaskState *ts;
 246    unsigned long offset, len, saved_auxv, auxv_len;
 247
 248    if (params->len < 2) {
 249        gdb_put_packet("E22");
 250        return;
 251    }
 252
 253    offset = get_param(params, 0)->val_ul;
 254    len = get_param(params, 1)->val_ul;
 255    ts = gdbserver_state.c_cpu->opaque;
 256    saved_auxv = ts->info->saved_auxv;
 257    auxv_len = ts->info->auxv_len;
 258
 259    if (offset >= auxv_len) {
 260        gdb_put_packet("E00");
 261        return;
 262    }
 263
 264    if (len > (MAX_PACKET_LENGTH - 5) / 2) {
 265        len = (MAX_PACKET_LENGTH - 5) / 2;
 266    }
 267
 268    if (len < auxv_len - offset) {
 269        g_string_assign(gdbserver_state.str_buf, "m");
 270    } else {
 271        g_string_assign(gdbserver_state.str_buf, "l");
 272        len = auxv_len - offset;
 273    }
 274
 275    g_byte_array_set_size(gdbserver_state.mem_buf, len);
 276    if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
 277                               gdbserver_state.mem_buf->data, len, false)) {
 278        gdb_put_packet("E14");
 279        return;
 280    }
 281
 282    gdb_memtox(gdbserver_state.str_buf,
 283           (const char *)gdbserver_state.mem_buf->data, len);
 284    gdb_put_packet_binary(gdbserver_state.str_buf->str,
 285                      gdbserver_state.str_buf->len, true);
 286}
 287#endif
 288
 289static const char *get_filename_param(GArray *params, int i)
 290{
 291    const char *hex_filename = get_param(params, i)->data;
 292    gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
 293                 strlen(hex_filename) / 2);
 294    g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
 295    return (const char *)gdbserver_state.mem_buf->data;
 296}
 297
 298static void hostio_reply_with_data(const void *buf, size_t n)
 299{
 300    g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
 301    gdb_memtox(gdbserver_state.str_buf, buf, n);
 302    gdb_put_packet_binary(gdbserver_state.str_buf->str,
 303                          gdbserver_state.str_buf->len, true);
 304}
 305
 306void gdb_handle_v_file_open(GArray *params, void *user_ctx)
 307{
 308    const char *filename = get_filename_param(params, 0);
 309    uint64_t flags = get_param(params, 1)->val_ull;
 310    uint64_t mode = get_param(params, 2)->val_ull;
 311
 312#ifdef CONFIG_LINUX
 313    int fd = do_guest_openat(gdbserver_state.g_cpu->env_ptr, 0, filename,
 314                             flags, mode, false);
 315#else
 316    int fd = open(filename, flags, mode);
 317#endif
 318    if (fd < 0) {
 319        g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
 320    } else {
 321        g_string_printf(gdbserver_state.str_buf, "F%d", fd);
 322    }
 323    gdb_put_strbuf();
 324}
 325
 326void gdb_handle_v_file_close(GArray *params, void *user_ctx)
 327{
 328    int fd = get_param(params, 0)->val_ul;
 329
 330    if (close(fd) == -1) {
 331        g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
 332        gdb_put_strbuf();
 333        return;
 334    }
 335
 336    gdb_put_packet("F00");
 337}
 338
 339void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
 340{
 341    int fd = get_param(params, 0)->val_ul;
 342    size_t count = get_param(params, 1)->val_ull;
 343    off_t offset = get_param(params, 2)->val_ull;
 344
 345    size_t bufsiz = MIN(count, BUFSIZ);
 346    g_autofree char *buf = g_try_malloc(bufsiz);
 347    if (buf == NULL) {
 348        gdb_put_packet("E12");
 349        return;
 350    }
 351
 352    ssize_t n = pread(fd, buf, bufsiz, offset);
 353    if (n < 0) {
 354        g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
 355        gdb_put_strbuf();
 356        return;
 357    }
 358    hostio_reply_with_data(buf, n);
 359}
 360
 361void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
 362{
 363    const char *filename = get_filename_param(params, 0);
 364
 365    g_autofree char *buf = g_try_malloc(BUFSIZ);
 366    if (buf == NULL) {
 367        gdb_put_packet("E12");
 368        return;
 369    }
 370
 371#ifdef CONFIG_LINUX
 372    ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
 373#else
 374    ssize_t n = readlink(filename, buf, BUFSIZ);
 375#endif
 376    if (n < 0) {
 377        g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
 378        gdb_put_strbuf();
 379        return;
 380    }
 381    hostio_reply_with_data(buf, n);
 382}
 383
 384void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
 385{
 386    uint32_t pid = get_param(params, 0)->val_ul;
 387    uint32_t offset = get_param(params, 1)->val_ul;
 388    uint32_t length = get_param(params, 2)->val_ul;
 389
 390    GDBProcess *process = gdb_get_process(pid);
 391    if (!process) {
 392        gdb_put_packet("E00");
 393        return;
 394    }
 395
 396    CPUState *cpu = gdb_get_first_cpu_in_process(process);
 397    if (!cpu) {
 398        gdb_put_packet("E00");
 399        return;
 400    }
 401
 402    TaskState *ts = cpu->opaque;
 403    if (!ts || !ts->bprm || !ts->bprm->filename) {
 404        gdb_put_packet("E00");
 405        return;
 406    }
 407
 408    size_t total_length = strlen(ts->bprm->filename);
 409    if (offset > total_length) {
 410        gdb_put_packet("E00");
 411        return;
 412    }
 413    if (offset + length > total_length) {
 414        length = total_length - offset;
 415    }
 416
 417    g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
 418                    ts->bprm->filename + offset);
 419    gdb_put_strbuf();
 420}
 421