Mostly complete tracing. Probably a lot of bugs.

This commit is contained in:
Ben Vanik
2014-08-14 20:28:44 -07:00
parent cebf595958
commit c275562594
54 changed files with 1052 additions and 161 deletions

View File

@@ -12,18 +12,14 @@
#include <gflags/gflags.h>
DECLARE_bool(trace_function_generation);
DECLARE_bool(trace_kernel_calls);
DECLARE_bool(trace_user_calls);
DECLARE_bool(trace_instructions);
DECLARE_bool(trace_registers);
DECLARE_bool(trace_branches);
DECLARE_bool(trace_user_calls);
DECLARE_bool(trace_kernel_calls);
DECLARE_uint64(trace_thread_mask);
DECLARE_string(load_module_map);
DECLARE_string(dump_path);
DECLARE_bool(dump_module_map);
#endif // XENIA_CPU_PRIVATE_H_

View File

@@ -9,32 +9,22 @@
#include <xenia/cpu/cpu-private.h>
// Tracing:
DEFINE_bool(trace_instructions, false,
"Trace all instructions.");
DEFINE_bool(trace_registers, false,
"Trace register values when tracing instructions.");
DEFINE_bool(trace_branches, false,
"Trace all branches.");
DEFINE_bool(trace_user_calls, false,
"Trace all user function calls.");
DEFINE_bool(trace_kernel_calls, false,
"Trace all kernel function calls.");
DEFINE_uint64(trace_thread_mask, -1,
"Trace threads with IDs in the mask, or -1 for all.");
// Debugging:
DEFINE_string(load_module_map, "",
DEFINE_bool(trace_function_generation, false,
"Trace function generation/JITing.");
DEFINE_bool(trace_kernel_calls, false, "Trace all kernel function calls.");
DEFINE_bool(trace_user_calls, false, "Trace all user function calls.");
DEFINE_bool(trace_instructions, false, "Trace all instructions.");
DEFINE_bool(trace_registers, false,
"Trace register values when tracing instructions.");
DEFINE_string(
load_module_map, "",
"Loads a .map for symbol names and to diff with the generated symbol "
"database.");
// Dumping:
DEFINE_string(dump_path, "build/",
"Directory that dump files are placed into.");
"Directory that dump files are placed into.");
DEFINE_bool(dump_module_bitcode, true,
"Writes the module bitcode both before and after optimizations.");
DEFINE_bool(dump_module_map, true,
"Dumps the module symbol database.");
"Writes the module bitcode both before and after optimizations.");
DEFINE_bool(dump_module_map, true, "Dumps the module symbol database.");

View File

