accel/tcg: Introduce cpu_unwind_state_data
Add a way to examine the unwind data without actually restoring the data back into env. Reviewed-by: Claudio Fontana <cfontana@suse.de> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
9dd1d56e57
commit
6392bd6b90
@ -106,8 +106,8 @@ void tb_reset_jump(TranslationBlock *tb, int n);
|
|||||||
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||||
tb_page_addr_t phys_page2);
|
tb_page_addr_t phys_page2);
|
||||||
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
|
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
|
||||||
int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
uintptr_t searched_pc, bool reset_icount);
|
uintptr_t host_pc, bool reset_icount);
|
||||||
|
|
||||||
/* Return the current PC from CPU, which may be cached in TB. */
|
/* Return the current PC from CPU, which may be cached in TB. */
|
||||||
static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb)
|
static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb)
|
||||||
|
@ -247,52 +247,66 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
|
|||||||
return p - block;
|
return p - block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The cpu state corresponding to 'searched_pc' is restored.
|
static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc,
|
||||||
* When reset_icount is true, current TB will be interrupted and
|
uint64_t *data)
|
||||||
* icount should be recalculated.
|
|
||||||
*/
|
|
||||||
int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
|
||||||
uintptr_t searched_pc, bool reset_icount)
|
|
||||||
{
|
{
|
||||||
uint64_t data[TARGET_INSN_START_WORDS];
|
uintptr_t iter_pc = (uintptr_t)tb->tc.ptr;
|
||||||
uintptr_t host_pc = (uintptr_t)tb->tc.ptr;
|
|
||||||
const uint8_t *p = tb->tc.ptr + tb->tc.size;
|
const uint8_t *p = tb->tc.ptr + tb->tc.size;
|
||||||
int i, j, num_insns = tb->icount;
|
int i, j, num_insns = tb->icount;
|
||||||
#ifdef CONFIG_PROFILER
|
|
||||||
TCGProfile *prof = &tcg_ctx->prof;
|
|
||||||
int64_t ti = profile_getclock();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
searched_pc -= GETPC_ADJ;
|
host_pc -= GETPC_ADJ;
|
||||||
|
|
||||||
if (searched_pc < host_pc) {
|
if (host_pc < iter_pc) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(data, 0, sizeof(data));
|
memset(data, 0, sizeof(uint64_t) * TARGET_INSN_START_WORDS);
|
||||||
if (!TARGET_TB_PCREL) {
|
if (!TARGET_TB_PCREL) {
|
||||||
data[0] = tb_pc(tb);
|
data[0] = tb_pc(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reconstruct the stored insn data while looking for the point at
|
/*
|
||||||
which the end of the insn exceeds the searched_pc. */
|
* Reconstruct the stored insn data while looking for the point
|
||||||
|
* at which the end of the insn exceeds host_pc.
|
||||||
|
*/
|
||||||
for (i = 0; i < num_insns; ++i) {
|
for (i = 0; i < num_insns; ++i) {
|
||||||
for (j = 0; j < TARGET_INSN_START_WORDS; ++j) {
|
for (j = 0; j < TARGET_INSN_START_WORDS; ++j) {
|
||||||
data[j] += decode_sleb128(&p);
|
data[j] += decode_sleb128(&p);
|
||||||
}
|
}
|
||||||
host_pc += decode_sleb128(&p);
|
iter_pc += decode_sleb128(&p);
|
||||||
if (host_pc > searched_pc) {
|
if (iter_pc > host_pc) {
|
||||||
goto found;
|
return num_insns - i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cpu state corresponding to 'host_pc' is restored.
|
||||||
|
* When reset_icount is true, current TB will be interrupted and
|
||||||
|
* icount should be recalculated.
|
||||||
|
*/
|
||||||
|
void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
|
uintptr_t host_pc, bool reset_icount)
|
||||||
|
{
|
||||||
|
uint64_t data[TARGET_INSN_START_WORDS];
|
||||||
|
#ifdef CONFIG_PROFILER
|
||||||
|
TCGProfile *prof = &tcg_ctx->prof;
|
||||||
|
int64_t ti = profile_getclock();
|
||||||
|
#endif
|
||||||
|
int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data);
|
||||||
|
|
||||||
|
if (insns_left < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
found:
|
|
||||||
if (reset_icount && (tb_cflags(tb) & CF_USE_ICOUNT)) {
|
if (reset_icount && (tb_cflags(tb) & CF_USE_ICOUNT)) {
|
||||||
assert(icount_enabled());
|
assert(icount_enabled());
|
||||||
/* Reset the cycle counter to the start of the block
|
/*
|
||||||
and shift if to the number of actually executed instructions */
|
* Reset the cycle counter to the start of the block and
|
||||||
cpu_neg(cpu)->icount_decr.u16.low += num_insns - i;
|
* shift if to the number of actually executed instructions.
|
||||||
|
*/
|
||||||
|
cpu_neg(cpu)->icount_decr.u16.low += insns_left;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data);
|
cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data);
|
||||||
@ -302,7 +316,6 @@ int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
|||||||
prof->restore_time + profile_getclock() - ti);
|
prof->restore_time + profile_getclock() - ti);
|
||||||
qatomic_set(&prof->restore_count, prof->restore_count + 1);
|
qatomic_set(&prof->restore_count, prof->restore_count + 1);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
||||||
@ -335,6 +348,17 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data)
|
||||||
|
{
|
||||||
|
if (in_code_gen_buffer((const void *)(host_pc - tcg_splitwx_diff))) {
|
||||||
|
TranslationBlock *tb = tcg_tb_lookup(host_pc);
|
||||||
|
if (tb) {
|
||||||
|
return cpu_unwind_data_from_tb(tb, host_pc, data) >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void page_init(void)
|
void page_init(void)
|
||||||
{
|
{
|
||||||
page_size_init();
|
page_size_init();
|
||||||
|
@ -39,20 +39,33 @@ typedef ram_addr_t tb_page_addr_t;
|
|||||||
#define TB_PAGE_ADDR_FMT RAM_ADDR_FMT
|
#define TB_PAGE_ADDR_FMT RAM_ADDR_FMT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_unwind_state_data:
|
||||||
|
* @cpu: the cpu context
|
||||||
|
* @host_pc: the host pc within the translation
|
||||||
|
* @data: output data
|
||||||
|
*
|
||||||
|
* Attempt to load the the unwind state for a host pc occurring in
|
||||||
|
* translated code. If @host_pc is not in translated code, the
|
||||||
|
* function returns false; otherwise @data is loaded.
|
||||||
|
* This is the same unwind info as given to restore_state_to_opc.
|
||||||
|
*/
|
||||||
|
bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpu_restore_state:
|
* cpu_restore_state:
|
||||||
* @cpu: the vCPU state is to be restore to
|
* @cpu: the cpu context
|
||||||
* @searched_pc: the host PC the fault occurred at
|
* @host_pc: the host pc within the translation
|
||||||
* @will_exit: true if the TB executed will be interrupted after some
|
* @will_exit: true if the TB executed will be interrupted after some
|
||||||
cpu adjustments. Required for maintaining the correct
|
cpu adjustments. Required for maintaining the correct
|
||||||
icount valus
|
icount valus
|
||||||
* @return: true if state was restored, false otherwise
|
* @return: true if state was restored, false otherwise
|
||||||
*
|
*
|
||||||
* Attempt to restore the state for a fault occurring in translated
|
* Attempt to restore the state for a fault occurring in translated
|
||||||
* code. If the searched_pc is not in translated code no state is
|
* code. If @host_pc is not in translated code no state is
|
||||||
* restored and the function returns false.
|
* restored and the function returns false.
|
||||||
*/
|
*/
|
||||||
bool cpu_restore_state(CPUState *cpu, uintptr_t searched_pc, bool will_exit);
|
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit);
|
||||||
|
|
||||||
G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu);
|
G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu);
|
||||||
G_NORETURN void cpu_loop_exit(CPUState *cpu);
|
G_NORETURN void cpu_loop_exit(CPUState *cpu);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user