mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +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:
		
							parent
							
								
									d14695f823
								
							
						
					
					
						commit
						1965fc5b98
					
				
					 9 changed files with 127 additions and 70 deletions
				
			
		|  | @ -2,6 +2,7 @@ set(SOURCES | |||
|     Emulator.cpp | ||||
|     MallocTracer.cpp | ||||
|     MmapRegion.cpp | ||||
|     Region.cpp | ||||
|     SharedBufferRegion.cpp | ||||
|     SimpleRegion.cpp | ||||
|     SoftCPU.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); | ||||
|  |  | |||
|  | @ -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; | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
									
								
								DevTools/UserspaceEmulator/Region.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								DevTools/UserspaceEmulator/Region.cpp
									
										
									
									
									
										Normal 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) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -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 }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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)); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling