gdbstub: add support to Xfer:auxv:read: packet
This allows gdb to access the target’s auxiliary vector, which can be helpful for telling system libraries important details about the hardware, operating system, and process. Signed-off-by: Lirong Yuan <yuanzi@google.com> [AJB: minor tweaks to test case, update MAINTAINERS, restrict to Linux] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20200730193932.3654677-1-yuanzi@google.com> Message-Id: <20210108224256.2321-7-alex.bennee@linaro.org>
This commit is contained in:
parent
c00506aa26
commit
51c623b0de
@ -2322,6 +2322,7 @@ R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: gdbstub*
|
F: gdbstub*
|
||||||
F: gdb-xml/
|
F: gdb-xml/
|
||||||
|
F: tests/tcg/multiarch/gdbstub/
|
||||||
|
|
||||||
Memory API
|
Memory API
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
|
54
gdbstub.c
54
gdbstub.c
@ -2172,6 +2172,12 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
|
|||||||
";ReverseStep+;ReverseContinue+");
|
";ReverseStep+;ReverseContinue+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
if (gdbserver_state.c_cpu->opaque) {
|
||||||
|
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (gdb_ctx->num_params &&
|
if (gdb_ctx->num_params &&
|
||||||
strstr(gdb_ctx->params[0].data, "multiprocess+")) {
|
strstr(gdb_ctx->params[0].data, "multiprocess+")) {
|
||||||
gdbserver_state.multiprocess = true;
|
gdbserver_state.multiprocess = true;
|
||||||
@ -2233,6 +2239,46 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
|
|||||||
gdbserver_state.str_buf->len, true);
|
gdbserver_state.str_buf->len, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER)
|
||||||
|
static void handle_query_xfer_auxv(GdbCmdContext *gdb_ctx, void *user_ctx)
|
||||||
|
{
|
||||||
|
TaskState *ts;
|
||||||
|
unsigned long offset, len, saved_auxv, auxv_len;
|
||||||
|
const char *mem;
|
||||||
|
|
||||||
|
if (gdb_ctx->num_params < 2) {
|
||||||
|
put_packet("E22");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = gdb_ctx->params[0].val_ul;
|
||||||
|
len = gdb_ctx->params[1].val_ul;
|
||||||
|
ts = gdbserver_state.c_cpu->opaque;
|
||||||
|
saved_auxv = ts->info->saved_auxv;
|
||||||
|
auxv_len = ts->info->auxv_len;
|
||||||
|
mem = (const char *)(saved_auxv + offset);
|
||||||
|
if (offset > auxv_len) {
|
||||||
|
put_packet("E00");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > (MAX_PACKET_LENGTH - 5) / 2) {
|
||||||
|
len = (MAX_PACKET_LENGTH - 5) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < auxv_len - offset) {
|
||||||
|
g_string_assign(gdbserver_state.str_buf, "m");
|
||||||
|
memtox(gdbserver_state.str_buf, mem, len);
|
||||||
|
} else {
|
||||||
|
g_string_assign(gdbserver_state.str_buf, "l");
|
||||||
|
memtox(gdbserver_state.str_buf, mem, auxv_len - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_packet_binary(gdbserver_state.str_buf->str,
|
||||||
|
gdbserver_state.str_buf->len, true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
|
static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
|
||||||
{
|
{
|
||||||
put_packet(GDB_ATTACHED);
|
put_packet(GDB_ATTACHED);
|
||||||
@ -2338,6 +2384,14 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
|
|||||||
.cmd_startswith = 1,
|
.cmd_startswith = 1,
|
||||||
.schema = "s:l,l0"
|
.schema = "s:l,l0"
|
||||||
},
|
},
|
||||||
|
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX_USER)
|
||||||
|
{
|
||||||
|
.handler = handle_query_xfer_auxv,
|
||||||
|
.cmd = "Xfer:auxv:read::",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "l,l0"
|
||||||
|
},
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
.handler = handle_query_attached,
|
.handler = handle_query_attached,
|
||||||
.cmd = "Attached:",
|
.cmd = "Attached:",
|
||||||
|
@ -55,6 +55,15 @@ run-gdbstub-sha1: sha1
|
|||||||
"basic gdbstub support")
|
"basic gdbstub support")
|
||||||
|
|
||||||
EXTRA_RUNS += run-gdbstub-sha1
|
EXTRA_RUNS += run-gdbstub-sha1
|
||||||
|
|
||||||
|
run-gdbstub-qxfer-auxv-read: sha1
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(HAVE_GDB_BIN) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
|
||||||
|
"basic gdbstub qXfer:auxv:read support")
|
||||||
|
|
||||||
|
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
57
tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py
Normal file
57
tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
#
|
||||||
|
# Test auxiliary vector is loaded via gdbstub
|
||||||
|
#
|
||||||
|
# This is launched via tests/guest-debug/run-test.py
|
||||||
|
#
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
|
||||||
|
failcount = 0
|
||||||
|
|
||||||
|
def report(cond, msg):
|
||||||
|
"Report success/fail of test"
|
||||||
|
if cond:
|
||||||
|
print ("PASS: %s" % (msg))
|
||||||
|
else:
|
||||||
|
print ("FAIL: %s" % (msg))
|
||||||
|
global failcount
|
||||||
|
failcount += 1
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"Run through the tests one by one"
|
||||||
|
|
||||||
|
auxv = gdb.execute("info auxv", False, True)
|
||||||
|
report(isinstance(auxv, str), "Fetched auxv from inferior")
|
||||||
|
report(auxv.find("sha1"), "Found test binary name in auxv")
|
||||||
|
|
||||||
|
#
|
||||||
|
# This runs as the script it sourced (via -x, via run-test.py)
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
arch = inferior.architecture()
|
||||||
|
print("ATTACHED: %s" % arch.name())
|
||||||
|
except (gdb.error, AttributeError):
|
||||||
|
print("SKIPPING (not connected)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if gdb.parse_and_eval('$pc') == 0:
|
||||||
|
print("SKIP: PC not set")
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# These are not very useful in scripts
|
||||||
|
gdb.execute("set pagination off")
|
||||||
|
gdb.execute("set confirm off")
|
||||||
|
|
||||||
|
# Run the actual tests
|
||||||
|
run_test()
|
||||||
|
except (gdb.error):
|
||||||
|
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||||
|
failcount += 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
print("All tests complete: %d failures" % failcount)
|
||||||
|
exit(failcount)
|
Loading…
Reference in New Issue
Block a user