Преглед изворни кода

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

This avoids the cost of calling Emulator::the() in some very hot paths.
Andreas Kling пре 4 година
родитељ
комит
1965fc5b98

+ 1 - 0
DevTools/UserspaceEmulator/CMakeLists.txt

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

+ 2 - 1
DevTools/UserspaceEmulator/Emulator.cpp

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

+ 29 - 28
DevTools/UserspaceEmulator/MallocTracer.cpp

@@ -36,14 +36,15 @@
 
 namespace UserspaceEmulator {
 
-MallocTracer::MallocTracer()
+MallocTracer::MallocTracer(Emulator& emulator)
+    : m_emulator(emulator)
 {
 }
 
 template<typename Callback>
 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()) {
             auto* malloc_data = static_cast<MmapRegion&>(region).malloc_metadata();
             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)
 {
-    auto* region = Emulator::the().mmu().find_region({ 0x20, address });
+    auto* region = m_emulator.mmu().find_region({ 0x20, address });
     ASSERT(region);
     ASSERT(region->is_mmap());
     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);
         existing_mallocation->size = size;
         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();
         return;
     }
@@ -92,7 +93,7 @@ void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t siz
             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());
     }
-    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
@@ -120,22 +121,22 @@ void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
         if (mallocation->freed) {
             reportln("\n=={}==  \033[31;1mDouble free()\033[0m, {:p}", getpid(), address);
             reportln("=={}==  Address {} has already been passed to free()", getpid(), address);
-            Emulator::the().dump_backtrace();
+            m_emulator.dump_backtrace();
         } else {
             mallocation->freed = true;
-            mallocation->free_backtrace = Emulator::the().raw_backtrace();
+            mallocation->free_backtrace = m_emulator.raw_backtrace();
         }
         return;
     }
 
     reportln("\n=={}==  \033[31;1mInvalid free()\033[0m, {:p}", 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)
 {
-    auto* region = Emulator::the().mmu().find_region({ 0x20, address });
+    auto* region = m_emulator.mmu().find_region({ 0x20, address });
     ASSERT(region);
     ASSERT(region->is_mmap());
     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;
     // 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)
@@ -179,7 +180,7 @@ Mallocation* MallocTracer::find_mallocation(const Region& region, FlatPtr addres
 
 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)
         return nullptr;
     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)
         return;
 
-    if (Emulator::the().is_in_malloc_or_free())
+    if (m_emulator.is_in_malloc_or_free())
         return;
 
     auto* mallocation = find_mallocation(region, address);
 
     if (!mallocation) {
         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_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_after = mallocation_after ? (mallocation_after->address - address) : 0;
         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);
-            Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace);
+            m_emulator.dump_backtrace(mallocation_before->malloc_backtrace);
             return;
         }
         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);
-            Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace);
+            m_emulator.dump_backtrace(mallocation_after->malloc_backtrace);
         }
         return;
     }
@@ -244,11 +245,11 @@ void MallocTracer::audit_read(const Region& region, FlatPtr address, size_t size
 
     if (mallocation->freed) {
         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);
-        Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
+        m_emulator.dump_backtrace(mallocation->malloc_backtrace);
         reportln("=={}==  Later freed at:", getpid());
-        Emulator::the().dump_backtrace(mallocation->free_backtrace);
+        m_emulator.dump_backtrace(mallocation->free_backtrace);
         return;
     }
 }
@@ -258,25 +259,25 @@ void MallocTracer::audit_write(const Region& region, FlatPtr address, size_t siz
     if (!m_auditing_enabled)
         return;
 
-    if (Emulator::the().is_in_malloc_or_free())
+    if (m_emulator.is_in_malloc_or_free())
         return;
 
     auto* mallocation = find_mallocation(region, address);
     if (!mallocation) {
         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_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_after = mallocation_after ? (mallocation_after->address - address) : 0;
         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);
-            Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace);
+            m_emulator.dump_backtrace(mallocation_before->malloc_backtrace);
             return;
         }
         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);
