maintainer updates: testing, fuzz, plugins, docs, gdbstub
- clean up gitlab artefact handling - ensure gitlab publishes artefacts with coverage data - reduce testing scope for coverage job - mention CI pipeline in developer docs - add ability to add plugin args to check-tcg - fix some memory leaks and UB in tests - suppress xcb leaks from fuzzing output - add a test-fuzz to mirror the CI run - allow lci-refresh to be run in $SRC - update lcitool to latest version - add qemu-minimal package set with gcc-native - convert riscv64-cross to lcitool - update sbsa-ref tests - don't include arm_casq_ptw emulation unless TCG - convert plugins to use g_memdup2 - ensure plugins instrument SVE helper mem access - improve documentation of QOM/QDEV - make gdbstub send stop responses when it should - report user-mode pid in gdbstub - add support for info proc mappings in gdbstub -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmSiuH4ACgkQ+9DbCVqe KkRt0Qf+N0oD/VuEcRSxK1bWlLtf5nxQpPKKzkRItPc5jqJnLWa/gh21sfQgs5Uq BczAT+JfgTnMozbq0mjvQ+uAGI4MHzBs+UAn60+ZcXfk2inyk77XKBEoHOFuK1ry rgQ4+p21/hcZedDiDLnLSfbGfUU0KkM/pbAegOz7HO0EQDV0CSXqeAW3WAuM1lne +YmXkKwoFI1V8HvslzCT12GFiaUfmSSBtASqWcf67Ief97K24+rpkAVM7JChLm5X fC1MOFNuNYV+jO+9U3KIs15P1WH12oMcpNUY+KqQ5ZWovBg83yOLtKY1o3f6Z2Y+ iQgFJr6F8ZVBdKNJtqVi8DkbiFfbsA== =Ho/h -----END PGP SIGNATURE----- Merge tag 'pull-maintainer-ominbus-030723-1' of https://gitlab.com/stsquad/qemu into staging maintainer updates: testing, fuzz, plugins, docs, gdbstub - clean up gitlab artefact handling - ensure gitlab publishes artefacts with coverage data - reduce testing scope for coverage job - mention CI pipeline in developer docs - add ability to add plugin args to check-tcg - fix some memory leaks and UB in tests - suppress xcb leaks from fuzzing output - add a test-fuzz to mirror the CI run - allow lci-refresh to be run in $SRC - update lcitool to latest version - add qemu-minimal package set with gcc-native - convert riscv64-cross to lcitool - update sbsa-ref tests - don't include arm_casq_ptw emulation unless TCG - convert plugins to use g_memdup2 - ensure plugins instrument SVE helper mem access - improve documentation of QOM/QDEV - make gdbstub send stop responses when it should - report user-mode pid in gdbstub - add support for info proc mappings in gdbstub # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmSiuH4ACgkQ+9DbCVqe # KkRt0Qf+N0oD/VuEcRSxK1bWlLtf5nxQpPKKzkRItPc5jqJnLWa/gh21sfQgs5Uq # BczAT+JfgTnMozbq0mjvQ+uAGI4MHzBs+UAn60+ZcXfk2inyk77XKBEoHOFuK1ry # rgQ4+p21/hcZedDiDLnLSfbGfUU0KkM/pbAegOz7HO0EQDV0CSXqeAW3WAuM1lne # +YmXkKwoFI1V8HvslzCT12GFiaUfmSSBtASqWcf67Ief97K24+rpkAVM7JChLm5X # fC1MOFNuNYV+jO+9U3KIs15P1WH12oMcpNUY+KqQ5ZWovBg83yOLtKY1o3f6Z2Y+ # iQgFJr6F8ZVBdKNJtqVi8DkbiFfbsA== # =Ho/h # -----END PGP SIGNATURE----- # gpg: Signature made Mon 03 Jul 2023 02:01:02 PM CEST # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-maintainer-ominbus-030723-1' of https://gitlab.com/stsquad/qemu: (38 commits) tests/tcg: Add a test for info proc mappings docs: Document security implications of debugging gdbstub: Add support for info proc mappings gdbstub: Report the actual qemu-user pid gdbstub: Expose gdb_get_process() and gdb_get_first_cpu_in_process() linux-user: Emulate /proc/self/smaps linux-user: Add "safe" parameter to do_guest_openat() linux-user: Expose do_guest_openat() and do_guest_readlink() gdbstub: clean-up vcont handling to avoid goto gdbstub: Permit reverse step/break to provide stop response gdbstub: lightly refactor connection to avoid snprintf docs/devel: introduce some key concepts for QOM development docs/devel: split qom-api reference into new file docs/devel/qom.rst: Correct code style include/hw/qdev-core: fixup kerneldoc annotations include/migration: mark vmstate_register() as a legacy function docs/devel: add some front matter to the devel index plugins: update lockstep to use g_memdup2 plugins: fix memory leak while parsing options plugins: force slow path when plugins instrument memory ops ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
2a6ae69154
@ -25,6 +25,7 @@
|
|||||||
# rebuilding all the object files we skip in the artifacts
|
# rebuilding all the object files we skip in the artifacts
|
||||||
.native_build_artifact_template:
|
.native_build_artifact_template:
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_success
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
paths:
|
paths:
|
||||||
- build
|
- build
|
||||||
@ -53,6 +54,7 @@
|
|||||||
extends: .common_test_job_template
|
extends: .common_test_job_template
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||||
|
when: always
|
||||||
expire_in: 7 days
|
expire_in: 7 days
|
||||||
paths:
|
paths:
|
||||||
- build/meson-logs/testlog.txt
|
- build/meson-logs/testlog.txt
|
||||||
@ -68,7 +70,7 @@
|
|||||||
policy: pull-push
|
policy: pull-push
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||||
when: on_failure
|
when: always
|
||||||
expire_in: 7 days
|
expire_in: 7 days
|
||||||
paths:
|
paths:
|
||||||
- build/tests/results/latest/results.xml
|
- build/tests/results/latest/results.xml
|
||||||
|
@ -454,7 +454,7 @@ gcov:
|
|||||||
IMAGE: ubuntu2204
|
IMAGE: ubuntu2204
|
||||||
CONFIGURE_ARGS: --enable-gcov
|
CONFIGURE_ARGS: --enable-gcov
|
||||||
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check-unit check-softfloat
|
||||||
after_script:
|
after_script:
|
||||||
- cd build
|
- cd build
|
||||||
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary
|
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary
|
||||||
@ -462,8 +462,12 @@ gcov:
|
|||||||
coverage: /^\s*lines:\s*\d+.\d+\%/
|
coverage: /^\s*lines:\s*\d+.\d+\%/
|
||||||
artifacts:
|
artifacts:
|
||||||
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||||
|
when: always
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
|
paths:
|
||||||
|
- build/meson-logs/testlog.txt
|
||||||
reports:
|
reports:
|
||||||
|
junit: build/meson-logs/testlog.junit.xml
|
||||||
coverage_report:
|
coverage_report:
|
||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: build/coverage.xml
|
path: build/coverage.xml
|
||||||
@ -587,6 +591,7 @@ pages:
|
|||||||
- make -C build install DESTDIR=$(pwd)/temp-install
|
- make -C build install DESTDIR=$(pwd)/temp-install
|
||||||
- mv temp-install/usr/local/share/doc/qemu/* public/
|
- mv temp-install/usr/local/share/doc/qemu/* public/
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_success
|
||||||
paths:
|
paths:
|
||||||
- public
|
- public
|
||||||
variables:
|
variables:
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
.cross_test_artifacts:
|
.cross_test_artifacts:
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||||
|
when: always
|
||||||
expire_in: 7 days
|
expire_in: 7 days
|
||||||
paths:
|
paths:
|
||||||
- build/meson-logs/testlog.txt
|
- build/meson-logs/testlog.txt
|
||||||
|
@ -169,6 +169,7 @@ cross-win32-system:
|
|||||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_success
|
||||||
paths:
|
paths:
|
||||||
- build/qemu-setup*.exe
|
- build/qemu-setup*.exe
|
||||||
|
|
||||||
@ -184,6 +185,7 @@ cross-win64-system:
|
|||||||
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
||||||
tricore-softmmu xtensaeb-softmmu
|
tricore-softmmu xtensaeb-softmmu
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_success
|
||||||
paths:
|
paths:
|
||||||
- build/qemu-setup*.exe
|
- build/qemu-setup*.exe
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ build-opensbi:
|
|||||||
stage: build
|
stage: build
|
||||||
needs: ['docker-opensbi']
|
needs: ['docker-opensbi']
|
||||||
artifacts:
|
artifacts:
|
||||||
|
when: on_success
|
||||||
paths: # 'artifacts.zip' will contains the following files:
|
paths: # 'artifacts.zip' will contains the following files:
|
||||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||||
|
@ -3106,6 +3106,7 @@ R: Qiuhao Li <Qiuhao.Li@outlook.com>
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: tests/qtest/fuzz/
|
F: tests/qtest/fuzz/
|
||||||
F: tests/qtest/fuzz-*test.c
|
F: tests/qtest/fuzz-*test.c
|
||||||
|
F: tests/docker/test-fuzz
|
||||||
F: scripts/oss-fuzz/
|
F: scripts/oss-fuzz/
|
||||||
F: hw/mem/sparse-mem.c
|
F: hw/mem/sparse-mem.c
|
||||||
F: docs/devel/fuzzing.rst
|
F: docs/devel/fuzzing.rst
|
||||||
|
2
Makefile
2
Makefile
@ -28,7 +28,7 @@ quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
|
|||||||
|
|
||||||
UNCHECKED_GOALS := TAGS gtags cscope ctags dist \
|
UNCHECKED_GOALS := TAGS gtags cscope ctags dist \
|
||||||
help check-help print-% \
|
help check-help print-% \
|
||||||
docker docker-% vm-help vm-test vm-build-%
|
docker docker-% lcitool-refresh vm-help vm-test vm-build-%
|
||||||
|
|
||||||
all:
|
all:
|
||||||
.PHONY: all clean distclean recurse-all dist msi FORCE
|
.PHONY: all clean distclean recurse-all dist msi FORCE
|
||||||
|
@ -1513,13 +1513,14 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
|||||||
int fault_size, MMUAccessType access_type,
|
int fault_size, MMUAccessType access_type,
|
||||||
int mmu_idx, bool nonfault,
|
int mmu_idx, bool nonfault,
|
||||||
void **phost, CPUTLBEntryFull **pfull,
|
void **phost, CPUTLBEntryFull **pfull,
|
||||||
uintptr_t retaddr)
|
uintptr_t retaddr, bool check_mem_cbs)
|
||||||
{
|
{
|
||||||
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
||||||
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
|
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
|
||||||
uint64_t tlb_addr = tlb_read_idx(entry, access_type);
|
uint64_t tlb_addr = tlb_read_idx(entry, access_type);
|
||||||
vaddr page_addr = addr & TARGET_PAGE_MASK;
|
vaddr page_addr = addr & TARGET_PAGE_MASK;
|
||||||
int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW;
|
int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW;
|
||||||
|
bool force_mmio = check_mem_cbs && cpu_plugin_mem_cbs_enabled(env_cpu(env));
|
||||||
CPUTLBEntryFull *full;
|
CPUTLBEntryFull *full;
|
||||||
|
|
||||||
if (!tlb_hit_page(tlb_addr, page_addr)) {
|
if (!tlb_hit_page(tlb_addr, page_addr)) {
|
||||||
@ -1553,7 +1554,9 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
|||||||
flags |= full->slow_flags[access_type];
|
flags |= full->slow_flags[access_type];
|
||||||
|
|
||||||
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
|
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
|
||||||
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) {
|
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))
|
||||||
|
||
|
||||||
|
(access_type != MMU_INST_FETCH && force_mmio)) {
|
||||||
*phost = NULL;
|
*phost = NULL;
|
||||||
return TLB_MMIO;
|
return TLB_MMIO;
|
||||||
}
|
}
|
||||||
@ -1569,7 +1572,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
|||||||
uintptr_t retaddr)
|
uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
int flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
int flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||||
nonfault, phost, pfull, retaddr);
|
nonfault, phost, pfull, retaddr, true);
|
||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
@ -1580,6 +1583,29 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
||||||
|
MMUAccessType access_type, int mmu_idx,
|
||||||
|
void **phost, CPUTLBEntryFull **pfull)
|
||||||
|
{
|
||||||
|
void *discard_phost;
|
||||||
|
CPUTLBEntryFull *discard_tlb;
|
||||||
|
|
||||||
|
/* privately handle users that don't need full results */
|
||||||
|
phost = phost ? phost : &discard_phost;
|
||||||
|
pfull = pfull ? pfull : &discard_tlb;
|
||||||
|
|
||||||
|
int flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||||
|
true, phost, pfull, 0, false);
|
||||||
|
|
||||||
|
/* Handle clean RAM pages. */
|
||||||
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
|
notdirty_write(env_cpu(env), addr, 1, *pfull, 0);
|
||||||
|
flags &= ~TLB_NOTDIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
||||||
MMUAccessType access_type, int mmu_idx,
|
MMUAccessType access_type, int mmu_idx,
|
||||||
bool nonfault, void **phost, uintptr_t retaddr)
|
bool nonfault, void **phost, uintptr_t retaddr)
|
||||||
@ -1590,7 +1616,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
|||||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||||
|
|
||||||
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||||
nonfault, phost, &full, retaddr);
|
nonfault, phost, &full, retaddr, true);
|
||||||
|
|
||||||
/* Handle clean RAM pages. */
|
/* Handle clean RAM pages. */
|
||||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||||
@ -1611,7 +1637,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
|||||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||||
|
|
||||||
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||||
false, &host, &full, retaddr);
|
false, &host, &full, retaddr, true);
|
||||||
|
|
||||||
/* Per the interface, size == 0 merely faults the access. */
|
/* Per the interface, size == 0 merely faults the access. */
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
@ -1644,7 +1670,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
|
|||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
flags = probe_access_internal(env, addr, 0, access_type,
|
flags = probe_access_internal(env, addr, 0, access_type,
|
||||||
mmu_idx, true, &host, &full, 0);
|
mmu_idx, true, &host, &full, 0, false);
|
||||||
|
|
||||||
/* No combination of flags are expected by the caller. */
|
/* No combination of flags are expected by the caller. */
|
||||||
return flags ? NULL : host;
|
return flags ? NULL : host;
|
||||||
@ -1667,7 +1693,8 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
|
|||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
(void)probe_access_internal(env, addr, 1, MMU_INST_FETCH,
|
(void)probe_access_internal(env, addr, 1, MMU_INST_FETCH,
|
||||||
cpu_mmu_index(env, true), false, &p, &full, 0);
|
cpu_mmu_index(env, true), false,
|
||||||
|
&p, &full, 0, false);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -745,6 +745,10 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
|||||||
if (guest_addr_valid_untagged(addr)) {
|
if (guest_addr_valid_untagged(addr)) {
|
||||||
int page_flags = page_get_flags(addr);
|
int page_flags = page_get_flags(addr);
|
||||||
if (page_flags & acc_flag) {
|
if (page_flags & acc_flag) {
|
||||||
|
if ((acc_flag == PAGE_READ || acc_flag == PAGE_WRITE)
|
||||||
|
&& cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
|
||||||
|
return TLB_MMIO;
|
||||||
|
}
|
||||||
return 0; /* success */
|
return 0; /* success */
|
||||||
}
|
}
|
||||||
maperr = !(page_flags & PAGE_VALID);
|
maperr = !(page_flags & PAGE_VALID);
|
||||||
@ -767,7 +771,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||||
flags = probe_access_internal(env, addr, size, access_type, nonfault, ra);
|
flags = probe_access_internal(env, addr, size, access_type, nonfault, ra);
|
||||||
*phost = flags ? NULL : g2h(env_cpu(env), addr);
|
*phost = (flags & TLB_INVALID_MASK) ? NULL : g2h(env_cpu(env), addr);
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,7 +782,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
|||||||
|
|
||||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||||
flags = probe_access_internal(env, addr, size, access_type, false, ra);
|
flags = probe_access_internal(env, addr, size, access_type, false, ra);
|
||||||
g_assert(flags == 0);
|
g_assert((flags & ~TLB_MMIO) == 0);
|
||||||
|
|
||||||
return size ? g2h(env_cpu(env), addr) : NULL;
|
return size ? g2h(env_cpu(env), addr) : NULL;
|
||||||
}
|
}
|
||||||
|
@ -772,7 +772,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "iblksize") == 0) {
|
if (g_strcmp0(tokens[0], "iblksize") == 0) {
|
||||||
l1_iblksize = STRTOLL(tokens[1]);
|
l1_iblksize = STRTOLL(tokens[1]);
|
||||||
|
@ -148,7 +148,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
|||||||
int argc, char **argv)
|
int argc, char **argv)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
g_autofree char **tokens = g_strsplit(argv[i], "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(argv[i], "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "filename") == 0) {
|
if (g_strcmp0(tokens[0], "filename") == 0) {
|
||||||
file_name = g_strdup(tokens[1]);
|
file_name = g_strdup(tokens[1]);
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "ifilter") == 0) {
|
if (g_strcmp0(tokens[0], "ifilter") == 0) {
|
||||||
parse_insn_match(tokens[1]);
|
parse_insn_match(tokens[1]);
|
||||||
} else if (g_strcmp0(tokens[0], "afilter") == 0) {
|
} else if (g_strcmp0(tokens[0], "afilter") == 0) {
|
||||||
|
@ -135,7 +135,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||||
|
@ -169,7 +169,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", -1);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", -1);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "sortby") == 0) {
|
if (g_strcmp0(tokens[0], "sortby") == 0) {
|
||||||
if (g_strcmp0(tokens[1], "reads") == 0) {
|
if (g_strcmp0(tokens[1], "reads") == 0) {
|
||||||
|
@ -333,7 +333,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *p = argv[i];
|
char *p = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(p, "=", -1);
|
g_auto(GStrv) tokens = g_strsplit(p, "=", -1);
|
||||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||||
fprintf(stderr, "boolean argument parsing failed: %s\n", p);
|
fprintf(stderr, "boolean argument parsing failed: %s\n", p);
|
||||||
|
@ -263,7 +263,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "track") == 0) {
|
if (g_strcmp0(tokens[0], "track") == 0) {
|
||||||
if (g_strcmp0(tokens[1], "read") == 0) {
|
if (g_strcmp0(tokens[1], "read") == 0) {
|
||||||
|
@ -130,7 +130,7 @@ static void report_divergance(ExecState *us, ExecState *them)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
divergence_log = g_slist_prepend(divergence_log,
|
divergence_log = g_slist_prepend(divergence_log,
|
||||||
g_memdup(&divrec, sizeof(divrec)));
|
g_memdup2(&divrec, sizeof(divrec)));
|
||||||
|
|
||||||
/* Output short log entry of going out of sync... */
|
/* Output short log entry of going out of sync... */
|
||||||
if (verbose || divrec.distance == 1 || diverged) {
|
if (verbose || divrec.distance == 1 || diverged) {
|
||||||
@ -323,7 +323,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *p = argv[i];
|
char *p = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(p, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(p, "=", 2);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "verbose") == 0) {
|
if (g_strcmp0(tokens[0], "verbose") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) {
|
||||||
|
@ -11,5 +11,7 @@ generated from in-code annotations to function prototypes.
|
|||||||
loads-stores
|
loads-stores
|
||||||
memory
|
memory
|
||||||
modules
|
modules
|
||||||
|
qom-api
|
||||||
|
qdev-api
|
||||||
ui
|
ui
|
||||||
zoned-storage
|
zoned-storage
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _development_process:
|
||||||
|
|
||||||
QEMU Community Processes
|
QEMU Community Processes
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _tcg:
|
||||||
|
|
||||||
TCG Emulation
|
TCG Emulation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -2,10 +2,30 @@
|
|||||||
Developer Information
|
Developer Information
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
This section of the manual documents various parts of the internals of QEMU.
|
This section of the manual documents various parts of the internals of
|
||||||
You only need to read it if you are interested in reading or
|
QEMU. You only need to read it if you are interested in reading or
|
||||||
modifying QEMU's source code.
|
modifying QEMU's source code.
|
||||||
|
|
||||||
|
QEMU is a large and mature project with a number of complex subsystems
|
||||||
|
that can be overwhelming to understand. The development documentation
|
||||||
|
is not comprehensive but hopefully presents enough to get you started.
|
||||||
|
If there are areas that are unclear please reach out either via the
|
||||||
|
IRC channel or mailing list and hopefully we can improve the
|
||||||
|
documentation for future developers.
|
||||||
|
|
||||||
|
All developers will want to familiarise themselves with
|
||||||
|
:ref:`development_process` and how the community interacts. Please pay
|
||||||
|
particular attention to the :ref:`coding-style` and
|
||||||
|
:ref:`submitting-a-patch` sections to avoid common pitfalls.
|
||||||
|
|
||||||
|
If you wish to implement a new hardware model you will want to read
|
||||||
|
through the :ref:`qom` documentation to understand how QEMU's object
|
||||||
|
model works.
|
||||||
|
|
||||||
|
Those wishing to enhance or add new CPU emulation capabilities will
|
||||||
|
want to read our :ref:`tcg` documentation, especially the overview of
|
||||||
|
the :ref:`tcg_internals`.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
7
docs/devel/qdev-api.rst
Normal file
7
docs/devel/qdev-api.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.. _qdev-api:
|
||||||
|
|
||||||
|
================================
|
||||||
|
QEMU Device (qdev) API Reference
|
||||||
|
================================
|
||||||
|
|
||||||
|
.. kernel-doc:: include/hw/qdev-core.h
|
9
docs/devel/qom-api.rst
Normal file
9
docs/devel/qom-api.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.. _qom-api:
|
||||||
|
|
||||||
|
=====================================
|
||||||
|
QEMU Object Model (QOM) API Reference
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This is the complete API documentation for :ref:`qom`.
|
||||||
|
|
||||||
|
.. kernel-doc:: include/qom/object.h
|
@ -13,6 +13,24 @@ features:
|
|||||||
- System for dynamically registering types
|
- System for dynamically registering types
|
||||||
- Support for single-inheritance of types
|
- Support for single-inheritance of types
|
||||||
- Multiple inheritance of stateless interfaces
|
- Multiple inheritance of stateless interfaces
|
||||||
|
- Mapping internal members to publicly exposed properties
|
||||||
|
|
||||||
|
The root object class is TYPE_OBJECT which provides for the basic
|
||||||
|
object methods.
|
||||||
|
|
||||||
|
The QOM tree
|
||||||
|
============
|
||||||
|
|
||||||
|
The QOM tree is a composition tree which represents all of the objects
|
||||||
|
that make up a QEMU "machine". You can view this tree by running
|
||||||
|
``info qom-tree`` in the :ref:`QEMU monitor`. It will contain both
|
||||||
|
objects created by the machine itself as well those created due to
|
||||||
|
user configuration.
|
||||||
|
|
||||||
|
Creating a QOM class
|
||||||
|
====================
|
||||||
|
|
||||||
|
A simple minimal device implementation may look something like bellow:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
:caption: Creating a minimal type
|
:caption: Creating a minimal type
|
||||||
@ -26,7 +44,7 @@ features:
|
|||||||
typedef DeviceClass MyDeviceClass;
|
typedef DeviceClass MyDeviceClass;
|
||||||
typedef struct MyDevice
|
typedef struct MyDevice
|
||||||
{
|
{
|
||||||
DeviceState parent;
|
DeviceState parent_obj;
|
||||||
|
|
||||||
int reg0, reg1, reg2;
|
int reg0, reg1, reg2;
|
||||||
} MyDevice;
|
} MyDevice;
|
||||||
@ -48,6 +66,12 @@ In the above example, we create a simple type that is described by #TypeInfo.
|
|||||||
#TypeInfo describes information about the type including what it inherits
|
#TypeInfo describes information about the type including what it inherits
|
||||||
from, the instance and class size, and constructor/destructor hooks.
|
from, the instance and class size, and constructor/destructor hooks.
|
||||||
|
|
||||||
|
The TYPE_DEVICE class is the parent class for all modern devices
|
||||||
|
implemented in QEMU and adds some specific methods to handle QEMU
|
||||||
|
device model. This includes managing the lifetime of devices from
|
||||||
|
creation through to when they become visible to the guest and
|
||||||
|
eventually unrealized.
|
||||||
|
|
||||||
Alternatively several static types could be registered using helper macro
|
Alternatively several static types could be registered using helper macro
|
||||||
DEFINE_TYPES()
|
DEFINE_TYPES()
|
||||||
|
|
||||||
@ -98,7 +122,7 @@ when the object is needed.
|
|||||||
module_obj(TYPE_MY_DEVICE);
|
module_obj(TYPE_MY_DEVICE);
|
||||||
|
|
||||||
Class Initialization
|
Class Initialization
|
||||||
====================
|
--------------------
|
||||||
|
|
||||||
Before an object is initialized, the class for the object must be
|
Before an object is initialized, the class for the object must be
|
||||||
initialized. There is only one class object for all instance objects
|
initialized. There is only one class object for all instance objects
|
||||||
@ -147,7 +171,7 @@ will also have a wrapper function to call it easily:
|
|||||||
|
|
||||||
typedef struct MyDeviceClass
|
typedef struct MyDeviceClass
|
||||||
{
|
{
|
||||||
DeviceClass parent;
|
DeviceClass parent_class;
|
||||||
|
|
||||||
void (*frobnicate) (MyDevice *obj);
|
void (*frobnicate) (MyDevice *obj);
|
||||||
} MyDeviceClass;
|
} MyDeviceClass;
|
||||||
@ -168,7 +192,7 @@ will also have a wrapper function to call it easily:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Interfaces
|
Interfaces
|
||||||
==========
|
----------
|
||||||
|
|
||||||
Interfaces allow a limited form of multiple inheritance. Instances are
|
Interfaces allow a limited form of multiple inheritance. Instances are
|
||||||
similar to normal types except for the fact that are only defined by
|
similar to normal types except for the fact that are only defined by
|
||||||
@ -182,7 +206,7 @@ an argument to a method on its corresponding SomethingIfClass, or to
|
|||||||
dynamically cast it to an object that implements the interface.
|
dynamically cast it to an object that implements the interface.
|
||||||
|
|
||||||
Methods
|
Methods
|
||||||
=======
|
-------
|
||||||
|
|
||||||
A *method* is a function within the namespace scope of
|
A *method* is a function within the namespace scope of
|
||||||
a class. It usually operates on the object instance by passing it as a
|
a class. It usually operates on the object instance by passing it as a
|
||||||
@ -275,8 +299,8 @@ Alternatively, object_class_by_name() can be used to obtain the class and
|
|||||||
its non-overridden methods for a specific type. This would correspond to
|
its non-overridden methods for a specific type. This would correspond to
|
||||||
``MyClass::method(...)`` in C++.
|
``MyClass::method(...)`` in C++.
|
||||||
|
|
||||||
The first example of such a QOM method was #CPUClass.reset,
|
One example of such methods is ``DeviceClass.reset``. More examples
|
||||||
another example is #DeviceClass.realize.
|
can be found at :ref:`device-life-cycle`.
|
||||||
|
|
||||||
Standard type declaration and definition macros
|
Standard type declaration and definition macros
|
||||||
===============================================
|
===============================================
|
||||||
@ -382,9 +406,32 @@ OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
|
|||||||
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device,
|
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device,
|
||||||
MY_DEVICE, DEVICE)
|
MY_DEVICE, DEVICE)
|
||||||
|
|
||||||
|
.. _device-life-cycle:
|
||||||
|
|
||||||
|
Device Life-cycle
|
||||||
|
=================
|
||||||
|
|
||||||
|
As class initialisation cannot fail devices have an two additional
|
||||||
|
methods to handle the creation of dynamic devices. The ``realize``
|
||||||
|
function is called with ``Error **`` pointer which should be set if
|
||||||
|
the device cannot complete its setup. Otherwise on successful
|
||||||
|
completion of the ``realize`` method the device object is added to the
|
||||||
|
QOM tree and made visible to the guest.
|
||||||
|
|
||||||
|
The reverse function is ``unrealize`` and should be were clean-up
|
||||||
|
code lives to tidy up after the system is done with the device.
|
||||||
|
|
||||||
|
All devices can be instantiated by C code, however only some can
|
||||||
|
created dynamically via the command line or monitor.
|
||||||
|
|
||||||
|
Likewise only some can be unplugged after creation and need an
|
||||||
|
explicit ``unrealize`` implementation. This is determined by the
|
||||||
|
``user_creatable`` variable in the root ``DeviceClass`` structure.
|
||||||
|
Devices can only be unplugged if their ``parent_bus`` has a registered
|
||||||
|
``HotplugHandler``.
|
||||||
|
|
||||||
API Reference
|
API Reference
|
||||||
-------------
|
=============
|
||||||
|
|
||||||
.. kernel-doc:: include/qom/object.h
|
See the :ref:`QOM API<qom-api>` and :ref:`QDEV API<qdev-api>`
|
||||||
|
documents for the complete API description.
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
.. _tcg_internals:
|
||||||
|
|
||||||
====================
|
====================
|
||||||
Translator Internals
|
Translator Internals
|
||||||
====================
|
====================
|
||||||
|
@ -485,6 +485,12 @@ first to contribute the mapping to the ``libvirt-ci`` project:
|
|||||||
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
|
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
|
||||||
page on how to trigger gitlab CI pipelines on your change.
|
page on how to trigger gitlab CI pipelines on your change.
|
||||||
|
|
||||||
|
* Please also trigger gitlab container generation pipelines on your change
|
||||||
|
for as many OS distros as practical to make sure that there are no
|
||||||
|
obvious breakages when adding the new pre-requisite. Please see
|
||||||
|
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
|
||||||
|
page on how to trigger gitlab CI pipelines on your change.
|
||||||
|
|
||||||
For enterprise distros that default to old, end-of-life versions of the
|
For enterprise distros that default to old, end-of-life versions of the
|
||||||
Python runtime, QEMU uses a separate set of mappings that work with more
|
Python runtime, QEMU uses a separate set of mappings that work with more
|
||||||
recent versions. These can be found in ``tests/lcitool/mappings.yml``.
|
recent versions. These can be found in ``tests/lcitool/mappings.yml``.
|
||||||
|
@ -214,3 +214,18 @@ The memory mode can be checked by sending the following command:
|
|||||||
|
|
||||||
``maintenance packet Qqemu.PhyMemMode:0``
|
``maintenance packet Qqemu.PhyMemMode:0``
|
||||||
This will change it back to normal memory mode.
|
This will change it back to normal memory mode.
|
||||||
|
|
||||||
|
Security considerations
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Connecting to the GDB socket allows running arbitrary code inside the guest;
|
||||||
|
in case of the TCG emulation, which is not considered a security boundary, this
|
||||||
|
also means running arbitrary code on the host. Additionally, when debugging
|
||||||
|
qemu-user, it allows directly downloading any file readable by QEMU from the
|
||||||
|
host.
|
||||||
|
|
||||||
|
The GDB socket is not protected by authentication, authorization or encryption.
|
||||||
|
It is therefore a responsibility of the user to make sure that only authorized
|
||||||
|
clients can connect to it, e.g., by using a unix socket with proper
|
||||||
|
permissions, or by opening a TCP socket only on interfaces that are not
|
||||||
|
reachable by potential attackers.
|
||||||
|
@ -202,16 +202,19 @@ void gdb_memtox(GString *buf, const char *mem, int len)
|
|||||||
|
|
||||||
static uint32_t gdb_get_cpu_pid(CPUState *cpu)
|
static uint32_t gdb_get_cpu_pid(CPUState *cpu)
|
||||||
{
|
{
|
||||||
/* TODO: In user mode, we should use the task state PID */
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
return getpid();
|
||||||
|
#else
|
||||||
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
|
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
|
||||||
/* Return the default process' PID */
|
/* Return the default process' PID */
|
||||||
int index = gdbserver_state.process_num - 1;
|
int index = gdbserver_state.process_num - 1;
|
||||||
return gdbserver_state.processes[index].pid;
|
return gdbserver_state.processes[index].pid;
|
||||||
}
|
}
|
||||||
return cpu->cluster_index + 1;
|
return cpu->cluster_index + 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static GDBProcess *gdb_get_process(uint32_t pid)
|
GDBProcess *gdb_get_process(uint32_t pid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -247,7 +250,7 @@ static CPUState *find_cpu(uint32_t thread_id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUState *get_first_cpu_in_process(GDBProcess *process)
|
CPUState *gdb_get_first_cpu_in_process(GDBProcess *process)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
|
||||||
@ -325,7 +328,7 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_first_cpu_in_process(process);
|
return gdb_get_first_cpu_in_process(process);
|
||||||
} else {
|
} else {
|
||||||
/* a specific thread */
|
/* a specific thread */
|
||||||
cpu = find_cpu(tid);
|
cpu = find_cpu(tid);
|
||||||
@ -354,7 +357,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
|||||||
size_t len;
|
size_t len;
|
||||||
int i;
|
int i;
|
||||||
const char *name;
|
const char *name;
|
||||||
CPUState *cpu = get_first_cpu_in_process(process);
|
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
@ -490,7 +493,7 @@ void gdb_register_coprocessor(CPUState *cpu,
|
|||||||
|
|
||||||
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
|
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
|
||||||
{
|
{
|
||||||
CPUState *cpu = get_first_cpu_in_process(p);
|
CPUState *cpu = gdb_get_first_cpu_in_process(p);
|
||||||
|
|
||||||
while (cpu) {
|
while (cpu) {
|
||||||
gdb_breakpoint_remove_all(cpu);
|
gdb_breakpoint_remove_all(cpu);
|
||||||
@ -573,7 +576,6 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
{
|
{
|
||||||
int res, signal = 0;
|
int res, signal = 0;
|
||||||
char cur_action;
|
char cur_action;
|
||||||
char *newstates;
|
|
||||||
unsigned long tmp;
|
unsigned long tmp;
|
||||||
uint32_t pid, tid;
|
uint32_t pid, tid;
|
||||||
GDBProcess *process;
|
GDBProcess *process;
|
||||||
@ -581,7 +583,7 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
GDBThreadIdKind kind;
|
GDBThreadIdKind kind;
|
||||||
unsigned int max_cpus = gdb_get_max_cpus();
|
unsigned int max_cpus = gdb_get_max_cpus();
|
||||||
/* uninitialised CPUs stay 0 */
|
/* uninitialised CPUs stay 0 */
|
||||||
newstates = g_new0(char, max_cpus);
|
g_autofree char *newstates = g_new0(char, max_cpus);
|
||||||
|
|
||||||
/* mark valid CPUs with 1 */
|
/* mark valid CPUs with 1 */
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
@ -597,8 +599,7 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
res = 0;
|
res = 0;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
if (*p++ != ';') {
|
if (*p++ != ';') {
|
||||||
res = -ENOTSUP;
|
return -ENOTSUP;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_action = *p++;
|
cur_action = *p++;
|
||||||
@ -606,13 +607,12 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
cur_action = qemu_tolower(cur_action);
|
cur_action = qemu_tolower(cur_action);
|
||||||
res = qemu_strtoul(p, &p, 16, &tmp);
|
res = qemu_strtoul(p, &p, 16, &tmp);
|
||||||
if (res) {
|
if (res) {
|
||||||
goto out;
|
return res;
|
||||||
}
|
}
|
||||||
signal = gdb_signal_to_target(tmp);
|
signal = gdb_signal_to_target(tmp);
|
||||||
} else if (cur_action != 'c' && cur_action != 's') {
|
} else if (cur_action != 'c' && cur_action != 's') {
|
||||||
/* unknown/invalid/unsupported command */
|
/* unknown/invalid/unsupported command */
|
||||||
res = -ENOTSUP;
|
return -ENOTSUP;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '\0' || *p == ';') {
|
if (*p == '\0' || *p == ';') {
|
||||||
@ -625,14 +625,12 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
} else if (*p++ == ':') {
|
} else if (*p++ == ':') {
|
||||||
kind = read_thread_id(p, &p, &pid, &tid);
|
kind = read_thread_id(p, &p, &pid, &tid);
|
||||||
} else {
|
} else {
|
||||||
res = -ENOTSUP;
|
return -ENOTSUP;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case GDB_READ_THREAD_ERR:
|
case GDB_READ_THREAD_ERR:
|
||||||
res = -EINVAL;
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
|
|
||||||
case GDB_ALL_PROCESSES:
|
case GDB_ALL_PROCESSES:
|
||||||
cpu = gdb_first_attached_cpu();
|
cpu = gdb_first_attached_cpu();
|
||||||
@ -649,11 +647,10 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
process = gdb_get_process(pid);
|
process = gdb_get_process(pid);
|
||||||
|
|
||||||
if (!process->attached) {
|
if (!process->attached) {
|
||||||
res = -EINVAL;
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = get_first_cpu_in_process(process);
|
cpu = gdb_get_first_cpu_in_process(process);
|
||||||
while (cpu) {
|
while (cpu) {
|
||||||
if (newstates[cpu->cpu_index] == 1) {
|
if (newstates[cpu->cpu_index] == 1) {
|
||||||
newstates[cpu->cpu_index] = cur_action;
|
newstates[cpu->cpu_index] = cur_action;
|
||||||
@ -668,8 +665,7 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
|
|
||||||
/* invalid CPU/thread specified */
|
/* invalid CPU/thread specified */
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
res = -EINVAL;
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only use if no previous match occourred */
|
/* only use if no previous match occourred */
|
||||||
@ -679,12 +675,9 @@ static int gdb_handle_vcont(const char *p)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gdbserver_state.signal = signal;
|
gdbserver_state.signal = signal;
|
||||||
gdb_continue_partial(newstates);
|
gdb_continue_partial(newstates);
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(newstates);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1280,7 +1273,7 @@ static void handle_v_attach(GArray *params, void *user_ctx)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = get_first_cpu_in_process(process);
|
cpu = gdb_get_first_cpu_in_process(process);
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -1334,6 +1327,36 @@ static const GdbCmdParseEntry gdb_v_commands_table[] = {
|
|||||||
.cmd = "Kill;",
|
.cmd = "Kill;",
|
||||||
.cmd_startswith = 1
|
.cmd_startswith = 1
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/*
|
||||||
|
* Host I/O Packets. See [1] for details.
|
||||||
|
* [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_v_file_open,
|
||||||
|
.cmd = "File:open:",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "s,L,L0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_v_file_close,
|
||||||
|
.cmd = "File:close:",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "l0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_v_file_pread,
|
||||||
|
.cmd = "File:pread:",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "l,L,L0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_v_file_readlink,
|
||||||
|
.cmd = "File:readlink:",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "s0"
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_v_commands(GArray *params, void *user_ctx)
|
static void handle_v_commands(GArray *params, void *user_ctx)
|
||||||
@ -1403,7 +1426,7 @@ static void handle_query_curr_tid(GArray *params, void *user_ctx)
|
|||||||
* first thread).
|
* first thread).
|
||||||
*/
|
*/
|
||||||
process = gdb_get_cpu_process(gdbserver_state.g_cpu);
|
process = gdb_get_cpu_process(gdbserver_state.g_cpu);
|
||||||
cpu = get_first_cpu_in_process(process);
|
cpu = gdb_get_first_cpu_in_process(process);
|
||||||
g_string_assign(gdbserver_state.str_buf, "QC");
|
g_string_assign(gdbserver_state.str_buf, "QC");
|
||||||
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
|
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
|
||||||
gdb_put_strbuf();
|
gdb_put_strbuf();
|
||||||
@ -1479,11 +1502,14 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
|||||||
";ReverseStep+;ReverseContinue+");
|
";ReverseStep+;ReverseContinue+");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
#if defined(CONFIG_LINUX)
|
||||||
if (gdbserver_state.c_cpu->opaque) {
|
if (gdbserver_state.c_cpu->opaque) {
|
||||||
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (params->len &&
|
if (params->len &&
|
||||||
strstr(get_param(params, 0)->data, "multiprocess+")) {
|
strstr(get_param(params, 0)->data, "multiprocess+")) {
|
||||||
@ -1622,13 +1648,21 @@ static const 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)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
#if defined(CONFIG_LINUX)
|
||||||
{
|
{
|
||||||
.handler = gdb_handle_query_xfer_auxv,
|
.handler = gdb_handle_query_xfer_auxv,
|
||||||
.cmd = "Xfer:auxv:read::",
|
.cmd = "Xfer:auxv:read::",
|
||||||
.cmd_startswith = 1,
|
.cmd_startswith = 1,
|
||||||
.schema = "l,l0"
|
.schema = "l,l0"
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
.handler = gdb_handle_query_xfer_exec_file,
|
||||||
|
.cmd = "Xfer:exec-file:read:",
|
||||||
|
.cmd_startswith = 1,
|
||||||
|
.schema = "l:l,l0"
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
.handler = gdb_handle_query_attached,
|
.handler = gdb_handle_query_attached,
|
||||||
@ -1814,6 +1848,7 @@ static int gdb_handle_packet(const char *line_buf)
|
|||||||
.handler = handle_backward,
|
.handler = handle_backward,
|
||||||
.cmd = "b",
|
.cmd = "b",
|
||||||
.cmd_startswith = 1,
|
.cmd_startswith = 1,
|
||||||
|
.allow_stop_reply = true,
|
||||||
.schema = "o0"
|
.schema = "o0"
|
||||||
};
|
};
|
||||||
cmd_parser = &backward_cmd_desc;
|
cmd_parser = &backward_cmd_desc;
|
||||||
@ -2146,19 +2181,25 @@ void gdb_read_byte(uint8_t ch)
|
|||||||
void gdb_create_default_process(GDBState *s)
|
void gdb_create_default_process(GDBState *s)
|
||||||
{
|
{
|
||||||
GDBProcess *process;
|
GDBProcess *process;
|
||||||
int max_pid = 0;
|
int pid;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
assert(gdbserver_state.process_num == 0);
|
||||||
|
pid = getpid();
|
||||||
|
#else
|
||||||
if (gdbserver_state.process_num) {
|
if (gdbserver_state.process_num) {
|
||||||
max_pid = s->processes[s->process_num - 1].pid;
|
pid = s->processes[s->process_num - 1].pid;
|
||||||
|
} else {
|
||||||
|
pid = 0;
|
||||||
}
|
}
|
||||||
|
/* We need an available PID slot for this process */
|
||||||
|
assert(pid < UINT32_MAX);
|
||||||
|
pid++;
|
||||||
|
#endif
|
||||||
|
|
||||||
s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
|
s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
|
||||||
process = &s->processes[s->process_num - 1];
|
process = &s->processes[s->process_num - 1];
|
||||||
|
process->pid = pid;
|
||||||
/* We need an available PID slot for this process */
|
|
||||||
assert(max_pid < UINT32_MAX);
|
|
||||||
|
|
||||||
process->pid = max_pid + 1;
|
|
||||||
process->attached = false;
|
process->attached = false;
|
||||||
process->target_xml[0] = '\0';
|
process->target_xml[0] = '\0';
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,8 @@ void gdb_read_byte(uint8_t ch);
|
|||||||
*/
|
*/
|
||||||
bool gdb_got_immediate_ack(void);
|
bool gdb_got_immediate_ack(void);
|
||||||
/* utility helpers */
|
/* utility helpers */
|
||||||
|
GDBProcess *gdb_get_process(uint32_t pid);
|
||||||
|
CPUState *gdb_get_first_cpu_in_process(GDBProcess *process);
|
||||||
CPUState *gdb_first_attached_cpu(void);
|
CPUState *gdb_first_attached_cpu(void);
|
||||||
void gdb_append_thread_id(CPUState *cpu, GString *buf);
|
void gdb_append_thread_id(CPUState *cpu, GString *buf);
|
||||||
int gdb_get_cpu_index(CPUState *cpu);
|
int gdb_get_cpu_index(CPUState *cpu);
|
||||||
@ -187,6 +189,11 @@ typedef union GdbCmdVariant {
|
|||||||
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
||||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
||||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
||||||
|
void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
|
||||||
|
void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
|
||||||
|
void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
|
||||||
|
void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
|
||||||
|
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
|
||||||
|
|
||||||
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
|
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
|
||||||
|
|
||||||
|
@ -332,11 +332,9 @@ static void create_processes(GDBState *s)
|
|||||||
|
|
||||||
int gdbserver_start(const char *device)
|
int gdbserver_start(const char *device)
|
||||||
{
|
{
|
||||||
trace_gdbstub_op_start(device);
|
|
||||||
|
|
||||||
char gdbstub_device_name[128];
|
|
||||||
Chardev *chr = NULL;
|
Chardev *chr = NULL;
|
||||||
Chardev *mon_chr;
|
Chardev *mon_chr;
|
||||||
|
g_autoptr(GString) cs = g_string_new(device);
|
||||||
|
|
||||||
if (!first_cpu) {
|
if (!first_cpu) {
|
||||||
error_report("gdbstub: meaningless to attach gdb to a "
|
error_report("gdbstub: meaningless to attach gdb to a "
|
||||||
@ -350,15 +348,16 @@ int gdbserver_start(const char *device)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device) {
|
if (cs->len == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (strcmp(device, "none") != 0) {
|
|
||||||
if (strstart(device, "tcp:", NULL)) {
|
trace_gdbstub_op_start(cs->str);
|
||||||
|
|
||||||
|
if (g_strcmp0(cs->str, "none") != 0) {
|
||||||
|
if (g_str_has_prefix(cs->str, "tcp:")) {
|
||||||
/* enforce required TCP attributes */
|
/* enforce required TCP attributes */
|
||||||
snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
|
g_string_append_printf(cs, ",wait=off,nodelay=on,server=on");
|
||||||
"%s,wait=off,nodelay=on,server=on", device);
|
|
||||||
device = gdbstub_device_name;
|
|
||||||
}
|
}
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
else if (strcmp(device, "stdio") == 0) {
|
else if (strcmp(device, "stdio") == 0) {
|
||||||
@ -373,7 +372,7 @@ int gdbserver_start(const char *device)
|
|||||||
* FIXME: it's a bit weird to allow using a mux chardev here
|
* FIXME: it's a bit weird to allow using a mux chardev here
|
||||||
* and implicitly setup a monitor. We may want to break this.
|
* and implicitly setup a monitor. We may want to break this.
|
||||||
*/
|
*/
|
||||||
chr = qemu_chr_new_noreplay("gdb", device, true, NULL);
|
chr = qemu_chr_new_noreplay("gdb", cs->str, true, NULL);
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
|
#ifdef CONFIG_LINUX
|
||||||
|
#include "linux-user/loader.h"
|
||||||
|
#include "linux-user/qemu.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Map target signal numbers to GDB protocol signal numbers and vice
|
* 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)
|
|||||||
gdbserver_state.str_buf->len, true);
|
gdbserver_state.str_buf->len, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const char *get_filename_param(GArray *params, int i)
|
||||||
|
{
|
||||||
|
const char *hex_filename = get_param(params, i)->data;
|
||||||
|
gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
|
||||||
|
strlen(hex_filename) / 2);
|
||||||
|
g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
|
||||||
|
return (const char *)gdbserver_state.mem_buf->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hostio_reply_with_data(const void *buf, size_t n)
|
||||||
|
{
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
|
||||||
|
gdb_memtox(gdbserver_state.str_buf, buf, n);
|
||||||
|
gdb_put_packet_binary(gdbserver_state.str_buf->str,
|
||||||
|
gdbserver_state.str_buf->len, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
const char *filename = get_filename_param(params, 0);
|
||||||
|
uint64_t flags = get_param(params, 1)->val_ull;
|
||||||
|
uint64_t mode = get_param(params, 2)->val_ull;
|
||||||
|
|
||||||
|
#ifdef CONFIG_LINUX
|
||||||
|
int fd = do_guest_openat(gdbserver_state.g_cpu->env_ptr, 0, filename,
|
||||||
|
flags, mode, false);
|
||||||
|
#else
|
||||||
|
int fd = open(filename, flags, mode);
|
||||||
|
#endif
|
||||||
|
if (fd < 0) {
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||||
|
} else {
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F%d", fd);
|
||||||
|
}
|
||||||
|
gdb_put_strbuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
int fd = get_param(params, 0)->val_ul;
|
||||||
|
|
||||||
|
if (close(fd) == -1) {
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||||
|
gdb_put_strbuf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_put_packet("F00");
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
int fd = get_param(params, 0)->val_ul;
|
||||||
|
size_t count = get_param(params, 1)->val_ull;
|
||||||
|
off_t offset = get_param(params, 2)->val_ull;
|
||||||
|
|
||||||
|
size_t bufsiz = MIN(count, BUFSIZ);
|
||||||
|
g_autofree char *buf = g_try_malloc(bufsiz);
|
||||||
|
if (buf == NULL) {
|
||||||
|
gdb_put_packet("E12");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t n = pread(fd, buf, bufsiz, offset);
|
||||||
|
if (n < 0) {
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||||
|
gdb_put_strbuf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hostio_reply_with_data(buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
const char *filename = get_filename_param(params, 0);
|
||||||
|
|
||||||
|
g_autofree char *buf = g_try_malloc(BUFSIZ);
|
||||||
|
if (buf == NULL) {
|
||||||
|
gdb_put_packet("E12");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_LINUX
|
||||||
|
ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
|
||||||
|
#else
|
||||||
|
ssize_t n = readlink(filename, buf, BUFSIZ);
|
||||||
|
#endif
|
||||||
|
if (n < 0) {
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||||
|
gdb_put_strbuf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hostio_reply_with_data(buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
uint32_t pid = get_param(params, 0)->val_ul;
|
||||||
|
uint32_t offset = get_param(params, 1)->val_ul;
|
||||||
|
uint32_t length = get_param(params, 2)->val_ul;
|
||||||
|
|
||||||
|
GDBProcess *process = gdb_get_process(pid);
|
||||||
|
if (!process) {
|
||||||
|
gdb_put_packet("E00");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
||||||
|
if (!cpu) {
|
||||||
|
gdb_put_packet("E00");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskState *ts = cpu->opaque;
|
||||||
|
if (!ts || !ts->bprm || !ts->bprm->filename) {
|
||||||
|
gdb_put_packet("E00");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_length = strlen(ts->bprm->filename);
|
||||||
|
if (offset > total_length) {
|
||||||
|
gdb_put_packet("E00");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset + length > total_length) {
|
||||||
|
length = total_length - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
|
||||||
|
ts->bprm->filename + offset);
|
||||||
|
gdb_put_strbuf();
|
||||||
|
}
|
||||||
|
@ -301,7 +301,7 @@ CPUArchState *cpu_copy(CPUArchState *env);
|
|||||||
* be signaled by probe_access_flags().
|
* be signaled by probe_access_flags().
|
||||||
*/
|
*/
|
||||||
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1))
|
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1))
|
||||||
#define TLB_MMIO 0
|
#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2))
|
||||||
#define TLB_WATCHPOINT 0
|
#define TLB_WATCHPOINT 0
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -464,6 +464,29 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
|||||||
MMUAccessType access_type, int mmu_idx,
|
MMUAccessType access_type, int mmu_idx,
|
||||||
bool nonfault, void **phost,
|
bool nonfault, void **phost,
|
||||||
CPUTLBEntryFull **pfull, uintptr_t retaddr);
|
CPUTLBEntryFull **pfull, uintptr_t retaddr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* probe_access_mmu() - Like probe_access_full except cannot fault and
|
||||||
|
* doesn't trigger instrumentation.
|
||||||
|
*
|
||||||
|
* @env: CPUArchState
|
||||||
|
* @vaddr: virtual address to probe
|
||||||
|
* @size: size of the probe
|
||||||
|
* @access_type: read, write or execute permission
|
||||||
|
* @mmu_idx: softmmu index
|
||||||
|
* @phost: ptr to return value host address or NULL
|
||||||
|
* @pfull: ptr to return value CPUTLBEntryFull structure or NULL
|
||||||
|
*
|
||||||
|
* The CPUTLBEntryFull structure returned via @pfull is transient
|
||||||
|
* and must be consumed or copied immediately, before any further
|
||||||
|
* access or changes to TLB @mmu_idx.
|
||||||
|
*
|
||||||
|
* Returns: TLB flags as per probe_access_flags()
|
||||||
|
*/
|
||||||
|
int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
||||||
|
MMUAccessType access_type, int mmu_idx,
|
||||||
|
void **phost, CPUTLBEntryFull **pfull);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Hide the qatomic_read to make code a little easier on the eyes */
|
/* Hide the qatomic_read to make code a little easier on the eyes */
|
||||||
|
@ -976,6 +976,23 @@ void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint);
|
|||||||
void cpu_watchpoint_remove_all(CPUState *cpu, int mask);
|
void cpu_watchpoint_remove_all(CPUState *cpu, int mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_plugin_mem_cbs_enabled() - are plugin memory callbacks enabled?
|
||||||
|
* @cs: CPUState pointer
|
||||||
|
*
|
||||||
|
* The memory callbacks are installed if a plugin has instrumented an
|
||||||
|
* instruction for memory. This can be useful to know if you want to
|
||||||
|
* force a slow path for a series of memory accesses.
|
||||||
|
*/
|
||||||
|
static inline bool cpu_plugin_mem_cbs_enabled(const CPUState *cpu)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_PLUGIN
|
||||||
|
return !!cpu->plugin_mem_cbs;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpu_get_address_space:
|
* cpu_get_address_space:
|
||||||
* @cpu: CPU to get address space from
|
* @cpu: CPU to get address space from
|
||||||
|
@ -10,6 +10,65 @@
|
|||||||
#include "hw/hotplug.h"
|
#include "hw/hotplug.h"
|
||||||
#include "hw/resettable.h"
|
#include "hw/resettable.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: The QEMU Device API
|
||||||
|
*
|
||||||
|
* All modern devices should represented as a derived QOM class of
|
||||||
|
* TYPE_DEVICE. The device API introduces the additional methods of
|
||||||
|
* @realize and @unrealize to represent additional stages in a device
|
||||||
|
* objects life cycle.
|
||||||
|
*
|
||||||
|
* Realization
|
||||||
|
* -----------
|
||||||
|
*
|
||||||
|
* Devices are constructed in two stages:
|
||||||
|
*
|
||||||
|
* 1) object instantiation via object_initialize() and
|
||||||
|
* 2) device realization via the #DeviceState.realized property
|
||||||
|
*
|
||||||
|
* The former may not fail (and must not abort or exit, since it is called
|
||||||
|
* during device introspection already), and the latter may return error
|
||||||
|
* information to the caller and must be re-entrant.
|
||||||
|
* Trivial field initializations should go into #TypeInfo.instance_init.
|
||||||
|
* Operations depending on @props static properties should go into @realize.
|
||||||
|
* After successful realization, setting static properties will fail.
|
||||||
|
*
|
||||||
|
* As an interim step, the #DeviceState.realized property can also be
|
||||||
|
* set with qdev_realize(). In the future, devices will propagate this
|
||||||
|
* state change to their children and along busses they expose. The
|
||||||
|
* point in time will be deferred to machine creation, so that values
|
||||||
|
* set in @realize will not be introspectable beforehand. Therefore
|
||||||
|
* devices must not create children during @realize; they should
|
||||||
|
* initialize them via object_initialize() in their own
|
||||||
|
* #TypeInfo.instance_init and forward the realization events
|
||||||
|
* appropriately.
|
||||||
|
*
|
||||||
|
* Any type may override the @realize and/or @unrealize callbacks but needs
|
||||||
|
* to call the parent type's implementation if keeping their functionality
|
||||||
|
* is desired. Refer to QOM documentation for further discussion and examples.
|
||||||
|
*
|
||||||
|
* .. note::
|
||||||
|
* Since TYPE_DEVICE doesn't implement @realize and @unrealize, types
|
||||||
|
* derived directly from it need not call their parent's @realize and
|
||||||
|
* @unrealize. For other types consult the documentation and
|
||||||
|
* implementation of the respective parent types.
|
||||||
|
*
|
||||||
|
* Hiding a device
|
||||||
|
* ---------------
|
||||||
|
*
|
||||||
|
* To hide a device, a DeviceListener function hide_device() needs to
|
||||||
|
* be registered. It can be used to defer adding a device and
|
||||||
|
* therefore hide it from the guest. The handler registering to this
|
||||||
|
* DeviceListener can save the QOpts passed to it for re-using it
|
||||||
|
* later. It must return if it wants the device to be hidden or
|
||||||
|
* visible. When the handler function decides the device shall be
|
||||||
|
* visible it will be added with qdev_device_add() and realized as any
|
||||||
|
* other device. Otherwise qdev_device_add() will return early without
|
||||||
|
* adding the device. The guest will not see a "hidden" device until
|
||||||
|
* it was marked visible and qdev_device_add called again.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DEV_NVECTORS_UNSPECIFIED = -1,
|
DEV_NVECTORS_UNSPECIFIED = -1,
|
||||||
};
|
};
|
||||||
@ -38,7 +97,7 @@ typedef void (*BusRealize)(BusState *bus, Error **errp);
|
|||||||
typedef void (*BusUnrealize)(BusState *bus);
|
typedef void (*BusUnrealize)(BusState *bus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeviceClass:
|
* struct DeviceClass - The base class for all devices.
|
||||||
* @props: Properties accessing state fields.
|
* @props: Properties accessing state fields.
|
||||||
* @realize: Callback function invoked when the #DeviceState:realized
|
* @realize: Callback function invoked when the #DeviceState:realized
|
||||||
* property is changed to %true.
|
* property is changed to %true.
|
||||||
@ -47,72 +106,37 @@ typedef void (*BusUnrealize)(BusState *bus);
|
|||||||
* @hotpluggable: indicates if #DeviceClass is hotpluggable, available
|
* @hotpluggable: indicates if #DeviceClass is hotpluggable, available
|
||||||
* as readonly "hotpluggable" property of #DeviceState instance
|
* as readonly "hotpluggable" property of #DeviceState instance
|
||||||
*
|
*
|
||||||
* # Realization #
|
|
||||||
* Devices are constructed in two stages,
|
|
||||||
* 1) object instantiation via object_initialize() and
|
|
||||||
* 2) device realization via #DeviceState:realized property.
|
|
||||||
* The former may not fail (and must not abort or exit, since it is called
|
|
||||||
* during device introspection already), and the latter may return error
|
|
||||||
* information to the caller and must be re-entrant.
|
|
||||||
* Trivial field initializations should go into #TypeInfo.instance_init.
|
|
||||||
* Operations depending on @props static properties should go into @realize.
|
|
||||||
* After successful realization, setting static properties will fail.
|
|
||||||
*
|
|
||||||
* As an interim step, the #DeviceState:realized property can also be
|
|
||||||
* set with qdev_realize().
|
|
||||||
* In the future, devices will propagate this state change to their children
|
|
||||||
* and along busses they expose.
|
|
||||||
* The point in time will be deferred to machine creation, so that values
|
|
||||||
* set in @realize will not be introspectable beforehand. Therefore devices
|
|
||||||
* must not create children during @realize; they should initialize them via
|
|
||||||
* object_initialize() in their own #TypeInfo.instance_init and forward the
|
|
||||||
* realization events appropriately.
|
|
||||||
*
|
|
||||||
* Any type may override the @realize and/or @unrealize callbacks but needs
|
|
||||||
* to call the parent type's implementation if keeping their functionality
|
|
||||||
* is desired. Refer to QOM documentation for further discussion and examples.
|
|
||||||
*
|
|
||||||
* <note>
|
|
||||||
* <para>
|
|
||||||
* Since TYPE_DEVICE doesn't implement @realize and @unrealize, types
|
|
||||||
* derived directly from it need not call their parent's @realize and
|
|
||||||
* @unrealize.
|
|
||||||
* For other types consult the documentation and implementation of the
|
|
||||||
* respective parent types.
|
|
||||||
* </para>
|
|
||||||
* </note>
|
|
||||||
*
|
|
||||||
* # Hiding a device #
|
|
||||||
* To hide a device, a DeviceListener function hide_device() needs to
|
|
||||||
* be registered.
|
|
||||||
* It can be used to defer adding a device and therefore hide it from
|
|
||||||
* the guest. The handler registering to this DeviceListener can save
|
|
||||||
* the QOpts passed to it for re-using it later. It must return if it
|
|
||||||
* wants the device to be hidden or visible. When the handler function
|
|
||||||
* decides the device shall be visible it will be added with
|
|
||||||
* qdev_device_add() and realized as any other device. Otherwise
|
|
||||||
* qdev_device_add() will return early without adding the device. The
|
|
||||||
* guest will not see a "hidden" device until it was marked visible
|
|
||||||
* and qdev_device_add called again.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
struct DeviceClass {
|
struct DeviceClass {
|
||||||
/*< private >*/
|
/* private: */
|
||||||
ObjectClass parent_class;
|
ObjectClass parent_class;
|
||||||
/*< public >*/
|
|
||||||
|
|
||||||
|
/* public: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @categories: device categories device belongs to
|
||||||
|
*/
|
||||||
DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
|
DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX);
|
||||||
|
/**
|
||||||
|
* @fw_name: name used to identify device to firmware interfaces
|
||||||
|
*/
|
||||||
const char *fw_name;
|
const char *fw_name;
|
||||||
|
/**
|
||||||
|
* @desc: human readable description of device
|
||||||
|
*/
|
||||||
const char *desc;
|
const char *desc;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* The underscore at the end ensures a compile-time error if someone
|
* @props_: properties associated with device, should only be
|
||||||
* assigns to dc->props instead of using device_class_set_props.
|
* assigned by using device_class_set_props(). The underscore
|
||||||
|
* ensures a compile-time error if someone attempts to assign
|
||||||
|
* dc->props directly.
|
||||||
*/
|
*/
|
||||||
Property *props_;
|
Property *props_;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Can this device be instantiated with -device / device_add?
|
* @user_creatable: Can user instantiate with -device / device_add?
|
||||||
|
*
|
||||||
* All devices should support instantiation with device_add, and
|
* All devices should support instantiation with device_add, and
|
||||||
* this flag should not exist. But we're not there, yet. Some
|
* this flag should not exist. But we're not there, yet. Some
|
||||||
* devices fail to instantiate with cryptic error messages.
|
* devices fail to instantiate with cryptic error messages.
|
||||||
@ -120,25 +144,35 @@ struct DeviceClass {
|
|||||||
* behavior would be cruel; clearing this flag will protect them.
|
* behavior would be cruel; clearing this flag will protect them.
|
||||||
* It should never be cleared without a comment explaining why it
|
* It should never be cleared without a comment explaining why it
|
||||||
* is cleared.
|
* is cleared.
|
||||||
|
*
|
||||||
* TODO remove once we're there
|
* TODO remove once we're there
|
||||||
*/
|
*/
|
||||||
bool user_creatable;
|
bool user_creatable;
|
||||||
bool hotpluggable;
|
bool hotpluggable;
|
||||||
|
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
/*
|
/**
|
||||||
* Reset method here is deprecated and replaced by methods in the
|
* @reset: deprecated device reset method pointer
|
||||||
* resettable class interface to implement a multi-phase reset.
|
*
|
||||||
|
* Modern code should use the ResettableClass interface to
|
||||||
|
* implement a multi-phase reset.
|
||||||
|
*
|
||||||
* TODO: remove once every reset callback is unused
|
* TODO: remove once every reset callback is unused
|
||||||
*/
|
*/
|
||||||
DeviceReset reset;
|
DeviceReset reset;
|
||||||
DeviceRealize realize;
|
DeviceRealize realize;
|
||||||
DeviceUnrealize unrealize;
|
DeviceUnrealize unrealize;
|
||||||
|
|
||||||
/* device state */
|
/**
|
||||||
|
* @vmsd: device state serialisation description for
|
||||||
|
* migration/save/restore
|
||||||
|
*/
|
||||||
const VMStateDescription *vmsd;
|
const VMStateDescription *vmsd;
|
||||||
|
|
||||||
/* Private to qdev / bus. */
|
/**
|
||||||
|
* @bus_type: bus type
|
||||||
|
* private: to qdev / bus.
|
||||||
|
*/
|
||||||
const char *bus_type;
|
const char *bus_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,37 +201,96 @@ typedef struct {
|
|||||||
bool engaged_in_io;
|
bool engaged_in_io;
|
||||||
} MemReentrancyGuard;
|
} MemReentrancyGuard;
|
||||||
|
|
||||||
|
|
||||||
|
typedef QLIST_HEAD(, NamedGPIOList) NamedGPIOListHead;
|
||||||
|
typedef QLIST_HEAD(, NamedClockList) NamedClockListHead;
|
||||||
|
typedef QLIST_HEAD(, BusState) BusStateHead;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeviceState:
|
* struct DeviceState - common device state, accessed with qdev helpers
|
||||||
* @reset: ResettableState for the device; handled by Resettable interface.
|
|
||||||
*
|
*
|
||||||
* This structure should not be accessed directly. We declare it here
|
* This structure should not be accessed directly. We declare it here
|
||||||
* so that it can be embedded in individual device state structures.
|
* so that it can be embedded in individual device state structures.
|
||||||
*/
|
*/
|
||||||
struct DeviceState {
|
struct DeviceState {
|
||||||
/*< private >*/
|
/* private: */
|
||||||
Object parent_obj;
|
Object parent_obj;
|
||||||
/*< public >*/
|
/* public: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @id: global device id
|
||||||
|
*/
|
||||||
char *id;
|
char *id;
|
||||||
|
/**
|
||||||
|
* @canonical_path: canonical path of realized device in the QOM tree
|
||||||
|
*/
|
||||||
char *canonical_path;
|
char *canonical_path;
|
||||||
|
/**
|
||||||
|
* @realized: has device been realized?
|
||||||
|
*/
|
||||||
bool realized;
|
bool realized;
|
||||||
|
/**
|
||||||
|
* @pending_deleted_event: track pending deletion events during unplug
|
||||||
|
*/
|
||||||
bool pending_deleted_event;
|
bool pending_deleted_event;
|
||||||
|
/**
|
||||||
|
* @pending_deleted_expires_ms: optional timeout for deletion events
|
||||||
|
*/
|
||||||
int64_t pending_deleted_expires_ms;
|
int64_t pending_deleted_expires_ms;
|
||||||
|
/**
|
||||||
|
* @opts: QDict of options for the device
|
||||||
|
*/
|
||||||
QDict *opts;
|
QDict *opts;
|
||||||
|
/**
|
||||||
|
* @hotplugged: was device added after PHASE_MACHINE_READY?
|
||||||
|
*/
|
||||||
int hotplugged;
|
int hotplugged;
|
||||||
|
/**
|
||||||
|
* @allow_unplug_during_migration: can device be unplugged during migration
|
||||||
|
*/
|
||||||
bool allow_unplug_during_migration;
|
bool allow_unplug_during_migration;
|
||||||
|
/**
|
||||||
|
* @parent_bus: bus this device belongs to
|
||||||
|
*/
|
||||||
BusState *parent_bus;
|
BusState *parent_bus;
|
||||||
QLIST_HEAD(, NamedGPIOList) gpios;
|
/**
|
||||||
QLIST_HEAD(, NamedClockList) clocks;
|
* @gpios: QLIST of named GPIOs the device provides.
|
||||||
QLIST_HEAD(, BusState) child_bus;
|
*/
|
||||||
|
NamedGPIOListHead gpios;
|
||||||
|
/**
|
||||||
|
* @clocks: QLIST of named clocks the device provides.
|
||||||
|
*/
|
||||||
|
NamedClockListHead clocks;
|
||||||
|
/**
|
||||||
|
* @child_bus: QLIST of child buses
|
||||||
|
*/
|
||||||
|
BusStateHead child_bus;
|
||||||
|
/**
|
||||||
|
* @num_child_bus: number of @child_bus entries
|
||||||
|
*/
|
||||||
int num_child_bus;
|
int num_child_bus;
|
||||||
|
/**
|
||||||
|
* @instance_id_alias: device alias for handling legacy migration setups
|
||||||
|
*/
|
||||||
int instance_id_alias;
|
int instance_id_alias;
|
||||||
|
/**
|
||||||
|
* @alias_required_for_version: indicates @instance_id_alias is
|
||||||
|
* needed for migration
|
||||||
|
*/
|
||||||
int alias_required_for_version;
|
int alias_required_for_version;
|
||||||
|
/**
|
||||||
|
* @reset: ResettableState for the device; handled by Resettable interface.
|
||||||
|
*/
|
||||||
ResettableState reset;
|
ResettableState reset;
|
||||||
|
/**
|
||||||
|
* @unplug_blockers: list of reasons to block unplugging of device
|
||||||
|
*/
|
||||||
GSList *unplug_blockers;
|
GSList *unplug_blockers;
|
||||||
|
/**
|
||||||
/* Is the device currently in mmio/pio/dma? Used to prevent re-entrancy */
|
* @mem_reentrancy_guard: Is the device currently in mmio/pio/dma?
|
||||||
|
*
|
||||||
|
* Used to prevent re-entrancy confusing things.
|
||||||
|
*/
|
||||||
MemReentrancyGuard mem_reentrancy_guard;
|
MemReentrancyGuard mem_reentrancy_guard;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -264,13 +357,24 @@ typedef struct BusChild {
|
|||||||
|
|
||||||
#define QDEV_HOTPLUG_HANDLER_PROPERTY "hotplug-handler"
|
#define QDEV_HOTPLUG_HANDLER_PROPERTY "hotplug-handler"
|
||||||
|
|
||||||
|
typedef QTAILQ_HEAD(, BusChild) BusChildHead;
|
||||||
|
typedef QLIST_ENTRY(BusState) BusStateEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BusState:
|
* struct BusState:
|
||||||
|
* @obj: parent object
|
||||||
|
* @parent: parent Device
|
||||||
|
* @name: name of bus
|
||||||
* @hotplug_handler: link to a hotplug handler associated with bus.
|
* @hotplug_handler: link to a hotplug handler associated with bus.
|
||||||
* @reset: ResettableState for the bus; handled by Resettable interface.
|
* @max_index: max number of child buses
|
||||||
|
* @realized: is the bus itself realized?
|
||||||
|
* @full: is the bus full?
|
||||||
|
* @num_children: current number of child buses
|
||||||
*/
|
*/
|
||||||
struct BusState {
|
struct BusState {
|
||||||
|
/* private: */
|
||||||
Object obj;
|
Object obj;
|
||||||
|
/* public: */
|
||||||
DeviceState *parent;
|
DeviceState *parent;
|
||||||
char *name;
|
char *name;
|
||||||
HotplugHandler *hotplug_handler;
|
HotplugHandler *hotplug_handler;
|
||||||
@ -279,18 +383,24 @@ struct BusState {
|
|||||||
bool full;
|
bool full;
|
||||||
int num_children;
|
int num_children;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* children is a RCU QTAILQ, thus readers must use RCU to access it,
|
* @children: an RCU protected QTAILQ, thus readers must use RCU
|
||||||
* and writers must hold the big qemu lock
|
* to access it, and writers must hold the big qemu lock
|
||||||
|
*/
|
||||||
|
BusChildHead children;
|
||||||
|
/**
|
||||||
|
* @sibling: next bus
|
||||||
|
*/
|
||||||
|
BusStateEntry sibling;
|
||||||
|
/**
|
||||||
|
* @reset: ResettableState for the bus; handled by Resettable interface.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QTAILQ_HEAD(, BusChild) children;
|
|
||||||
QLIST_ENTRY(BusState) sibling;
|
|
||||||
ResettableState reset;
|
ResettableState reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GlobalProperty:
|
* typedef GlobalProperty - a global property type
|
||||||
|
*
|
||||||
* @used: Set to true if property was used when initializing a device.
|
* @used: Set to true if property was used when initializing a device.
|
||||||
* @optional: If set to true, GlobalProperty will be skipped without errors
|
* @optional: If set to true, GlobalProperty will be skipped without errors
|
||||||
* if the property doesn't exist.
|
* if the property doesn't exist.
|
||||||
@ -324,7 +434,8 @@ compat_props_add(GPtrArray *arr,
|
|||||||
* This only allocates the memory and initializes the device state
|
* This only allocates the memory and initializes the device state
|
||||||
* structure, ready for the caller to set properties if they wish.
|
* structure, ready for the caller to set properties if they wish.
|
||||||
* The device still needs to be realized.
|
* The device still needs to be realized.
|
||||||
* The returned object has a reference count of 1.
|
*
|
||||||
|
* Return: a derived DeviceState object with a reference count of 1.
|
||||||
*/
|
*/
|
||||||
DeviceState *qdev_new(const char *name);
|
DeviceState *qdev_new(const char *name);
|
||||||
|
|
||||||
@ -334,16 +445,18 @@ DeviceState *qdev_new(const char *name);
|
|||||||
*
|
*
|
||||||
* This is like qdev_new(), except it returns %NULL when type @name
|
* This is like qdev_new(), except it returns %NULL when type @name
|
||||||
* does not exist, rather than asserting.
|
* does not exist, rather than asserting.
|
||||||
|
*
|
||||||
|
* Return: a derived DeviceState object with a reference count of 1 or
|
||||||
|
* NULL if type @name does not exist.
|
||||||
*/
|
*/
|
||||||
DeviceState *qdev_try_new(const char *name);
|
DeviceState *qdev_try_new(const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_is_realized:
|
* qdev_is_realized() - check if device is realized
|
||||||
* @dev: The device to check.
|
* @dev: The device to check.
|
||||||
*
|
*
|
||||||
* May be called outside big qemu lock.
|
* Context: May be called outside big qemu lock.
|
||||||
*
|
* Return: true if the device has been fully constructed, false otherwise.
|
||||||
* Returns: %true% if the device has been fully constructed, %false% otherwise.
|
|
||||||
*/
|
*/
|
||||||
static inline bool qdev_is_realized(DeviceState *dev)
|
static inline bool qdev_is_realized(DeviceState *dev)
|
||||||
{
|
{
|
||||||
@ -361,11 +474,11 @@ static inline bool qdev_is_realized(DeviceState *dev)
|
|||||||
* @dev must not be plugged into a bus already.
|
* @dev must not be plugged into a bus already.
|
||||||
* If @bus, plug @dev into @bus. This takes a reference to @dev.
|
* If @bus, plug @dev into @bus. This takes a reference to @dev.
|
||||||
* If @dev has no QOM parent, make one up, taking another reference.
|
* If @dev has no QOM parent, make one up, taking another reference.
|
||||||
* On success, return true.
|
|
||||||
* On failure, store an error through @errp and return false.
|
|
||||||
*
|
*
|
||||||
* If you created @dev using qdev_new(), you probably want to use
|
* If you created @dev using qdev_new(), you probably want to use
|
||||||
* qdev_realize_and_unref() instead.
|
* qdev_realize_and_unref() instead.
|
||||||
|
*
|
||||||
|
* Return: true on success, else false setting @errp with error
|
||||||
*/
|
*/
|
||||||
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
||||||
|
|
||||||
@ -392,6 +505,8 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
|||||||
* for the only reference to the child device to be held by the parent
|
* for the only reference to the child device to be held by the parent
|
||||||
* via the child<> property, and so the reference-count-drop done here
|
* via the child<> property, and so the reference-count-drop done here
|
||||||
* would be incorrect. For that use case you want qdev_realize().
|
* would be incorrect. For that use case you want qdev_realize().
|
||||||
|
*
|
||||||
|
* Return: true on success, else false setting @errp with error
|
||||||
*/
|
*/
|
||||||
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
|
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
|
||||||
|
|
||||||
@ -420,15 +535,15 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
|
|||||||
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
|
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
|
||||||
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
|
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev);
|
||||||
bool qdev_hotplug_allowed(DeviceState *dev, Error **errp);
|
bool qdev_hotplug_allowed(DeviceState *dev, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_get_hotplug_handler: Get handler responsible for device wiring
|
* qdev_get_hotplug_handler() - Get handler responsible for device wiring
|
||||||
*
|
* @dev: the device we want the HOTPLUG_HANDLER for.
|
||||||
* Find HOTPLUG_HANDLER for @dev that provides [pre|un]plug callbacks for it.
|
|
||||||
*
|
*
|
||||||
* Note: in case @dev has a parent bus, it will be returned as handler unless
|
* Note: in case @dev has a parent bus, it will be returned as handler unless
|
||||||
* machine handler overrides it.
|
* machine handler overrides it.
|
||||||
*
|
*
|
||||||
* Returns: pointer to object that implements TYPE_HOTPLUG_HANDLER interface
|
* Return: pointer to object that implements TYPE_HOTPLUG_HANDLER interface
|
||||||
* or NULL if there aren't any.
|
* or NULL if there aren't any.
|
||||||
*/
|
*/
|
||||||
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
|
HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
|
||||||
@ -459,15 +574,15 @@ void qdev_del_unplug_blocker(DeviceState *dev, Error *reason);
|
|||||||
* qdev_unplug_blocked: Confirm if a device is blocked from unplug
|
* qdev_unplug_blocked: Confirm if a device is blocked from unplug
|
||||||
*
|
*
|
||||||
* @dev: Device to be tested
|
* @dev: Device to be tested
|
||||||
* @reason: Returns one of the reasons why the device is blocked,
|
* @errp: The reasons why the device is blocked, if any
|
||||||
* if any
|
|
||||||
*
|
*
|
||||||
* Returns: true if device is blocked from unplug, false otherwise
|
* Returns: true (also setting @errp) if device is blocked from unplug,
|
||||||
|
* false otherwise
|
||||||
*/
|
*/
|
||||||
bool qdev_unplug_blocked(DeviceState *dev, Error **errp);
|
bool qdev_unplug_blocked(DeviceState *dev, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GpioPolarity: Polarity of a GPIO line
|
* typedef GpioPolarity - Polarity of a GPIO line
|
||||||
*
|
*
|
||||||
* GPIO lines use either positive (active-high) logic,
|
* GPIO lines use either positive (active-high) logic,
|
||||||
* or negative (active-low) logic.
|
* or negative (active-low) logic.
|
||||||
@ -499,6 +614,8 @@ typedef enum {
|
|||||||
* connect another device's output GPIO line to this input.
|
* connect another device's output GPIO line to this input.
|
||||||
*
|
*
|
||||||
* For named input GPIO lines, use qdev_get_gpio_in_named().
|
* For named input GPIO lines, use qdev_get_gpio_in_named().
|
||||||
|
*
|
||||||
|
* Return: qemu_irq corresponding to anonymous input GPIO line
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||||
|
|
||||||
@ -516,6 +633,8 @@ qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
|||||||
* array); this function will assert() if passed an invalid name or index.
|
* array); this function will assert() if passed an invalid name or index.
|
||||||
*
|
*
|
||||||
* For anonymous input GPIO lines, use qdev_get_gpio_in().
|
* For anonymous input GPIO lines, use qdev_get_gpio_in().
|
||||||
|
*
|
||||||
|
* Return: qemu_irq corresponding to named input GPIO line
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
||||||
|
|
||||||
@ -523,7 +642,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
|||||||
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
|
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
|
||||||
* @dev: Device whose GPIO to connect
|
* @dev: Device whose GPIO to connect
|
||||||
* @n: Number of the anonymous output GPIO line (which must be in range)
|
* @n: Number of the anonymous output GPIO line (which must be in range)
|
||||||
* @input_pin: qemu_irq to connect the output line to
|
* @pin: qemu_irq to connect the output line to
|
||||||
*
|
*
|
||||||
* This function connects an anonymous output GPIO line on a device
|
* This function connects an anonymous output GPIO line on a device
|
||||||
* up to an arbitrary qemu_irq, so that when the device asserts that
|
* up to an arbitrary qemu_irq, so that when the device asserts that
|
||||||
@ -594,6 +713,8 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
|||||||
*
|
*
|
||||||
* You probably don't need to use this function -- it is used only
|
* You probably don't need to use this function -- it is used only
|
||||||
* by the platform-bus subsystem.
|
* by the platform-bus subsystem.
|
||||||
|
*
|
||||||
|
* Return: qemu_irq associated with GPIO or NULL if un-wired.
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
||||||
|
|
||||||
@ -604,6 +725,7 @@ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
|||||||
* @name: Name of the output GPIO array
|
* @name: Name of the output GPIO array
|
||||||
* @n: Number of the GPIO line in the array
|
* @n: Number of the GPIO line in the array
|
||||||
*
|
*
|
||||||
|
* .. note::
|
||||||
* This function is provided only for use by the qtest testing framework
|
* This function is provided only for use by the qtest testing framework
|
||||||
* and is not suitable for use in non-testing parts of QEMU.
|
* and is not suitable for use in non-testing parts of QEMU.
|
||||||
*
|
*
|
||||||
@ -612,6 +734,8 @@ qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
|||||||
* ``qdev_connect_gpio_out_named(dev, icpt, name, n)`` had been called.
|
* ``qdev_connect_gpio_out_named(dev, icpt, name, n)`` had been called.
|
||||||
* The previously connected qemu_irq is returned, so it can be restored
|
* The previously connected qemu_irq is returned, so it can be restored
|
||||||
* by a second call to qdev_intercept_gpio_out() if desired.
|
* by a second call to qdev_intercept_gpio_out() if desired.
|
||||||
|
*
|
||||||
|
* Return: old disconnected qemu_irq if one existed
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
|
qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
|
||||||
const char *name, int n);
|
const char *name, int n);
|
||||||
@ -683,9 +807,7 @@ void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
|||||||
const char *name, int n);
|
const char *name, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_init_gpio_in_named_with_opaque: create an array of input GPIO lines
|
* qdev_init_gpio_in_named_with_opaque() - create an array of input GPIO lines
|
||||||
* for the specified device
|
|
||||||
*
|
|
||||||
* @dev: Device to create input GPIOs for
|
* @dev: Device to create input GPIOs for
|
||||||
* @handler: Function to call when GPIO line value is set
|
* @handler: Function to call when GPIO line value is set
|
||||||
* @opaque: Opaque data pointer to pass to @handler
|
* @opaque: Opaque data pointer to pass to @handler
|
||||||
@ -698,8 +820,11 @@ void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
|
|||||||
const char *name, int n);
|
const char *name, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_init_gpio_in_named: create an array of input GPIO lines
|
* qdev_init_gpio_in_named() - create an array of input GPIO lines
|
||||||
* for the specified device
|
* @dev: device to add array to
|
||||||
|
* @handler: a &typedef qemu_irq_handler function to call when GPIO is set
|
||||||
|
* @name: Name of the GPIO input (must be unique for this device)
|
||||||
|
* @n: Number of GPIO lines in this input set
|
||||||
*
|
*
|
||||||
* Like qdev_init_gpio_in_named_with_opaque(), but the opaque pointer
|
* Like qdev_init_gpio_in_named_with_opaque(), but the opaque pointer
|
||||||
* passed to the handler is @dev (which is the most commonly desired behaviour).
|
* passed to the handler is @dev (which is the most commonly desired behaviour).
|
||||||
@ -762,14 +887,17 @@ int qdev_walk_children(DeviceState *dev,
|
|||||||
void *opaque);
|
void *opaque);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_cold_reset:
|
* device_cold_reset() - perform a recursive cold reset on a device
|
||||||
|
* @dev: device to reset.
|
||||||
|
*
|
||||||
* Reset device @dev and perform a recursive processing using the resettable
|
* Reset device @dev and perform a recursive processing using the resettable
|
||||||
* interface. It triggers a RESET_TYPE_COLD.
|
* interface. It triggers a RESET_TYPE_COLD.
|
||||||
*/
|
*/
|
||||||
void device_cold_reset(DeviceState *dev);
|
void device_cold_reset(DeviceState *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bus_cold_reset:
|
* bus_cold_reset() - perform a recursive cold reset on a bus
|
||||||
|
* @bus: bus to reset
|
||||||
*
|
*
|
||||||
* Reset bus @bus and perform a recursive processing using the resettable
|
* Reset bus @bus and perform a recursive processing using the resettable
|
||||||
* interface. It triggers a RESET_TYPE_COLD.
|
* interface. It triggers a RESET_TYPE_COLD.
|
||||||
@ -777,14 +905,18 @@ void device_cold_reset(DeviceState *dev);
|
|||||||
void bus_cold_reset(BusState *bus);
|
void bus_cold_reset(BusState *bus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_is_in_reset:
|
* device_is_in_reset() - check device reset state
|
||||||
* Return true if the device @dev is currently being reset.
|
* @dev: device to check
|
||||||
|
*
|
||||||
|
* Return: true if the device @dev is currently being reset.
|
||||||
*/
|
*/
|
||||||
bool device_is_in_reset(DeviceState *dev);
|
bool device_is_in_reset(DeviceState *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bus_is_in_reset:
|
* bus_is_in_reset() - check bus reset state
|
||||||
* Return true if the bus @bus is currently being reset.
|
* @bus: bus to check
|
||||||
|
*
|
||||||
|
* Return: true if the bus @bus is currently being reset.
|
||||||
*/
|
*/
|
||||||
bool bus_is_in_reset(BusState *bus);
|
bool bus_is_in_reset(BusState *bus);
|
||||||
|
|
||||||
@ -797,7 +929,14 @@ char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev);
|
|||||||
void device_class_set_props(DeviceClass *dc, Property *props);
|
void device_class_set_props(DeviceClass *dc, Property *props);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_class_set_parent_reset:
|
* device_class_set_parent_reset() - legacy set device reset handlers
|
||||||
|
* @dc: device class
|
||||||
|
* @dev_reset: function pointer to reset handler
|
||||||
|
* @parent_reset: function pointer to parents reset handler
|
||||||
|
*
|
||||||
|
* Modern code should use the ResettableClass interface to
|
||||||
|
* implement a multi-phase reset instead.
|
||||||
|
*
|
||||||
* TODO: remove the function when DeviceClass's reset method
|
* TODO: remove the function when DeviceClass's reset method
|
||||||
* is not used anymore.
|
* is not used anymore.
|
||||||
*/
|
*/
|
||||||
@ -871,14 +1010,15 @@ void device_listener_register(DeviceListener *listener);
|
|||||||
void device_listener_unregister(DeviceListener *listener);
|
void device_listener_unregister(DeviceListener *listener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qdev_should_hide_device:
|
* qdev_should_hide_device() - check if device should be hidden
|
||||||
|
*
|
||||||
* @opts: options QDict
|
* @opts: options QDict
|
||||||
* @from_json: true if @opts entries are typed, false for all strings
|
* @from_json: true if @opts entries are typed, false for all strings
|
||||||
* @errp: pointer to error object
|
* @errp: pointer to error object
|
||||||
*
|
*
|
||||||
* Check if a device should be added.
|
* When a device is added via qdev_device_add() this will be called.
|
||||||
* When a device is added via qdev_device_add() this will be called,
|
*
|
||||||
* and return if the device should be added now or not.
|
* Return: if the device should be added now or not.
|
||||||
*/
|
*/
|
||||||
bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
|
bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
|
||||||
|
|
||||||
|
@ -1209,7 +1209,15 @@ int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id,
|
|||||||
int required_for_version,
|
int required_for_version,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
|
||||||
/* Returns: 0 on success, -1 on failure */
|
/**
|
||||||
|
* vmstate_register() - legacy function to register state
|
||||||
|
* serialisation description
|
||||||
|
*
|
||||||
|
* New code shouldn't be using this function as QOM-ified devices have
|
||||||
|
* dc->vmsd to store the serialisation description.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
static inline int vmstate_register(VMStateIf *obj, int instance_id,
|
static inline int vmstate_register(VMStateIf *obj, int instance_id,
|
||||||
const VMStateDescription *vmsd,
|
const VMStateDescription *vmsd,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
|
@ -165,6 +165,9 @@ typedef struct TaskState {
|
|||||||
} TaskState;
|
} TaskState;
|
||||||
|
|
||||||
abi_long do_brk(abi_ulong new_brk);
|
abi_long do_brk(abi_ulong new_brk);
|
||||||
|
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
|
||||||
|
int flags, mode_t mode, bool safe);
|
||||||
|
ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz);
|
||||||
|
|
||||||
/* user access */
|
/* user access */
|
||||||
|
|
||||||
|
@ -8042,7 +8042,36 @@ static int open_self_cmdline(CPUArchState *cpu_env, int fd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_self_maps(CPUArchState *cpu_env, int fd)
|
static void show_smaps(int fd, unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long page_size_kb = TARGET_PAGE_SIZE >> 10;
|
||||||
|
unsigned long size_kb = size >> 10;
|
||||||
|
|
||||||
|
dprintf(fd, "Size: %lu kB\n"
|
||||||
|
"KernelPageSize: %lu kB\n"
|
||||||
|
"MMUPageSize: %lu kB\n"
|
||||||
|
"Rss: 0 kB\n"
|
||||||
|
"Pss: 0 kB\n"
|
||||||
|
"Pss_Dirty: 0 kB\n"
|
||||||
|
"Shared_Clean: 0 kB\n"
|
||||||
|
"Shared_Dirty: 0 kB\n"
|
||||||
|
"Private_Clean: 0 kB\n"
|
||||||
|
"Private_Dirty: 0 kB\n"
|
||||||
|
"Referenced: 0 kB\n"
|
||||||
|
"Anonymous: 0 kB\n"
|
||||||
|
"LazyFree: 0 kB\n"
|
||||||
|
"AnonHugePages: 0 kB\n"
|
||||||
|
"ShmemPmdMapped: 0 kB\n"
|
||||||
|
"FilePmdMapped: 0 kB\n"
|
||||||
|
"Shared_Hugetlb: 0 kB\n"
|
||||||
|
"Private_Hugetlb: 0 kB\n"
|
||||||
|
"Swap: 0 kB\n"
|
||||||
|
"SwapPss: 0 kB\n"
|
||||||
|
"Locked: 0 kB\n"
|
||||||
|
"THPeligible: 0\n", size_kb, page_size_kb, page_size_kb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_self_maps_1(CPUArchState *cpu_env, int fd, bool smaps)
|
||||||
{
|
{
|
||||||
CPUState *cpu = env_cpu(cpu_env);
|
CPUState *cpu = env_cpu(cpu_env);
|
||||||
TaskState *ts = cpu->opaque;
|
TaskState *ts = cpu->opaque;
|
||||||
@ -8089,6 +8118,18 @@ static int open_self_maps(CPUArchState *cpu_env, int fd)
|
|||||||
} else {
|
} else {
|
||||||
dprintf(fd, "\n");
|
dprintf(fd, "\n");
|
||||||
}
|
}
|
||||||
|
if (smaps) {
|
||||||
|
show_smaps(fd, max - min);
|
||||||
|
dprintf(fd, "VmFlags:%s%s%s%s%s%s%s%s\n",
|
||||||
|
(flags & PAGE_READ) ? " rd" : "",
|
||||||
|
(flags & PAGE_WRITE_ORG) ? " wr" : "",
|
||||||
|
(flags & PAGE_EXEC) ? " ex" : "",
|
||||||
|
e->is_priv ? "" : " sh",
|
||||||
|
(flags & PAGE_READ) ? " mr" : "",
|
||||||
|
(flags & PAGE_WRITE_ORG) ? " mw" : "",
|
||||||
|
(flags & PAGE_EXEC) ? " me" : "",
|
||||||
|
e->is_priv ? "" : " ms");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8103,11 +8144,25 @@ static int open_self_maps(CPUArchState *cpu_env, int fd)
|
|||||||
" --xp 00000000 00:00 0",
|
" --xp 00000000 00:00 0",
|
||||||
TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE);
|
TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE);
|
||||||
dprintf(fd, "%*s%s\n", 73 - count, "", "[vsyscall]");
|
dprintf(fd, "%*s%s\n", 73 - count, "", "[vsyscall]");
|
||||||
|
if (smaps) {
|
||||||
|
show_smaps(fd, TARGET_PAGE_SIZE);
|
||||||
|
dprintf(fd, "VmFlags: ex\n");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int open_self_maps(CPUArchState *cpu_env, int fd)
|
||||||
|
{
|
||||||
|
return open_self_maps_1(cpu_env, fd, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_self_smaps(CPUArchState *cpu_env, int fd)
|
||||||
|
{
|
||||||
|
return open_self_maps_1(cpu_env, fd, true);
|
||||||
|
}
|
||||||
|
|
||||||
static int open_self_stat(CPUArchState *cpu_env, int fd)
|
static int open_self_stat(CPUArchState *cpu_env, int fd)
|
||||||
{
|
{
|
||||||
CPUState *cpu = env_cpu(cpu_env);
|
CPUState *cpu = env_cpu(cpu_env);
|
||||||
@ -8448,7 +8503,8 @@ static int open_hardware(CPUArchState *cpu_env, int fd)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
|
int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
|
||||||
|
int flags, mode_t mode, bool safe)
|
||||||
{
|
{
|
||||||
struct fake_open {
|
struct fake_open {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
@ -8458,6 +8514,7 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
|
|||||||
const struct fake_open *fake_open;
|
const struct fake_open *fake_open;
|
||||||
static const struct fake_open fakes[] = {
|
static const struct fake_open fakes[] = {
|
||||||
{ "maps", open_self_maps, is_proc_myself },
|
{ "maps", open_self_maps, is_proc_myself },
|
||||||
|
{ "smaps", open_self_smaps, is_proc_myself },
|
||||||
{ "stat", open_self_stat, is_proc_myself },
|
{ "stat", open_self_stat, is_proc_myself },
|
||||||
{ "auxv", open_self_auxv, is_proc_myself },
|
{ "auxv", open_self_auxv, is_proc_myself },
|
||||||
{ "cmdline", open_self_cmdline, is_proc_myself },
|
{ "cmdline", open_self_cmdline, is_proc_myself },
|
||||||
@ -8475,7 +8532,11 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (is_proc_myself(pathname, "exe")) {
|
if (is_proc_myself(pathname, "exe")) {
|
||||||
|
if (safe) {
|
||||||
return safe_openat(dirfd, exec_path, flags, mode);
|
return safe_openat(dirfd, exec_path, flags, mode);
|
||||||
|
} else {
|
||||||
|
return openat(dirfd, exec_path, flags, mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (fake_open = fakes; fake_open->filename; fake_open++) {
|
for (fake_open = fakes; fake_open->filename; fake_open++) {
|
||||||
@ -8517,7 +8578,41 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (safe) {
|
||||||
return safe_openat(dirfd, path(pathname), flags, mode);
|
return safe_openat(dirfd, path(pathname), flags, mode);
|
||||||
|
} else {
|
||||||
|
return openat(dirfd, path(pathname), flags, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (!pathname || !buf) {
|
||||||
|
errno = EFAULT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bufsiz) {
|
||||||
|
/* Short circuit this for the magic exe check. */
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_proc_myself((const char *)pathname, "exe")) {
|
||||||
|
/*
|
||||||
|
* Don't worry about sign mismatch as earlier mapping
|
||||||
|
* logic would have thrown a bad address error.
|
||||||
|
*/
|
||||||
|
ret = MIN(strlen(exec_path), bufsiz);
|
||||||
|
/* We cannot NUL terminate the string. */
|
||||||
|
memcpy(buf, exec_path, ret);
|
||||||
|
} else {
|
||||||
|
ret = readlink(path(pathname), buf, bufsiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_execveat(CPUArchState *cpu_env, int dirfd,
|
static int do_execveat(CPUArchState *cpu_env, int dirfd,
|
||||||
@ -8994,9 +9089,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
case TARGET_NR_open:
|
case TARGET_NR_open:
|
||||||
if (!(p = lock_user_string(arg1)))
|
if (!(p = lock_user_string(arg1)))
|
||||||
return -TARGET_EFAULT;
|
return -TARGET_EFAULT;
|
||||||
ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
|
ret = get_errno(do_guest_openat(cpu_env, AT_FDCWD, p,
|
||||||
target_to_host_bitmask(arg2, fcntl_flags_tbl),
|
target_to_host_bitmask(arg2, fcntl_flags_tbl),
|
||||||
arg3));
|
arg3, true));
|
||||||
fd_trans_unregister(ret);
|
fd_trans_unregister(ret);
|
||||||
unlock_user(p, arg1, 0);
|
unlock_user(p, arg1, 0);
|
||||||
return ret;
|
return ret;
|
||||||
@ -9004,9 +9099,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
case TARGET_NR_openat:
|
case TARGET_NR_openat:
|
||||||
if (!(p = lock_user_string(arg2)))
|
if (!(p = lock_user_string(arg2)))
|
||||||
return -TARGET_EFAULT;
|
return -TARGET_EFAULT;
|
||||||
ret = get_errno(do_openat(cpu_env, arg1, p,
|
ret = get_errno(do_guest_openat(cpu_env, arg1, p,
|
||||||
target_to_host_bitmask(arg3, fcntl_flags_tbl),
|
target_to_host_bitmask(arg3, fcntl_flags_tbl),
|
||||||
arg4));
|
arg4, true));
|
||||||
fd_trans_unregister(ret);
|
fd_trans_unregister(ret);
|
||||||
unlock_user(p, arg2, 0);
|
unlock_user(p, arg2, 0);
|
||||||
return ret;
|
return ret;
|
||||||
@ -10229,22 +10324,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
void *p2;
|
void *p2;
|
||||||
p = lock_user_string(arg1);
|
p = lock_user_string(arg1);
|
||||||
p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
|
p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
|
||||||
if (!p || !p2) {
|
ret = get_errno(do_guest_readlink(p, p2, arg3));
|
||||||
ret = -TARGET_EFAULT;
|
|
||||||
} else if (!arg3) {
|
|
||||||
/* Short circuit this for the magic exe check. */
|
|
||||||
ret = -TARGET_EINVAL;
|
|
||||||
} else if (is_proc_myself((const char *)p, "exe")) {
|
|
||||||
/*
|
|
||||||
* Don't worry about sign mismatch as earlier mapping
|
|
||||||
* logic would have thrown a bad address error.
|
|
||||||
*/
|
|
||||||
ret = MIN(strlen(exec_path), arg3);
|
|
||||||
/* We cannot NUL terminate the string. */
|
|
||||||
memcpy(p2, exec_path, ret);
|
|
||||||
} else {
|
|
||||||
ret = get_errno(readlink(path(p), p2, arg3));
|
|
||||||
}
|
|
||||||
unlock_user(p2, arg2, ret);
|
unlock_user(p2, arg2, ret);
|
||||||
unlock_user(p, arg1, 0);
|
unlock_user(p, arg1, 0);
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,18 @@ static void usage(FILE *out)
|
|||||||
names.options ?: "-");
|
names.options ?: "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xkb_mod_mask_t get_mod(struct xkb_keymap *map, const char *name)
|
||||||
|
{
|
||||||
|
xkb_mod_index_t mod;
|
||||||
|
xkb_mod_mask_t mask = 0;
|
||||||
|
|
||||||
|
mod = xkb_keymap_mod_get_index(map, name);
|
||||||
|
if (mod != XKB_MOD_INVALID) {
|
||||||
|
mask = (1 << mod);
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct xkb_context *ctx;
|
struct xkb_context *ctx;
|
||||||
@ -215,14 +227,10 @@ int main(int argc, char *argv[])
|
|||||||
mod, xkb_keymap_mod_get_name(map, mod));
|
mod, xkb_keymap_mod_get_name(map, mod));
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = xkb_keymap_mod_get_index(map, "Shift");
|
shift = get_mod(map, "Shift");
|
||||||
shift = (1 << mod);
|
ctrl = get_mod(map, "Control");
|
||||||
mod = xkb_keymap_mod_get_index(map, "Control");
|
altgr = get_mod(map, "AltGr");
|
||||||
ctrl = (1 << mod);
|
numlock = get_mod(map, "NumLock");
|
||||||
mod = xkb_keymap_mod_get_index(map, "AltGr");
|
|
||||||
altgr = (1 << mod);
|
|
||||||
mod = xkb_keymap_mod_get_index(map, "NumLock");
|
|
||||||
numlock = (1 << mod);
|
|
||||||
|
|
||||||
state = xkb_state_new(map);
|
state = xkb_state_new(map);
|
||||||
xkb_keymap_key_for_each(map, walk_map, state);
|
xkb_keymap_key_for_each(map, walk_map, state);
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
# The tcmalloc on Fedora37 confuses things
|
# The tcmalloc on Fedora37 confuses things
|
||||||
leak:/lib64/libtcmalloc_minimal.so.4
|
leak:/lib64/libtcmalloc_minimal.so.4
|
||||||
|
|
||||||
|
# libxkbcommon also leaks in qemu-keymap
|
||||||
|
leak:/lib64/libxkbcommon.so.0
|
||||||
|
@ -489,9 +489,9 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
|||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
env->tlb_fi = fi;
|
env->tlb_fi = fi;
|
||||||
flags = probe_access_full(env, addr, 0, MMU_DATA_LOAD,
|
flags = probe_access_full_mmu(env, addr, 0, MMU_DATA_LOAD,
|
||||||
arm_to_core_mmu_idx(s2_mmu_idx),
|
arm_to_core_mmu_idx(s2_mmu_idx),
|
||||||
true, &ptw->out_host, &full, 0);
|
&ptw->out_host, &full);
|
||||||
env->tlb_fi = NULL;
|
env->tlb_fi = NULL;
|
||||||
|
|
||||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||||
@ -628,7 +628,7 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
|
|||||||
uint64_t new_val, S1Translate *ptw,
|
uint64_t new_val, S1Translate *ptw,
|
||||||
ARMMMUFaultInfo *fi)
|
ARMMMUFaultInfo *fi)
|
||||||
{
|
{
|
||||||
#ifdef TARGET_AARCH64
|
#if defined(TARGET_AARCH64) && defined(CONFIG_TCG)
|
||||||
uint64_t cur_val;
|
uint64_t cur_val;
|
||||||
void *host = ptw->out_host;
|
void *host = ptw->out_host;
|
||||||
|
|
||||||
@ -644,12 +644,12 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
|
|||||||
*/
|
*/
|
||||||
if (unlikely(!ptw->out_rw)) {
|
if (unlikely(!ptw->out_rw)) {
|
||||||
int flags;
|
int flags;
|
||||||
void *discard;
|
|
||||||
|
|
||||||
env->tlb_fi = fi;
|
env->tlb_fi = fi;
|
||||||
flags = probe_access_flags(env, ptw->out_virt, 0, MMU_DATA_STORE,
|
flags = probe_access_full_mmu(env, ptw->out_virt, 0,
|
||||||
|
MMU_DATA_STORE,
|
||||||
arm_to_core_mmu_idx(ptw->in_ptw_idx),
|
arm_to_core_mmu_idx(ptw->in_ptw_idx),
|
||||||
true, &discard, 0);
|
NULL, NULL);
|
||||||
env->tlb_fi = NULL;
|
env->tlb_fi = NULL;
|
||||||
|
|
||||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||||
@ -709,7 +709,7 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val,
|
|||||||
|
|
||||||
return cur_val;
|
return cur_val;
|
||||||
#else
|
#else
|
||||||
/* AArch32 does not have FEAT_HADFS. */
|
/* AArch32 does not have FEAT_HADFS; non-TCG guests only use debug-mode. */
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -5688,9 +5688,6 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
|
|||||||
|
|
||||||
flags = info.page[0].flags | info.page[1].flags;
|
flags = info.page[0].flags | info.page[1].flags;
|
||||||
if (unlikely(flags != 0)) {
|
if (unlikely(flags != 0)) {
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
g_assert_not_reached();
|
|
||||||
#else
|
|
||||||
/*
|
/*
|
||||||
* At least one page includes MMIO.
|
* At least one page includes MMIO.
|
||||||
* Any bus operation can fail with cpu_transaction_failed,
|
* Any bus operation can fail with cpu_transaction_failed,
|
||||||
@ -5727,7 +5724,6 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
|
|||||||
memcpy(&env->vfp.zregs[(rd + i) & 31], &scratch[i], reg_max);
|
memcpy(&env->vfp.zregs[(rd + i) & 31], &scratch[i], reg_max);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The entire operation is in RAM, on valid pages. */
|
/* The entire operation is in RAM, on valid pages. */
|
||||||
|
@ -869,7 +869,7 @@ class BootLinuxConsole(LinuxKernelTest):
|
|||||||
self.vm.set_console()
|
self.vm.set_console()
|
||||||
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
|
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
|
||||||
'console=ttyS0,115200 '
|
'console=ttyS0,115200 '
|
||||||
'root=/dev/mmcblk0 rootwait rw '
|
'root=b300 rootwait rw '
|
||||||
'panic=-1 noreboot')
|
'panic=-1 noreboot')
|
||||||
self.vm.add_args('-kernel', kernel_path,
|
self.vm.add_args('-kernel', kernel_path,
|
||||||
'-dtb', dtb_path,
|
'-dtb', dtb_path,
|
||||||
@ -885,7 +885,7 @@ class BootLinuxConsole(LinuxKernelTest):
|
|||||||
exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
|
exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
|
||||||
'Allwinner sun8i Family')
|
'Allwinner sun8i Family')
|
||||||
exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
|
exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
|
||||||
'mmcblk0')
|
'mmcblk')
|
||||||
exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
|
exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
|
||||||
'eth0: Link is Up')
|
'eth0: Link is Up')
|
||||||
exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
|
exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
|
||||||
|
@ -29,23 +29,23 @@ class Aarch64SbsarefMachine(QemuSystemTest):
|
|||||||
"""
|
"""
|
||||||
Flash volumes generated using:
|
Flash volumes generated using:
|
||||||
|
|
||||||
- Fedora GNU Toolchain version 12.2.1 20220819 (Red Hat Cross 12.2.1-2)
|
- Fedora GNU Toolchain version 13.1.1 20230511 (Red Hat 13.1.1-2)
|
||||||
|
|
||||||
- Trusted Firmware-A
|
- Trusted Firmware-A
|
||||||
https://github.com/ARM-software/arm-trusted-firmware/tree/5fdb2e54
|
https://github.com/ARM-software/arm-trusted-firmware/tree/c0d8ee38
|
||||||
|
|
||||||
- Tianocore EDK II
|
- Tianocore EDK II
|
||||||
https://github.com/tianocore/edk2/tree/494127613b
|
https://github.com/tianocore/edk2/tree/0f9283429dd4
|
||||||
https://github.com/tianocore/edk2-non-osi/tree/41876073
|
https://github.com/tianocore/edk2-non-osi/tree/f0bb00937ad6
|
||||||
https://github.com/tianocore/edk2-platforms/tree/8efa4f42
|
https://github.com/tianocore/edk2-platforms/tree/7880b92e2a04
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Secure BootRom (TF-A code)
|
# Secure BootRom (TF-A code)
|
||||||
fs0_xz_url = (
|
fs0_xz_url = (
|
||||||
"https://fileserver.linaro.org/s/ATnSmq6k8SoXgbH/"
|
"https://fileserver.linaro.org/s/HrYMCjP7MEccjRP/"
|
||||||
"download/SBSA_FLASH0.fd.xz"
|
"download/SBSA_FLASH0.fd.xz"
|
||||||
)
|
)
|
||||||
fs0_xz_hash = "a210a09692bcbe0a3743ffd0df44e80e0c7ad8ab"
|
fs0_xz_hash = "447eff64a90b84ce47703c6ec41fbfc25befaaea"
|
||||||
tar_xz_path = self.fetch_asset(fs0_xz_url, asset_hash=fs0_xz_hash)
|
tar_xz_path = self.fetch_asset(fs0_xz_url, asset_hash=fs0_xz_hash)
|
||||||
archive.extract(tar_xz_path, self.workdir)
|
archive.extract(tar_xz_path, self.workdir)
|
||||||
fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd")
|
fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd")
|
||||||
@ -93,15 +93,15 @@ class Aarch64SbsarefMachine(QemuSystemTest):
|
|||||||
|
|
||||||
# AP Trusted ROM
|
# AP Trusted ROM
|
||||||
wait_for_console_pattern(self, "Booting Trusted Firmware")
|
wait_for_console_pattern(self, "Booting Trusted Firmware")
|
||||||
wait_for_console_pattern(self, "BL1: v2.8(release):v2.8")
|
wait_for_console_pattern(self, "BL1: v2.9(release):v2.9")
|
||||||
wait_for_console_pattern(self, "BL1: Booting BL2")
|
wait_for_console_pattern(self, "BL1: Booting BL2")
|
||||||
|
|
||||||
# Trusted Boot Firmware
|
# Trusted Boot Firmware
|
||||||
wait_for_console_pattern(self, "BL2: v2.8(release)")
|
wait_for_console_pattern(self, "BL2: v2.9(release)")
|
||||||
wait_for_console_pattern(self, "Booting BL31")
|
wait_for_console_pattern(self, "Booting BL31")
|
||||||
|
|
||||||
# EL3 Runtime Software
|
# EL3 Runtime Software
|
||||||
wait_for_console_pattern(self, "BL31: v2.8(release)")
|
wait_for_console_pattern(self, "BL31: v2.9(release)")
|
||||||
|
|
||||||
# Non-trusted Firmware
|
# Non-trusted Firmware
|
||||||
wait_for_console_pattern(self, "UEFI firmware (version 1.0")
|
wait_for_console_pattern(self, "UEFI firmware (version 1.0")
|
||||||
@ -136,21 +136,18 @@ class Aarch64SbsarefMachine(QemuSystemTest):
|
|||||||
self.vm.launch()
|
self.vm.launch()
|
||||||
wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
|
wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
|
||||||
|
|
||||||
@skipUnless(os.getenv("AVOCADO_TIMEOUT_EXPECTED"), "Test might timeout")
|
|
||||||
def test_sbsaref_alpine_linux_cortex_a57(self):
|
def test_sbsaref_alpine_linux_cortex_a57(self):
|
||||||
"""
|
"""
|
||||||
:avocado: tags=cpu:cortex-a57
|
:avocado: tags=cpu:cortex-a57
|
||||||
"""
|
"""
|
||||||
self.boot_alpine_linux("cortex-a57")
|
self.boot_alpine_linux("cortex-a57")
|
||||||
|
|
||||||
@skipUnless(os.getenv("AVOCADO_TIMEOUT_EXPECTED"), "Test might timeout")
|
|
||||||
def test_sbsaref_alpine_linux_neoverse_n1(self):
|
def test_sbsaref_alpine_linux_neoverse_n1(self):
|
||||||
"""
|
"""
|
||||||
:avocado: tags=cpu:max
|
:avocado: tags=cpu:max
|
||||||
"""
|
"""
|
||||||
self.boot_alpine_linux("neoverse-n1")
|
self.boot_alpine_linux("neoverse-n1")
|
||||||
|
|
||||||
@skip("requires TF-A update to handle FEAT_FGT")
|
|
||||||
def test_sbsaref_alpine_linux_max(self):
|
def test_sbsaref_alpine_linux_max(self):
|
||||||
"""
|
"""
|
||||||
:avocado: tags=cpu:max
|
:avocado: tags=cpu:max
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# $ lcitool dockerfile --layers all alpine-316 qemu
|
# $ lcitool dockerfile --layers all alpine-318 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.16
|
FROM docker.io/library/alpine:3.18
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk upgrade && \
|
apk upgrade && \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -1,54 +1,85 @@
|
|||||||
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# Docker cross-compiler target for riscv64
|
# $ lcitool dockerfile --layers all --cross riscv64 debian-sid qemu-minimal
|
||||||
#
|
|
||||||
# Currently the only distro that gets close to cross compiling riscv64
|
|
||||||
# images is Debian Sid (with unofficial ports). As this is a moving
|
|
||||||
# target we keep the library list minimal and are aiming to migrate
|
|
||||||
# from this hack as soon as we are able.
|
|
||||||
#
|
#
|
||||||
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
FROM docker.io/library/debian:sid-slim
|
FROM docker.io/library/debian:sid-slim
|
||||||
|
|
||||||
# Add ports
|
RUN export DEBIAN_FRONTEND=noninteractive && \
|
||||||
RUN apt update && \
|
apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
apt-get install -y eatmydata && \
|
||||||
DEBIAN_FRONTEND=noninteractive eatmydata apt update -yy && \
|
eatmydata apt-get dist-upgrade -y && \
|
||||||
DEBIAN_FRONTEND=noninteractive eatmydata apt upgrade -yy
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
|
bash \
|
||||||
# Install common build utilities
|
|
||||||
RUN DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy \
|
|
||||||
bison \
|
|
||||||
bc \
|
bc \
|
||||||
build-essential \
|
bison \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
debian-ports-archive-keyring \
|
ccache \
|
||||||
dpkg-dev \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
gettext \
|
gcc \
|
||||||
git \
|
git \
|
||||||
libglib2.0-dev \
|
libglib2.0-dev \
|
||||||
|
locales \
|
||||||
|
make \
|
||||||
|
meson \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
pkg-config \
|
pkgconf \
|
||||||
python3 \
|
python3 \
|
||||||
python3-venv
|
python3-venv \
|
||||||
|
sed \
|
||||||
|
tar && \
|
||||||
|
eatmydata apt-get autoremove -y && \
|
||||||
|
eatmydata apt-get autoclean -y && \
|
||||||
|
sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \
|
||||||
|
dpkg-reconfigure locales
|
||||||
|
|
||||||
# Add ports and riscv64 architecture
|
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
|
||||||
RUN echo "deb http://ftp.ports.debian.org/debian-ports/ sid main" >> /etc/apt/sources.list
|
ENV LANG "en_US.UTF-8"
|
||||||
RUN dpkg --add-architecture riscv64
|
ENV MAKE "/usr/bin/make"
|
||||||
|
ENV NINJA "/usr/bin/ninja"
|
||||||
|
ENV PYTHON "/usr/bin/python3"
|
||||||
|
|
||||||
# Duplicate deb line as deb-src
|
RUN export DEBIAN_FRONTEND=noninteractive && \
|
||||||
RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list
|
dpkg --add-architecture riscv64 && \
|
||||||
|
eatmydata apt-get install debian-ports-archive-keyring && \
|
||||||
RUN apt update && \
|
eatmydata echo 'deb http://ftp.ports.debian.org/debian-ports/ sid main' > /etc/apt/sources.list.d/ports.list && \
|
||||||
DEBIAN_FRONTEND=noninteractive eatmydata \
|
eatmydata echo 'deb http://ftp.ports.debian.org/debian-ports/ unreleased main' >> /etc/apt/sources.list.d/ports.list && \
|
||||||
apt install -y --no-install-recommends \
|
eatmydata apt-get update && \
|
||||||
|
eatmydata apt-get dist-upgrade -y && \
|
||||||
|
eatmydata apt-get install --no-install-recommends -y dpkg-dev && \
|
||||||
|
eatmydata apt-get install --no-install-recommends -y \
|
||||||
|
g++-riscv64-linux-gnu \
|
||||||
gcc-riscv64-linux-gnu \
|
gcc-riscv64-linux-gnu \
|
||||||
libc6-dev-riscv64-cross \
|
libc6-dev:riscv64 \
|
||||||
libfdt-dev:riscv64 \
|
libfdt-dev:riscv64 \
|
||||||
libffi-dev:riscv64 \
|
libffi-dev:riscv64 \
|
||||||
libglib2.0-dev:riscv64 \
|
libglib2.0-dev:riscv64 \
|
||||||
libpixman-1-dev:riscv64
|
libpixman-1-dev:riscv64 && \
|
||||||
|
eatmydata apt-get autoremove -y && \
|
||||||
|
eatmydata apt-get autoclean -y && \
|
||||||
|
mkdir -p /usr/local/share/meson/cross && \
|
||||||
|
printf "[binaries]\n\
|
||||||
|
c = '/usr/bin/riscv64-linux-gnu-gcc'\n\
|
||||||
|
ar = '/usr/bin/riscv64-linux-gnu-gcc-ar'\n\
|
||||||
|
strip = '/usr/bin/riscv64-linux-gnu-strip'\n\
|
||||||
|
pkgconfig = '/usr/bin/riscv64-linux-gnu-pkg-config'\n\
|
||||||
|
\n\
|
||||||
|
[host_machine]\n\
|
||||||
|
system = 'linux'\n\
|
||||||
|
cpu_family = 'riscv64'\n\
|
||||||
|
cpu = 'riscv64'\n\
|
||||||
|
endian = 'little'\n" > /usr/local/share/meson/cross/riscv64-linux-gnu && \
|
||||||
|
dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \
|
||||||
|
mkdir -p /usr/libexec/ccache-wrappers && \
|
||||||
|
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/riscv64-linux-gnu-c++ && \
|
||||||
|
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/riscv64-linux-gnu-cc && \
|
||||||
|
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/riscv64-linux-gnu-g++ && \
|
||||||
|
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/riscv64-linux-gnu-gcc
|
||||||
|
|
||||||
# Specify the cross prefix for this image (see tests/docker/common.rc)
|
ENV ABI "riscv64-linux-gnu"
|
||||||
|
ENV MESON_OPTS "--cross-file=riscv64-linux-gnu"
|
||||||
ENV QEMU_CONFIGURE_OPTS --cross-prefix=riscv64-linux-gnu-
|
ENV QEMU_CONFIGURE_OPTS --cross-prefix=riscv64-linux-gnu-
|
||||||
ENV DEF_TARGET_LIST riscv64-softmmu,riscv64-linux-user
|
ENV DEF_TARGET_LIST riscv64-softmmu,riscv64-linux-user
|
||||||
# As a final step configure the user (if env is defined)
|
# As a final step configure the user (if env is defined)
|
||||||
|
@ -24,6 +24,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
|
|||||||
exuberant-ctags \
|
exuberant-ctags \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# $ lcitool dockerfile --layers all --cross mingw32 fedora-37 qemu
|
# $ lcitool dockerfile --layers all --cross mingw32 fedora-38 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
FROM registry.fedoraproject.org/fedora:37
|
FROM registry.fedoraproject.org/fedora:38
|
||||||
|
|
||||||
RUN dnf install -y nosync && \
|
RUN dnf install -y nosync && \
|
||||||
printf '#!/bin/sh\n\
|
printf '#!/bin/sh\n\
|
||||||
@ -29,6 +29,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
diffutils \
|
diffutils \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
git \
|
git \
|
||||||
glib2-devel \
|
glib2-devel \
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# $ lcitool dockerfile --layers all --cross mingw64 fedora-37 qemu
|
# $ lcitool dockerfile --layers all --cross mingw64 fedora-38 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
FROM registry.fedoraproject.org/fedora:37
|
FROM registry.fedoraproject.org/fedora:38
|
||||||
|
|
||||||
RUN dnf install -y nosync && \
|
RUN dnf install -y nosync && \
|
||||||
printf '#!/bin/sh\n\
|
printf '#!/bin/sh\n\
|
||||||
@ -29,6 +29,7 @@ exec "$@"\n' > /usr/bin/nosync && \
|
|||||||
diffutils \
|
diffutils \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
gcc \
|
||||||
gcovr \
|
gcovr \
|
||||||
git \
|
git \
|
||||||
glib2-devel \
|
glib2-devel \
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
#
|
#
|
||||||
# $ lcitool dockerfile --layers all fedora-37 qemu
|
# $ lcitool dockerfile --layers all fedora-38 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci
|
||||||
|
|
||||||
FROM registry.fedoraproject.org/fedora:37
|
FROM registry.fedoraproject.org/fedora:38
|
||||||
|
|
||||||
RUN dnf install -y nosync && \
|
RUN dnf install -y nosync && \
|
||||||
printf '#!/bin/sh\n\
|
printf '#!/bin/sh\n\
|
||||||
|
28
tests/docker/test-fuzz
Executable file
28
tests/docker/test-fuzz
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
#
|
||||||
|
# Compile and check with oss-fuzz.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2023 Linaro Ltd.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Alex Bennée <alex.bennee@linaro.org>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
. common.rc
|
||||||
|
|
||||||
|
requires_binary clang
|
||||||
|
|
||||||
|
# the build script runs out of $src so we need to copy across
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
cp -a $QEMU_SRC .
|
||||||
|
cd src
|
||||||
|
mkdir build-oss-fuzz
|
||||||
|
export LSAN_OPTIONS=suppressions=scripts/oss-fuzz/lsan_suppressions.txt
|
||||||
|
env CC="clang" CXX="clang++" CFLAGS="-fsanitize=address" ./scripts/oss-fuzz/build.sh
|
||||||
|
export ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||||
|
for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f | grep -v slirp); do
|
||||||
|
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
|
||||||
|
echo Testing ${fuzzer} ... ;
|
||||||
|
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
||||||
|
done
|
@ -1 +1 @@
|
|||||||
Subproject commit c8971e90ac169ee2b539c747f74d96c876debdf9
|
Subproject commit b0f44f929a81c0a604fb7fbf8afc34d37ab0eae9
|
27
tests/lcitool/projects/qemu-minimal.yml
Normal file
27
tests/lcitool/projects/qemu-minimal.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Very minimal set of qemu packages, used for minimal cross-compile sanity checks
|
||||||
|
---
|
||||||
|
packages:
|
||||||
|
- bash
|
||||||
|
- bc
|
||||||
|
- bison
|
||||||
|
- ccache
|
||||||
|
- findutils
|
||||||
|
- flex
|
||||||
|
- g++
|
||||||
|
- gcc
|
||||||
|
- gcc-native
|
||||||
|
- glib2
|
||||||
|
- glib2-native
|
||||||
|
- glib2-static
|
||||||
|
- libc-static
|
||||||
|
- libfdt
|
||||||
|
- libffi
|
||||||
|
- make
|
||||||
|
- meson
|
||||||
|
- ninja
|
||||||
|
- pixman
|
||||||
|
- pkg-config
|
||||||
|
- python3
|
||||||
|
- python3-venv
|
||||||
|
- sed
|
||||||
|
- tar
|
@ -24,6 +24,7 @@ packages:
|
|||||||
- fuse3
|
- fuse3
|
||||||
- g++
|
- g++
|
||||||
- gcc
|
- gcc
|
||||||
|
- gcc-native
|
||||||
- gcovr
|
- gcovr
|
||||||
- gettext
|
- gettext
|
||||||
- glib2
|
- glib2
|
||||||
|
@ -63,12 +63,12 @@ add_user_mapping = [
|
|||||||
" id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi\n"
|
" id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi\n"
|
||||||
]
|
]
|
||||||
|
|
||||||
def generate_dockerfile(host, target, cross=None, trailer=None):
|
def generate_dockerfile(host, target, project="qemu", cross=None, trailer=None):
|
||||||
filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker")
|
filename = Path(src_dir, "tests", "docker", "dockerfiles", host + ".docker")
|
||||||
cmd = lcitool_cmd + ["dockerfile"]
|
cmd = lcitool_cmd + ["dockerfile"]
|
||||||
if cross is not None:
|
if cross is not None:
|
||||||
cmd.extend(["--cross", cross])
|
cmd.extend(["--cross", cross])
|
||||||
cmd.extend([target, "qemu"])
|
cmd.extend([target, project])
|
||||||
|
|
||||||
if trailer is not None:
|
if trailer is not None:
|
||||||
trailer += "\n".join(add_user_mapping)
|
trailer += "\n".join(add_user_mapping)
|
||||||
@ -115,11 +115,11 @@ try:
|
|||||||
#
|
#
|
||||||
# Standard native builds
|
# Standard native builds
|
||||||
#
|
#
|
||||||
generate_dockerfile("alpine", "alpine-316")
|
generate_dockerfile("alpine", "alpine-318")
|
||||||
generate_dockerfile("centos8", "centos-stream-8")
|
generate_dockerfile("centos8", "centos-stream-8")
|
||||||
generate_dockerfile("debian-amd64", "debian-11",
|
generate_dockerfile("debian-amd64", "debian-11",
|
||||||
trailer="".join(debian11_extras))
|
trailer="".join(debian11_extras))
|
||||||
generate_dockerfile("fedora", "fedora-37")
|
generate_dockerfile("fedora", "fedora-38")
|
||||||
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
|
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
|
||||||
generate_dockerfile("ubuntu2004", "ubuntu-2004")
|
generate_dockerfile("ubuntu2004", "ubuntu-2004")
|
||||||
generate_dockerfile("ubuntu2204", "ubuntu-2204")
|
generate_dockerfile("ubuntu2204", "ubuntu-2204")
|
||||||
@ -164,17 +164,23 @@ try:
|
|||||||
trailer=cross_build("powerpc64le-linux-gnu-",
|
trailer=cross_build("powerpc64le-linux-gnu-",
|
||||||
"ppc64-softmmu,ppc64-linux-user"))
|
"ppc64-softmmu,ppc64-linux-user"))
|
||||||
|
|
||||||
|
generate_dockerfile("debian-riscv64-cross", "debian-sid",
|
||||||
|
project="qemu-minimal",
|
||||||
|
cross="riscv64",
|
||||||
|
trailer=cross_build("riscv64-linux-gnu-",
|
||||||
|
"riscv64-softmmu,riscv64-linux-user"))
|
||||||
|
|
||||||
generate_dockerfile("debian-s390x-cross", "debian-11",
|
generate_dockerfile("debian-s390x-cross", "debian-11",
|
||||||
cross="s390x",
|
cross="s390x",
|
||||||
trailer=cross_build("s390x-linux-gnu-",
|
trailer=cross_build("s390x-linux-gnu-",
|
||||||
"s390x-softmmu,s390x-linux-user"))
|
"s390x-softmmu,s390x-linux-user"))
|
||||||
|
|
||||||
generate_dockerfile("fedora-win32-cross", "fedora-37",
|
generate_dockerfile("fedora-win32-cross", "fedora-38",
|
||||||
cross="mingw32",
|
cross="mingw32",
|
||||||
trailer=cross_build("i686-w64-mingw32-",
|
trailer=cross_build("i686-w64-mingw32-",
|
||||||
"i386-softmmu"))
|
"i386-softmmu"))
|
||||||
|
|
||||||
generate_dockerfile("fedora-win64-cross", "fedora-37",
|
generate_dockerfile("fedora-win64-cross", "fedora-38",
|
||||||
cross="mingw64",
|
cross="mingw64",
|
||||||
trailer=cross_build("x86_64-w64-mingw32-",
|
trailer=cross_build("x86_64-w64-mingw32-",
|
||||||
"x86_64-softmmu"))
|
"x86_64-softmmu"))
|
||||||
|
@ -104,7 +104,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||||
|
@ -189,7 +189,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||||
|
@ -83,7 +83,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "haddr") == 0) {
|
if (g_strcmp0(tokens[0], "haddr") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_haddr)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_haddr)) {
|
||||||
|
@ -121,7 +121,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
|||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
|
|
||||||
if (g_strcmp0(tokens[0], "print") == 0) {
|
if (g_strcmp0(tokens[0], "print") == 0) {
|
||||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
|
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
|
||||||
|
@ -954,17 +954,10 @@ static void register_generic_fuzz_targets(void)
|
|||||||
.crossover = generic_fuzz_crossover
|
.crossover = generic_fuzz_crossover
|
||||||
});
|
});
|
||||||
|
|
||||||
GString *name;
|
for (int i = 0; i < ARRAY_SIZE(predefined_configs); i++) {
|
||||||
const generic_fuzz_config *config;
|
const generic_fuzz_config *config = predefined_configs + i;
|
||||||
|
|
||||||
for (int i = 0;
|
|
||||||
i < sizeof(predefined_configs) / sizeof(generic_fuzz_config);
|
|
||||||
i++) {
|
|
||||||
config = predefined_configs + i;
|
|
||||||
name = g_string_new("generic-fuzz");
|
|
||||||
g_string_append_printf(name, "-%s", config->name);
|
|
||||||
fuzz_add_target(&(FuzzTarget){
|
fuzz_add_target(&(FuzzTarget){
|
||||||
.name = name->str,
|
.name = g_strconcat("generic-fuzz-", config->name, NULL),
|
||||||
.description = "Predefined generic-fuzz config.",
|
.description = "Predefined generic-fuzz config.",
|
||||||
.get_init_cmdline = generic_fuzz_predefined_config_cmdline,
|
.get_init_cmdline = generic_fuzz_predefined_config_cmdline,
|
||||||
.pre_fuzz = generic_pre_fuzz,
|
.pre_fuzz = generic_pre_fuzz,
|
||||||
|
@ -169,13 +169,17 @@ extract-plugin = $(wordlist 2, 2, $(subst -with-, ,$1))
|
|||||||
|
|
||||||
RUN_TESTS+=$(EXTRA_RUNS)
|
RUN_TESTS+=$(EXTRA_RUNS)
|
||||||
|
|
||||||
|
# Some plugins need additional arguments above the default to fully
|
||||||
|
# exercise things. We can define them on a per-test basis here.
|
||||||
|
run-plugin-%-with-libmem.so: PLUGIN_ARGS=$(COMMA)inline=true$(COMMA)callback=true
|
||||||
|
|
||||||
ifeq ($(filter %-softmmu, $(TARGET)),)
|
ifeq ($(filter %-softmmu, $(TARGET)),)
|
||||||
run-%: %
|
run-%: %
|
||||||
$(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<)
|
$(call run-test, $<, $(QEMU) $(QEMU_OPTS) $<)
|
||||||
|
|
||||||
run-plugin-%:
|
run-plugin-%:
|
||||||
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
|
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
|
||||||
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
|
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
|
||||||
-d plugin -D $*.pout \
|
-d plugin -D $*.pout \
|
||||||
$(call strip-plugin,$<))
|
$(call strip-plugin,$<))
|
||||||
else
|
else
|
||||||
@ -189,7 +193,7 @@ run-plugin-%:
|
|||||||
$(call run-test, $@, \
|
$(call run-test, $@, \
|
||||||
$(QEMU) -monitor none -display none \
|
$(QEMU) -monitor none -display none \
|
||||||
-chardev file$(COMMA)path=$@.out$(COMMA)id=output \
|
-chardev file$(COMMA)path=$@.out$(COMMA)id=output \
|
||||||
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@) \
|
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
|
||||||
-d plugin -D $*.pout \
|
-d plugin -D $*.pout \
|
||||||
$(QEMU_OPTS) $(call strip-plugin,$<))
|
$(QEMU_OPTS) $(call strip-plugin,$<))
|
||||||
endif
|
endif
|
||||||
|
@ -91,6 +91,14 @@ sha512-vector: sha512.c
|
|||||||
|
|
||||||
TESTS += sha512-vector
|
TESTS += sha512-vector
|
||||||
|
|
||||||
|
ifneq ($(CROSS_CC_HAS_SVE),)
|
||||||
|
sha512-sve: CFLAGS=-O3 -march=armv8.1-a+sve
|
||||||
|
sha512-sve: sha512.c
|
||||||
|
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
TESTS += sha512-sve
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HOST_GDB_SUPPORTS_ARCH),y)
|
ifeq ($(HOST_GDB_SUPPORTS_ARCH),y)
|
||||||
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
|
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
|
||||||
|
|
||||||
|
@ -81,6 +81,13 @@ run-gdbstub-qxfer-auxv-read: sha1
|
|||||||
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-qxfer-auxv-read.py, \
|
||||||
basic gdbstub qXfer:auxv:read support)
|
basic gdbstub qXfer:auxv:read support)
|
||||||
|
|
||||||
|
run-gdbstub-proc-mappings: sha1
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(HAVE_GDB_BIN) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(MULTIARCH_SRC)/gdbstub/test-proc-mappings.py, \
|
||||||
|
proc mappings support)
|
||||||
|
|
||||||
run-gdbstub-thread-breakpoint: testthread
|
run-gdbstub-thread-breakpoint: testthread
|
||||||
$(call run-test, $@, $(GDB_SCRIPT) \
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
--gdb $(HAVE_GDB_BIN) \
|
--gdb $(HAVE_GDB_BIN) \
|
||||||
@ -97,7 +104,7 @@ run-gdbstub-%:
|
|||||||
$(call skip-test, "gdbstub test $*", "need working gdb")
|
$(call skip-test, "gdbstub test $*", "need working gdb")
|
||||||
endif
|
endif
|
||||||
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
||||||
run-gdbstub-thread-breakpoint
|
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint
|
||||||
|
|
||||||
# ARM Compatible Semi Hosting Tests
|
# ARM Compatible Semi Hosting Tests
|
||||||
#
|
#
|
||||||
|
65
tests/tcg/multiarch/gdbstub/test-proc-mappings.py
Normal file
65
tests/tcg/multiarch/gdbstub/test-proc-mappings.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"""Test that gdbstub has access to proc mappings.
|
||||||
|
|
||||||
|
This runs as a sourced script (via -x, via run-test.py)."""
|
||||||
|
from __future__ import print_function
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
n_failures = 0
|
||||||
|
|
||||||
|
|
||||||
|
def report(cond, msg):
|
||||||
|
"""Report success/fail of a test"""
|
||||||
|
if cond:
|
||||||
|
print("PASS: {}".format(msg))
|
||||||
|
else:
|
||||||
|
print("FAIL: {}".format(msg))
|
||||||
|
global n_failures
|
||||||
|
n_failures += 1
|
||||||
|
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"""Run through the tests one by one"""
|
||||||
|
try:
|
||||||
|
mappings = gdb.execute("info proc mappings", False, True)
|
||||||
|
except gdb.error as exc:
|
||||||
|
exc_str = str(exc)
|
||||||
|
if "Not supported on this target." in exc_str:
|
||||||
|
# Detect failures due to an outstanding issue with how GDB handles
|
||||||
|
# the x86_64 QEMU's target.xml, which does not contain the
|
||||||
|
# definition of orig_rax. Skip the test in this case.
|
||||||
|
print("SKIP: {}".format(exc_str))
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
report(isinstance(mappings, str), "Fetched the mappings from the inferior")
|
||||||
|
report("/sha1" in mappings, "Found the test binary name in the mappings")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Prepare the environment and run through the tests"""
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
print("ATTACHED: {}".format(inferior.architecture().name()))
|
||||||
|
except (gdb.error, AttributeError):
|
||||||
|
print("SKIPPING (not connected)")
|
||||||
|
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:
|
||||||
|
report(False, "GDB Exception: {}".format(sys.exc_info()[0]))
|
||||||
|
print("All tests complete: %d failures" % n_failures)
|
||||||
|
exit(n_failures)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
Loading…
x
Reference in New Issue
Block a user