/* * Log a memory access. */ static void log_mem(app_pc addr, uint size, uint write, const char *loc) { if (outfile == INVALID_FILE || logging_paused) return; struct allocation *alloc = find_allocation((const void *)addr); if (!alloc) { dr_fprintf(outfile, "%s: %s %"PRIuMAX" @ %"PRIxMAX"\n", loc, write ? "store" : "load", (uintmax_t)size, (uintmax_t)addr); } else { dr_fprintf(outfile, "%s: %s %"PRIuMAX" @ allocations[%"PRIuPTR"]" " + %"PRIxMAX"\n", loc, write ? "store" : "load", (uintmax_t)size, alloc->index, (uintmax_t)(addr - alloc->start)); } }
/* * We wrap the C library function memset, because I've noticed that at * least one optimised implementation of it diverges control flow * internally based on what appears to be the _alignment_ of the input * pointer - and that alignment check can vary depending on the * addresses of allocated blocks. So I can't guarantee no divergence * of control flow inside memset if malloc doesn't return the same * values, and instead I just have to trust that memset isn't reading * the contents of the block and basing control flow decisions on that. */ static void wrap_memset_pre(void *wrapctx, void **user_data) { uint was_already_paused = logging_paused++; if (outfile == INVALID_FILE || was_already_paused) return; const void *addr = drwrap_get_arg(wrapctx, 0); size_t size = (size_t)drwrap_get_arg(wrapctx, 2); struct allocation *alloc = find_allocation(addr); if (!alloc) { dr_fprintf(outfile, "memset %"PRIuMAX" @ %"PRIxMAX"\n", (uintmax_t)size, (uintmax_t)addr); } else { dr_fprintf(outfile, "memset %"PRIuMAX" @ allocations[%"PRIuPTR"]" " + %"PRIxMAX"\n", (uintmax_t)size, alloc->index, (uintmax_t)(addr - alloc->start)); } }
static bool do_protect(void *address, int size, int protect) { #ifdef TRACK_ALLOCATIONS uae_u32 allocated_size = find_allocation(address); assert(allocated_size == size); #endif #ifdef _WIN32 DWORD old; if (VirtualProtect(address, size, protect_to_native(protect), &old) == 0) { uae_log("VM: uae_vm_protect(%p, %d, %d) VirtualProtect failed (%d)\n", address, size, protect, GetLastError()); return false; } #else if (mprotect(address, size, protect_to_native(protect)) != 0) { uae_log("VM: uae_vm_protect(%p, %d, %d) mprotect failed (%d)\n", address, size, protect, errno); return false; } #endif return true; }
/* * Record that memory has been freed. Note that we may free something * that was allocated when we weren't logging, so we must cope with * find_allocation returning NULL. */ static void freed(void *ptr) { struct allocation *alloc = find_allocation(ptr); if (alloc) free_allocation(alloc); }