-            Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace);
+            m_emulator.dump_backtrace(mallocation_after->malloc_backtrace);
         }
         return;
     }
@@ -285,11 +286,11 @@ void MallocTracer::audit_write(const Region& region, FlatPtr address, size_t siz
 
     if (mallocation->freed) {
         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);
-        Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
+        m_emulator.dump_backtrace(mallocation->malloc_backtrace);
         reportln("=={}==  Later freed at:", getpid());
-        Emulator::the().dump_backtrace(mallocation->free_backtrace);
+        m_emulator.dump_backtrace(mallocation->free_backtrace);
         return;
     }
 }
@@ -308,7 +309,7 @@ bool MallocTracer::is_reachable(const Mallocation& mallocation) const
             return IterationDecision::Continue;
         size_t pointers_in_mallocation = other_mallocation.size / sizeof(u32);
         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()) {
 #ifdef REACHABLE_DEBUG
                 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;
 
     // 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
         if (region.is_stack())
             return IterationDecision::Continue;
@@ -364,7 +365,7 @@ void MallocTracer::dump_leak_report()
         ++leaks_found;
         bytes_leaked += mallocation.size;
         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;
     });
 

+ 4 - 2
DevTools/UserspaceEmulator/MallocTracer.h

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

+ 16 - 16
DevTools/UserspaceEmulator/MmapRegion.cpp

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

+ 39 - 0
DevTools/UserspaceEmulator/Region.cpp

@@ -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)
+{
+}
+
+}

+ 8 - 5
DevTools/UserspaceEmulator/Region.h

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

+ 23 - 18
DevTools/UserspaceEmulator/SoftMMU.cpp

@@ -34,6 +34,11 @@
 
 namespace UserspaceEmulator {
 
+SoftMMU::SoftMMU(Emulator& emulator)
+    : m_emulator(emulator)
+{
+}
+
 Region* SoftMMU::find_region(X86::LogicalAddress address)
 {
     if (address.selector() == 0x28)
@@ -82,13 +87,13 @@ ValueWithShadow<u8> SoftMMU::read8(X86::LogicalAddress address)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::read8: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_readable()) {
         reportln("SoftMMU::read8: Non-readable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -100,13 +105,13 @@ ValueWithShadow<u16> SoftMMU::read16(X86::LogicalAddress address)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::read16: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_readable()) {
         reportln("SoftMMU::read16: Non-readable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -118,13 +123,13 @@ ValueWithShadow<u32> SoftMMU::read32(X86::LogicalAddress address)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::read32: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_readable()) {
         reportln("SoftMMU::read32: Non-readable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -136,13 +141,13 @@ ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::read64: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_readable()) {
         reportln("SoftMMU::read64: Non-readable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -154,13 +159,13 @@ void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::write8: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_writable()) {
         reportln("SoftMMU::write8: Non-writable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
     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);
     if (!region) {
         reportln("SoftMMU::write16: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_writable()) {
         reportln("SoftMMU::write16: Non-writable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -189,13 +194,13 @@ void SoftMMU::write32(X86::LogicalAddress address, ValueWithShadow<u32> value)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::write32: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_writable()) {
         reportln("SoftMMU::write32: Non-writable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -207,13 +212,13 @@ void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value)
     auto* region = find_region(address);
     if (!region) {
         reportln("SoftMMU::write64: No region for @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
     if (!region->is_writable()) {
         reportln("SoftMMU::write64: Non-writable region @ {:p}", address.offset());
-        Emulator::the().dump_backtrace();
+        m_emulator.dump_backtrace();
         TODO();
     }
 
@@ -257,7 +262,7 @@ bool SoftMMU::fast_fill_memory8(X86::LogicalAddress address, size_t size, ValueW
         return false;
 
     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!
             for (size_t i = 0; i < size; ++i) {
                 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;
 
     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!
             for (size_t i = 0; i < count; ++i) {
                 tracer->audit_write(*region, address.offset() + (i * sizeof(u32)), sizeof(u32));

+ 5 - 0
DevTools/UserspaceEmulator/SoftMMU.h

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