|
11 | 11 | #include "exec/gdbstub.h"
|
12 | 12 | #include "qemu.h"
|
13 | 13 | #include "internals.h"
|
| 14 | +#ifdef CONFIG_LINUX |
| 15 | +#include "linux-user/loader.h" |
| 16 | +#include "linux-user/qemu.h" |
| 17 | +#endif |
14 | 18 |
|
15 | 19 | /*
|
16 | 20 | * Map target signal numbers to GDB protocol signal numbers and vice
|
@@ -281,3 +285,136 @@ void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
281 | 285 | gdbserver_state.str_buf->len, true);
|
282 | 286 | }
|
283 | 287 | #endif
|
| 288 | + |
| 289 | +static 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 | + |
| 298 | +static 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 | + |
| 306 | +void 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 | + |
| 326 | +void 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 | + |
| 339 | +void 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 | + |
| 361 | +void 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 | + |
| 384 | +void 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 | +} |
0 commit comments