mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:47:45 +00:00
UserspaceEmulator: Optionally write reports to the debug log
...and take a flag '--report-to-debug' that determines this behaviour.
This commit is contained in:
parent
201d34f6cd
commit
9afe9069a9
8 changed files with 118 additions and 70 deletions
|
@ -219,9 +219,9 @@ void Emulator::dump_backtrace(const Vector<FlatPtr>& backtrace)
|
||||||
auto source_position = m_debug_info->get_source_position(address);
|
auto source_position = m_debug_info->get_source_position(address);
|
||||||
new_warn("=={}== {:p} {}", getpid(), address, symbol);
|
new_warn("=={}== {:p} {}", getpid(), address, symbol);
|
||||||
if (source_position.has_value())
|
if (source_position.has_value())
|
||||||
warnln(" (\033[34;1m{}\033[0m:{})", LexicalPath(source_position.value().file_path).basename(), source_position.value().line_number);
|
reportln(" (\033[34;1m{}\033[0m:{})", LexicalPath(source_position.value().file_path).basename(), source_position.value().line_number);
|
||||||
else
|
else
|
||||||
warnln(" +{:x}", offset);
|
reportln(" +{:x}", offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ void Emulator::dump_backtrace()
|
||||||
u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
|
u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_SPAM
|
#ifdef DEBUG_SPAM
|
||||||
dbgln("Syscall: {} ({:x})", Syscall::to_string((Syscall::Function)function), function);
|
reportln("Syscall: {} ({:x})", Syscall::to_string((Syscall::Function)function), function);
|
||||||
#endif
|
#endif
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case SC_chdir:
|
case SC_chdir:
|
||||||
|
@ -378,7 +378,7 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
|
||||||
case SC_fork:
|
case SC_fork:
|
||||||
return virt$fork();
|
return virt$fork();
|
||||||
default:
|
default:
|
||||||
warnln("\n=={}== \033[31;1mUnimplemented syscall: {}\033[0m, {:p}", getpid(), Syscall::to_string((Syscall::Function)function), function);
|
reportln("\n=={}== \033[31;1mUnimplemented syscall: {}\033[0m, {:p}", getpid(), Syscall::to_string((Syscall::Function)function), function);
|
||||||
dump_backtrace();
|
dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -896,7 +896,7 @@ u32 Emulator::virt$read(int fd, FlatPtr buffer, ssize_t size)
|
||||||
|
|
||||||
void Emulator::virt$exit(int status)
|
void Emulator::virt$exit(int status)
|
||||||
{
|
{
|
||||||
warnln("\n=={}== \033[33;1mSyscall: exit({})\033[0m, shutting down!", getpid(), status);
|
reportln("\n=={}== \033[33;1mSyscall: exit({})\033[0m, shutting down!", getpid(), status);
|
||||||
m_exit_status = status;
|
m_exit_status = status;
|
||||||
m_shutdown = true;
|
m_shutdown = true;
|
||||||
}
|
}
|
||||||
|
@ -949,7 +949,7 @@ int Emulator::virt$ioctl(int fd, unsigned request, FlatPtr arg)
|
||||||
mmu().copy_from_vm(&termios, arg, sizeof(termios));
|
mmu().copy_from_vm(&termios, arg, sizeof(termios));
|
||||||
return syscall(SC_ioctl, fd, request, &termios);
|
return syscall(SC_ioctl, fd, request, &termios);
|
||||||
}
|
}
|
||||||
dbgln("Unsupported ioctl: {}", request);
|
reportln("Unsupported ioctl: {}", request);
|
||||||
dump_backtrace();
|
dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -982,16 +982,19 @@ int Emulator::virt$execve(FlatPtr params_addr)
|
||||||
copy_string_list(arguments, params.arguments);
|
copy_string_list(arguments, params.arguments);
|
||||||
copy_string_list(environment, params.environment);
|
copy_string_list(environment, params.environment);
|
||||||
|
|
||||||
warnln("\n=={}== \033[33;1mSyscall:\033[0m execve", getpid());
|
reportln("\n=={}== \033[33;1mSyscall:\033[0m execve", getpid());
|
||||||
warnln("=={}== @ {}", getpid(), path);
|
reportln("=={}== @ {}", getpid(), path);
|
||||||
for (auto& argument : arguments)
|
for (auto& argument : arguments)
|
||||||
warnln("=={}== - {}", getpid(), argument);
|
reportln("=={}== - {}", getpid(), argument);
|
||||||
|
|
||||||
Vector<char*> argv;
|
Vector<char*> argv;
|
||||||
Vector<char*> envp;
|
Vector<char*> envp;
|
||||||
|
|
||||||
argv.append(const_cast<char*>("/bin/UserspaceEmulator"));
|
argv.append(const_cast<char*>("/bin/UserspaceEmulator"));
|
||||||
argv.append(const_cast<char*>(path.characters()));
|
argv.append(const_cast<char*>(path.characters()));
|
||||||
|
if (g_report_to_debug)
|
||||||
|
argv.append(const_cast<char*>("--report-to-debug"));
|
||||||
|
argv.append(const_cast<char*>("--"));
|
||||||
|
|
||||||
auto create_string_vector = [](auto& output_vector, auto& input_vector) {
|
auto create_string_vector = [](auto& output_vector, auto& input_vector) {
|
||||||
for (auto& string : input_vector)
|
for (auto& string : input_vector)
|
||||||
|
@ -1003,7 +1006,7 @@ int Emulator::virt$execve(FlatPtr params_addr)
|
||||||
create_string_vector(envp, environment);
|
create_string_vector(envp, environment);
|
||||||
|
|
||||||
// Yoink duplicated program name.
|
// Yoink duplicated program name.
|
||||||
argv.remove(2);
|
argv.remove(3 + (g_report_to_debug ? 1 : 0));
|
||||||
|
|
||||||
return execve(argv[0], (char* const*)argv.data(), (char* const*)envp.data());
|
return execve(argv[0], (char* const*)argv.data(), (char* const*)envp.data());
|
||||||
}
|
}
|
||||||
|
@ -1070,7 +1073,7 @@ void Emulator::register_signal_handlers()
|
||||||
int Emulator::virt$sigaction(int signum, FlatPtr act, FlatPtr oldact)
|
int Emulator::virt$sigaction(int signum, FlatPtr act, FlatPtr oldact)
|
||||||
{
|
{
|
||||||
if (signum == SIGKILL) {
|
if (signum == SIGKILL) {
|
||||||
dbgln("Attempted to sigaction() with SIGKILL");
|
reportln("Attempted to sigaction() with SIGKILL");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,7 +1201,7 @@ void Emulator::dispatch_one_pending_signal()
|
||||||
auto action = default_signal_action(signum);
|
auto action = default_signal_action(signum);
|
||||||
if (action == DefaultSignalAction::Ignore)
|
if (action == DefaultSignalAction::Ignore)
|
||||||
return;
|
return;
|
||||||
warnln("\n=={}== Got signal {} ({}), no handler registered", getpid(), signum, strsignal(signum));
|
reportln("\n=={}== Got signal {} ({}), no handler registered", getpid(), signum, strsignal(signum));
|
||||||
m_shutdown = true;
|
m_shutdown = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1208,7 +1211,7 @@ void Emulator::dispatch_one_pending_signal()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
warnln("\n=={}== Got signal {} ({}), handler at {:p}", getpid(), signum, strsignal(signum), handler.handler);
|
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();
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MallocTracer.h"
|
#include "MallocTracer.h"
|
||||||
|
#include "Report.h"
|
||||||
#include "SoftCPU.h"
|
#include "SoftCPU.h"
|
||||||
#include "SoftMMU.h"
|
#include "SoftMMU.h"
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
|
@ -71,8 +71,8 @@ void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
|
||||||
for (auto& mallocation : m_mallocations) {
|
for (auto& mallocation : m_mallocations) {
|
||||||
if (mallocation.address == address) {
|
if (mallocation.address == address) {
|
||||||
if (mallocation.freed) {
|
if (mallocation.freed) {
|
||||||
warnln("\n=={}== \033[31;1mDouble free()\033[0m, {:p}", getpid(), address);
|
reportln("\n=={}== \033[31;1mDouble free()\033[0m, {:p}", getpid(), address);
|
||||||
warnln("=={}== Address {} has already been passed to free()", getpid(), address);
|
reportln("=={}== Address {} has already been passed to free()", getpid(), address);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
} else {
|
} else {
|
||||||
mallocation.freed = true;
|
mallocation.freed = true;
|
||||||
|
@ -82,8 +82,8 @@ void MallocTracer::target_did_free(Badge<SoftCPU>, FlatPtr address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warnln("\n=={}== \033[31;1mInvalid free()\033[0m, {:p}", getpid(), address);
|
reportln("\n=={}== \033[31;1mInvalid free()\033[0m, {:p}", getpid(), address);
|
||||||
warnln("=={}== Address {} has never been returned by malloc()", getpid(), address);
|
reportln("=={}== Address {} has never been returned by malloc()", getpid(), address);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,11 +119,11 @@ void MallocTracer::audit_read(FlatPtr address, size_t size)
|
||||||
auto* mallocation = find_mallocation(address);
|
auto* mallocation = find_mallocation(address);
|
||||||
|
|
||||||
if (!mallocation) {
|
if (!mallocation) {
|
||||||
warnln("\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();
|
Emulator::the().dump_backtrace();
|
||||||
if ((mallocation = find_mallocation_before(address))) {
|
if ((mallocation = find_mallocation_before(address))) {
|
||||||
size_t offset_into_mallocation = address - mallocation->address;
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
warnln("=={}== Address is {} byte(s) after block of size {}, allocated at:", getpid(), offset_into_mallocation - mallocation->size, mallocation->size);
|
reportln("=={}== Address is {} byte(s) after block of size {}, allocated at:", getpid(), offset_into_mallocation - mallocation->size, mallocation->size);
|
||||||
Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
|
Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -132,11 +132,11 @@ void MallocTracer::audit_read(FlatPtr address, size_t size)
|
||||||
size_t offset_into_mallocation = address - mallocation->address;
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
|
|
||||||
if (mallocation->freed) {
|
if (mallocation->freed) {
|
||||||
warnln("\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();
|
Emulator::the().dump_backtrace();
|
||||||
warnln("=={}== 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);
|
Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
|
||||||
warnln("=={}== Later freed at:", getpid());
|
reportln("=={}== Later freed at:", getpid());
|
||||||
Emulator::the().dump_backtrace(mallocation->free_backtrace);
|
Emulator::the().dump_backtrace(mallocation->free_backtrace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -152,11 +152,11 @@ void MallocTracer::audit_write(FlatPtr address, size_t size)
|
||||||
|
|
||||||
auto* mallocation = find_mallocation(address);
|
auto* mallocation = find_mallocation(address);
|
||||||
if (!mallocation) {
|
if (!mallocation) {
|
||||||
warnln("\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();
|
Emulator::the().dump_backtrace();
|
||||||
if ((mallocation = find_mallocation_before(address))) {
|
if ((mallocation = find_mallocation_before(address))) {
|
||||||
size_t offset_into_mallocation = address - mallocation->address;
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
warnln("=={}== 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);
|
Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -165,11 +165,11 @@ void MallocTracer::audit_write(FlatPtr address, size_t size)
|
||||||
size_t offset_into_mallocation = address - mallocation->address;
|
size_t offset_into_mallocation = address - mallocation->address;
|
||||||
|
|
||||||
if (mallocation->freed) {
|
if (mallocation->freed) {
|
||||||
warnln("\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();
|
Emulator::the().dump_backtrace();
|
||||||
warnln("=={}== 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);
|
Emulator::the().dump_backtrace(mallocation->malloc_backtrace);
|
||||||
warnln("=={}== Later freed at:", getpid());
|
reportln("=={}== Later freed at:", getpid());
|
||||||
Emulator::the().dump_backtrace(mallocation->free_backtrace);
|
Emulator::the().dump_backtrace(mallocation->free_backtrace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ bool MallocTracer::is_reachable(const Mallocation& mallocation) const
|
||||||
auto value = Emulator::the().mmu().read32({ 0x20, other_mallocation.address + i * sizeof(u32) });
|
auto value = Emulator::the().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
|
||||||
warnln("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);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ bool MallocTracer::is_reachable(const Mallocation& mallocation) const
|
||||||
auto value = region.read32(i * sizeof(u32));
|
auto value = region.read32(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
|
||||||
warnln("mallocation {:p} is reachable from region {:p}-{:p}", mallocation.address, region.base(), region.end() - 1);
|
reportln("mallocation {:p} is reachable from region {:p}-{:p}", mallocation.address, region.base(), region.end() - 1);
|
||||||
#endif
|
#endif
|
||||||
reachable = true;
|
reachable = true;
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
|
@ -239,14 +239,14 @@ void MallocTracer::dump_leak_report()
|
||||||
continue;
|
continue;
|
||||||
++leaks_found;
|
++leaks_found;
|
||||||
bytes_leaked += mallocation.size;
|
bytes_leaked += mallocation.size;
|
||||||
warnln("\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);
|
Emulator::the().dump_backtrace(mallocation.malloc_backtrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leaks_found)
|
if (!leaks_found)
|
||||||
warnln("\n=={}== \033[32;1mNo leaks found!\033[0m", getpid());
|
reportln("\n=={}== \033[32;1mNo leaks found!\033[0m", getpid());
|
||||||
else
|
else
|
||||||
warnln("\n=={}== \033[31;1m{} leak(s) found: {} byte(s) leaked\033[0m", getpid(), leaks_found, bytes_leaked);
|
reportln("\n=={}== \033[31;1m{} leak(s) found: {} byte(s) leaked\033[0m", getpid(), leaks_found, bytes_leaked);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ MmapRegion::~MmapRegion()
|
||||||
ValueWithShadow<u8> MmapRegion::read8(FlatPtr offset)
|
ValueWithShadow<u8> MmapRegion::read8(FlatPtr offset)
|
||||||
{
|
{
|
||||||
if (!is_readable()) {
|
if (!is_readable()) {
|
||||||
warnln("8-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
reportln("8-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ ValueWithShadow<u8> MmapRegion::read8(FlatPtr offset)
|
||||||
ValueWithShadow<u16> MmapRegion::read16(u32 offset)
|
ValueWithShadow<u16> MmapRegion::read16(u32 offset)
|
||||||
{
|
{
|
||||||
if (!is_readable()) {
|
if (!is_readable()) {
|
||||||
warnln("16-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
reportln("16-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ ValueWithShadow<u16> MmapRegion::read16(u32 offset)
|
||||||
ValueWithShadow<u32> MmapRegion::read32(u32 offset)
|
ValueWithShadow<u32> MmapRegion::read32(u32 offset)
|
||||||
{
|
{
|
||||||
if (!is_readable()) {
|
if (!is_readable()) {
|
||||||
warnln("32-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
reportln("32-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ ValueWithShadow<u32> MmapRegion::read32(u32 offset)
|
||||||
ValueWithShadow<u64> MmapRegion::read64(u32 offset)
|
ValueWithShadow<u64> MmapRegion::read64(u32 offset)
|
||||||
{
|
{
|
||||||
if (!is_readable()) {
|
if (!is_readable()) {
|
||||||
warnln("64-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
reportln("64-bit read from unreadable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ ValueWithShadow<u64> MmapRegion::read64(u32 offset)
|
||||||
void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
if (!is_writable()) {
|
if (!is_writable()) {
|
||||||
warnln("8-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
reportln("8-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ void MmapRegion::write8(u32 offset, ValueWithShadow<u8> value)
|
||||||
void MmapRegion::write16(u32 offset, ValueWithShadow<u16> value)
|
void MmapRegion::write16(u32 offset, ValueWithShadow<u16> value)
|
||||||
{
|
{
|
||||||
if (!is_writable()) {
|
if (!is_writable()) {
|
||||||
warnln("16-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
reportln("16-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ void MmapRegion::write16(u32 offset, ValueWithShadow<u16> value)
|
||||||
void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
||||||
{
|
{
|
||||||
if (!is_writable()) {
|
if (!is_writable()) {
|
||||||
warnln("32-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
reportln("32-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ void MmapRegion::write32(u32 offset, ValueWithShadow<u32> value)
|
||||||
void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
void MmapRegion::write64(u32 offset, ValueWithShadow<u64> value)
|
||||||
{
|
{
|
||||||
if (!is_writable()) {
|
if (!is_writable()) {
|
||||||
warnln("64-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
reportln("64-bit write from unwritable MmapRegion @ {:p}", base() + offset);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
40
DevTools/UserspaceEmulator/Report.h
Normal file
40
DevTools/UserspaceEmulator/Report.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, the SerenityOS developers.
|
||||||
|
* 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/LogStream.h>
|
||||||
|
|
||||||
|
extern bool g_report_to_debug;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
void reportln(const StringView& format, Ts... args)
|
||||||
|
{
|
||||||
|
if (g_report_to_debug)
|
||||||
|
dbgln(format, args...);
|
||||||
|
else
|
||||||
|
warnln(format, args...);
|
||||||
|
}
|
|
@ -34,11 +34,11 @@
|
||||||
# pragma GCC optimize("O3")
|
# pragma GCC optimize("O3")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TODO_INSN() \
|
#define TODO_INSN() \
|
||||||
do { \
|
do { \
|
||||||
warnln("\n=={}== Unimplemented instruction: {}\n", getpid(), __FUNCTION__); \
|
reportln("\n=={}== Unimplemented instruction: {}\n", getpid(), __FUNCTION__); \
|
||||||
m_emulator.dump_backtrace(); \
|
m_emulator.dump_backtrace(); \
|
||||||
_exit(0); \
|
_exit(0); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
//#define MEMORY_DEBUG
|
//#define MEMORY_DEBUG
|
||||||
|
@ -60,7 +60,7 @@ template<typename T>
|
||||||
void warn_if_uninitialized(T value_with_shadow, const char* message)
|
void warn_if_uninitialized(T value_with_shadow, const char* message)
|
||||||
{
|
{
|
||||||
if (value_with_shadow.is_uninitialized()) {
|
if (value_with_shadow.is_uninitialized()) {
|
||||||
dbgln("\033[31;1mWarning! Use of uninitialized value: {}\033[0m\n", message);
|
reportln("\033[31;1mWarning! Use of uninitialized value: {}\033[0m\n", message);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ void warn_if_uninitialized(T value_with_shadow, const char* message)
|
||||||
void SoftCPU::warn_if_flags_tainted(const char* message) const
|
void SoftCPU::warn_if_flags_tainted(const char* message) const
|
||||||
{
|
{
|
||||||
if (m_flags_tainted) {
|
if (m_flags_tainted) {
|
||||||
warnln("\n=={}== \033[31;1mConditional depends on uninitialized data\033[0m ({})\n", getpid(), message);
|
reportln("\n=={}== \033[31;1mConditional depends on uninitialized data\033[0m ({})\n", getpid(), message);
|
||||||
Emulator::the().dump_backtrace();
|
Emulator::the().dump_backtrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1342,13 +1342,13 @@ void SoftCPU::DIV_RM16(const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
auto divisor = insn.modrm().read16(*this, insn);
|
auto divisor = insn.modrm().read16(*this, insn);
|
||||||
if (divisor.value() == 0) {
|
if (divisor.value() == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
u32 dividend = ((u32)dx().value() << 16) | ax().value();
|
u32 dividend = ((u32)dx().value() << 16) | ax().value();
|
||||||
auto quotient = dividend / divisor.value();
|
auto quotient = dividend / divisor.value();
|
||||||
if (quotient > NumericLimits<u16>::max()) {
|
if (quotient > NumericLimits<u16>::max()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,13 +1363,13 @@ void SoftCPU::DIV_RM32(const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
auto divisor = insn.modrm().read32(*this, insn);
|
auto divisor = insn.modrm().read32(*this, insn);
|
||||||
if (divisor.value() == 0) {
|
if (divisor.value() == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
u64 dividend = ((u64)edx().value() << 32) | eax().value();
|
u64 dividend = ((u64)edx().value() << 32) | eax().value();
|
||||||
auto quotient = dividend / divisor.value();
|
auto quotient = dividend / divisor.value();
|
||||||
if (quotient > NumericLimits<u32>::max()) {
|
if (quotient > NumericLimits<u32>::max()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1384,13 +1384,13 @@ void SoftCPU::DIV_RM8(const X86::Instruction& insn)
|
||||||
{
|
{
|
||||||
auto divisor = insn.modrm().read8(*this, insn);
|
auto divisor = insn.modrm().read8(*this, insn);
|
||||||
if (divisor.value() == 0) {
|
if (divisor.value() == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
u16 dividend = ax().value();
|
u16 dividend = ax().value();
|
||||||
auto quotient = dividend / divisor.value();
|
auto quotient = dividend / divisor.value();
|
||||||
if (quotient > NumericLimits<u8>::max()) {
|
if (quotient > NumericLimits<u8>::max()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1405,7 +1405,7 @@ void SoftCPU::ENTER32(const X86::Instruction&) { TODO_INSN(); }
|
||||||
|
|
||||||
void SoftCPU::ESCAPE(const X86::Instruction&)
|
void SoftCPU::ESCAPE(const X86::Instruction&)
|
||||||
{
|
{
|
||||||
dbgln("FIXME: x87 floating-point support");
|
reportln("FIXME: x87 floating-point support");
|
||||||
m_emulator.dump_backtrace();
|
m_emulator.dump_backtrace();
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
@ -1546,13 +1546,13 @@ void SoftCPU::IDIV_RM16(const X86::Instruction& insn)
|
||||||
auto divisor_with_shadow = insn.modrm().read16(*this, insn);
|
auto divisor_with_shadow = insn.modrm().read16(*this, insn);
|
||||||
auto divisor = (i16)divisor_with_shadow.value();
|
auto divisor = (i16)divisor_with_shadow.value();
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
i32 dividend = (i32)(((u32)dx().value() << 16) | (u32)ax().value());
|
i32 dividend = (i32)(((u32)dx().value() << 16) | (u32)ax().value());
|
||||||
i32 result = dividend / divisor;
|
i32 result = dividend / divisor;
|
||||||
if (result > NumericLimits<i16>::max() || result < NumericLimits<i16>::min()) {
|
if (result > NumericLimits<i16>::max() || result < NumericLimits<i16>::min()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1566,13 +1566,13 @@ void SoftCPU::IDIV_RM32(const X86::Instruction& insn)
|
||||||
auto divisor_with_shadow = insn.modrm().read32(*this, insn);
|
auto divisor_with_shadow = insn.modrm().read32(*this, insn);
|
||||||
auto divisor = (i32)divisor_with_shadow.value();
|
auto divisor = (i32)divisor_with_shadow.value();
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
i64 dividend = (i64)(((u64)edx().value() << 32) | (u64)eax().value());
|
i64 dividend = (i64)(((u64)edx().value() << 32) | (u64)eax().value());
|
||||||
i64 result = dividend / divisor;
|
i64 result = dividend / divisor;
|
||||||
if (result > NumericLimits<i32>::max() || result < NumericLimits<i32>::min()) {
|
if (result > NumericLimits<i32>::max() || result < NumericLimits<i32>::min()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1586,13 +1586,13 @@ void SoftCPU::IDIV_RM8(const X86::Instruction& insn)
|
||||||
auto divisor_with_shadow = insn.modrm().read8(*this, insn);
|
auto divisor_with_shadow = insn.modrm().read8(*this, insn);
|
||||||
auto divisor = (i8)divisor_with_shadow.value();
|
auto divisor = (i8)divisor_with_shadow.value();
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
warnln("Divide by zero");
|
reportln("Divide by zero");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
i16 dividend = ax().value();
|
i16 dividend = ax().value();
|
||||||
i16 result = dividend / divisor;
|
i16 result = dividend / divisor;
|
||||||
if (result > NumericLimits<i8>::max() || result < NumericLimits<i8>::min()) {
|
if (result > NumericLimits<i8>::max() || result < NumericLimits<i8>::min()) {
|
||||||
warnln("Divide overflow");
|
reportln("Divide overflow");
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SoftMMU.h"
|
#include "SoftMMU.h"
|
||||||
|
#include "Report.h"
|
||||||
#include "SharedBufferRegion.h"
|
#include "SharedBufferRegion.h"
|
||||||
#include <AK/ByteBuffer.h>
|
#include <AK/ByteBuffer.h>
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ ValueWithShadow<u8> SoftMMU::read8(X86::LogicalAddress address)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::read8: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::read8: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ ValueWithShadow<u16> SoftMMU::read16(X86::LogicalAddress address)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::read16: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::read16: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ ValueWithShadow<u32> SoftMMU::read32(X86::LogicalAddress address)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::read32: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::read32: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ ValueWithShadow<u64> SoftMMU::read64(X86::LogicalAddress address)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::read64: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::read64: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ void SoftMMU::write8(X86::LogicalAddress address, ValueWithShadow<u8> value)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::write8: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::write8: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ void SoftMMU::write16(X86::LogicalAddress address, ValueWithShadow<u16> value)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::write16: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::write16: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +135,7 @@ void SoftMMU::write32(X86::LogicalAddress address, ValueWithShadow<u32> value)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::write32: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::write32: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +146,7 @@ void SoftMMU::write64(X86::LogicalAddress address, ValueWithShadow<u64> value)
|
||||||
{
|
{
|
||||||
auto* region = find_region(address);
|
auto* region = find_region(address);
|
||||||
if (!region) {
|
if (!region) {
|
||||||
warnln("SoftMMU::write64: No region for @ {:p}", address.offset());
|
reportln("SoftMMU::write64: No region for @ {:p}", address.offset());
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,14 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
bool g_report_to_debug = false;
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env)
|
int main(int argc, char** argv, char** env)
|
||||||
{
|
{
|
||||||
Vector<const char*> command;
|
Vector<const char*> command;
|
||||||
|
|
||||||
Core::ArgsParser parser;
|
Core::ArgsParser parser;
|
||||||
|
parser.add_option(g_report_to_debug, "Write reports to the debug log", "report-to-debug", 0);
|
||||||
parser.add_positional_argument(command, "Command to emulate", "command");
|
parser.add_positional_argument(command, "Command to emulate", "command");
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
|
@ -49,7 +52,7 @@ int main(int argc, char** argv, char** env)
|
||||||
|
|
||||||
MappedFile mapped_file(executable_path);
|
MappedFile mapped_file(executable_path);
|
||||||
if (!mapped_file.is_valid()) {
|
if (!mapped_file.is_valid()) {
|
||||||
warnln("Unable to map {}", executable_path);
|
reportln("Unable to map {}", executable_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +81,7 @@ int main(int argc, char** argv, char** env)
|
||||||
}
|
}
|
||||||
int rc = pthread_setname_np(pthread_self(), builder.to_string().characters());
|
int rc = pthread_setname_np(pthread_self(), builder.to_string().characters());
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
warnln("pthread_setname_np: {}", strerror(rc));
|
reportln("pthread_setname_np: {}", strerror(rc));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return emulator.exec();
|
return emulator.exec();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue