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