mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 15:27:42 +00:00
UserspaceEmulator: Catch use-after-frees by tracking malloc/free :^)
This patch introduces a "MallocTracer" to the UserspaceEmulator. If this object is present on the Emulator, it can be notified whenever the emulated program does a malloc() or free(). The notifications come in via a magic instruction sequence that we embed in the LibC malloc() and free() functions. The sequence is: "salc x2, push reg32 x2, pop reg32 x3" The data about the malloc/free operation is in the three pushes. We make sure the sequence is harmless when running natively. Memory accesses on MmapRegion are then audited to see if they fall inside a known-to-be-freed malloc chunk. If so, we complain loud and red in the debugger output. :^) This is very, very cool! :^) It's also a whole lot slower than before, since now we're auditing memory accesses against a new set of metadata. This will need to be optimized (and running in this mode should be opt-in, perhaps even a separate program, etc.)
This commit is contained in:
parent
d7c87e84f3
commit
c314292319
9 changed files with 274 additions and 5 deletions
|
@ -1,5 +1,6 @@
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
Emulator.cpp
|
Emulator.cpp
|
||||||
|
MallocTracer.cpp
|
||||||
MmapRegion.cpp
|
MmapRegion.cpp
|
||||||
SharedBufferRegion.cpp
|
SharedBufferRegion.cpp
|
||||||
SimpleRegion.cpp
|
SimpleRegion.cpp
|
||||||
|
|
|
@ -66,6 +66,7 @@ Emulator::Emulator(const Vector<String>& arguments, NonnullRefPtr<ELF::Loader> e
|
||||||
: m_elf(move(elf))
|
: m_elf(move(elf))
|
||||||
, m_cpu(*this)
|
, m_cpu(*this)
|
||||||
{
|
{
|
||||||
|
m_malloc_tracer = make<MallocTracer>();
|
||||||
ASSERT(!s_the);
|
ASSERT(!s_the);
|
||||||
s_the = this;
|
s_the = this;
|
||||||
setup_stack(arguments);
|
setup_stack(arguments);
|
||||||
|
@ -167,12 +168,20 @@ int Emulator::exec()
|
||||||
return m_exit_status;
|
return m_exit_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Emulator::is_in_malloc_or_free() const
|
||||||
|
{
|
||||||
|
auto symbol = m_elf->symbolicate(m_cpu.eip());
|
||||||
|
return symbol.starts_with("malloc") || symbol.starts_with("free");
|
||||||
|
}
|
||||||
|
|
||||||
|
static pid_t s_pid = getpid();
|
||||||
|
|
||||||
void Emulator::dump_backtrace()
|
void Emulator::dump_backtrace()
|
||||||
{
|
{
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
String symbol = m_elf->symbolicate(m_cpu.eip(), &offset);
|
String symbol = m_elf->symbolicate(m_cpu.eip(), &offset);
|
||||||
|
|
||||||
printf("> %#08x %s +%#x\n", m_cpu.eip(), symbol.characters(), offset);
|
dbgprintf("==%d== %#08x %s +%#x\n", s_pid, m_cpu.eip(), symbol.characters(), offset);
|
||||||
|
|
||||||
u32 frame_ptr = m_cpu.ebp();
|
u32 frame_ptr = m_cpu.ebp();
|
||||||
while (frame_ptr) {
|
while (frame_ptr) {
|
||||||
|
@ -181,7 +190,7 @@ void Emulator::dump_backtrace()
|
||||||
return;
|
return;
|
||||||
symbol = m_elf->symbolicate(ret_ptr, &offset);
|
symbol = m_elf->symbolicate(ret_ptr, &offset);
|
||||||
if (!symbol.is_null())
|
if (!symbol.is_null())
|
||||||
printf("> %#08x %s +%#x\n", ret_ptr, symbol.characters(), offset);
|
dbgprintf("==%d== %#08x %s +%#x\n", s_pid, ret_ptr, symbol.characters(), offset);
|
||||||
|
|
||||||
frame_ptr = m_mmu.read32({ 0x20, frame_ptr });
|
frame_ptr = m_mmu.read32({ 0x20, frame_ptr });
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "MallocTracer.h"
|
||||||
#include "SoftCPU.h"
|
#include "SoftCPU.h"
|
||||||
#include "SoftMMU.h"
|
#include "SoftMMU.h"
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
@ -35,6 +36,8 @@
|
||||||
|
|
||||||
namespace UserspaceEmulator {
|
namespace UserspaceEmulator {
|
||||||
|
|
||||||
|
class MallocTracer;
|
||||||
|
|
||||||
class Emulator {
|
class Emulator {
|
||||||
public:
|
public:
|
||||||
static Emulator& the();
|
static Emulator& the();
|
||||||
|
@ -49,12 +52,18 @@ public:
|
||||||
|
|
||||||
SoftMMU& mmu() { return m_mmu; }
|
SoftMMU& mmu() { return m_mmu; }
|
||||||
|
|
||||||
|
MallocTracer* malloc_tracer() { return m_malloc_tracer; }
|
||||||
|
|
||||||
|
bool is_in_malloc_or_free() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NonnullRefPtr<ELF::Loader> m_elf;
|
NonnullRefPtr<ELF::Loader> m_elf;
|
||||||
|
|
||||||
SoftMMU m_mmu;
|
SoftMMU m_mmu;
|
||||||
SoftCPU m_cpu;
|
SoftCPU m_cpu;
|
||||||
|
|
||||||
|
OwnPtr<MallocTracer> m_malloc_tracer;
|
||||||
|
|
||||||
void setup_stack(const Vector<String>& arguments);
|
void setup_stack(const Vector<String>& arguments);
|
||||||
|
|
||||||
int virt$shbuf_create(int size, FlatPtr buffer);
|
int virt$shbuf_create(int size, FlatPtr buffer);
|
||||||
|
|
110
DevTools/UserspaceEmulator/MallocTracer.cpp
Normal file
110
DevTools/UserspaceEmulator/MallocTracer.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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 "MallocTracer.h"
|
||||||
|
#include "Emulator.h"
|
||||||
|
#include <AK/LogStream.h>
|
||||||
|
|
||||||
|
namespace UserspaceEmulator {
|
||||||
|
|
||||||
|
static pid_t s_pid = getpid();
|
||||||
|
|
||||||
|
MallocTracer::MallocTracer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MallocTracer::target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t size)
|
||||||
|
{
|
||||||
|
if (auto* existing_mallocation = find_mallocation(address)) {
|
||||||
|
ASSERT(existing_mallocation->freed);
|
||||||
|
existing_mallocation->size = size;
|
||||||
|
existing_mallocation->freed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mallocations.append({ address, size });
|
||||||
|
}
|
||||||
|
|
||||||
|
void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
|
||||||
|
{
|
||||||
|
for (auto& mallocation : m_mallocations) {
|
||||||
|
if (mallocation.address == address) {
|
||||||
|
mallocation.freed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
MallocTracer::Mallocation* MallocTracer::find_mallocation(FlatPtr address)
|
||||||
|
{
|
||||||
|
for (auto& mallocation : m_mallocations) {
|
||||||
|
if (mallocation.contains(address))
|
||||||
|
return &mallocation;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MallocTracer::audit_read(FlatPtr address, size_t size)
|
||||||
|
{
|
||||||
|
if (Emulator::the().is_in_malloc_or_free())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto* mallocation = find_mallocation(address);
|
||||||
|
if (!mallocation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
|
|
||||||
|
if (mallocation->freed) {
|
||||||
|
dbgprintf("\n");
|
||||||
|
dbgprintf("==%d== \033[31;1mUAF\033[0m, invalid %zu-byte read at address %p\n", s_pid, size, address);
|
||||||
|
dbgprintf("==%d== Address is %zu bytes into freed block of size %zu\n", s_pid, offset_into_mallocation, mallocation->size);
|
||||||
|
Emulator::the().dump_backtrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MallocTracer::audit_write(FlatPtr address, size_t size)
|
||||||
|
{
|
||||||
|
if (Emulator::the().is_in_malloc_or_free())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto* mallocation = find_mallocation(address);
|
||||||
|
if (!mallocation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
|
|
||||||
|
if (mallocation->freed) {
|
||||||
|
dbgprintf("\n");
|
||||||
|
dbgprintf("==%d== \033[31;1mUAF\033[0m, invalid %zu-byte write at address %p\n", s_pid, size, address);
|
||||||
|
dbgprintf("==%d== Address is %zu bytes into freed block of size %zu\n", s_pid, offset_into_mallocation, mallocation->size);
|
||||||
|
Emulator::the().dump_backtrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
64
DevTools/UserspaceEmulator/MallocTracer.h
Normal file
64
DevTools/UserspaceEmulator/MallocTracer.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Badge.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
|
||||||
|
namespace UserspaceEmulator {
|
||||||
|
|
||||||
|
class SoftCPU;
|
||||||
|
|
||||||
|
class MallocTracer {
|
||||||
|
public:
|
||||||
|
MallocTracer();
|
||||||
|
|
||||||
|
void target_did_malloc(Badge<SoftCPU>, FlatPtr address, size_t);
|
||||||
|
void target_did_free(Badge<SoftCPU>, FlatPtr address);
|
||||||
|
|
||||||
|
void audit_read(FlatPtr address, size_t);
|
||||||
|
void audit_write(FlatPtr address, size_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Mallocation {
|
||||||
|
bool contains(FlatPtr a) const
|
||||||
|
{
|
||||||
|
return a >= address && a < (address + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlatPtr address { 0 };
|
||||||
|
size_t size { 0 };
|
||||||
|
bool freed { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
Mallocation* find_mallocation(FlatPtr);
|
||||||
|
|
||||||
|
Vector<Mallocation> m_mallocations;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -61,6 +61,13 @@ MmapRegion::~MmapRegion()
|
||||||
free(m_data);
|
free(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MmapRegion::is_malloc_block() const
|
||||||
|
{
|
||||||
|
// FIXME: This is obviously incomplete!
|
||||||
|
// We should somehow know which mmap regions are malloc blocks.
|
||||||
|
return !m_file_backed;
|
||||||
|
}
|
||||||
|
|
||||||
u8 MmapRegion::read8(FlatPtr offset)
|
u8 MmapRegion::read8(FlatPtr offset)
|
||||||
{
|
{
|
||||||
if (!is_readable()) {
|
if (!is_readable()) {
|
||||||
|
@ -69,6 +76,11 @@ u8 MmapRegion::read8(FlatPtr offset)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_read(base() + offset, 1);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset < size());
|
ASSERT(offset < size());
|
||||||
return *reinterpret_cast<const u8*>(m_data + offset);
|
return *reinterpret_cast<const u8*>(m_data + offset);
|
||||||
}
|
}
|
||||||
|
@ -81,6 +93,11 @@ u16 MmapRegion::read16(u32 offset)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_read(base() + offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset + 1 < size());
|
ASSERT(offset + 1 < size());
|
||||||
return *reinterpret_cast<const u16*>(m_data + offset);
|
return *reinterpret_cast<const u16*>(m_data + offset);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +110,11 @@ u32 MmapRegion::read32(u32 offset)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_read(base() + offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset + 3 < size());
|
ASSERT(offset + 3 < size());
|
||||||
return *reinterpret_cast<const u32*>(m_data + offset);
|
return *reinterpret_cast<const u32*>(m_data + offset);
|
||||||
}
|
}
|
||||||
|
@ -105,6 +127,11 @@ void MmapRegion::write8(u32 offset, u8 value)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_write(base() + offset, 1);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset < size());
|
ASSERT(offset < size());
|
||||||
*reinterpret_cast<u8*>(m_data + offset) = value;
|
*reinterpret_cast<u8*>(m_data + offset) = value;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +144,11 @@ void MmapRegion::write16(u32 offset, u16 value)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_write(base() + offset, 2);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset + 1 < size());
|
ASSERT(offset + 1 < size());
|
||||||
*reinterpret_cast<u16*>(m_data + offset) = value;
|
*reinterpret_cast<u16*>(m_data + offset) = value;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +161,11 @@ void MmapRegion::write32(u32 offset, u32 value)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_malloc_block()) {
|
||||||
|
if (auto* tracer = Emulator::the().malloc_tracer())
|
||||||
|
tracer->audit_write(base() + offset, 4);
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(offset + 3 < size());
|
ASSERT(offset + 3 < size());
|
||||||
*reinterpret_cast<u32*>(m_data + offset) = value;
|
*reinterpret_cast<u32*>(m_data + offset) = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ public:
|
||||||
bool is_writable() const { return m_prot & PROT_WRITE; }
|
bool is_writable() const { return m_prot & PROT_WRITE; }
|
||||||
bool is_executable() const { return m_prot & PROT_EXEC; }
|
bool is_executable() const { return m_prot & PROT_EXEC; }
|
||||||
|
|
||||||
|
bool is_malloc_block() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MmapRegion(u32 base, u32 size, int prot);
|
MmapRegion(u32 base, u32 size, int prot);
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,19 @@ void SoftCPU::dump() const
|
||||||
printf("o=%u s=%u z=%u a=%u p=%u c=%u\n", of(), sf(), zf(), af(), pf(), cf());
|
printf("o=%u s=%u z=%u a=%u p=%u c=%u\n", of(), sf(), zf(), af(), pf(), cf());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftCPU::did_receive_secret_data()
|
||||||
|
{
|
||||||
|
if (m_secret_data[0] == 1) {
|
||||||
|
if (auto* tracer = m_emulator.malloc_tracer())
|
||||||
|
tracer->target_did_malloc({}, m_secret_data[2], m_secret_data[1]);
|
||||||
|
} else if (m_secret_data[0] == 2) {
|
||||||
|
if (auto* tracer = m_emulator.malloc_tracer())
|
||||||
|
tracer->target_did_free({}, m_secret_data[1]);
|
||||||
|
} else {
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SoftCPU::update_code_cache()
|
void SoftCPU::update_code_cache()
|
||||||
{
|
{
|
||||||
auto* region = m_emulator.mmu().find_region({ cs(), eip() });
|
auto* region = m_emulator.mmu().find_region({ cs(), eip() });
|
||||||
|
@ -604,7 +617,6 @@ ALWAYS_INLINE static T op_shrd(SoftCPU& cpu, T data, T extra_bits, u8 steps)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ALWAYS_INLINE static T op_shld(SoftCPU& cpu, T data, T extra_bits, u8 steps)
|
ALWAYS_INLINE static T op_shld(SoftCPU& cpu, T data, T extra_bits, u8 steps)
|
||||||
{
|
{
|
||||||
|
@ -633,7 +645,6 @@ ALWAYS_INLINE static T op_shld(SoftCPU& cpu, T data, T extra_bits, u8 steps)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<bool update_dest, typename Op>
|
template<bool update_dest, typename Op>
|
||||||
ALWAYS_INLINE void SoftCPU::generic_AL_imm8(Op op, const X86::Instruction& insn)
|
ALWAYS_INLINE void SoftCPU::generic_AL_imm8(Op op, const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
|
@ -1477,6 +1488,18 @@ void SoftCPU::PUSH_reg16(const X86::Instruction&) { TODO(); }
|
||||||
void SoftCPU::PUSH_reg32(const X86::Instruction& insn)
|
void SoftCPU::PUSH_reg32(const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
push32(gpr32(insn.reg32()));
|
push32(gpr32(insn.reg32()));
|
||||||
|
|
||||||
|
if (m_secret_handshake_state == 2) {
|
||||||
|
m_secret_data[0] = gpr32(insn.reg32());
|
||||||
|
++m_secret_handshake_state;
|
||||||
|
} else if (m_secret_handshake_state == 3) {
|
||||||
|
m_secret_data[1] = gpr32(insn.reg32());
|
||||||
|
++m_secret_handshake_state;
|
||||||
|
} else if (m_secret_handshake_state == 4) {
|
||||||
|
m_secret_data[2] = gpr32(insn.reg32());
|
||||||
|
m_secret_handshake_state = 0;
|
||||||
|
did_receive_secret_data();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftCPU::RCL_RM16_1(const X86::Instruction&) { TODO(); }
|
void SoftCPU::RCL_RM16_1(const X86::Instruction&) { TODO(); }
|
||||||
|
@ -1534,7 +1557,16 @@ void SoftCPU::ROR_RM8_1(const X86::Instruction&) { TODO(); }
|
||||||
void SoftCPU::ROR_RM8_CL(const X86::Instruction&) { TODO(); }
|
void SoftCPU::ROR_RM8_CL(const X86::Instruction&) { TODO(); }
|
||||||
void SoftCPU::ROR_RM8_imm8(const X86::Instruction&) { TODO(); }
|
void SoftCPU::ROR_RM8_imm8(const X86::Instruction&) { TODO(); }
|
||||||
void SoftCPU::SAHF(const X86::Instruction&) { TODO(); }
|
void SoftCPU::SAHF(const X86::Instruction&) { TODO(); }
|
||||||
void SoftCPU::SALC(const X86::Instruction&) { TODO(); }
|
|
||||||
|
void SoftCPU::SALC(const X86::Instruction&)
|
||||||
|
{
|
||||||
|
set_al(cf() ? 0x01 : 0x00);
|
||||||
|
|
||||||
|
if (m_secret_handshake_state < 2)
|
||||||
|
++m_secret_handshake_state;
|
||||||
|
else
|
||||||
|
m_secret_handshake_state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T op_sar(SoftCPU& cpu, T data, u8 steps)
|
static T op_sar(SoftCPU& cpu, T data, u8 steps)
|
||||||
|
|
|
@ -799,6 +799,8 @@ private:
|
||||||
|
|
||||||
void update_code_cache();
|
void update_code_cache();
|
||||||
|
|
||||||
|
void did_receive_secret_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator& m_emulator;
|
Emulator& m_emulator;
|
||||||
|
|
||||||
|
@ -810,6 +812,9 @@ private:
|
||||||
|
|
||||||
const u8* m_cached_code_ptr { nullptr };
|
const u8* m_cached_code_ptr { nullptr };
|
||||||
const u8* m_cached_code_end { nullptr };
|
const u8* m_cached_code_end { nullptr };
|
||||||
|
|
||||||
|
u32 m_secret_handshake_state { 0 };
|
||||||
|
u32 m_secret_data[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
ALWAYS_INLINE u8 SoftCPU::read8()
|
ALWAYS_INLINE u8 SoftCPU::read8()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue