Skip to content

Commit e282010

Browse files
iii-istsquad
authored andcommitted
gdbstub: Add support for info proc mappings
Currently the GDB's generate-core-file command doesn't work well with qemu-user: the resulting dumps are huge [1] and at the same time incomplete (argv and envp are missing). The reason is that GDB has no access to proc mappings and therefore has to fall back to using heuristics for discovering them. This is, in turn, because qemu-user does not implement the Host I/O feature of the GDB Remote Serial Protocol. Implement vFile:{open,close,pread,readlink} and also qXfer:exec-file:read+. With that, generate-core-file begins to work on aarch64 and s390x. [1] https://sourceware.org/pipermail/gdb-patches/2023-May/199432.html Co-developed-by: Dominik 'Disconnect3d' Czarnota <[email protected]> Signed-off-by: Ilya Leoshkevich <[email protected]> Message-Id: <[email protected]> Signed-off-by: Alex Bennée <[email protected]> Message-Id: <[email protected]>
1 parent dc14a7a commit e282010

File tree

3 files changed

+185
-2
lines changed

3 files changed

+185
-2
lines changed

gdbstub/gdbstub.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,36 @@ static const GdbCmdParseEntry gdb_v_commands_table[] = {
13271327
.cmd = "Kill;",
13281328
.cmd_startswith = 1
13291329
},
1330+
#ifdef CONFIG_USER_ONLY
1331+
/*
1332+
* Host I/O Packets. See [1] for details.
1333+
* [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
1334+
*/
1335+
{
1336+
.handler = gdb_handle_v_file_open,
1337+
.cmd = "File:open:",
1338+
.cmd_startswith = 1,
1339+
.schema = "s,L,L0"
1340+
},
1341+
{
1342+
.handler = gdb_handle_v_file_close,
1343+
.cmd = "File:close:",
1344+
.cmd_startswith = 1,
1345+
.schema = "l0"
1346+
},
1347+
{
1348+
.handler = gdb_handle_v_file_pread,
1349+
.cmd = "File:pread:",
1350+
.cmd_startswith = 1,
1351+
.schema = "l,L,L0"
1352+
},
1353+
{
1354+
.handler = gdb_handle_v_file_readlink,
1355+
.cmd = "File:readlink:",
1356+
.cmd_startswith = 1,
1357+
.schema = "s0"
1358+
},
1359+
#endif
13301360
};
13311361

13321362
static void handle_v_commands(GArray *params, void *user_ctx)
@@ -1472,11 +1502,14 @@ static void handle_query_supported(GArray *params, void *user_ctx)
14721502
";ReverseStep+;ReverseContinue+");
14731503
}
14741504

1475-
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
1505+
#if defined(CONFIG_USER_ONLY)
1506+
#if defined(CONFIG_LINUX)
14761507
if (gdbserver_state.c_cpu->opaque) {
14771508
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
14781509
}
14791510
#endif
1511+
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
1512+
#endif
14801513

14811514
if (params->len &&
14821515
strstr(get_param(params, 0)->data, "multiprocess+")) {
@@ -1615,13 +1648,21 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
16151648
.cmd_startswith = 1,
16161649
.schema = "s:l,l0"
16171650
},
1618-
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
1651+
#if defined(CONFIG_USER_ONLY)
1652+
#if defined(CONFIG_LINUX)
16191653
{
16201654
.handler = gdb_handle_query_xfer_auxv,
16211655
.cmd = "Xfer:auxv:read::",
16221656
.cmd_startswith = 1,
16231657
.schema = "l,l0"
16241658
},
1659+
#endif
1660+
{
1661+
.handler = gdb_handle_query_xfer_exec_file,
1662+
.cmd = "Xfer:exec-file:read:",
1663+
.cmd_startswith = 1,
1664+
.schema = "l:l,l0"
1665+
},
16251666
#endif
16261667
{
16271668
.handler = gdb_handle_query_attached,

gdbstub/internals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ typedef union GdbCmdVariant {
189189
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
190190
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
191191
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
192+
void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
193+
void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
194+
void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
195+
void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
196+
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
192197

193198
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
194199

gdbstub/user-target.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include "exec/gdbstub.h"
1212
#include "qemu.h"
1313
#include "internals.h"
14+
#ifdef CONFIG_LINUX
15+
#include "linux-user/loader.h"
16+
#include "linux-user/qemu.h"
17+
#endif
1418

1519
/*
1620
* 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)
281285
gdbserver_state.str_buf->len, true);
282286
}
283287
#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

Comments
 (0)