@@ -11,6 +11,7 @@
#include <xenia/emulator.h>
#include <xenia/export_resolver.h>
#include <xenia/cpu/cpu-private.h>
#include <xenia/cpu/xenon_memory.h>
#include <xenia/cpu/xenon_runtime.h>
#include <xenia/cpu/xex_module.h>
@@ -70,7 +71,26 @@ Processor::~Processor() {
int Processor::Setup() {
assert_null(runtime_);
runtime_ = new XenonRuntime(memory_, export_resolver_);
uint32_t debug_info_flags = DEBUG_INFO_DEFAULT;
uint32_t trace_flags = 0;
if (FLAGS_trace_function_generation) {
trace_flags |= TRACE_FUNCTION_GENERATION;
}
if (FLAGS_trace_kernel_calls) {
trace_flags |= TRACE_EXTERN_CALLS;
}
if (FLAGS_trace_user_calls) {
trace_flags |= TRACE_USER_CALLS;
}
if (FLAGS_trace_instructions) {
trace_flags |= TRACE_SOURCE;
}
if (FLAGS_trace_registers) {
trace_flags |= TRACE_SOURCE_VALUES;
}
runtime_ = new XenonRuntime(memory_, export_resolver_, debug_info_flags,
trace_flags);
if (!runtime_) {
return 1;
}

View File

@@ -19,12 +19,11 @@ using namespace alloy::runtime;
using namespace xe;
using namespace xe::cpu;
XenonRuntime::XenonRuntime(
alloy::Memory* memory, ExportResolver* export_resolver) :
Runtime(memory),
export_resolver_(export_resolver) {
}
XenonRuntime::XenonRuntime(alloy::Memory* memory,
ExportResolver* export_resolver,
uint32_t debug_info_flags, uint32_t trace_flags)
: Runtime(memory, debug_info_flags, trace_flags),
export_resolver_(export_resolver) {}
XenonRuntime::~XenonRuntime() = default;

View File

@@ -17,29 +17,26 @@
XEDECLARECLASS1(xe, ExportResolver);
namespace xe {
namespace cpu {
class XenonThreadState;
class XenonRuntime : public alloy::runtime::Runtime {
public:
XenonRuntime(Memory* memory, ExportResolver* export_resolver);
public:
XenonRuntime(Memory* memory, ExportResolver* export_resolver,
uint32_t debug_info_flags, uint32_t trace_flags);
virtual ~XenonRuntime();
ExportResolver* export_resolver() const { return export_resolver_; }
virtual int Initialize(std::unique_ptr<alloy::backend::Backend> backend = 0);
private:
private:
ExportResolver* export_resolver_;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_XENON_RUNTIME_H_

View File

@@ -9,6 +9,7 @@
#include <xenia/cpu/xenon_thread_state.h>
#include <xdb/protocol.h>
#include <xenia/cpu/xenon_runtime.h>
using namespace alloy;
@@ -36,6 +37,7 @@ XenonThreadState::XenonThreadState(XenonRuntime* runtime, uint32_t thread_id,
context_->membase = memory_->membase();
context_->runtime = runtime;
context_->thread_state = this;
context_->thread_id = thread_id_;
// Set initial registers.
context_->r[1] = stack_address_ + stack_size;
@@ -56,3 +58,28 @@ XenonThreadState::~XenonThreadState() {
xe_free_aligned(context_);
memory_->HeapFree(stack_address_, stack_size_);
}
void XenonThreadState::WriteRegisters(xdb::protocol::Registers* registers) {
registers->lr = context_->lr;
registers->ctr = context_->ctr;
registers->xer = 0xFEFEFEFE;
registers->cr[0] = context_->cr0.value;
registers->cr[1] = context_->cr1.value;
registers->cr[2] = context_->cr2.value;
registers->cr[3] = context_->cr3.value;
registers->cr[4] = context_->cr4.value;
registers->cr[5] = context_->cr5.value;
registers->cr[6] = context_->cr6.value;
registers->cr[7] = context_->cr7.value;
registers->fpscr = context_->fpscr.value;
registers->vscr = context_->vscr_sat;
static_assert(sizeof(registers->gpr) == sizeof(context_->r),
"structs must match");
static_assert(sizeof(registers->fpr) == sizeof(context_->f),
"structs must match");
static_assert(sizeof(registers->vr) == sizeof(context_->v),
"structs must match");
memcpy(registers->gpr, context_->r, sizeof(context_->r));
memcpy(registers->fpr, context_->f, sizeof(context_->f));
memcpy(registers->vr, context_->v, sizeof(context_->v));
}

View File

@@ -14,6 +14,11 @@
#include <alloy/runtime/thread_state.h>
#include <xenia/core.h>
namespace xdb {
namespace protocol {
struct Registers;
} // namespace protocol
} // namespace xdb
namespace xe {
namespace cpu {
@@ -34,6 +39,8 @@ public:
uint64_t thread_state_address() const { return thread_state_address_; }
PPCContext* context() const { return context_; }
void WriteRegisters(xdb::protocol::Registers* registers);
private:
uint64_t stack_address_;
size_t stack_size_;

79
src/xenia/debug_agent.cc Normal file
View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/debug_agent.h>
#include <codecvt>
#include <gflags/gflags.h>
DEFINE_string(trace_file, "", "Trace to the given file.");
DEFINE_uint64(trace_capacity, 0x40000000, "Trace file capacity to allocate.");
namespace xe {
DebugAgent::DebugAgent(Emulator* emulator)
: emulator_(emulator),
file_(nullptr),
file_mapping_(nullptr),
trace_base_(0) {}
DebugAgent::~DebugAgent() {
if (trace_base_) {
UnmapViewOfFile(trace_base_);
}
CloseHandle(file_mapping_);
CloseHandle(file_);
}
int DebugAgent::Initialize() {
if (!FLAGS_trace_file.empty()) {
if (SetupTracing(FLAGS_trace_file, FLAGS_trace_capacity)) {
XELOGE("Failed to setup tracing - out of disk space?");
return 1;
}
}
return 0;
}
int DebugAgent::SetupTracing(const std::string& trace_file, uint64_t capacity) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt;
auto file_path = cvt.from_bytes(trace_file);
file_ = CreateFile(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
nullptr);
if (!file_) {
XELOGE("Could not open trace file for writing");
return 1;
}
file_mapping_ = CreateFileMapping(
file_, nullptr, PAGE_READWRITE, static_cast<uint32_t>(capacity >> 32),
static_cast<uint32_t>(capacity), L"Local\\xenia_xdb_trace");
if (!file_mapping_) {
XELOGE("Could not create trace file mapping - out of disk space?");
return 1;
}
trace_base_ = MapViewOfFile(file_mapping_, FILE_MAP_WRITE, 0, 0, 0);
if (!trace_base_) {
XELOGE("Could not map view of trace file - out of disk space?");
return 1;
}
// Store initial trace base.
poly::store<uint64_t>(trace_base_, trace_base() + 8);
return 0;
}
} // namespace xe

44
src/xenia/debug_agent.h Normal file
View File

@@ -0,0 +1,44 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_DEBUG_AGENT_H_
#define XENIA_DEBUG_AGENT_H_
#include <string>
#include <xenia/core.h>
namespace xe {
class Emulator;
class DebugAgent {
public:
DebugAgent(Emulator* emulator);
~DebugAgent();
uint64_t trace_base() const {
return reinterpret_cast<uint64_t>(trace_base_);
}
int Initialize();
private:
int SetupTracing(const std::string& trace_file, uint64_t capacity);
Emulator* emulator_;
HANDLE file_;
HANDLE file_mapping_;
void* trace_base_;
};
} // namespace xe
#endif // XENIA_DEBUG_AGENT_H_

View File

@@ -9,6 +9,7 @@
#include <xenia/emulator.h>
#include <xdb/protocol.h>
#include <xenia/apu/apu.h>
#include <xenia/cpu/cpu.h>
#include <xenia/cpu/xenon_memory.h>
@@ -44,10 +45,17 @@ Emulator::Emulator(const xechar_t* command_line) :
Emulator::~Emulator() {
// Note that we delete things in the reverse order they were initialized.
auto ev = xdb::protocol::ProcessExitEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_EXIT;
}
if (main_window_) {
main_window_->Close();
}
debug_agent_.reset();
delete xam_;
delete xboxkrnl_;
delete kernel_state_;
@@ -70,11 +78,16 @@ Emulator::~Emulator() {
X_STATUS Emulator::Setup() {
X_STATUS result = X_STATUS_UNSUCCESSFUL;
debug_agent_.reset(new DebugAgent(this));
result = debug_agent_->Initialize();
XEEXPECTZERO(result);
// Create memory system first, as it is required for other systems.
memory_ = new XenonMemory();
XEEXPECTNOTNULL(memory_);
result = memory_->Initialize();
XEEXPECTZERO(result);
memory_->set_trace_base(debug_agent_->trace_base());
// Shared export resolver used to attach and query for HLE exports.
export_resolver_ = new ExportResolver();
@@ -144,6 +157,11 @@ X_STATUS Emulator::LaunchXexFile(const xechar_t* path) {
// and then get that symlinked to game:\, so
// -> game:\foo.xex
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
}
int result_code = 0;
// Get just the filename (foo.xex).
@@ -193,6 +211,11 @@ X_STATUS Emulator::LaunchXexFile(const xechar_t* path) {
X_STATUS Emulator::LaunchDiscImage(const xechar_t* path) {
int result_code = 0;
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
}
// Register the disc image in the virtual filesystem.
result_code = file_system_->RegisterDiscImageDevice(
"\\Device\\Cdrom0", path);
@@ -216,6 +239,11 @@ X_STATUS Emulator::LaunchDiscImage(const xechar_t* path) {
X_STATUS Emulator::LaunchSTFSTitle(const xechar_t* path) {
int result_code = 0;
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
}
// TODO(benvanik): figure out paths.
// Register the disc image in the virtual filesystem.

View File

@@ -12,6 +12,7 @@
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/debug_agent.h>
#include <xenia/xbox.h>
#include <xenia/cpu/xenon_memory.h>
@@ -19,7 +20,6 @@
XEDECLARECLASS1(xe, ExportResolver);
XEDECLARECLASS2(xe, apu, AudioSystem);
XEDECLARECLASS2(xe, cpu, Processor);
XEDECLARECLASS2(xe, debug, DebugServer);
XEDECLARECLASS2(xe, gpu, GraphicsSystem);
XEDECLARECLASS2(xe, hid, InputSystem);
XEDECLARECLASS2(xe, kernel, KernelState);
@@ -31,7 +31,6 @@ XEDECLARECLASS2(xe, ui, Window);
namespace xe {
class Emulator {
public:
Emulator(const xechar_t* command_line);
@@ -44,7 +43,7 @@ public:
cpu::XenonMemory* memory() const { return memory_; }
debug::DebugServer* debug_server() const { return debug_server_; }
DebugAgent* debug_agent() const { return debug_agent_.get(); }
cpu::Processor* processor() const { return processor_; }
apu::AudioSystem* audio_system() const { return audio_system_; }
@@ -71,7 +70,7 @@ private:
cpu::XenonMemory* memory_;
debug::DebugServer* debug_server_;
std::unique_ptr<DebugAgent> debug_agent_;
cpu::Processor* processor_;
apu::AudioSystem* audio_system_;

View File

@@ -73,6 +73,10 @@ KernelState* KernelState::shared() {
return shared_kernel_state_;
}
void KernelState::RegisterModule(XModule* module) {}
void KernelState::UnregisterModule(XModule* module) {}
XModule* KernelState::GetModule(const char* name) {
if (!name) {
// NULL name = self.

View File

@@ -56,6 +56,8 @@ public:
ObjectTable* object_table() const { return object_table_; }
void RegisterModule(XModule* module);
void UnregisterModule(XModule* module);
XModule* GetModule(const char* name);
XUserModule* GetExecutableModule();
void SetExecutableModule(XUserModule* module);

View File

@@ -24,6 +24,8 @@ XKernelModule::XKernelModule(KernelState* kernel_state, const char* path) :
emulator_ = kernel_state->emulator();
memory_ = emulator_->memory();
export_resolver_ = kernel_state->emulator()->export_resolver();
OnLoad();
}
XKernelModule::~XKernelModule() {

View File

@@ -9,6 +9,8 @@
#include <xenia/kernel/objects/xmodule.h>
#include <xdb/protocol.h>
using namespace xe;
using namespace xe::cpu;
@@ -32,6 +34,23 @@ XModule::XModule(KernelState* kernel_state, const char* path) :
}
XModule::~XModule() {
auto ev = xdb::protocol::ModuleUnloadEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::MODULE_UNLOAD;
ev->module_id = handle();
}
kernel_state_->UnregisterModule(this);
}
void XModule::OnLoad() {
auto ev = xdb::protocol::ModuleLoadEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::MODULE_LOAD;
ev->module_id = handle();
}
kernel_state_->RegisterModule(this);
}
X_STATUS XModule::GetSection(

View File

@@ -33,6 +33,8 @@ public:
uint32_t* out_section_data, uint32_t* out_section_size);
protected:
void OnLoad();
char name_[256];
char path_[poly::max_path];
};

View File

@@ -11,6 +11,7 @@
#include <poly/math.h>
#include <xdb/protocol.h>
#include <xenia/cpu/cpu.h>
#include <xenia/kernel/native_list.h>
#include <xenia/kernel/xboxkrnl_threading.h>
@@ -70,6 +71,12 @@ XThread::XThread(KernelState* kernel_state,
}
XThread::~XThread() {
auto ev = xdb::protocol::ThreadExitEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::THREAD_EXIT;
ev->thread_id = handle();
}
// Unregister first to prevent lookups while deleting.
kernel_state_->UnregisterThread(this);
@@ -254,6 +261,13 @@ X_STATUS XThread::Create() {
SetAffinity(proc_mask);
}
auto ev = xdb::protocol::ThreadCreateEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::THREAD_CREATE;
ev->thread_id = handle();
thread_state_->WriteRegisters(&ev->registers);
}
module->Release();
return X_STATUS_SUCCESS;
}

View File

@@ -122,6 +122,8 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
return X_STATUS_UNSUCCESSFUL;
}
OnLoad();
return X_STATUS_SUCCESS;
}

View File

@@ -4,6 +4,8 @@
'common.h',
'config.h',
'core.h',
'debug_agent.cc',
'debug_agent.h',
'emulator.cc',
'emulator.h',
'export_resolver.cc',