UserspaceEmulator: Let SoftCPU.h include Emulator.h

...instead of Emulator.h including SoftCPU.h.
This will be used in a later commit to access into Emulator from a
template in SoftCPU.h.
This commit is contained in:
Ali Mohammad Pur 2022-02-28 00:02:37 +03:30 committed by Andreas Kling
parent 23f6a00162
commit e08cf8f554
Notes: sideshowbarker 2024-07-17 17:56:58 +09:00
3 changed files with 88 additions and 87 deletions

View file

@ -49,7 +49,7 @@ Emulator::Emulator(String const& executable_path, Vector<StringView> const& argu
, m_arguments(arguments)
, m_environment(environment)
, m_mmu(*this)
, m_cpu(*this)
, m_cpu(make<SoftCPU>(*this))
, m_editor(Line::Editor::construct())
{
m_malloc_tracer = make<MallocTracer>(*this);
@ -101,53 +101,53 @@ void Emulator::setup_stack(Vector<ELF::AuxiliaryValue> aux_vector)
auto stack_region = make<SimpleRegion>(stack_location, stack_size);
stack_region->set_stack(true);
m_mmu.add_region(move(stack_region));
m_cpu.set_esp(shadow_wrap_as_initialized<u32>(stack_location + stack_size));
m_cpu->set_esp(shadow_wrap_as_initialized<u32>(stack_location + stack_size));
Vector<u32> argv_entries;
for (auto const& argument : m_arguments) {
m_cpu.push_string(argument);
argv_entries.append(m_cpu.esp().value());
m_cpu->push_string(argument);
argv_entries.append(m_cpu->esp().value());
}
Vector<u32> env_entries;
for (auto const& variable : m_environment) {
m_cpu.push_string(variable.characters());
env_entries.append(m_cpu.esp().value());
m_cpu->push_string(variable.characters());
env_entries.append(m_cpu->esp().value());
}
for (auto& auxv : aux_vector) {
if (!auxv.optional_string.is_empty()) {
m_cpu.push_string(auxv.optional_string);
auxv.auxv.a_un.a_ptr = (void*)m_cpu.esp().value();
m_cpu->push_string(auxv.optional_string);
auxv.auxv.a_un.a_ptr = (void*)m_cpu->esp().value();
}
}
for (ssize_t i = aux_vector.size() - 1; i >= 0; --i) {
auto& value = aux_vector[i].auxv;
m_cpu.push_buffer((u8 const*)&value, sizeof(value));
m_cpu->push_buffer((u8 const*)&value, sizeof(value));
}
m_cpu.push32(shadow_wrap_as_initialized<u32>(0)); // char** envp = { envv_entries..., nullptr }
m_cpu->push32(shadow_wrap_as_initialized<u32>(0)); // char** envp = { envv_entries..., nullptr }
for (ssize_t i = env_entries.size() - 1; i >= 0; --i)
m_cpu.push32(shadow_wrap_as_initialized(env_entries[i]));
u32 envp = m_cpu.esp().value();
m_cpu->push32(shadow_wrap_as_initialized(env_entries[i]));
u32 envp = m_cpu->esp().value();
m_cpu.push32(shadow_wrap_as_initialized<u32>(0)); // char** argv = { argv_entries..., nullptr }
m_cpu->push32(shadow_wrap_as_initialized<u32>(0)); // char** argv = { argv_entries..., nullptr }
for (ssize_t i = argv_entries.size() - 1; i >= 0; --i)
m_cpu.push32(shadow_wrap_as_initialized(argv_entries[i]));
u32 argv = m_cpu.esp().value();
m_cpu->push32(shadow_wrap_as_initialized(argv_entries[i]));
u32 argv = m_cpu->esp().value();
while ((m_cpu.esp().value() + 4) % 16 != 0)
m_cpu.push32(shadow_wrap_as_initialized<u32>(0)); // (alignment)
while ((m_cpu->esp().value() + 4) % 16 != 0)
m_cpu->push32(shadow_wrap_as_initialized<u32>(0)); // (alignment)
u32 argc = argv_entries.size();
m_cpu.push32(shadow_wrap_as_initialized(envp));
m_cpu.push32(shadow_wrap_as_initialized(argv));
m_cpu.push32(shadow_wrap_as_initialized(argc));
m_cpu->push32(shadow_wrap_as_initialized(envp));
m_cpu->push32(shadow_wrap_as_initialized(argv));
m_cpu->push32(shadow_wrap_as_initialized(argc));
VERIFY(m_cpu.esp().value() % 16 == 0);
VERIFY(m_cpu->esp().value() % 16 == 0);
}
bool Emulator::load_elf()
@ -207,7 +207,7 @@ bool Emulator::load_elf()
});
auto entry_point = interpreter_image.entry().offset(interpreter_load_offset).get();
m_cpu.set_eip(entry_point);
m_cpu->set_eip(entry_point);
// executable_fd will be used by the loader
int executable_fd = open(m_executable_path.characters(), O_RDONLY);
@ -233,14 +233,14 @@ int Emulator::exec()
while (!m_shutdown) {
if (m_steps_til_pause) [[likely]] {
m_cpu.save_base_eip();
auto insn = X86::Instruction::from_stream(m_cpu, true, true);
m_cpu->save_base_eip();
auto insn = X86::Instruction::from_stream(*m_cpu, true, true);
// Exec cycle
if constexpr (trace) {
outln("{:p} \033[33;1m{}\033[0m", m_cpu.base_eip(), insn.to_string(m_cpu.base_eip(), symbol_provider));
outln("{:p} \033[33;1m{}\033[0m", m_cpu->base_eip(), insn.to_string(m_cpu->base_eip(), symbol_provider));
}
(m_cpu.*insn.handler())(insn);
(m_cpu->*insn.handler())(insn);
if (is_profiling()) {
if (instructions_until_next_profile_dump == 0) {
@ -252,7 +252,7 @@ int Emulator::exec()
}
if constexpr (trace) {
m_cpu.dump();
m_cpu->dump();
}
if (m_pending_signals) [[unlikely]] {
@ -277,26 +277,26 @@ void Emulator::handle_repl()
// Console interface
// FIXME: Previous Instruction**s**
// FIXME: Function names (base, call, jump)
auto saved_eip = m_cpu.eip();
m_cpu.save_base_eip();
auto insn = X86::Instruction::from_stream(m_cpu, true, true);
auto saved_eip = m_cpu->eip();
m_cpu->save_base_eip();
auto insn = X86::Instruction::from_stream(*m_cpu, true, true);
// FIXME: This does not respect inlining
// another way of getting the current function is at need
if (auto symbol = symbol_at(m_cpu.base_eip()); symbol.has_value()) {
if (auto symbol = symbol_at(m_cpu->base_eip()); symbol.has_value()) {
outln("[{}]: {}", symbol->lib_name, symbol->symbol);
}
outln("==> {}", create_instruction_line(m_cpu.base_eip(), insn));
outln("==> {}", create_instruction_line(m_cpu->base_eip(), insn));
for (int i = 0; i < 7; ++i) {
m_cpu.save_base_eip();
insn = X86::Instruction::from_stream(m_cpu, true, true);
outln(" {}", create_instruction_line(m_cpu.base_eip(), insn));
m_cpu->save_base_eip();
insn = X86::Instruction::from_stream(*m_cpu, true, true);
outln(" {}", create_instruction_line(m_cpu->base_eip(), insn));
}
// We don't want to increase EIP here, we just want the instructions
m_cpu.set_eip(saved_eip);
m_cpu->set_eip(saved_eip);
outln();
m_cpu.dump();
m_cpu->dump();
outln();
auto line_or_error = m_editor->get_line(">> ");
@ -340,7 +340,7 @@ void Emulator::handle_repl()
} else if (parts[0].is_one_of("r"sv, "ret"sv)) {
m_run_til_return = true;
// FIXME: This may be uninitialized
m_watched_addr = m_mmu.read32({ 0x23, m_cpu.ebp().value() + 4 }).value();
m_watched_addr = m_mmu.read32({ 0x23, m_cpu->ebp().value() + 4 }).value();
m_steps_til_pause = -1;
} else if (parts[0].is_one_of("q"sv, "quit"sv)) {
m_shutdown = true;
@ -365,11 +365,11 @@ void Emulator::handle_repl()
Vector<FlatPtr> Emulator::raw_backtrace()
{
Vector<FlatPtr, 128> backtrace;
backtrace.append(m_cpu.base_eip());
backtrace.append(m_cpu->base_eip());
// FIXME: Maybe do something if the backtrace has uninitialized data in the frame chain.
u32 frame_ptr = m_cpu.ebp().value();
u32 frame_ptr = m_cpu->ebp().value();
while (frame_ptr) {
u32 ret_ptr = m_mmu.read32({ 0x23, frame_ptr + 4 }).value();
if (!ret_ptr)
@ -616,33 +616,33 @@ void Emulator::dispatch_one_pending_signal()
reportln("\n=={}== Got signal {} ({}), handler at {:p}", getpid(), signum, strsignal(signum), handler.handler);
auto old_esp = m_cpu.esp();
auto old_esp = m_cpu->esp();
u32 stack_alignment = (m_cpu.esp().value() - 52) % 16;
m_cpu.set_esp(shadow_wrap_as_initialized(m_cpu.esp().value() - stack_alignment));
u32 stack_alignment = (m_cpu->esp().value() - 52) % 16;
m_cpu->set_esp(shadow_wrap_as_initialized(m_cpu->esp().value() - stack_alignment));
m_cpu.push32(shadow_wrap_as_initialized(m_cpu.eflags()));
m_cpu.push32(shadow_wrap_as_initialized(m_cpu.eip()));
m_cpu.push32(m_cpu.eax());
m_cpu.push32(m_cpu.ecx());
m_cpu.push32(m_cpu.edx());
m_cpu.push32(m_cpu.ebx());
m_cpu.push32(old_esp);
m_cpu.push32(m_cpu.ebp());
m_cpu.push32(m_cpu.esi());
m_cpu.push32(m_cpu.edi());
m_cpu->push32(shadow_wrap_as_initialized(m_cpu->eflags()));
m_cpu->push32(shadow_wrap_as_initialized(m_cpu->eip()));
m_cpu->push32(m_cpu->eax());
m_cpu->push32(m_cpu->ecx());
m_cpu->push32(m_cpu->edx());
m_cpu->push32(m_cpu->ebx());
m_cpu->push32(old_esp);
m_cpu->push32(m_cpu->ebp());
m_cpu->push32(m_cpu->esi());
m_cpu->push32(m_cpu->edi());
// FIXME: Push old signal mask here.
m_cpu.push32(shadow_wrap_as_initialized(0u));
m_cpu->push32(shadow_wrap_as_initialized(0u));
m_cpu.push32(shadow_wrap_as_initialized((u32)signum));
m_cpu.push32(shadow_wrap_as_initialized(handler.handler));
m_cpu->push32(shadow_wrap_as_initialized((u32)signum));
m_cpu->push32(shadow_wrap_as_initialized(handler.handler));
VERIFY((m_cpu.esp().value() % 16) == 0);
VERIFY((m_cpu->esp().value() % 16) == 0);
m_cpu.push32(shadow_wrap_as_initialized(0u));
m_cpu->push32(shadow_wrap_as_initialized(0u));
m_cpu.set_eip(m_signal_trampoline);
m_cpu->set_eip(m_signal_trampoline);
}
// Make sure the compiler doesn't "optimize away" this function:
@ -707,4 +707,16 @@ void Emulator::dump_regions() const
});
}
bool Emulator::is_in_libsystem() const
{
return m_cpu->base_eip() >= m_libsystem_start && m_cpu->base_eip() < m_libsystem_end;
}
bool Emulator::is_in_loader_code() const
{
if (!m_loader_text_base.has_value() || !m_loader_text_size.has_value())
return false;
return (m_cpu->base_eip() >= m_loader_text_base.value() && m_cpu->base_eip() < m_loader_text_base.value() + m_loader_text_size.value());
}
}

View file

@ -10,7 +10,6 @@
#include "MallocTracer.h"
#include "RangeAllocator.h"
#include "Report.h"
#include "SoftCPU.h"
#include "SoftMMU.h"
#include <AK/FileStream.h>
#include <AK/Types.h>
@ -26,6 +25,7 @@
namespace UserspaceEmulator {
class MallocTracer;
class SoftCPU;
class Emulator {
public:
@ -117,7 +117,7 @@ private:
const Vector<String> m_environment;
SoftMMU m_mmu;
SoftCPU m_cpu;
NonnullOwnPtr<SoftCPU> m_cpu;
OwnPtr<MallocTracer> m_malloc_tracer;
@ -293,16 +293,4 @@ private:
bool m_is_memory_auditing_suppressed { false };
};
ALWAYS_INLINE bool Emulator::is_in_libsystem() const
{
return m_cpu.base_eip() >= m_libsystem_start && m_cpu.base_eip() < m_libsystem_end;
}
ALWAYS_INLINE bool Emulator::is_in_loader_code() const
{
if (!m_loader_text_base.has_value() || !m_loader_text_size.has_value())
return false;
return (m_cpu.base_eip() >= m_loader_text_base.value() && m_cpu.base_eip() < m_loader_text_base.value() + m_loader_text_size.value());
}
}

View file

@ -8,6 +8,7 @@
#include "Emulator.h"
#include "MmapRegion.h"
#include "SimpleRegion.h"
#include "SoftCPU.h"
#include <AK/Debug.h>
#include <AK/FileStream.h>
#include <AK/Format.h>
@ -485,7 +486,7 @@ int Emulator::virt$setsockopt(FlatPtr params_addr)
int Emulator::virt$get_stack_bounds(FlatPtr base, FlatPtr size)
{
auto* region = mmu().find_region({ m_cpu.ss(), m_cpu.esp().value() });
auto* region = mmu().find_region({ m_cpu->ss(), m_cpu->esp().value() });
FlatPtr b = region->base();
size_t s = region->size();
mmu().copy_to_vm(base, &b, sizeof(b));
@ -940,7 +941,7 @@ FlatPtr Emulator::virt$mremap(FlatPtr params_addr)
mmu().copy_from_vm(&params, params_addr, sizeof(params));
// FIXME: Support regions that have been split in the past (e.g. due to mprotect or munmap).
if (auto* region = mmu().find_region({ m_cpu.ds(), (FlatPtr)params.old_address })) {
if (auto* region = mmu().find_region({ m_cpu->ds(), (FlatPtr)params.old_address })) {
if (!is<MmapRegion>(*region))
return -EINVAL;
VERIFY(region->size() == params.old_size);
@ -1398,9 +1399,9 @@ int Emulator::virt$sigprocmask(int how, FlatPtr set, FlatPtr old_set)
int Emulator::virt$sigreturn()
{
u32 stack_ptr = m_cpu.esp().value();
u32 stack_ptr = m_cpu->esp().value();
auto local_pop = [&]() -> ValueWithShadow<u32> {
auto value = m_cpu.read_memory32({ m_cpu.ss(), stack_ptr });
auto value = m_cpu->read_memory32({ m_cpu->ss(), stack_ptr });
stack_ptr += sizeof(u32);
return value;
};
@ -1411,17 +1412,17 @@ int Emulator::virt$sigreturn()
m_signal_mask = local_pop().value();
m_cpu.set_edi(local_pop());
m_cpu.set_esi(local_pop());
m_cpu.set_ebp(local_pop());
m_cpu.set_esp(local_pop());
m_cpu.set_ebx(local_pop());
m_cpu.set_edx(local_pop());
m_cpu.set_ecx(local_pop());
m_cpu.set_eax(local_pop());
m_cpu->set_edi(local_pop());
m_cpu->set_esi(local_pop());
m_cpu->set_ebp(local_pop());
m_cpu->set_esp(local_pop());
m_cpu->set_ebx(local_pop());
m_cpu->set_edx(local_pop());
m_cpu->set_ecx(local_pop());
m_cpu->set_eax(local_pop());
m_cpu.set_eip(local_pop().value());
m_cpu.set_eflags(local_pop());
m_cpu->set_eip(local_pop().value());
m_cpu->set_eflags(local_pop());
// FIXME: We're losing shadow bits here.
return smuggled_eax.value();