tcg/wasm32: trace compiled-store TLB corruption under ramrace

This commit is contained in:
2026-07-23 07:50:54 -04:00
parent 346c789851
commit cd3f083fb0
4 changed files with 122 additions and 3 deletions
+47
View File
@@ -1107,6 +1107,16 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
is_ram = memory_region_is_ram(section->mr);
is_romd = memory_region_is_romd(section->mr);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && paddr_page == 0x3fcb8000u) {
printf("FAULTTRACE tlb_fill vaddr=0x%llx paddr=0x%llx asidx=%d prot=0x%x mr=%p name=%s ram=%d romd=%d readonly=%d xlat=0x%llx sz=0x%llx\n",
(unsigned long long)addr_page, (unsigned long long)paddr_page,
asidx, prot, section->mr, memory_region_name(section->mr) ?: "(null)",
is_ram, is_romd, section->readonly,
(unsigned long long)xlat, (unsigned long long)sz);
fflush(stdout);
}
#endif
if (is_ram || is_romd) {
/* RAM and ROMD both have associated host memory. */
@@ -1199,6 +1209,15 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
full = &desc->fulltlb[index];
full->xlat_section = iotlb - addr_page;
full->phys_addr = paddr_page;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && paddr_page == 0x3fcb8000u) {
printf("FAULTTRACE tlb_store index=%u iotlb=0x%llx addr_page=0x%llx stored_xlat=0x%llx phys=0x%llx\n",
index, (unsigned long long)iotlb, (unsigned long long)addr_page,
(unsigned long long)full->xlat_section,
(unsigned long long)full->phys_addr);
fflush(stdout);
}
#endif
/* Now calculate the new entry */
tn.addend = addend - addr_page;
@@ -1418,6 +1437,15 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
*pfull = full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index];
flags |= full->slow_flags[access_type];
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE probe addr=0x%llx index=%lu access=%d tlb_addr=0x%llx flags=0x%x slow=0x%x addend=0x%llx full_xlat=0x%llx\n",
(unsigned long long)addr, (unsigned long)index, access_type,
(unsigned long long)tlb_addr, flags, full->slow_flags[access_type],
(unsigned long long)entry->addend, (unsigned long long)full->xlat_section);
fflush(stdout);
}
#endif
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY | TLB_CHECK_ALIGNED))
@@ -1708,6 +1736,16 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, MemOp memop,
data->full = full;
data->flags = flags;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE mmu_lookup1 addr=0x%llx index=%lu maybe_resized=%d tlb_addr=0x%llx flags=0x%x full=%p full_xlat=0x%llx addend=0x%llx\n",
(unsigned long long)addr, (unsigned long)index, maybe_resized,
(unsigned long long)tlb_addr, flags, full,
(unsigned long long)full->xlat_section,
(unsigned long long)entry->addend);
fflush(stdout);
}
#endif
/* Compute haddr speculatively; depending on flags it might be invalid. */
data->haddr = (void *)((uintptr_t)addr + entry->addend);
@@ -2007,6 +2045,15 @@ static uint64_t do_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full,
attrs = full->attrs;
section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra);
mr = section->mr;
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && ((addr & TARGET_PAGE_MASK) == 0x3fcb8000u)) {
printf("FAULTTRACE mmio_read addr=0x%llx xlat_section=0x%llx mr_offset=0x%llx mr=%p name=%s ram=%d romd=%d readonly=%d\n",
(unsigned long long)addr, (unsigned long long)full->xlat_section,
(unsigned long long)mr_offset, mr, memory_region_name(mr) ?: "(null)",
memory_region_is_ram(mr), memory_region_is_romd(mr), section->readonly);
fflush(stdout);
}
#endif
BQL_LOCK_GUARD();
return int_ld_mmio_beN(cpu, full, ret_be, addr, size, mmu_idx,
+15
View File
@@ -32,6 +32,7 @@
#include "sysemu/tcg.h"
#include "qemu/accel.h"
#include "hw/boards.h"
#include "hw/core/cpu.h"
#include "migration/vmstate.h"
#include "exec/address-spaces.h"
@@ -1404,6 +1405,10 @@ static const MemoryRegionOps ram_device_mem_ops = {
},
};
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
extern int wasm_ramrace_trace;
#endif
bool memory_region_access_valid(MemoryRegion *mr,
hwaddr addr,
unsigned size,
@@ -1416,6 +1421,16 @@ bool memory_region_access_valid(MemoryRegion *mr,
", size %u, region '%s', reason: rejected\n",
is_write ? "write" : "read",
addr, size, memory_region_name(mr));
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace) {
printf("FAULTTRACE rejected %s addr=0x%llx size=%u mr=%p name=%s ops=%p opaque=%p ram=%d rom=%d readonly=%d current_cpu=%p\n",
is_write ? "write" : "read", (unsigned long long)addr,
size, mr, memory_region_name(mr) ?: "(null)", mr->ops,
mr->opaque, memory_region_is_ram(mr), memory_region_is_rom(mr),
mr->readonly, current_cpu);
fflush(stdout);
}
#endif
return false;
}
+9
View File
@@ -2979,6 +2979,15 @@ static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
l = len;
mr = flatview_translate(fv, addr, &mr_addr, &l, false, attrs);
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
if (wasm_ramrace_trace && current_cpu && mr->ops == &unassigned_mem_ops) {
printf("FAULTTRACE flatview_read addr=0x%llx len=0x%llx mr_addr=0x%llx translated_len=0x%llx fv=%p root=%p root_name=%s nr=%u\n",
(unsigned long long)addr, (unsigned long long)len,
(unsigned long long)mr_addr, (unsigned long long)l,
fv, fv->root, memory_region_name(fv->root) ?: "(null)", fv->nr);
fflush(stdout);
}
#endif
if (!flatview_access_allowed(mr, attrs, addr, len)) {
return MEMTX_ACCESS_ERROR;
}
+51 -3
View File
@@ -32,6 +32,7 @@
#include <emscripten/threading.h>
#include "wasm32.h"
extern int wasm_ramrace_trace;
__thread uintptr_t tci_tb_ptr;
__thread bool wasm_tci_only_tb;
static int instantiated_wasm_count;
@@ -1318,6 +1319,7 @@ static __thread size_t diff_fulltlb_size[NB_MMU_MODES];
static __thread uint32_t diff_compiled_ret;
static __thread int diff_tci_iters;
static __thread uint32_t diff2_eligible, diff2_incomplete, diff2_race;
static __thread uint64_t tlbtrace_last_read, tlbtrace_last_write, tlbtrace_last_addend, tlbtrace_last_xlat;
/* Mode 2 (E11): compiled runs LIVE, so its post-state must be re-applied after
* the TCI shadow. These hold the full compiled-post machine state. */
@@ -1398,12 +1400,53 @@ int wasm_diff_needs_nochain_at(uint64_t pc)
pc >= DIFF_PC_LO && pc < DIFF_PC_HI;
}
static void wasm_trace_dram_tlb(CPUArchState *env, uint64_t pc)
{
CPUState *cpu;
const vaddr page = 0x3fcb8000u;
if (!wasm_ramrace_trace || pc < DIFF_PC_LO || pc >= DIFF_PC_HI) {
return;
}
cpu = env_cpu(env);
for (int mmu = 0; mmu < NB_MMU_MODES; mmu++) {
CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu];
CPUTLBDesc *desc = &cpu->neg.tlb.d[mmu];
if (!fast->table || !desc->fulltlb) {
continue;
}
size_t n = (fast->mask >> CPU_TLB_ENTRY_BITS) + 1;
for (size_t i = 0; i < n; i++) {
CPUTLBEntry *e = &fast->table[i];
if (((e->addr_read & TARGET_PAGE_MASK) == page) ||
((e->addr_write & TARGET_PAGE_MASK) == page)) {
CPUTLBEntryFull *f = &desc->fulltlb[i];
if (e->addr_read != tlbtrace_last_read ||
e->addr_write != tlbtrace_last_write ||
e->addend != tlbtrace_last_addend ||
f->xlat_section != tlbtrace_last_xlat) {
printf("TLBTRACE pc=0x%llx mmu=%d index=%zu read=0x%llx write=0x%llx addend=0x%llx full_xlat=0x%llx\n",
(unsigned long long)pc, mmu, i,
(unsigned long long)e->addr_read,
(unsigned long long)e->addr_write,
(unsigned long long)e->addend,
(unsigned long long)f->xlat_section);
fflush(stdout);
tlbtrace_last_read = e->addr_read;
tlbtrace_last_write = e->addr_write;
tlbtrace_last_addend = e->addend;
tlbtrace_last_xlat = f->xlat_section;
}
return;
}
}
}
}
void wasm_diff_register_tb(const void *rw_ptr, const void *rx_ptr, uint64_t pc,
bool has_store, bool safe_shadow)
{
if (!wasm_diff_on()) {
return;
}
if (!diff_store_tbs) {
diff_store_tbs = g_hash_table_new(g_direct_hash, g_direct_equal);
diff_safe_tbs = g_hash_table_new(g_direct_hash, g_direct_equal);
@@ -1750,6 +1793,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx);
was_compiled = true;
}
if (was_compiled) {
uint64_t pc = 0;
wasm_diff_lookup_store_tb((void *)prev_tb, &pc);
wasm_trace_dram_tlb(env, pc);
}
/* E17: a compiled TB that returns non-zero with the same tb_ptr and
* do_init still clear is a mid-TB yield/resume (rewind path), not a
* chain (chains set do_init=1) and not completion (tb_ptr==0). */