qemu

Форк
0
/
syscalls.c 
206 строк · 5.1 Кб
1
/*
2
 * GDB Syscall Handling
3
 *
4
 * GDB can execute syscalls on the guests behalf, currently used by
5
 * the various semihosting extensions.
6
 *
7
 * Copyright (c) 2003-2005 Fabrice Bellard
8
 * Copyright (c) 2023 Linaro Ltd
9
 *
10
 * SPDX-License-Identifier: LGPL-2.0+
11
 */
12

13
#include "qemu/osdep.h"
14
#include "qemu/error-report.h"
15
#include "semihosting/semihost.h"
16
#include "sysemu/runstate.h"
17
#include "gdbstub/user.h"
18
#include "gdbstub/syscalls.h"
19
#include "gdbstub/commands.h"
20
#include "trace.h"
21
#include "internals.h"
22

23
/* Syscall specific state */
24
typedef struct {
25
    char syscall_buf[256];
26
    gdb_syscall_complete_cb current_syscall_cb;
27
} GDBSyscallState;
28

29
static GDBSyscallState gdbserver_syscall_state;
30

31
/*
32
 * Return true if there is a GDB currently connected to the stub
33
 * and attached to a CPU
34
 */
35
static bool gdb_attached(void)
36
{
37
    return gdbserver_state.init && gdbserver_state.c_cpu;
38
}
39

40
static enum {
41
    GDB_SYS_UNKNOWN,
42
    GDB_SYS_ENABLED,
43
    GDB_SYS_DISABLED,
44
} gdb_syscall_mode;
45

46
/* Decide if either remote gdb syscalls or native file IO should be used. */
47
int use_gdb_syscalls(void)
48
{
49
    SemihostingTarget target = semihosting_get_target();
50
    if (target == SEMIHOSTING_TARGET_NATIVE) {
51
        /* -semihosting-config target=native */
52
        return false;
53
    } else if (target == SEMIHOSTING_TARGET_GDB) {
54
        /* -semihosting-config target=gdb */
55
        return true;
56
    }
57

58
    /* -semihosting-config target=auto */
59
    /* On the first call check if gdb is connected and remember. */
60
    if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
61
        gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED;
62
    }
63
    return gdb_syscall_mode == GDB_SYS_ENABLED;
64
}
65

66
/* called when the stub detaches */
67
void gdb_disable_syscalls(void)
68
{
69
    gdb_syscall_mode = GDB_SYS_DISABLED;
70
}
71

72
void gdb_syscall_reset(void)
73
{
74
    gdbserver_syscall_state.current_syscall_cb = NULL;
75
}
76

77
bool gdb_handled_syscall(void)
78
{
79
    if (gdbserver_syscall_state.current_syscall_cb) {
80
        gdb_put_packet(gdbserver_syscall_state.syscall_buf);
81
        return true;
82
    }
83

84
    return false;
85
}
86

87
/*
88
 * Send a gdb syscall request.
89
 *  This accepts limited printf-style format specifiers, specifically:
90
 *   %x  - target_ulong argument printed in hex.
91
 *   %lx - 64-bit argument printed in hex.
92
 *   %s  - string pointer (target_ulong) and length (int) pair.
93
 */
94
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
95
{
96
    char *p, *p_end;
97
    va_list va;
98

99
    if (!gdb_attached()) {
100
        return;
101
    }
102

103
    gdbserver_syscall_state.current_syscall_cb = cb;
104
    va_start(va, fmt);
105

106
    p = gdbserver_syscall_state.syscall_buf;
107
    p_end = p + sizeof(gdbserver_syscall_state.syscall_buf);
108
    *(p++) = 'F';
109
    while (*fmt) {
110
        if (*fmt == '%') {
111
            uint64_t i64;
112
            uint32_t i32;
113

114
            fmt++;
115
            switch (*fmt++) {
116
            case 'x':
117
                i32 = va_arg(va, uint32_t);
118
                p += snprintf(p, p_end - p, "%" PRIx32, i32);
119
                break;
120
            case 'l':
121
                if (*(fmt++) != 'x') {
122
                    goto bad_format;
123
                }
124
                i64 = va_arg(va, uint64_t);
125
                p += snprintf(p, p_end - p, "%" PRIx64, i64);
126
                break;
127
            case 's':
128
                i64 = va_arg(va, uint64_t);
129
                i32 = va_arg(va, uint32_t);
130
                p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);
131
                break;
132
            default:
133
            bad_format:
134
                error_report("gdbstub: Bad syscall format string '%s'",
135
                             fmt - 1);
136
                break;
137
            }
138
        } else {
139
            *(p++) = *(fmt++);
140
        }
141
    }
142
    *p = 0;
143

144
    va_end(va);
145
    gdb_syscall_handling(gdbserver_syscall_state.syscall_buf);
146
}
147

148
/*
149
 * GDB Command Handlers
150
 */
151

152
void gdb_handle_file_io(GArray *params, void *user_ctx)
153
{
154
    if (params->len >= 1 && gdbserver_syscall_state.current_syscall_cb) {
155
        uint64_t ret;
156
        int err;
157

158
        ret = gdb_get_cmd_param(params, 0)->val_ull;
159
        if (params->len >= 2) {
160
            err = gdb_get_cmd_param(params, 1)->val_ull;
161
        } else {
162
            err = 0;
163
        }
164

165
        /* Convert GDB error numbers back to host error numbers. */
166
#define E(X)  case GDB_E##X: err = E##X; break
167
        switch (err) {
168
        case 0:
169
            break;
170
        E(PERM);
171
        E(NOENT);
172
        E(INTR);
173
        E(BADF);
174
        E(ACCES);
175
        E(FAULT);
176
        E(BUSY);
177
        E(EXIST);
178
        E(NODEV);
179
        E(NOTDIR);
180
        E(ISDIR);
181
        E(INVAL);
182
        E(NFILE);
183
        E(MFILE);
184
        E(FBIG);
185
        E(NOSPC);
186
        E(SPIPE);
187
        E(ROFS);
188
        E(NAMETOOLONG);
189
        default:
190
            err = EINVAL;
191
            break;
192
        }
193
#undef E
194

195
        gdbserver_syscall_state.current_syscall_cb(gdbserver_state.c_cpu,
196
                                                   ret, err);
197
        gdbserver_syscall_state.current_syscall_cb = NULL;
198
    }
199

200
    if (params->len >= 3 && gdb_get_cmd_param(params, 2)->opcode == (uint8_t)'C') {
201
        gdb_put_packet("T02");
202
        return;
203
    }
204

205
    gdb_continue();
206
}
207

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.