mirror of https://github.com/xemu-project/xemu.git
linux-user: Allow gdbstub to ignore page protection
cpu-exec: simplify jump cache management include/exec: Cleanups toward building accel/tcg once -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmW4LXcdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+CgAf8CdqkvKsUK9/5bu99 9E4kRBkR8KqWYvBfRs4IFmjoEdEa4sCujWrHliOcW7Kh+XlVyAPI9rZG32QkxCEQ hi9WXieXjfPLTTmrbeiq7cwxztSj8Z55wwvbxkrtFyGDQ0AMccp49tAvfejEb6VD Ssx96nWQDgryLrn+My+wMQjl9aVKUWp5vB8k12aAcpRXPH2yoGE2JHAZ1C743nA6 rShiJAT78HwERcMXDeYmmriYg0s4Z4+A6ErTiXDnFgj87YanHZc0I/55G5Sh+pW8 REicD3jwS0GHOOHL0K781FopE1wTM442GLVxobXoxUXsHEiO+3TK5JdEIqvSstYA fRB8Pg== =xZOe -----END PGP SIGNATURE----- Merge tag 'pull-tcg-20240130' of https://gitlab.com/rth7680/qemu into staging linux-user: Allow gdbstub to ignore page protection cpu-exec: simplify jump cache management include/exec: Cleanups toward building accel/tcg once # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmW4LXcdHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+CgAf8CdqkvKsUK9/5bu99 # 9E4kRBkR8KqWYvBfRs4IFmjoEdEa4sCujWrHliOcW7Kh+XlVyAPI9rZG32QkxCEQ # hi9WXieXjfPLTTmrbeiq7cwxztSj8Z55wwvbxkrtFyGDQ0AMccp49tAvfejEb6VD # Ssx96nWQDgryLrn+My+wMQjl9aVKUWp5vB8k12aAcpRXPH2yoGE2JHAZ1C743nA6 # rShiJAT78HwERcMXDeYmmriYg0s4Z4+A6ErTiXDnFgj87YanHZc0I/55G5Sh+pW8 # REicD3jwS0GHOOHL0K781FopE1wTM442GLVxobXoxUXsHEiO+3TK5JdEIqvSstYA # fRB8Pg== # =xZOe # -----END PGP SIGNATURE----- # gpg: Signature made Mon 29 Jan 2024 22:57:59 GMT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * tag 'pull-tcg-20240130' of https://gitlab.com/rth7680/qemu: (31 commits) target/i386: Extract x86_cpu_exec_halt() from accel/tcg/ accel/tcg: Introduce TCGCPUOps::cpu_exec_halt() handler accel/tcg: Inline need_replay_interrupt target/i386: Extract x86_need_replay_interrupt() from accel/tcg/ accel/tcg: Introduce TCGCPUOps::need_replay_interrupt() handler accel/tcg: Use CPUState.cc instead of CPU_GET_CLASS in cpu-exec.c target/loongarch: Constify loongarch_tcg_ops include/qemu: Add TCGCPUOps typedef to typedefs.h accel/tcg: Un-inline icount_exit_request() for clarity accel/tcg: Rename tcg_cpus_exec() -> tcg_cpu_exec() accel/tcg: Rename tcg_cpus_destroy() -> tcg_cpu_destroy() accel/tcg: Rename tcg_ss[] -> tcg_specific_ss[] in meson accel/tcg: Move perf and debuginfo support to tcg/ accel/tcg: Remove #ifdef TARGET_I386 from perf.c tcg: Make tb_cflags() usable from target-agnostic code accel/tcg: Make use of qemu_target_page_mask() in perf.c target: Make qemu_target_page_mask() available for *-user accel/tcg/cpu-exec: Use RCU_READ_LOCK_GUARD tests/tcg: Add the PROT_NONE gdbstub test tests/tcg: Factor out gdbstub test functions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1c8e621f09
|
@ -30,9 +30,6 @@
|
|||
#include "qemu/rcu.h"
|
||||
#include "exec/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/i386/apic.h"
|
||||
#endif
|
||||
#include "sysemu/cpus.h"
|
||||
#include "exec/cpu-all.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
|
@ -253,43 +250,29 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, vaddr pc,
|
|||
hash = tb_jmp_cache_hash_func(pc);
|
||||
jc = cpu->tb_jmp_cache;
|
||||
|
||||
if (cflags & CF_PCREL) {
|
||||
/* Use acquire to ensure current load of pc from jc. */
|
||||
tb = qatomic_load_acquire(&jc->array[hash].tb);
|
||||
|
||||
if (likely(tb &&
|
||||
jc->array[hash].pc == pc &&
|
||||
tb->cs_base == cs_base &&
|
||||
tb->flags == flags &&
|
||||
tb_cflags(tb) == cflags)) {
|
||||
return tb;
|
||||
}
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
jc->array[hash].pc = pc;
|
||||
/* Ensure pc is written first. */
|
||||
qatomic_store_release(&jc->array[hash].tb, tb);
|
||||
} else {
|
||||
/* Use rcu_read to ensure current load of pc from *tb. */
|
||||
tb = qatomic_rcu_read(&jc->array[hash].tb);
|
||||
|
||||
if (likely(tb &&
|
||||
tb->pc == pc &&
|
||||
tb->cs_base == cs_base &&
|
||||
tb->flags == flags &&
|
||||
tb_cflags(tb) == cflags)) {
|
||||
return tb;
|
||||
}
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* Use the pc value already stored in tb->pc. */
|
||||
qatomic_set(&jc->array[hash].tb, tb);
|
||||
tb = qatomic_read(&jc->array[hash].tb);
|
||||
if (likely(tb &&
|
||||
jc->array[hash].pc == pc &&
|
||||
tb->cs_base == cs_base &&
|
||||
tb->flags == flags &&
|
||||
tb_cflags(tb) == cflags)) {
|
||||
goto hit;
|
||||
}
|
||||
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jc->array[hash].pc = pc;
|
||||
qatomic_set(&jc->array[hash].tb, tb);
|
||||
|
||||
hit:
|
||||
/*
|
||||
* As long as tb is not NULL, the contents are consistent. Therefore,
|
||||
* the virtual PC has to match for non-CF_PCREL translations.
|
||||
*/
|
||||
assert((tb_cflags(tb) & CF_PCREL) || tb->pc == pc);
|
||||
return tb;
|
||||
}
|
||||
|
||||
|
@ -357,9 +340,9 @@ static bool check_for_breakpoints_slow(CPUState *cpu, vaddr pc,
|
|||
#ifdef CONFIG_USER_ONLY
|
||||
g_assert_not_reached();
|
||||
#else
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
assert(cc->tcg_ops->debug_check_breakpoint);
|
||||
match_bp = cc->tcg_ops->debug_check_breakpoint(cpu);
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
assert(tcg_ops->debug_check_breakpoint);
|
||||
match_bp = tcg_ops->debug_check_breakpoint(cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -476,10 +459,11 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||
* counter hit zero); we must restore the guest PC to the address
|
||||
* of the start of the TB.
|
||||
*/
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
CPUClass *cc = cpu->cc;
|
||||
const TCGCPUOps *tcg_ops = cc->tcg_ops;
|
||||
|
||||
if (cc->tcg_ops->synchronize_from_tb) {
|
||||
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
|
||||
if (tcg_ops->synchronize_from_tb) {
|
||||
tcg_ops->synchronize_from_tb(cpu, last_tb);
|
||||
} else {
|
||||
tcg_debug_assert(!(tb_cflags(last_tb) & CF_PCREL));
|
||||
assert(cc->set_pc);
|
||||
|
@ -511,19 +495,19 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||
|
||||
static void cpu_exec_enter(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_enter) {
|
||||
cc->tcg_ops->cpu_exec_enter(cpu);
|
||||
if (tcg_ops->cpu_exec_enter) {
|
||||
tcg_ops->cpu_exec_enter(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_exec_exit(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_exit) {
|
||||
cc->tcg_ops->cpu_exec_exit(cpu);
|
||||
if (tcg_ops->cpu_exec_exit) {
|
||||
tcg_ops->cpu_exec_exit(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -677,15 +661,11 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
|||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->halted) {
|
||||
#if defined(TARGET_I386)
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
bql_lock();
|
||||
apic_poll_irq(x86_cpu->apic_state);
|
||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||
bql_unlock();
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
|
||||
if (tcg_ops->cpu_exec_halt) {
|
||||
tcg_ops->cpu_exec_halt(cpu);
|
||||
}
|
||||
#endif /* TARGET_I386 */
|
||||
if (!cpu_has_work(cpu)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -699,7 +679,7 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
|||
|
||||
static inline void cpu_handle_debug_exception(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
CPUWatchpoint *wp;
|
||||
|
||||
if (!cpu->watchpoint_hit) {
|
||||
|
@ -708,8 +688,8 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
if (cc->tcg_ops->debug_excp_handler) {
|
||||
cc->tcg_ops->debug_excp_handler(cpu);
|
||||
if (tcg_ops->debug_excp_handler) {
|
||||
tcg_ops->debug_excp_handler(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,6 +706,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cpu->exception_index >= EXCP_INTERRUPT) {
|
||||
/* exit request from the cpu execution loop */
|
||||
*ret = cpu->exception_index;
|
||||
|
@ -734,62 +715,59 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
}
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
} else {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* if user mode only, we simulate a fake exception
|
||||
which will be handled outside the cpu execution
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tcg_ops->fake_user_interrupt(cpu);
|
||||
#endif /* TARGET_I386 */
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
#else
|
||||
if (replay_exception()) {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
bql_lock();
|
||||
cc->tcg_ops->do_interrupt(cpu);
|
||||
bql_unlock();
|
||||
cpu->exception_index = -1;
|
||||
}
|
||||
|
||||
if (unlikely(cpu->singlestep_enabled)) {
|
||||
/*
|
||||
* After processing the exception, ensure an EXCP_DEBUG is
|
||||
* raised when single-stepping so that GDB doesn't miss the
|
||||
* next instruction.
|
||||
*/
|
||||
*ret = EXCP_DEBUG;
|
||||
cpu_handle_debug_exception(cpu);
|
||||
return true;
|
||||
}
|
||||
} else if (!replay_has_interrupt()) {
|
||||
/* give a chance to iothread in replay mode */
|
||||
*ret = EXCP_INTERRUPT;
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/*
|
||||
* If user mode only, we simulate a fake exception which will be
|
||||
* handled outside the cpu execution loop.
|
||||
*/
|
||||
#if defined(TARGET_I386)
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
tcg_ops->fake_user_interrupt(cpu);
|
||||
#endif /* TARGET_I386 */
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
#else
|
||||
if (replay_exception()) {
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
|
||||
bql_lock();
|
||||
tcg_ops->do_interrupt(cpu);
|
||||
bql_unlock();
|
||||
cpu->exception_index = -1;
|
||||
|
||||
if (unlikely(cpu->singlestep_enabled)) {
|
||||
/*
|
||||
* After processing the exception, ensure an EXCP_DEBUG is
|
||||
* raised when single-stepping so that GDB doesn't miss the
|
||||
* next instruction.
|
||||
*/
|
||||
*ret = EXCP_DEBUG;
|
||||
cpu_handle_debug_exception(cpu);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
} else if (!replay_has_interrupt()) {
|
||||
/* give a chance to iothread in replay mode */
|
||||
*ret = EXCP_INTERRUPT;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||
* "real" interrupt event later. It does not need to be recorded for
|
||||
* replay purposes.
|
||||
*/
|
||||
static inline bool need_replay_interrupt(int interrupt_request)
|
||||
static inline bool icount_exit_request(CPUState *cpu)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
return !(interrupt_request & CPU_INTERRUPT_POLL);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
if (!icount_enabled()) {
|
||||
return false;
|
||||
}
|
||||
if (cpu->cflags_next_tb != -1 && !(cpu->cflags_next_tb & CF_USE_ICOUNT)) {
|
||||
return false;
|
||||
}
|
||||
return cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
|
@ -859,11 +837,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
True when it is, and we should restart on a new TB,
|
||||
and via longjmp via cpu_loop_exit. */
|
||||
else {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_interrupt &&
|
||||
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
if (need_replay_interrupt(interrupt_request)) {
|
||||
if (tcg_ops->cpu_exec_interrupt &&
|
||||
tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
if (!tcg_ops->need_replay_interrupt ||
|
||||
tcg_ops->need_replay_interrupt(interrupt_request)) {
|
||||
replay_interrupt();
|
||||
}
|
||||
/*
|
||||
|
@ -896,10 +875,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
}
|
||||
|
||||
/* Finally, check if we need to exit to the main loop. */
|
||||
if (unlikely(qatomic_read(&cpu->exit_request))
|
||||
|| (icount_enabled()
|
||||
&& (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT)
|
||||
&& cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0)) {
|
||||
if (unlikely(qatomic_read(&cpu->exit_request)) || icount_exit_request(cpu)) {
|
||||
qatomic_set(&cpu->exit_request, 0);
|
||||
if (cpu->exception_index == -1) {
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
|
@ -1012,14 +988,8 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
|
|||
*/
|
||||
h = tb_jmp_cache_hash_func(pc);
|
||||
jc = cpu->tb_jmp_cache;
|
||||
if (cflags & CF_PCREL) {
|
||||
jc->array[h].pc = pc;
|
||||
/* Ensure pc is written first. */
|
||||
qatomic_store_release(&jc->array[h].tb, tb);
|
||||
} else {
|
||||
/* Use the pc value already stored in tb->pc. */
|
||||
qatomic_set(&jc->array[h].tb, tb);
|
||||
}
|
||||
jc->array[h].pc = pc;
|
||||
qatomic_set(&jc->array[h].tb, tb);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@ -1070,7 +1040,7 @@ int cpu_exec(CPUState *cpu)
|
|||
return EXCP_HALTED;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
RCU_READ_LOCK_GUARD();
|
||||
cpu_exec_enter(cpu);
|
||||
|
||||
/*
|
||||
|
@ -1084,18 +1054,15 @@ int cpu_exec(CPUState *cpu)
|
|||
ret = cpu_exec_setjmp(cpu, &sc);
|
||||
|
||||
cpu_exec_exit(cpu);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
|
||||
{
|
||||
static bool tcg_target_initialized;
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (!tcg_target_initialized) {
|
||||
cc->tcg_ops->initialize();
|
||||
cpu->cc->tcg_ops->initialize();
|
||||
tcg_target_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
tcg_ss = ss.source_set()
|
||||
common_ss.add(when: 'CONFIG_TCG', if_true: files(
|
||||
'cpu-exec-common.c',
|
||||
))
|
||||
tcg_ss.add(files(
|
||||
tcg_specific_ss = ss.source_set()
|
||||
tcg_specific_ss.add(files(
|
||||
'tcg-all.c',
|
||||
'cpu-exec.c',
|
||||
'tb-maint.c',
|
||||
|
@ -11,16 +11,12 @@ tcg_ss.add(files(
|
|||
'translate-all.c',
|
||||
'translator.c',
|
||||
))
|
||||
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||
tcg_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c'))
|
||||
tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||
tcg_specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c'))
|
||||
if get_option('plugins')
|
||||
tcg_ss.add(files('plugin-gen.c'))
|
||||
tcg_specific_ss.add(files('plugin-gen.c'))
|
||||
endif
|
||||
tcg_ss.add(when: libdw, if_true: files('debuginfo.c'))
|
||||
if host_os == 'linux'
|
||||
tcg_ss.add(files('perf.c'))
|
||||
endif
|
||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss)
|
||||
|
||||
specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files(
|
||||
'cputlb.c',
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
|
||||
|
||||
/*
|
||||
* Accessed in parallel; all accesses to 'tb' must be atomic.
|
||||
* For CF_PCREL, accesses to 'pc' must be protected by a
|
||||
* load_acquire/store_release to 'tb'.
|
||||
* Invalidated in parallel; all accesses to 'tb' must be atomic.
|
||||
* A valid entry is read/written by a single CPU, therefore there is
|
||||
* no need for qatomic_rcu_read() and pc is always consistent with a
|
||||
* non-NULL value of 'tb'. Strictly speaking pc is only needed for
|
||||
* CF_PCREL, but it's used always for simplicity.
|
||||
*/
|
||||
struct CPUJumpCache {
|
||||
struct rcu_head rcu;
|
||||
|
|
|
@ -92,7 +92,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
|
|||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
bql_unlock();
|
||||
r = tcg_cpus_exec(cpu);
|
||||
r = tcg_cpu_exec(cpu);
|
||||
bql_lock();
|
||||
switch (r) {
|
||||
case EXCP_DEBUG:
|
||||
|
@ -118,7 +118,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
|
|||
qemu_wait_io_event(cpu);
|
||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||
|
||||
tcg_cpus_destroy(cpu);
|
||||
tcg_cpu_destroy(cpu);
|
||||
bql_unlock();
|
||||
rcu_remove_force_rcu_notifier(&force_rcu.notifier);
|
||||
rcu_unregister_thread();
|
||||
|
|
|
@ -131,7 +131,7 @@ static void rr_deal_with_unplugged_cpus(void)
|
|||
|
||||
CPU_FOREACH(cpu) {
|
||||
if (cpu->unplug && !cpu_can_run(cpu)) {
|
||||
tcg_cpus_destroy(cpu);
|
||||
tcg_cpu_destroy(cpu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ static void *rr_cpu_thread_fn(void *arg)
|
|||
if (icount_enabled()) {
|
||||
icount_prepare_for_run(cpu, cpu_budget);
|
||||
}
|
||||
r = tcg_cpus_exec(cpu);
|
||||
r = tcg_cpu_exec(cpu);
|
||||
if (icount_enabled()) {
|
||||
icount_process_data(cpu);
|
||||
}
|
||||
|
|
|
@ -63,12 +63,12 @@ void tcg_cpu_init_cflags(CPUState *cpu, bool parallel)
|
|||
cpu->tcg_cflags |= cflags;
|
||||
}
|
||||
|
||||
void tcg_cpus_destroy(CPUState *cpu)
|
||||
void tcg_cpu_destroy(CPUState *cpu)
|
||||
{
|
||||
cpu_thread_signal_destroyed(cpu);
|
||||
}
|
||||
|
||||
int tcg_cpus_exec(CPUState *cpu)
|
||||
int tcg_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
int ret;
|
||||
assert(tcg_enabled());
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
void tcg_cpus_destroy(CPUState *cpu);
|
||||
int tcg_cpus_exec(CPUState *cpu);
|
||||
void tcg_cpu_destroy(CPUState *cpu);
|
||||
int tcg_cpu_exec(CPUState *cpu);
|
||||
void tcg_handle_interrupt(CPUState *cpu, int mask);
|
||||
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
#include "tb-context.h"
|
||||
#include "internal-common.h"
|
||||
#include "internal-target.h"
|
||||
#include "perf.h"
|
||||
#include "tcg/perf.h"
|
||||
#include "tcg/insn-start-words.h"
|
||||
|
||||
TBContext tb_ctx;
|
||||
|
|
|
@ -1022,7 +1022,7 @@ void process_pending_signals(CPUArchState *env)
|
|||
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type, bool maperr, uintptr_t ra)
|
||||
{
|
||||
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
|
||||
if (tcg_ops->record_sigsegv) {
|
||||
tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
|
||||
|
@ -1038,7 +1038,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
|||
void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type, uintptr_t ra)
|
||||
{
|
||||
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
|
||||
if (tcg_ops->record_sigbus) {
|
||||
tcg_ops->record_sigbus(cpu, addr, access_type, ra);
|
||||
|
|
78
cpu-target.c
78
cpu-target.c
|
@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
|||
vaddr l, page;
|
||||
void * p;
|
||||
uint8_t *buf = ptr;
|
||||
ssize_t written;
|
||||
int ret = -1;
|
||||
int fd = -1;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
|
@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
|
|||
if (l > len)
|
||||
l = len;
|
||||
flags = page_get_flags(page);
|
||||
if (!(flags & PAGE_VALID))
|
||||
return -1;
|
||||
if (!(flags & PAGE_VALID)) {
|
||||
goto out_close;
|
||||
}
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return -1;
|
||||
if (flags & PAGE_WRITE) {
|
||||
/* XXX: this code should not depend on lock_user */
|
||||
p = lock_user(VERIFY_WRITE, addr, l, 0);
|
||||
if (!p) {
|
||||
goto out_close;
|
||||
}
|
||||
memcpy(p, buf, l);
|
||||
unlock_user(p, addr, l);
|
||||
} else {
|
||||
/* Bypass the host page protection using ptrace. */
|
||||
if (fd == -1) {
|
||||
fd = open("/proc/self/mem", O_WRONLY);
|
||||
if (fd == -1) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If there is a TranslationBlock and we weren't bypassing the
|
||||
* host page protection, the memcpy() above would SEGV,
|
||||
* ultimately leading to page_unprotect(). So invalidate the
|
||||
* translations manually. Both invalidation and pwrite() must
|
||||
* be under mmap_lock() in order to prevent the creation of
|
||||
* another TranslationBlock in between.
|
||||
*/
|
||||
mmap_lock();
|
||||
tb_invalidate_phys_range(addr, addr + l - 1);
|
||||
written = pwrite(fd, buf, l,
|
||||
(off_t)(uintptr_t)g2h_untagged(addr));
|
||||
mmap_unlock();
|
||||
if (written != l) {
|
||||
goto out_close;
|
||||
}
|
||||
}
|
||||
} else if (flags & PAGE_READ) {
|
||||
/* XXX: this code should not depend on lock_user */
|
||||
if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
|
||||
return -1;
|
||||
memcpy(p, buf, l);
|
||||
unlock_user(p, addr, l);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return -1;
|
||||
/* XXX: this code should not depend on lock_user */
|
||||
if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
|
||||
return -1;
|
||||
p = lock_user(VERIFY_READ, addr, l, 1);
|
||||
if (!p) {
|
||||
goto out_close;
|
||||
}
|
||||
memcpy(buf, p, l);
|
||||
unlock_user(p, addr, 0);
|
||||
} else {
|
||||
/* Bypass the host page protection using ptrace. */
|
||||
if (fd == -1) {
|
||||
fd = open("/proc/self/mem", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (pread(fd, buf, l,
|
||||
(off_t)(uintptr_t)g2h_untagged(addr)) != l) {
|
||||
goto out_close;
|
||||
}
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
return 0;
|
||||
ret = 0;
|
||||
out_close:
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
#include "hw/boards.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "accel/tcg/debuginfo.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
|
|
@ -171,34 +171,10 @@ extern const TargetPageBits target_page;
|
|||
|
||||
#define TARGET_PAGE_ALIGN(addr) ROUND_UP((addr), TARGET_PAGE_SIZE)
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/*
|
||||
* Original state of the write flag (used when tracking self-modifying code)
|
||||
*/
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
/*
|
||||
* Invalidate the TLB entry immediately, helpful for s390x
|
||||
* Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
|
||||
*/
|
||||
#define PAGE_WRITE_INV 0x0020
|
||||
/* For use with page_set_flags: page is being replaced; target_data cleared. */
|
||||
#define PAGE_RESET 0x0040
|
||||
/* For linux-user, indicates that the page is MAP_ANON. */
|
||||
#define PAGE_ANON 0x0080
|
||||
|
||||
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
|
||||
/* FIXME: Code that sets/uses this is broken and needs to go away. */
|
||||
#define PAGE_RESERVED 0x0100
|
||||
#endif
|
||||
/* Target-specific bits that will be used via page_get_flags(). */
|
||||
#define PAGE_TARGET_1 0x0200
|
||||
#define PAGE_TARGET_2 0x0400
|
||||
|
||||
/*
|
||||
* For linux-user, indicates that the page is mapped with the same semantics
|
||||
* in both guest and host.
|
||||
|
@ -408,33 +384,8 @@ static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr)
|
|||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/* accel/tcg/cpu-exec.c */
|
||||
int cpu_exec(CPUState *cpu);
|
||||
|
||||
/* Validate correct placement of CPUArchState. */
|
||||
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0);
|
||||
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState));
|
||||
|
||||
/**
|
||||
* env_archcpu(env)
|
||||
* @env: The architecture environment
|
||||
*
|
||||
* Return the ArchCPU associated with the environment.
|
||||
*/
|
||||
static inline ArchCPU *env_archcpu(CPUArchState *env)
|
||||
{
|
||||
return (void *)env - sizeof(CPUState);
|
||||
}
|
||||
|
||||
/**
|
||||
* env_cpu(env)
|
||||
* @env: The architecture environment
|
||||
*
|
||||
* Return the CPUState associated with the environment.
|
||||
*/
|
||||
static inline CPUState *env_cpu(CPUArchState *env)
|
||||
{
|
||||
return (void *)env - sizeof(CPUState);
|
||||
}
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
/* CPU interfaces that are target independent. */
|
||||
|
||||
#include "exec/vaddr.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "exec/hwaddr.h"
|
||||
#endif
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
#define EXCP_INTERRUPT 0x10000 /* async interruption */
|
||||
#define EXCP_HLT 0x10001 /* hlt instruction reached */
|
||||
|
@ -14,18 +16,6 @@
|
|||
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
|
||||
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
|
||||
|
||||
/**
|
||||
* vaddr:
|
||||
* Type wide enough to contain any #target_ulong virtual address.
|
||||
*/
|
||||
typedef uint64_t vaddr;
|
||||
#define VADDR_PRId PRId64
|
||||
#define VADDR_PRIu PRIu64
|
||||
#define VADDR_PRIo PRIo64
|
||||
#define VADDR_PRIx PRIx64
|
||||
#define VADDR_PRIX PRIX64
|
||||
#define VADDR_MAX UINT64_MAX
|
||||
|
||||
void cpu_exec_init_all(void);
|
||||
void cpu_exec_step_atomic(CPUState *cpu);
|
||||
|
||||
|
@ -217,4 +207,59 @@ G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc);
|
|||
G_NORETURN void cpu_loop_exit(CPUState *cpu);
|
||||
G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
|
||||
|
||||
/* same as PROT_xxx */
|
||||
#define PAGE_READ 0x0001
|
||||
#define PAGE_WRITE 0x0002
|
||||
#define PAGE_EXEC 0x0004
|
||||
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
|
||||
#define PAGE_VALID 0x0008
|
||||
/*
|
||||
* Original state of the write flag (used when tracking self-modifying code)
|
||||
*/
|
||||
#define PAGE_WRITE_ORG 0x0010
|
||||
/*
|
||||
* Invalidate the TLB entry immediately, helpful for s390x
|
||||
* Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
|
||||
*/
|
||||
#define PAGE_WRITE_INV 0x0020
|
||||
/* For use with page_set_flags: page is being replaced; target_data cleared. */
|
||||
#define PAGE_RESET 0x0040
|
||||
/* For linux-user, indicates that the page is MAP_ANON. */
|
||||
#define PAGE_ANON 0x0080
|
||||
|
||||
/* Target-specific bits that will be used via page_get_flags(). */
|
||||
#define PAGE_TARGET_1 0x0200
|
||||
#define PAGE_TARGET_2 0x0400
|
||||
|
||||
/*
|
||||
* For linux-user, indicates that the page is mapped with the same semantics
|
||||
* in both guest and host.
|
||||
*/
|
||||
#define PAGE_PASSTHROUGH 0x0800
|
||||
|
||||
/* accel/tcg/cpu-exec.c */
|
||||
int cpu_exec(CPUState *cpu);
|
||||
|
||||
/**
|
||||
* env_archcpu(env)
|
||||
* @env: The architecture environment
|
||||
*
|
||||
* Return the ArchCPU associated with the environment.
|
||||
*/
|
||||
static inline ArchCPU *env_archcpu(CPUArchState *env)
|
||||
{
|
||||
return (void *)env - sizeof(CPUState);
|
||||
}
|
||||
|
||||
/**
|
||||
* env_cpu(env)
|
||||
* @env: The architecture environment
|
||||
*
|
||||
* Return the CPUState associated with the environment.
|
||||
*/
|
||||
static inline CPUState *env_cpu(CPUArchState *env)
|
||||
{
|
||||
return (void *)env - sizeof(CPUState);
|
||||
}
|
||||
|
||||
#endif /* CPU_COMMON_H */
|
||||
|
|
|
@ -121,8 +121,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len)
|
|||
h2g_nocheck(x); \
|
||||
})
|
||||
#else
|
||||
typedef target_ulong abi_ptr;
|
||||
#define TARGET_ABI_FMT_ptr TARGET_FMT_lx
|
||||
typedef vaddr abi_ptr;
|
||||
#define TARGET_ABI_FMT_ptr VADDR_PRIx
|
||||
#endif
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr);
|
||||
|
|
|
@ -459,12 +459,6 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
|||
|
||||
#endif
|
||||
|
||||
/* Hide the qatomic_read to make code a little easier on the eyes */
|
||||
static inline uint32_t tb_cflags(const TranslationBlock *tb)
|
||||
{
|
||||
return qatomic_read(&tb->cflags);
|
||||
}
|
||||
|
||||
static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
|
|
@ -145,4 +145,10 @@ struct TranslationBlock {
|
|||
/* The alignment given to TranslationBlock during allocation. */
|
||||
#define CODE_GEN_ALIGN 16
|
||||
|
||||
/* Hide the qatomic_read to make code a little easier on the eyes */
|
||||
static inline uint32_t tb_cflags(const TranslationBlock *tb)
|
||||
{
|
||||
return qatomic_read(&tb->cflags);
|
||||
}
|
||||
|
||||
#endif /* EXEC_TRANSLATION_BLOCK_H */
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
* the target-specific DisasContext, and then invoke translator_loop.
|
||||
*/
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc);
|
||||
vaddr pc, void *host_pc);
|
||||
|
||||
/**
|
||||
* DisasJumpType:
|
||||
|
@ -79,8 +79,8 @@ typedef enum DisasJumpType {
|
|||
*/
|
||||
typedef struct DisasContextBase {
|
||||
TranslationBlock *tb;
|
||||
target_ulong pc_first;
|
||||
target_ulong pc_next;
|
||||
vaddr pc_first;
|
||||
vaddr pc_next;
|
||||
DisasJumpType is_jmp;
|
||||
int num_insns;
|
||||
int max_insns;
|
||||
|
@ -235,7 +235,7 @@ void translator_fake_ldb(uint8_t insn8, abi_ptr pc);
|
|||
* Translators can use this to enforce the rule that only single-insn
|
||||
* translation blocks are allowed to cross page boundaries.
|
||||
*/
|
||||
static inline bool is_same_page(const DisasContextBase *db, target_ulong addr)
|
||||
static inline bool is_same_page(const DisasContextBase *db, vaddr addr)
|
||||
{
|
||||
return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* Define vaddr. */
|
||||
|
||||
#ifndef VADDR_H
|
||||
#define VADDR_H
|
||||
|
||||
/**
|
||||
* vaddr:
|
||||
* Type wide enough to contain any #target_ulong virtual address.
|
||||
*/
|
||||
typedef uint64_t vaddr;
|
||||
#define VADDR_PRId PRId64
|
||||
#define VADDR_PRIu PRIu64
|
||||
#define VADDR_PRIo PRIo64
|
||||
#define VADDR_PRIx PRIx64
|
||||
#define VADDR_PRIX PRIX64
|
||||
#define VADDR_MAX UINT64_MAX
|
||||
|
||||
#endif
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
#include "hw/qdev-core.h"
|
||||
#include "disas/dis-asm.h"
|
||||
#include "exec/cpu-common.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "exec/vaddr.h"
|
||||
#include "exec/memattrs.h"
|
||||
#include "exec/tlb-common.h"
|
||||
#include "qapi/qapi-types-run-state.h"
|
||||
|
@ -90,9 +90,6 @@ typedef enum MMUAccessType {
|
|||
|
||||
typedef struct CPUWatchpoint CPUWatchpoint;
|
||||
|
||||
/* see tcg-cpu-ops.h */
|
||||
struct TCGCPUOps;
|
||||
|
||||
/* see accel-cpu.h */
|
||||
struct AccelCPUClass;
|
||||
|
||||
|
@ -177,7 +174,7 @@ struct CPUClass {
|
|||
const struct SysemuCPUOps *sysemu_ops;
|
||||
|
||||
/* when TCG is not available, this pointer is NULL */
|
||||
const struct TCGCPUOps *tcg_ops;
|
||||
const TCGCPUOps *tcg_ops;
|
||||
|
||||
/*
|
||||
* if not NULL, this is called in order for the CPUClass to initialize
|
||||
|
|
|
@ -50,7 +50,7 @@ struct TCGCPUOps {
|
|||
void (*debug_excp_handler)(CPUState *cpu);
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
#if defined(CONFIG_USER_ONLY) && defined(TARGET_I386)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/**
|
||||
* @fake_user_interrupt: Callback for 'fake exception' handling.
|
||||
*
|
||||
|
@ -58,13 +58,7 @@ struct TCGCPUOps {
|
|||
* cpu execution loop (hack for x86 user mode).
|
||||
*/
|
||||
void (*fake_user_interrupt)(CPUState *cpu);
|
||||
#else
|
||||
/**
|
||||
* @do_interrupt: Callback for interrupt handling.
|
||||
*/
|
||||
void (*do_interrupt)(CPUState *cpu);
|
||||
#endif /* !CONFIG_USER_ONLY || !TARGET_I386 */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
||||
/**
|
||||
* record_sigsegv:
|
||||
* @cpu: cpu context
|
||||
|
@ -114,8 +108,12 @@ struct TCGCPUOps {
|
|||
void (*record_sigbus)(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, uintptr_t ra);
|
||||
#else
|
||||
/** @do_interrupt: Callback for interrupt handling. */
|
||||
void (*do_interrupt)(CPUState *cpu);
|
||||
/** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
|
||||
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
|
||||
/** @cpu_exec_halt: Callback for handling halt in cpu_exec */
|
||||
void (*cpu_exec_halt)(CPUState *cpu);
|
||||
/**
|
||||
* @tlb_fill: Handle a softmmu tlb miss
|
||||
*
|
||||
|
@ -170,6 +168,11 @@ struct TCGCPUOps {
|
|||
*/
|
||||
bool (*io_recompile_replay_branch)(CPUState *cpu,
|
||||
const TranslationBlock *tb);
|
||||
/**
|
||||
* @need_replay_interrupt: Return %true if @interrupt_request
|
||||
* needs to be recorded for replay purposes.
|
||||
*/
|
||||
bool (*need_replay_interrupt)(int interrupt_request);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
#endif /* NEED_CPU_H */
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ typedef struct Range Range;
|
|||
typedef struct ReservedRegion ReservedRegion;
|
||||
typedef struct SHPCDevice SHPCDevice;
|
||||
typedef struct SSIBus SSIBus;
|
||||
typedef struct TCGCPUOps TCGCPUOps;
|
||||
typedef struct TCGHelperInfo TCGHelperInfo;
|
||||
typedef struct TranslationBlock TranslationBlock;
|
||||
typedef struct VirtIODevice VirtIODevice;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_TCG_DEBUGINFO_H
|
||||
#define ACCEL_TCG_DEBUGINFO_H
|
||||
#ifndef TCG_DEBUGINFO_H
|
||||
#define TCG_DEBUGINFO_H
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_TCG_PERF_H
|
||||
#define ACCEL_TCG_PERF_H
|
||||
#ifndef TCG_PERF_H
|
||||
#define TCG_PERF_H
|
||||
|
||||
#if defined(CONFIG_TCG) && defined(CONFIG_LINUX)
|
||||
/* Start writing perf-<pid>.map. */
|
|
@ -22,7 +22,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "target_signal.h"
|
||||
#include "accel/tcg/debuginfo.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
#include "target/arm/cpu-features.h"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "accel/tcg/perf.h"
|
||||
#include "tcg/perf.h"
|
||||
#include "gdbstub/syscalls.h"
|
||||
#include "qemu.h"
|
||||
#include "user-internals.h"
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
#include "signal-common.h"
|
||||
#include "loader.h"
|
||||
#include "user-mmap.h"
|
||||
#include "accel/tcg/perf.h"
|
||||
#include "tcg/perf.h"
|
||||
|
||||
#ifdef CONFIG_SEMIHOSTING
|
||||
#include "semihosting/semihost.h"
|
||||
|
|
|
@ -671,7 +671,7 @@ void force_sigsegv(int oldsig)
|
|||
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type, bool maperr, uintptr_t ra)
|
||||
{
|
||||
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
|
||||
if (tcg_ops->record_sigsegv) {
|
||||
tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
|
||||
|
@ -687,7 +687,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
|||
void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type, uintptr_t ra)
|
||||
{
|
||||
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
|
||||
|
||||
if (tcg_ops->record_sigbus) {
|
||||
tcg_ops->record_sigbus(cpu, addr, access_type, ra);
|
||||
|
|
|
@ -3431,11 +3431,6 @@ size_t qemu_target_page_size(void)
|
|||
return TARGET_PAGE_SIZE;
|
||||
}
|
||||
|
||||
int qemu_target_page_mask(void)
|
||||
{
|
||||
return TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
int qemu_target_page_bits(void)
|
||||
{
|
||||
return TARGET_PAGE_BITS;
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
#endif
|
||||
#include "sysemu/qtest.h"
|
||||
#ifdef CONFIG_TCG
|
||||
#include "accel/tcg/perf.h"
|
||||
#include "tcg/perf.h"
|
||||
#endif
|
||||
|
||||
#include "disas/disas.h"
|
||||
|
|
|
@ -203,7 +203,7 @@ static const struct SysemuCPUOps alpha_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps alpha_tcg_ops = {
|
||||
static const TCGCPUOps alpha_tcg_ops = {
|
||||
.initialize = alpha_translate_init,
|
||||
.restore_state_to_opc = alpha_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -2971,7 +2971,7 @@ static const TranslatorOps alpha_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
translator_loop(cpu, tb, max_insns, pc, host_pc, &alpha_tr_ops, &dc.base);
|
||||
|
|
|
@ -2458,7 +2458,7 @@ static const struct SysemuCPUOps arm_sysemu_ops = {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_TCG
|
||||
static const struct TCGCPUOps arm_tcg_ops = {
|
||||
static const TCGCPUOps arm_tcg_ops = {
|
||||
.initialize = arm_translate_init,
|
||||
.synchronize_from_tb = arm_cpu_synchronize_from_tb,
|
||||
.debug_excp_handler = arm_debug_excp_handler,
|
||||
|
|
|
@ -1018,7 +1018,7 @@ static void pxa270c5_initfn(Object *obj)
|
|||
cpu->reset_sctlr = 0x00000078;
|
||||
}
|
||||
|
||||
static const struct TCGCPUOps arm_v7m_tcg_ops = {
|
||||
static const TCGCPUOps arm_v7m_tcg_ops = {
|
||||
.initialize = arm_translate_init,
|
||||
.synchronize_from_tb = arm_cpu_synchronize_from_tb,
|
||||
.debug_excp_handler = arm_debug_excp_handler,
|
||||
|
|
|
@ -9691,7 +9691,7 @@ static const TranslatorOps thumb_translator_ops = {
|
|||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc = { };
|
||||
const TranslatorOps *ops = &arm_translator_ops;
|
||||
|
|
|
@ -210,7 +210,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps avr_tcg_ops = {
|
||||
static const TCGCPUOps avr_tcg_ops = {
|
||||
.initialize = avr_cpu_tcg_init,
|
||||
.synchronize_from_tb = avr_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = avr_restore_state_to_opc,
|
||||
|
|
|
@ -2805,7 +2805,7 @@ static const TranslatorOps avr_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc = { };
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base);
|
||||
|
|
|
@ -178,7 +178,7 @@ static const struct SysemuCPUOps cris_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps crisv10_tcg_ops = {
|
||||
static const TCGCPUOps crisv10_tcg_ops = {
|
||||
.initialize = cris_initialize_crisv10_tcg,
|
||||
.restore_state_to_opc = cris_restore_state_to_opc,
|
||||
|
||||
|
@ -189,7 +189,7 @@ static const struct TCGCPUOps crisv10_tcg_ops = {
|
|||
#endif /* !CONFIG_USER_ONLY */
|
||||
};
|
||||
|
||||
static const struct TCGCPUOps crisv32_tcg_ops = {
|
||||
static const TCGCPUOps crisv32_tcg_ops = {
|
||||
.initialize = cris_initialize_tcg,
|
||||
.restore_state_to_opc = cris_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -3172,7 +3172,7 @@ static const TranslatorOps cris_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc, &cris_tr_ops, &dc.base);
|
||||
|
|
|
@ -337,7 +337,7 @@ static void hexagon_cpu_init(Object *obj)
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps hexagon_tcg_ops = {
|
||||
static const TCGCPUOps hexagon_tcg_ops = {
|
||||
.initialize = hexagon_translate_init,
|
||||
.synchronize_from_tb = hexagon_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = hexagon_restore_state_to_opc,
|
||||
|
|
|
@ -234,7 +234,8 @@ static int read_packet_words(CPUHexagonState *env, DisasContext *ctx,
|
|||
g_assert(ctx->base.num_insns == 1);
|
||||
}
|
||||
|
||||
HEX_DEBUG_LOG("decode_packet: pc = 0x%x\n", ctx->base.pc_next);
|
||||
HEX_DEBUG_LOG("decode_packet: pc = 0x%" VADDR_PRIx "\n",
|
||||
ctx->base.pc_next);
|
||||
HEX_DEBUG_LOG(" words = { ");
|
||||
for (int i = 0; i < nwords; i++) {
|
||||
HEX_DEBUG_LOG("0x%x, ", words[i]);
|
||||
|
@ -1154,7 +1155,7 @@ static const TranslatorOps hexagon_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ static const struct SysemuCPUOps hppa_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps hppa_tcg_ops = {
|
||||
static const TCGCPUOps hppa_tcg_ops = {
|
||||
.initialize = hppa_translate_init,
|
||||
.synchronize_from_tb = hppa_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = hppa_restore_state_to_opc,
|
||||
|
|
|
@ -4631,7 +4631,7 @@ static const TranslatorOps hppa_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base);
|
||||
|
|
|
@ -39,6 +39,8 @@ QEMU_BUILD_BUG_ON(TCG_PHYS_ADDR_BITS > TARGET_PHYS_ADDR_SPACE_BITS);
|
|||
*/
|
||||
void x86_cpu_do_interrupt(CPUState *cpu);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void x86_cpu_exec_halt(CPUState *cpu);
|
||||
bool x86_need_replay_interrupt(int interrupt_request);
|
||||
bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
@ -127,6 +128,28 @@ void x86_cpu_do_interrupt(CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
void x86_cpu_exec_halt(CPUState *cpu)
|
||||
{
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
|
||||
bql_lock();
|
||||
apic_poll_irq(x86_cpu->apic_state);
|
||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||
bql_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool x86_need_replay_interrupt(int interrupt_request)
|
||||
{
|
||||
/*
|
||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||
* "real" interrupt event later. It does not need to be recorded for
|
||||
* replay purposes.
|
||||
*/
|
||||
return !(interrupt_request & CPU_INTERRUPT_POLL);
|
||||
}
|
||||
|
||||
bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
|
|
|
@ -106,7 +106,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs)
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps x86_tcg_ops = {
|
||||
static const TCGCPUOps x86_tcg_ops = {
|
||||
.initialize = tcg_x86_init,
|
||||
.synchronize_from_tb = x86_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = x86_restore_state_to_opc,
|
||||
|
@ -119,10 +119,12 @@ static const struct TCGCPUOps x86_tcg_ops = {
|
|||
#else
|
||||
.tlb_fill = x86_cpu_tlb_fill,
|
||||
.do_interrupt = x86_cpu_do_interrupt,
|
||||
.cpu_exec_halt = x86_cpu_exec_halt,
|
||||
.cpu_exec_interrupt = x86_cpu_exec_interrupt,
|
||||
.do_unaligned_access = x86_cpu_do_unaligned_access,
|
||||
.debug_excp_handler = breakpoint_handler,
|
||||
.debug_check_breakpoint = x86_debug_check_breakpoint,
|
||||
.need_replay_interrupt = x86_need_replay_interrupt,
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
};
|
||||
|
||||
|
|
|
@ -7088,7 +7088,7 @@ static const TranslatorOps i386_tr_ops = {
|
|||
|
||||
/* generate intermediate code for basic block 'tb'. */
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
|
||||
|
|
|
@ -734,7 +734,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|||
#ifdef CONFIG_TCG
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static struct TCGCPUOps loongarch_tcg_ops = {
|
||||
static const TCGCPUOps loongarch_tcg_ops = {
|
||||
.initialize = loongarch_translate_init,
|
||||
.synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = loongarch_restore_state_to_opc,
|
||||
|
|
|
@ -343,7 +343,7 @@ static const TranslatorOps loongarch_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -525,7 +525,7 @@ static const struct SysemuCPUOps m68k_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps m68k_tcg_ops = {
|
||||
static const TCGCPUOps m68k_tcg_ops = {
|
||||
.initialize = m68k_tcg_init,
|
||||
.restore_state_to_opc = m68k_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -1457,7 +1457,7 @@ DISAS_INSN(undef)
|
|||
* for the 680x0 series, as well as those that are implemented
|
||||
* but actually illegal for CPU32 or pre-68020.
|
||||
*/
|
||||
qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
|
||||
qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %" VADDR_PRIx "\n",
|
||||
insn, s->base.pc_next);
|
||||
gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
|
||||
}
|
||||
|
@ -6088,7 +6088,7 @@ static const TranslatorOps m68k_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
translator_loop(cpu, tb, max_insns, pc, host_pc, &m68k_tr_ops, &dc.base);
|
||||
|
|
|
@ -19,3 +19,5 @@ subdir('sh4')
|
|||
subdir('sparc')
|
||||
subdir('tricore')
|
||||
subdir('xtensa')
|
||||
|
||||
specific_ss.add(files('target-common.c'))
|
||||
|
|
|
@ -387,7 +387,7 @@ static const struct SysemuCPUOps mb_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps mb_tcg_ops = {
|
||||
static const TCGCPUOps mb_tcg_ops = {
|
||||
.initialize = mb_tcg_init,
|
||||
.synchronize_from_tb = mb_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = mb_restore_state_to_opc,
|
||||
|
|
|
@ -1792,7 +1792,7 @@ static const TranslatorOps mb_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base);
|
||||
|
|
|
@ -549,7 +549,7 @@ static const struct SysemuCPUOps mips_sysemu_ops = {
|
|||
* NB: cannot be const, as some elements are changed for specific
|
||||
* mips hardware (see hw/mips/jazz.c).
|
||||
*/
|
||||
static const struct TCGCPUOps mips_tcg_ops = {
|
||||
static const TCGCPUOps mips_tcg_ops = {
|
||||
.initialize = mips_tcg_init,
|
||||
.synchronize_from_tb = mips_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = mips_restore_state_to_opc,
|
||||
|
|
|
@ -4585,8 +4585,8 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc,
|
|||
|
||||
if (ctx->hflags & MIPS_HFLAG_BMASK) {
|
||||
#ifdef MIPS_DEBUG_DISAS
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x"
|
||||
TARGET_FMT_lx "\n", ctx->base.pc_next);
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016"
|
||||
VADDR_PRIx "\n", ctx->base.pc_next);
|
||||
#endif
|
||||
gen_reserved_instruction(ctx);
|
||||
goto out;
|
||||
|
@ -9061,8 +9061,8 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op,
|
|||
|
||||
if (ctx->hflags & MIPS_HFLAG_BMASK) {
|
||||
#ifdef MIPS_DEBUG_DISAS
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx
|
||||
"\n", ctx->base.pc_next);
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016"
|
||||
VADDR_PRIx "\n", ctx->base.pc_next);
|
||||
#endif
|
||||
gen_reserved_instruction(ctx);
|
||||
return;
|
||||
|
@ -11274,8 +11274,8 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc,
|
|||
|
||||
if (ctx->hflags & MIPS_HFLAG_BMASK) {
|
||||
#ifdef MIPS_DEBUG_DISAS
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx
|
||||
"\n", ctx->base.pc_next);
|
||||
LOG_DISAS("Branch in delay / forbidden slot at PC 0x%016"
|
||||
VADDR_PRIx "\n", ctx->base.pc_next);
|
||||
#endif
|
||||
gen_reserved_instruction(ctx);
|
||||
return;
|
||||
|
@ -15554,7 +15554,7 @@ static const TranslatorOps mips_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -202,7 +202,8 @@ extern TCGv bcond;
|
|||
do { \
|
||||
if (MIPS_DEBUG_DISAS) { \
|
||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, \
|
||||
TARGET_FMT_lx ": %08x Invalid %s %03x %03x %03x\n", \
|
||||
"%016" VADDR_PRIx \
|
||||
": %08x Invalid %s %03x %03x %03x\n", \
|
||||
ctx->base.pc_next, ctx->opcode, op, \
|
||||
ctx->opcode >> 26, ctx->opcode & 0x3F, \
|
||||
((ctx->opcode >> 16) & 0x1F)); \
|
||||
|
|
|
@ -354,7 +354,7 @@ static const struct SysemuCPUOps nios2_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps nios2_tcg_ops = {
|
||||
static const TCGCPUOps nios2_tcg_ops = {
|
||||
.initialize = nios2_tcg_init,
|
||||
.restore_state_to_opc = nios2_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -1036,7 +1036,7 @@ static const TranslatorOps nios2_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc, &nios2_tr_ops, &dc.base);
|
||||
|
|
|
@ -213,7 +213,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps openrisc_tcg_ops = {
|
||||
static const TCGCPUOps openrisc_tcg_ops = {
|
||||
.initialize = openrisc_translate_init,
|
||||
.synchronize_from_tb = openrisc_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = openrisc_restore_state_to_opc,
|
||||
|
|
|
@ -1658,7 +1658,7 @@ static const TranslatorOps openrisc_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -7332,7 +7332,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = {
|
|||
#ifdef CONFIG_TCG
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps ppc_tcg_ops = {
|
||||
static const TCGCPUOps ppc_tcg_ops = {
|
||||
.initialize = ppc_translate_init,
|
||||
.restore_state_to_opc = ppc_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -7518,7 +7518,7 @@ static const TranslatorOps ppc_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ static void riscv_restore_state_to_opc(CPUState *cs,
|
|||
env->bins = data[1];
|
||||
}
|
||||
|
||||
static const struct TCGCPUOps riscv_tcg_ops = {
|
||||
static const TCGCPUOps riscv_tcg_ops = {
|
||||
.initialize = riscv_translate_init,
|
||||
.synchronize_from_tb = riscv_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = riscv_restore_state_to_opc,
|
||||
|
|
|
@ -1287,7 +1287,7 @@ static const TranslatorOps riscv_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ static const struct SysemuCPUOps rx_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps rx_tcg_ops = {
|
||||
static const TCGCPUOps rx_tcg_ops = {
|
||||
.initialize = rx_translate_init,
|
||||
.synchronize_from_tb = rx_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = rx_restore_state_to_opc,
|
||||
|
|
|
@ -2266,7 +2266,7 @@ static const TranslatorOps rx_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ static void s390_cpu_reset_full(DeviceState *dev)
|
|||
#ifdef CONFIG_TCG
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps s390_tcg_ops = {
|
||||
static const TCGCPUOps s390_tcg_ops = {
|
||||
.initialize = s390x_translate_init,
|
||||
.restore_state_to_opc = s390x_restore_state_to_opc,
|
||||
|
||||
|
|
|
@ -6547,7 +6547,7 @@ static const TranslatorOps s390x_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc;
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ static const struct SysemuCPUOps sh4_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps superh_tcg_ops = {
|
||||
static const TCGCPUOps superh_tcg_ops = {
|
||||
.initialize = sh4_translate_init,
|
||||
.synchronize_from_tb = superh_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = superh_restore_state_to_opc,
|
||||
|
|
|
@ -2317,7 +2317,7 @@ static const TranslatorOps sh4_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
|
||||
|
|
|
@ -874,7 +874,7 @@ static const struct SysemuCPUOps sparc_sysemu_ops = {
|
|||
#ifdef CONFIG_TCG
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps sparc_tcg_ops = {
|
||||
static const TCGCPUOps sparc_tcg_ops = {
|
||||
.initialize = sparc_tcg_init,
|
||||
.synchronize_from_tb = sparc_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = sparc_restore_state_to_opc,
|
||||
|
|
|
@ -5327,7 +5327,7 @@ static const TranslatorOps sparc_tr_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc = {};
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/target_page.h"
|
||||
|
||||
int qemu_target_page_mask(void)
|
||||
{
|
||||
return TARGET_PAGE_MASK;
|
||||
}
|
|
@ -173,7 +173,7 @@ static const struct SysemuCPUOps tricore_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps tricore_tcg_ops = {
|
||||
static const TCGCPUOps tricore_tcg_ops = {
|
||||
.initialize = tricore_tcg_init,
|
||||
.synchronize_from_tb = tricore_cpu_synchronize_from_tb,
|
||||
.restore_state_to_opc = tricore_restore_state_to_opc,
|
||||
|
|
|
@ -8472,7 +8472,7 @@ static const TranslatorOps tricore_tr_ops = {
|
|||
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext ctx;
|
||||
translator_loop(cs, tb, max_insns, pc, host_pc,
|
||||
|
|
|
@ -222,7 +222,7 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = {
|
|||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps xtensa_tcg_ops = {
|
||||
static const TCGCPUOps xtensa_tcg_ops = {
|
||||
.initialize = xtensa_translate_init,
|
||||
.debug_excp_handler = xtensa_breakpoint_handler,
|
||||
.restore_state_to_opc = xtensa_restore_state_to_opc,
|
||||
|
|
|
@ -1239,7 +1239,7 @@ static const TranslatorOps xtensa_translator_ops = {
|
|||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
target_ulong pc, void *host_pc)
|
||||
vaddr pc, void *host_pc)
|
||||
{
|
||||
DisasContext dc = {};
|
||||
translator_loop(cpu, tb, max_insns, pc, host_pc,
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/lockable.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
#include "debuginfo.h"
|
||||
|
||||
static QemuMutex lock;
|
||||
static Dwfl *dwfl;
|
||||
static const Dwfl_Callbacks dwfl_callbacks = {
|
|
@ -22,6 +22,11 @@ if get_option('tcg_interpreter')
|
|||
tcg_ss.add(files('tci.c'))
|
||||
endif
|
||||
|
||||
tcg_ss.add(when: libdw, if_true: files('debuginfo.c'))
|
||||
if host_os == 'linux'
|
||||
tcg_ss.add(files('perf.c'))
|
||||
endif
|
||||
|
||||
tcg_ss = tcg_ss.apply({})
|
||||
|
||||
libtcg_user = static_library('tcg_user',
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "elf.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/target_page.h"
|
||||
#include "exec/translation-block.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "tcg/debuginfo.h"
|
||||
#include "tcg/perf.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
#include "debuginfo.h"
|
||||
#include "perf.h"
|
||||
|
||||
static FILE *safe_fopen_w(const char *path)
|
||||
{
|
||||
int saved_errno;
|
||||
|
@ -335,11 +335,7 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb,
|
|||
/* FIXME: This replicates the restore_state_to_opc() logic. */
|
||||
q[insn].address = gen_insn_data[insn * start_words + 0];
|
||||
if (tb_cflags(tb) & CF_PCREL) {
|
||||
q[insn].address |= (guest_pc & TARGET_PAGE_MASK);
|
||||
} else {
|
||||
#if defined(TARGET_I386)
|
||||
q[insn].address -= tb->cs_base;
|
||||
#endif
|
||||
q[insn].address |= (guest_pc & qemu_target_page_mask());
|
||||
}
|
||||
q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0);
|
||||
}
|
|
@ -55,7 +55,7 @@
|
|||
#include "tcg/tcg-ldst.h"
|
||||
#include "tcg/tcg-temp-internal.h"
|
||||
#include "tcg-internal.h"
|
||||
#include "accel/tcg/perf.h"
|
||||
#include "tcg/perf.h"
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#include "exec/user/guest-base.h"
|
||||
#endif
|
||||
|
|
|
@ -97,7 +97,12 @@ if __name__ == '__main__':
|
|||
sleep(1)
|
||||
log(output, "GDB CMD: %s" % (gdb_cmd))
|
||||
|
||||
result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr)
|
||||
gdb_env = dict(os.environ)
|
||||
gdb_pythonpath = gdb_env.get("PYTHONPATH", "").split(os.pathsep)
|
||||
gdb_pythonpath.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
gdb_env["PYTHONPATH"] = os.pathsep.join(gdb_pythonpath)
|
||||
result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr,
|
||||
env=gdb_env)
|
||||
|
||||
# A result of greater than 128 indicates a fatal signal (likely a
|
||||
# crash due to gdb internal failure). That's a problem for GDB and
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
"""Helper functions for gdbstub testing
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import gdb
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
fail_count = 0
|
||||
|
||||
|
||||
def report(cond, msg):
|
||||
"""Report success/fail of a test"""
|
||||
if cond:
|
||||
print("PASS: {}".format(msg))
|
||||
else:
|
||||
print("FAIL: {}".format(msg))
|
||||
global fail_count
|
||||
fail_count += 1
|
||||
|
||||
|
||||
def main(test, expected_arch=None):
|
||||
"""Run a test function
|
||||
|
||||
This runs as the script it sourced (via -x, via run-test.py)."""
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: {}".format(arch.name()))
|
||||
if expected_arch is not None:
|
||||
report(arch.name() == expected_arch,
|
||||
"connected to {}".format(expected_arch))
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIP: not connected")
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval("$pc") == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
test()
|
||||
except:
|
||||
print("GDB Exception:")
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
global fail_count
|
||||
fail_count += 1
|
||||
if "QEMU_TEST_INTERACTIVE" in os.environ:
|
||||
import code
|
||||
code.InteractiveConsole(locals=globals()).interact()
|
||||
raise
|
||||
|
||||
try:
|
||||
gdb.execute("kill")
|
||||
except gdb.error:
|
||||
pass
|
||||
|
||||
print("All tests complete: {} failures".format(fail_count))
|
||||
exit(fail_count)
|
|
@ -8,19 +8,10 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
from test_gdbstub import main, report
|
||||
|
||||
initial_vlen = 0
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print ("PASS: %s" % (msg))
|
||||
else:
|
||||
print ("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
class TestBreakpoint(gdb.Breakpoint):
|
||||
def __init__(self, sym_name="__sve_ld_done"):
|
||||
|
@ -64,26 +55,5 @@ def run_test():
|
|||
|
||||
gdb.execute("c")
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
report(arch.name() == "aarch64", "connected to aarch64")
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except:
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
import code
|
||||
code.InteractiveConsole(locals=globals()).interact()
|
||||
raise
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test, expected_arch="aarch64")
|
||||
|
|
|
@ -6,20 +6,10 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
from test_gdbstub import main, report
|
||||
|
||||
MAGIC = 0xDEADBEEF
|
||||
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print ("PASS: %s" % (msg))
|
||||
else:
|
||||
print ("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
def run_test():
|
||||
"Run through the tests one by one"
|
||||
|
@ -54,24 +44,5 @@ def run_test():
|
|||
report(str(v.type) == "uint64_t", "size of %s" % (reg))
|
||||
report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC))
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
report(arch.name() == "aarch64", "connected to aarch64")
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except:
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
|
||||
exit(failcount)
|
||||
main(run_test, expected_arch="aarch64")
|
||||
|
|
|
@ -101,13 +101,20 @@ run-gdbstub-registers: sha512
|
|||
--bin $< --test $(MULTIARCH_SRC)/gdbstub/registers.py, \
|
||||
checking register enumeration)
|
||||
|
||||
run-gdbstub-prot-none: prot-none
|
||||
$(call run-test, $@, env PROT_NONE_PY=1 $(GDB_SCRIPT) \
|
||||
--gdb $(GDB) \
|
||||
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||
--bin $< --test $(MULTIARCH_SRC)/gdbstub/prot-none.py, \
|
||||
accessing PROT_NONE memory)
|
||||
|
||||
else
|
||||
run-gdbstub-%:
|
||||
$(call skip-test, "gdbstub test $*", "need working gdb with $(patsubst -%,,$(TARGET_NAME)) support")
|
||||
endif
|
||||
EXTRA_RUNS += run-gdbstub-sha1 run-gdbstub-qxfer-auxv-read \
|
||||
run-gdbstub-proc-mappings run-gdbstub-thread-breakpoint \
|
||||
run-gdbstub-registers
|
||||
run-gdbstub-registers run-gdbstub-prot-none
|
||||
|
||||
# ARM Compatible Semi Hosting Tests
|
||||
#
|
||||
|
|
|
@ -8,19 +8,7 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
|
||||
failcount = 0
|
||||
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print("PASS: %s" % (msg))
|
||||
else:
|
||||
print("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def check_interrupt(thread):
|
||||
|
@ -59,6 +47,9 @@ def run_test():
|
|||
Test if interrupting the code always lands us on the same thread when
|
||||
running with scheduler-lock enabled.
|
||||
"""
|
||||
if len(gdb.selected_inferior().threads()) == 1:
|
||||
print("SKIP: set to run on a single thread")
|
||||
exit(0)
|
||||
|
||||
gdb.execute("set scheduler-locking on")
|
||||
for thread in gdb.selected_inferior().threads():
|
||||
|
@ -66,32 +57,4 @@ def run_test():
|
|||
"thread %d resumes correctly on interrupt" % thread.num)
|
||||
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
if len(gdb.selected_inferior().threads()) == 1:
|
||||
print("SKIP: set to run on a single thread")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
# Finally kill the inferior and exit gdb with a count of failures
|
||||
gdb.execute("kill")
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -9,18 +9,7 @@ from __future__ import print_function
|
|||
|
||||
import gdb
|
||||
import sys
|
||||
|
||||
failcount = 0
|
||||
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print("PASS: %s" % (msg))
|
||||
else:
|
||||
print("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def check_step():
|
||||
|
@ -99,29 +88,5 @@ def run_test():
|
|||
|
||||
report(cbp.hit_count == 0, "didn't reach backstop")
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
# Finally kill the inferior and exit gdb with a count of failures
|
||||
gdb.execute("kill")
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
"""Test that GDB can access PROT_NONE pages.
|
||||
|
||||
This runs as a sourced script (via -x, via run-test.py).
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
"""
|
||||
import ctypes
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def probe_proc_self_mem():
|
||||
buf = ctypes.create_string_buffer(b'aaa')
|
||||
try:
|
||||
with open("/proc/self/mem", "rb") as fp:
|
||||
fp.seek(ctypes.addressof(buf))
|
||||
return fp.read(3) == b'aaa'
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def run_test():
|
||||
"""Run through the tests one by one"""
|
||||
if not probe_proc_self_mem:
|
||||
print("SKIP: /proc/self/mem is not usable")
|
||||
exit(0)
|
||||
gdb.Breakpoint("break_here")
|
||||
gdb.execute("continue")
|
||||
val = gdb.parse_and_eval("*(char[2] *)q").string()
|
||||
report(val == "42", "{} == 42".format(val))
|
||||
gdb.execute("set *(char[3] *)q = \"24\"")
|
||||
gdb.execute("continue")
|
||||
exitcode = int(gdb.parse_and_eval("$_exitcode"))
|
||||
report(exitcode == 0, "{} == 0".format(exitcode))
|
||||
|
||||
|
||||
main(run_test)
|
|
@ -7,20 +7,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
initial_vlen = 0
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test."
|
||||
if cond:
|
||||
print("PASS: %s" % (msg))
|
||||
else:
|
||||
print("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
|
||||
def fetch_xml_regmap():
|
||||
|
@ -75,6 +66,7 @@ def fetch_xml_regmap():
|
|||
|
||||
return reg_map
|
||||
|
||||
|
||||
def get_register_by_regnum(reg_map, regnum):
|
||||
"""
|
||||
Helper to find a register from the map via its XML regnum
|
||||
|
@ -84,6 +76,7 @@ def get_register_by_regnum(reg_map, regnum):
|
|||
return entry
|
||||
return None
|
||||
|
||||
|
||||
def crosscheck_remote_xml(reg_map):
|
||||
"""
|
||||
Cross-check the list of remote-registers with the XML info.
|
||||
|
@ -144,6 +137,7 @@ def crosscheck_remote_xml(reg_map):
|
|||
elif "seen" not in x_reg:
|
||||
print(f"{x_reg} wasn't seen in remote-registers")
|
||||
|
||||
|
||||
def initial_register_read(reg_map):
|
||||
"""
|
||||
Do an initial read of all registers that we know gdb cares about
|
||||
|
@ -214,27 +208,4 @@ def run_test():
|
|||
complete_and_diff(reg_map)
|
||||
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -7,19 +7,11 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
initial_vlen = 0
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print("PASS: %s" % (msg))
|
||||
else:
|
||||
print("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
def check_break(sym_name):
|
||||
"Setup breakpoint, continue and check we stopped."
|
||||
|
@ -35,6 +27,7 @@ def check_break(sym_name):
|
|||
|
||||
bp.delete()
|
||||
|
||||
|
||||
def run_test():
|
||||
"Run through the tests one by one"
|
||||
|
||||
|
@ -57,28 +50,5 @@ def run_test():
|
|||
# finally check we don't barf inspecting registers
|
||||
gdb.execute("info registers")
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -3,20 +3,7 @@
|
|||
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
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def run_test():
|
||||
|
@ -37,26 +24,4 @@ def run_test():
|
|||
# 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:
|
||||
# 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()
|
||||
main(run_test)
|
||||
|
|
|
@ -6,18 +6,8 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
from test_gdbstub import main, report
|
||||
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print ("PASS: %s" % (msg))
|
||||
else:
|
||||
print ("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
def run_test():
|
||||
"Run through the tests one by one"
|
||||
|
@ -26,28 +16,5 @@ def run_test():
|
|||
report(isinstance(auxv, str), "Fetched auxv from inferior")
|
||||
report(auxv.find("sha1"), "Found test binary name in auxv")
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -6,18 +6,8 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
from test_gdbstub import main, report
|
||||
|
||||
failcount = 0
|
||||
|
||||
def report(cond, msg):
|
||||
"Report success/fail of test"
|
||||
if cond:
|
||||
print ("PASS: %s" % (msg))
|
||||
else:
|
||||
print ("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
|
||||
def run_test():
|
||||
"Run through the tests one by one"
|
||||
|
@ -29,28 +19,5 @@ def run_test():
|
|||
frame = gdb.selected_frame()
|
||||
report(str(frame.function()) == "thread1_func", "break @ %s"%frame)
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval('$pc') == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Test that GDB can access PROT_NONE pages.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void break_here(void *q)
|
||||
{
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
long pagesize = sysconf(_SC_PAGESIZE);
|
||||
void *p, *q;
|
||||
int err;
|
||||
|
||||
p = mmap(NULL, pagesize * 2, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
assert(p != MAP_FAILED);
|
||||
q = p + pagesize - 1;
|
||||
strcpy(q, "42");
|
||||
|
||||
err = mprotect(p, pagesize * 2, PROT_NONE);
|
||||
assert(err == 0);
|
||||
|
||||
break_here(q);
|
||||
|
||||
err = mprotect(p, pagesize * 2, PROT_READ);
|
||||
assert(err == 0);
|
||||
if (getenv("PROT_NONE_PY")) {
|
||||
assert(strcmp(q, "24") == 0);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -7,19 +7,7 @@ from __future__ import print_function
|
|||
#
|
||||
|
||||
import gdb
|
||||
import sys
|
||||
|
||||
failcount = 0
|
||||
|
||||
|
||||
def report(cond, msg):
|
||||
"""Report success/fail of test"""
|
||||
if cond:
|
||||
print("PASS: %s" % (msg))
|
||||
else:
|
||||
print("FAIL: %s" % (msg))
|
||||
global failcount
|
||||
failcount += 1
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def run_test():
|
||||
|
@ -42,31 +30,7 @@ def run_test():
|
|||
gdb.Breakpoint("_exit")
|
||||
gdb.execute("c")
|
||||
status = int(gdb.parse_and_eval("$r2"))
|
||||
report(status == 0, "status == 0");
|
||||
report(status == 0, "status == 0")
|
||||
|
||||
|
||||
#
|
||||
# This runs as the script it sourced (via -x, via run-test.py)
|
||||
#
|
||||
try:
|
||||
inferior = gdb.selected_inferior()
|
||||
arch = inferior.architecture()
|
||||
print("ATTACHED: %s" % arch.name())
|
||||
except (gdb.error, AttributeError):
|
||||
print("SKIPPING (not connected)", file=sys.stderr)
|
||||
exit(0)
|
||||
|
||||
if gdb.parse_and_eval("$pc") == 0:
|
||||
print("SKIP: PC not set")
|
||||
exit(0)
|
||||
|
||||
try:
|
||||
# Run the actual tests
|
||||
run_test()
|
||||
except (gdb.error):
|
||||
print("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||
failcount += 1
|
||||
pass
|
||||
|
||||
print("All tests complete: %d failures" % failcount)
|
||||
exit(failcount)
|
||||
main(run_test)
|
||||
|
|
|
@ -3,20 +3,7 @@
|
|||
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
|
||||
from test_gdbstub import main, report
|
||||
|
||||
|
||||
def run_test():
|
||||
|
@ -35,26 +22,4 @@ def run_test():
|
|||
gdb.execute("si")
|
||||
|
||||
|
||||
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:
|
||||
# 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()
|
||||
main(run_test)
|
||||
|
|
Loading…
Reference in New Issue