1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-30 23:38:11 +00:00

UserspaceEmulator: Keep Emulator& closer to the action in some places

This avoids the cost of calling Emulator::the() in some very hot paths.
This commit is contained in:
Andreas Kling 2020-11-16 14:39:05 +01:00
parent d14695f823
commit 1965fc5b98
9 changed files with 127 additions and 70 deletions

View file

@ -2,6 +2,7 @@ set(SOURCES
Emulator.cpp Emulator.cpp
MallocTracer.cpp MallocTracer.cpp
MmapRegion.cpp MmapRegion.cpp
Region.cpp
SharedBufferRegion.cpp SharedBufferRegion.cpp
SimpleRegion.cpp SimpleRegion.cpp
SoftCPU.cpp SoftCPU.cpp

View file

@ -72,9 +72,10 @@ Emulator& Emulator::the()
Emulator::Emulator(const Vector<String>& arguments, const Vector<String>& environment, NonnullRefPtr<ELF::Loader> elf) Emulator::Emulator(const Vector<String>& arguments, const Vector<String>& environment, NonnullRefPtr<ELF::Loader> elf)
: m_elf(move(elf)) : m_elf(move(elf))
, m_mmu(*this)
, m_cpu(*this) , m_cpu(*this)
{ {
m_malloc_tracer = make<MallocTracer>(); m_malloc_tracer = make<MallocTracer>(*this);
ASSERT(!s_the); ASSERT(!s_the);
s_the = this; s_the = this;
setup_stack(arguments, environment); setup_stack(arguments, environment);

View file

@ -36,14 +36,15 @@
namespace UserspaceEmulator { namespace UserspaceEmulator {
MallocTracer::MallocTracer() MallocTracer::MallocTracer(Emulator& emulator)
: m_emulator(emulator)
{ {
} }
template<typename Callback> template<typename Callback>
inline void MallocTracer::for_each_mallocation(Callback callback) const inline void MallocTracer::for_each_mallocation(Callback callback) const
{ {
Emulator::the().mmu().for_each_region([&](auto& region) { m_emulator.mmu().for_each_region([&](auto& region) {
if (region.is_mmap() && static_cast<const MmapRegion&>(region).is_malloc_block()) { if (region.is_mmap() && static_cast<const MmapRegion&>(region).is_malloc_block()) {
auto* malloc_data = static_cast<MmapRegion&>(region).malloc_metadata(); auto* malloc_data = static_cast<MmapRegion&>(region).malloc_metadata();
for (auto& mallocation : malloc_data->mallocations) { for (auto& mallocation : malloc_data->mallocations) {
@ -57,7 +58,7 @@ inline void MallocTracer::for_each_mallocation(Callback callback) const
void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t size) void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t size)
{ {
auto* region = Emulator::the().mmu().find_region({ 0x20, address }); auto* region = m_emulator.mmu().find_region({ 0x20, address });
ASSERT(region); ASSERT(region);
ASSERT(region->is_mmap()); ASSERT(region->is_mmap());
auto& mmap_region = static_cast<MmapRegion&>(*region); auto& mmap_region = static_cast<MmapRegion&>(*region);
@ -72,7 +73,7 @@ void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t siz
ASSERT(existing_mallocation->freed); ASSERT(existing_mallocation->freed);
existing_mallocation->size = size; existing_mallocation->size = size;
existing_mallocation->freed = false; existing_mallocation->freed = false;
existing_mallocation->malloc_backtrace = Emulator::the().raw_backtrace(); existing_mallocation->malloc_backtrace = m_emulator.raw_backtrace();
existing_mallocation->free_backtrace.clear(); existing_mallocation->free_backtrace.clear();
return; return;
} }
@ -92,7 +93,7 @@ void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t siz
malloc_data->mallocations.resize(1); malloc_data->mallocations.resize(1);
dbgln("Tracking malloc block @ {:p} with chunk_size={}, chunk_count={}", malloc_data->address, malloc_data->chunk_size, malloc_data->mallocations.size()); dbgln("Tracking malloc block @ {:p} with chunk_size={}, chunk_count={}", malloc_data->address, malloc_data->chunk_size, malloc_data->mallocations.size());
} }
malloc_data->mallocation_for_address(address) = { address, size, true, false, Emulator::the().raw_backtrace(), Vector<FlatPtr>() }; malloc_data->mallocation_for_address(address) = { address, size, true, false, m_emulator.raw_backtrace(), Vector<FlatPtr>() };
} }
ALWAYS_INLINE Mallocation& MallocRegionMetadata::mallocation_for_address(FlatPtr address) const ALWAYS_INLINE Mallocation& MallocRegionMetadata::mallocation_for_address(FlatPtr address) const
@ -120,22 +121,22 @@ void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
if (mallocation->freed) { if (mallocation->freed) {
reportln("\n=={}== \033[31;1mDouble free()\033[0m, {:p}", getpid(), address); reportln("\n=={}== \033[31;1mDouble free()\033[0m, {:p}", getpid(), address);
reportln("=={}== Address {} has already been passed to free()", getpid(), address); reportln("=={}== Address {} has already been passed to free()", getpid(), address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
} else { } else {
mallocation->freed = true; mallocation->freed = true;
mallocation->free_backtrace = Emulator::the().raw_backtrace(); mallocation->free_backtrace = m_emulator.raw_backtrace();
} }
return; return;
} }
reportln("\n=={}== \033[31;1mInvalid free()\033[0m, {:p}", getpid(), address); reportln("\n=={}== \033[31;1mInvalid free()\033[0m, {:p}", getpid(), address);
reportln("=={}== Address {} has never been returned by malloc()", getpid(), address); reportln("=={}== Address {} has never been returned by malloc()", getpid(), address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
} }
void MallocTracer::target_did_realloc(Badge<SoftCPU>, FlatPtr address, size_t size) void MallocTracer::target_did_realloc(Badge<SoftCPU>, FlatPtr address, size_t size)
{ {
auto* region = Emulator::the().mmu().find_region({ 0x20, address }); auto* region = m_emulator.mmu().find_region({ 0x20, address });
ASSERT(region); ASSERT(region);
ASSERT(region->is_mmap()); ASSERT(region->is_mmap());
auto& mmap_region = static_cast<MmapRegion&>(*region); auto& mmap_region = static_cast<MmapRegion&>(*region);
@ -158,7 +159,7 @@ void MallocTracer::target_did_realloc(Badge<SoftCPU>, FlatPtr address, size_t si
existing_mallocation->size = size; existing_mallocation->size = size;
// FIXME: Should we track malloc/realloc backtrace separately perhaps? // FIXME: Should we track malloc/realloc backtrace separately perhaps?
existing_mallocation->malloc_backtrace = Emulator::the().raw_backtrace(); existing_mallocation->malloc_backtrace = m_emulator.raw_backtrace();
} }
Mallocation* MallocTracer::find_mallocation(const Region& region, FlatPtr address) Mallocation* MallocTracer::find_mallocation(const Region& region, FlatPtr address)
@ -179,7 +180,7 @@ Mallocation* MallocTracer::find_mallocation(const Region& region, FlatPtr addres
Mallocation* MallocTracer::find_mallocation(FlatPtr address) Mallocation* MallocTracer::find_mallocation(FlatPtr address)
{ {
auto* region = Emulator::the().mmu().find_region({ 0x23, address }); auto* region = m_emulator.mmu().find_region({ 0x23, address });
if (!region) if (!region)
return nullptr; return nullptr;
return find_mallocation(*region, address); return find_mallocation(*region, address);
@ -216,26 +217,26 @@ void MallocTracer::audit_read(const Region& region, FlatPtr address, size_t size
if (!m_auditing_enabled) if (!m_auditing_enabled)
return; return;
if (Emulator::the().is_in_malloc_or_free()) if (m_emulator.is_in_malloc_or_free())
return; return;
auto* mallocation = find_mallocation(region, address); auto* mallocation = find_mallocation(region, address);
if (!mallocation) { if (!mallocation) {
reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte read at address {:p}", getpid(), size, address); reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte read at address {:p}", getpid(), size, address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
auto* mallocation_before = find_mallocation_before(address); auto* mallocation_before = find_mallocation_before(address);
auto* mallocation_after = find_mallocation_after(address); auto* mallocation_after = find_mallocation_after(address);
size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0; size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0;
size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0; size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0;
if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) { if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) {
reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address); reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address);
Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace); m_emulator.dump_backtrace(mallocation_before->malloc_backtrace);
return; return;
} }
if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) { if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) {
reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address); reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address);
Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace); m_emulator.dump_backtrace(mallocation_after->malloc_backtrace);
} }
return; return;
} }
@ -244,11 +245,11 @@ void MallocTracer::audit_read(const Region& region, FlatPtr address, size_t size
if (mallocation->freed) { if (mallocation->freed) {
reportln("\n=={}== \033[31;1mUse-after-free\033[0m, invalid {}-byte read at address {:p}", getpid(), size, address); reportln("\n=={}== \033[31;1mUse-after-free\033[0m, invalid {}-byte read at address {:p}", getpid(), size, address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
reportln("=={}== Address is {} byte(s) into block of size {}, allocated at:", getpid(), offset_into_mallocation, mallocation->size); reportln("=={}== Address is {} byte(s) into block of size {}, allocated at:", getpid(), offset_into_mallocation, mallocation->size);
Emulator::the().dump_backtrace(mallocation->malloc_backtrace); m_emulator.dump_backtrace(mallocation->malloc_backtrace);
reportln("=={}== Later freed at:", getpid()); reportln("=={}== Later freed at:", getpid());
Emulator::the().dump_backtrace(mallocation->free_backtrace); m_emulator.dump_backtrace(mallocation->free_backtrace);
return; return;
} }
} }
@ -258,25 +259,25 @@ void MallocTracer::audit_write(const Region& region, FlatPtr address, size_t siz
if (!m_auditing_enabled) if (!m_auditing_enabled)
return; return;
if (Emulator::the().is_in_malloc_or_free()) if (m_emulator.is_in_malloc_or_free())
return; return;
auto* mallocation = find_mallocation(region, address); auto* mallocation = find_mallocation(region, address);
if (!mallocation) { if (!mallocation) {
reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte write at address {:p}", getpid(), size, address); reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte write at address {:p}", getpid(), size, address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
auto* mallocation_before = find_mallocation_before(address); auto* mallocation_before = find_mallocation_before(address);
auto* mallocation_after = find_mallocation_after(address); auto* mallocation_after = find_mallocation_after(address);
size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0; size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0;
size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0; size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0;
if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) { if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) {
reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address); reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address);
Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace); m_emulator.dump_backtrace(mallocation_before->malloc_backtrace);
return; return;
} }
if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) { if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) {
reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address); reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address);
Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace); m_emulator.dump_backtrace(mallocation_after->malloc_backtrace);
} }
return; return;
} }
@ -285,11 +286,11 @@ void MallocTracer::audit_write(const Region& region, FlatPtr address, size_t siz
if (mallocation->freed) { if (mallocation->freed) {
reportln("\n=={}== \033[31;1mUse-after-free\033[0m, invalid {}-byte write at address {:p}", getpid(), size, address); reportln("\n=={}== \033[31;1mUse-after-free\033[0m, invalid {}-byte write at address {:p}", getpid(), size, address);
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
reportln("=={}== Address is {} byte(s) into block of size {}, allocated at:", getpid(), offset_into_mallocation, mallocation->size); reportln("=={}== Address is {} byte(s) into block of size {}, allocated at:", getpid(), offset_into_mallocation, mallocation->size);
Emulator::the().dump_backtrace(mallocation->malloc_backtrace); m_emulator.dump_backtrace(mallocation->malloc_backtrace);
reportln("=={}== Later freed at:", getpid()); reportln("=={}== Later freed at:", getpid());
Emulator::the().dump_backtrace(mallocation->free_backtrace); m_emulator.dump_backtrace(mallocation->free_backtrace);
return; return;
} }
} }
@ -308,7 +309,7 @@ bool MallocTracer::is_reachable(const Mallocation& mallocation) const
return IterationDecision::Continue; return IterationDecision::Continue;
size_t pointers_in_mallocation = other_mallocation.size / sizeof(u32); size_t pointers_in_mallocation = other_mallocation.size / sizeof(u32);
for (size_t i = 0; i < pointers_in_mallocation; ++i) { for (size_t i = 0; i < pointers_in_mallocation; ++i) {
auto value = Emulator::the().mmu().read32({ 0x20, other_mallocation.address + i * sizeof(u32) }); auto value = m_emulator.mmu().read32({ 0x20, other_mallocation.address + i * sizeof(u32) });
if (value.value() == mallocation.address && !value.is_uninitialized()) { if (value.value() == mallocation.address && !value.is_uninitialized()) {
#ifdef REACHABLE_DEBUG #ifdef REACHABLE_DEBUG
reportln("mallocation {:p} is reachable from other mallocation {:p}", mallocation.address, other_mallocation.address); reportln("mallocation {:p} is reachable from other mallocation {:p}", mallocation.address, other_mallocation.address);
@ -324,7 +325,7 @@ bool MallocTracer::is_reachable(const Mallocation& mallocation) const
return true; return true;
// 2. Search in other memory regions for pointers to this mallocation // 2. Search in other memory regions for pointers to this mallocation
Emulator::the().mmu().for_each_region([&](auto& region) { m_emulator.mmu().for_each_region([&](auto& region) {
// Skip the stack // Skip the stack
if (region.is_stack()) if (region.is_stack())
return IterationDecision::Continue; return IterationDecision::Continue;
@ -364,7 +365,7 @@ void MallocTracer::dump_leak_report()
++leaks_found; ++leaks_found;
bytes_leaked += mallocation.size; bytes_leaked += mallocation.size;
reportln("\n=={}== \033[31;1mLeak\033[0m, {}-byte allocation at address {:p}", getpid(), mallocation.size, mallocation.address); reportln("\n=={}== \033[31;1mLeak\033[0m, {}-byte allocation at address {:p}", getpid(), mallocation.size, mallocation.address);
Emulator::the().dump_backtrace(mallocation.malloc_backtrace); m_emulator.dump_backtrace(mallocation.malloc_backtrace);
return IterationDecision::Continue; return IterationDecision::Continue;
}); });

View file

@ -35,7 +35,7 @@
namespace UserspaceEmulator { namespace UserspaceEmulator {
class MmapRegion; class Emulator;
class SoftCPU; class SoftCPU;
struct Mallocation { struct Mallocation {
@ -66,7 +66,7 @@ public:
class MallocTracer { class MallocTracer {
public: public:
MallocTracer(); explicit MallocTracer(Emulator&);
void target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t); void target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t);
void target_did_free(Badge<SoftCPU>, FlatPtr address); void target_did_free(Badge<SoftCPU>, FlatPtr address);
@ -87,6 +87,8 @@ private:
Mallocation* find_mallocation_after(FlatPtr); Mallocation* find_mallocation_after(FlatPtr);
bool is_reachable(const Mallocation&) const; bool is_reachable(const Mallocation&) const;
Emulator& m_emulator;
bool m_auditing_enabled { true }; bool m_auditing_enabled { true };
}; };

View file

@ -69,12 +69,12 @@ ValueWithShadow<u8> MmapRegion::read8(FlatPtr offset)
{ {
if (!is_readable()) { if (!is_readable()) {
reportln("8-bit read from unreadable MmapRegion @ {:p}", base() + offset); reportln("8-bit read from unreadable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 1); tracer->audit_read(*this, base() + offset, 1);
} }
@ -86,12 +86,12 @@ ValueWithShadow<u16> MmapRegion::read16(u32 offset)
{ {
if (!is_readable()) { if (!is_readable()) {
reportln("16-bit read from unreadable MmapRegion @ {:p}", base() + offset); reportln("16-bit read from unreadable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 2); tracer->audit_read(*this, base() + offset, 2);
} }
@ -103,12 +103,12 @@ ValueWithShadow<u32> MmapRegion::read32(u32 offset)
{ {
if (!is_readable()) { if (!is_readable()) {
reportln("32-bit read from unreadable MmapRegion @ {:p}", base() + offset); reportln("32-bit read from unreadable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 4); tracer->audit_read(*this, base() + offset, 4);
} }
@ -120,12 +120,12 @@ ValueWithShadow<u64> MmapRegion::read64(u32 offset)
{ {
if (!is_readable()) { if (!is_readable()) {
reportln("64-bit read from unreadable MmapRegion @ {:p}", base() + offset); reportln("64-bit read from unreadable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_read(*this, base() + offset, 8); tracer->audit_read(*this, base() + offset, 8);
} }
@ -137,12 +137,12 @@ void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
{ {
if (!is_writable()) { if (!is_writable()) {
reportln("8-bit write from unwritable MmapRegion @ {:p}", base() + offset); reportln("8-bit write from unwritable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 1); tracer->audit_write(*this, base() + offset, 1);
} }
@ -155,12 +155,12 @@ void MmapRegion::write16(u32 offset, ValueWithShadow<u16> value)
{ {
if (!is_writable()) { if (!is_writable()) {
reportln("16-bit write from unwritable MmapRegion @ {:p}", base() + offset); reportln("16-bit write from unwritable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 2); tracer->audit_write(*this, base() + offset, 2);
} }
@ -173,12 +173,12 @@ void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
{ {
if (!is_writable()) { if (!is_writable()) {
reportln("32-bit write from unwritable MmapRegion @ {:p}", base() + offset); reportln("32-bit write from unwritable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 4); tracer->audit_write(*this, base() + offset, 4);
} }
@ -192,12 +192,12 @@ void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
{ {
if (!is_writable()) { if (!is_writable()) {
reportln("64-bit write from unwritable MmapRegion @ {:p}", base() + offset); reportln("64-bit write from unwritable MmapRegion @ {:p}", base() + offset);
Emulator::the().dump_backtrace(); emulator().dump_backtrace();
TODO(); TODO();
} }
if (is_malloc_block()) { if (is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) if (auto* tracer = emulator().malloc_tracer())
tracer->audit_write(*this, base() + offset, 8); tracer->audit_write(*this, base() + offset, 8);
} }

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Region.h"
#include "Emulator.h"
namespace UserspaceEmulator {
Region::Region(u32 base, u32 size)
: m_emulator(Emulator::the())
, m_base(base)
, m_size(size)
{
}
}

View file

@ -31,6 +31,8 @@
namespace UserspaceEmulator { namespace UserspaceEmulator {
class Emulator;
class Region { class Region {
public: public:
virtual ~Region() { } virtual ~Region() { }
@ -72,14 +74,15 @@ public:
virtual u8* data() = 0; virtual u8* data() = 0;
virtual u8* shadow_data() = 0; virtual u8* shadow_data() = 0;
Emulator& emulator() { return m_emulator; }
const Emulator& emulator() const { return m_emulator; }
protected: protected:
Region(u32 base, u32 size) Region(u32 base, u32 size);
: m_base(base)
, m_size(size)
{
}
private: private:
Emulator& m_emulator;
u32 m_base { 0 }; u32 m_base { 0 };
u32 m_size { 0 }; u32 m_size { 0 };

View file

@ -34,6 +34,11 @@
namespace UserspaceEmulator { namespace UserspaceEmulator {
SoftMMU::SoftMMU(Emulator& emulator)
: m_emulator(emulator)
{
}
Region* SoftMMU::find_region(X86::LogicalAddress address) Region* SoftMMU::find_region(X86::LogicalAddress address)
{ {
if (address.selector() == 0x28) if (address.selector() == 0x28)
@ -82,13 +87,13 @@ ValueWithShadow<u8> SoftMMU::read8(X86::LogicalAddress address)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::read8: No region for @ {:p}", address.offset()); reportln("SoftMMU::read8: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_readable()) { if (!region->is_readable()) {
reportln("SoftMMU::read8: Non-readable region @ {:p}", address.offset()); reportln("SoftMMU::read8: Non-readable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -100,13 +105,13 @@ ValueWithShadow<u16> SoftMMU::read16(X86::LogicalAddress address)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::read16: No region for @ {:p}", address.offset()); reportln("SoftMMU::read16: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_readable()) { if (!region->is_readable()) {
reportln("SoftMMU::read16: Non-readable region @ {:p}", address.offset()); reportln("SoftMMU::read16: Non-readable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -118,13 +123,13 @@ ValueWithShadow<u32> SoftMMU::read32(X86::LogicalAddress address)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::read32: No region for @ {:p}", address.offset()); reportln("SoftMMU::read32: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_readable()) { if (!region->is_readable()) {
reportln("SoftMMU::read32: Non-readable region @ {:p}", address.offset()); reportln("SoftMMU::read32: Non-readable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -136,13 +141,13 @@ ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::read64: No region for @ {:p}", address.offset()); reportln("SoftMMU::read64: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_readable()) { if (!region->is_readable()) {
reportln("SoftMMU::read64: Non-readable region @ {:p}", address.offset()); reportln("SoftMMU::read64: Non-readable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -154,13 +159,13 @@ void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::write8: No region for @ {:p}", address.offset()); reportln("SoftMMU::write8: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_writable()) { if (!region->is_writable()) {
reportln("SoftMMU::write8: Non-writable region @ {:p}", address.offset()); reportln("SoftMMU::write8: Non-writable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
region->write8(address.offset() - region->base(), value); region->write8(address.offset() - region->base(), value);
@ -171,13 +176,13 @@ void SoftMMU::write16(X86::LogicalAddress address, ValueWithShadow<u16> value)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::write16: No region for @ {:p}", address.offset()); reportln("SoftMMU::write16: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_writable()) { if (!region->is_writable()) {
reportln("SoftMMU::write16: Non-writable region @ {:p}", address.offset()); reportln("SoftMMU::write16: Non-writable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -189,13 +194,13 @@ void SoftMMU::write32(X86::LogicalAddress address, ValueWithShadow<u32> value)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::write32: No region for @ {:p}", address.offset()); reportln("SoftMMU::write32: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_writable()) { if (!region->is_writable()) {
reportln("SoftMMU::write32: Non-writable region @ {:p}", address.offset()); reportln("SoftMMU::write32: Non-writable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -207,13 +212,13 @@ void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value)
auto* region = find_region(address); auto* region = find_region(address);
if (!region) { if (!region) {
reportln("SoftMMU::write64: No region for @ {:p}", address.offset()); reportln("SoftMMU::write64: No region for @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
if (!region->is_writable()) { if (!region->is_writable()) {
reportln("SoftMMU::write64: Non-writable region @ {:p}", address.offset()); reportln("SoftMMU::write64: Non-writable region @ {:p}", address.offset());
Emulator::the().dump_backtrace(); m_emulator.dump_backtrace();
TODO(); TODO();
} }
@ -257,7 +262,7 @@ bool SoftMMU::fast_fill_memory8(X86::LogicalAddress address, size_t size, ValueW
return false; return false;
if (region->is_mmap() && static_cast<const MmapRegion&>(*region).is_malloc_block()) { if (region->is_mmap() && static_cast<const MmapRegion&>(*region).is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) { if (auto* tracer = m_emulator.malloc_tracer()) {
// FIXME: Add a way to audit an entire range of memory instead of looping here! // FIXME: Add a way to audit an entire range of memory instead of looping here!
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
tracer->audit_write(*region, address.offset() + (i * sizeof(u8)), sizeof(u8)); tracer->audit_write(*region, address.offset() + (i * sizeof(u8)), sizeof(u8));
@ -282,7 +287,7 @@ bool SoftMMU::fast_fill_memory32(X86::LogicalAddress address, size_t count, Valu
return false; return false;
if (region->is_mmap() && static_cast<const MmapRegion&>(*region).is_malloc_block()) { if (region->is_mmap() && static_cast<const MmapRegion&>(*region).is_malloc_block()) {
if (auto* tracer = Emulator::the().malloc_tracer()) { if (auto* tracer = m_emulator.malloc_tracer()) {
// FIXME: Add a way to audit an entire range of memory instead of looping here! // FIXME: Add a way to audit an entire range of memory instead of looping here!
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
tracer->audit_write(*region, address.offset() + (i * sizeof(u32)), sizeof(u32)); tracer->audit_write(*region, address.offset() + (i * sizeof(u32)), sizeof(u32));

View file

@ -36,10 +36,13 @@
namespace UserspaceEmulator { namespace UserspaceEmulator {
class Emulator;
class SharedBufferRegion; class SharedBufferRegion;
class SoftMMU { class SoftMMU {
public: public:
explicit SoftMMU(Emulator&);
ValueWithShadow<u8> read8(X86::LogicalAddress); ValueWithShadow<u8> read8(X86::LogicalAddress);
ValueWithShadow<u16> read16(X86::LogicalAddress); ValueWithShadow<u16> read16(X86::LogicalAddress);
ValueWithShadow<u32> read32(X86::LogicalAddress); ValueWithShadow<u32> read32(X86::LogicalAddress);
@ -80,6 +83,8 @@ public:
} }
private: private:
Emulator& m_emulator;
Region* m_page_to_region_map[786432]; Region* m_page_to_region_map[786432];
OwnPtr<Region> m_tls_region; OwnPtr<Region> m_tls_region;