mirror of
https://github.com/xenia-project/xenia.git
synced 2024-11-27 05:20:37 +00:00
Removing xdb and old tracing code before rewrite.
This commit is contained in:
parent
d1ee1512b9
commit
4c8f3501ad
1
.gitignore
vendored
1
.gitignore
vendored
@ -38,6 +38,7 @@ tmtags
|
||||
|
||||
# VS
|
||||
.vs
|
||||
*.user
|
||||
bin/
|
||||
obj/
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/cursor.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
//
|
||||
|
||||
} // namespace xdb
|
@ -1,57 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_CURSOR_H_
|
||||
#define XDB_CURSOR_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "xenia/base/delegate.h"
|
||||
#include <xdb/module.h>
|
||||
#include <xdb/protocol.h>
|
||||
#include <xdb/thread.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class Cursor {
|
||||
public:
|
||||
virtual ~Cursor() = default;
|
||||
|
||||
virtual bool can_step() const = 0;
|
||||
|
||||
// TODO(benvanik): breakpoints/events
|
||||
|
||||
xe::Delegate<void> end_of_stream;
|
||||
|
||||
std::vector<Module*> modules();
|
||||
std::vector<Thread*> threads();
|
||||
|
||||
xe::Delegate<Module*> module_loaded;
|
||||
xe::Delegate<Module*> module_unloaded;
|
||||
xe::Delegate<Thread*> thread_created;
|
||||
xe::Delegate<Thread*> thread_exited;
|
||||
|
||||
// TODO(benvanik): memory access
|
||||
|
||||
virtual void Continue(Thread* thread = nullptr) = 0;
|
||||
virtual void ContinueTo(uint32_t address, Thread* thread = nullptr) = 0;
|
||||
virtual void ContinueToNextCall(Thread* thread = nullptr) = 0;
|
||||
virtual void ContinueToReturn(Thread* thread = nullptr) = 0;
|
||||
virtual void ContinueUntil(
|
||||
const std::function<bool(protocol::EventType, uint8_t*)> predicate,
|
||||
Thread* thread = nullptr) = 0;
|
||||
virtual void Break() = 0;
|
||||
|
||||
protected:
|
||||
Cursor() = default;
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_CURSOR_H_
|
@ -1,42 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/debug_target.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
bool DebugTarget::InitializeFileSystem(const std::wstring& path) {
|
||||
file_system_.reset(new xe::kernel::fs::FileSystem());
|
||||
|
||||
// Infer the type (stfs/iso/etc) from the path.
|
||||
auto file_system_type = file_system_->InferType(path);
|
||||
|
||||
// Setup the file system exactly like the emulator does - this way we can
|
||||
// access all the same files.
|
||||
if (file_system_->InitializeFromPath(file_system_type, path)) {
|
||||
XELOGE("Unable to initialize filesystem from path");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Module* DebugTarget::GetModule(uint16_t module_id) {
|
||||
std::lock_guard<std::mutex> lock(object_lock_);
|
||||
auto it = module_map_.find(module_id);
|
||||
return it != module_map_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
Thread* DebugTarget::GetThread(uint16_t thread_id) {
|
||||
std::lock_guard<std::mutex> lock(object_lock_);
|
||||
auto it = thread_map_.find(thread_id);
|
||||
return it != thread_map_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
} // namespace xdb
|
@ -1,50 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_DEBUG_TARGET_H_
|
||||
#define XDB_DEBUG_TARGET_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <xdb/cursor.h>
|
||||
#include <xenia/kernel/fs/filesystem.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class DebugTarget {
|
||||
public:
|
||||
virtual ~DebugTarget() = default;
|
||||
|
||||
xe::kernel::fs::FileSystem* file_system() const { return file_system_.get(); }
|
||||
|
||||
virtual std::unique_ptr<Cursor> CreateCursor() = 0;
|
||||
|
||||
Module* GetModule(uint16_t module_id);
|
||||
Thread* GetThread(uint16_t thread_id);
|
||||
|
||||
protected:
|
||||
DebugTarget() = default;
|
||||
|
||||
bool InitializeFileSystem(const std::wstring& path);
|
||||
|
||||
std::unique_ptr<xe::kernel::fs::FileSystem> file_system_;
|
||||
|
||||
std::mutex object_lock_;
|
||||
std::vector<std::unique_ptr<Module>> modules_;
|
||||
std::vector<std::unique_ptr<Thread>> threads_;
|
||||
std::unordered_map<uint16_t, Module*> module_map_;
|
||||
std::unordered_map<uint16_t, Thread*> thread_map_;
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_DEBUG_TARGET_H_
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/module.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
//
|
||||
|
||||
} // namespace xdb
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_MODULE_H_
|
||||
#define XDB_MODULE_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class Module {
|
||||
public:
|
||||
uint16_t module_id;
|
||||
// info
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_MODULE_H_
|
@ -1,181 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/postmortem_cursor.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#include <xdb/postmortem_debug_target.h>
|
||||
#include <xdb/protocol.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
using xdb::protocol::EventType;
|
||||
|
||||
struct Command {
|
||||
enum class Type {
|
||||
EXIT,
|
||||
CONTINUE,
|
||||
};
|
||||
Type type;
|
||||
|
||||
protected:
|
||||
Command(Type type) : type(type) {}
|
||||
};
|
||||
|
||||
struct ExitCommand : public Command {
|
||||
ExitCommand() : Command(Type::EXIT) {}
|
||||
};
|
||||
|
||||
struct ContinueCommand : public Command {
|
||||
ContinueCommand() : Command(Type::CONTINUE), thread(nullptr) {}
|
||||
Thread* thread;
|
||||
};
|
||||
|
||||
class PostmortemCursor::Executor {
|
||||
public:
|
||||
Executor(PostmortemCursor* cursor) : cursor_(cursor), running_(true) {
|
||||
trace_ptr_ = cursor->target_->trace_base();
|
||||
|
||||
// Must be last, as it'll spin up here.
|
||||
thread_ = std::thread(std::bind(&Executor::ExecutionThread, this));
|
||||
}
|
||||
~Executor() {
|
||||
running_ = false;
|
||||
IssueCommand(std::make_unique<ExitCommand>());
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
bool eof() const { return eof_; }
|
||||
|
||||
void IssueCommand(std::unique_ptr<Command> command) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_lock_);
|
||||
queue_.push(std::move(command));
|
||||
pending_commands_ = true;
|
||||
}
|
||||
queue_cond_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
void ExecutionThread() {
|
||||
while (running_) {
|
||||
auto command = AwaitCommand();
|
||||
if (!running_ || !command || command->type == Command::Type::EXIT) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (command->type) {
|
||||
case Command::Type::CONTINUE: {
|
||||
auto cmd = static_cast<ContinueCommand*>(command.get());
|
||||
cmd->thread;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Process(pending_commands_);
|
||||
}
|
||||
}
|
||||
|
||||
void Process(std::atomic<bool>& exit_signal) {
|
||||
if (eof_) {
|
||||
return;
|
||||
}
|
||||
while (!exit_signal) {
|
||||
auto event_type = xe::load<EventType>(trace_ptr_);
|
||||
switch (event_type) {
|
||||
case EventType::END_OF_STREAM: {
|
||||
eof_ = true;
|
||||
cursor_->end_of_stream();
|
||||
return;
|
||||
}
|
||||
case EventType::MODULE_LOAD: {
|
||||
auto ev = protocol::ModuleLoadEvent::Get(trace_ptr_);
|
||||
break;
|
||||
}
|
||||
case EventType::MODULE_UNLOAD: {
|
||||
auto ev = protocol::ModuleLoadEvent::Get(trace_ptr_);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_CREATE: {
|
||||
auto ev = protocol::ThreadCreateEvent::Get(trace_ptr_);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_INFO: {
|
||||
auto ev = protocol::ThreadInfoEvent::Get(trace_ptr_);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_EXIT: {
|
||||
auto ev = protocol::ThreadExitEvent::Get(trace_ptr_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
trace_ptr_ += protocol::kEventSizes[static_cast<uint8_t>(event_type)];
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Command> AwaitCommand() {
|
||||
std::unique_lock<std::mutex> lock(queue_lock_);
|
||||
while (queue_.empty()) {
|
||||
queue_cond_.wait(lock);
|
||||
}
|
||||
auto command = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
pending_commands_ = !queue_.empty();
|
||||
return command;
|
||||
}
|
||||
|
||||
PostmortemCursor* cursor_;
|
||||
std::atomic<bool> running_;
|
||||
const uint8_t* trace_ptr_;
|
||||
std::atomic<bool> eof_;
|
||||
std::thread thread_;
|
||||
|
||||
std::queue<std::unique_ptr<Command>> queue_;
|
||||
std::mutex queue_lock_;
|
||||
std::condition_variable queue_cond_;
|
||||
std::atomic<bool> pending_commands_;
|
||||
};
|
||||
|
||||
PostmortemCursor::PostmortemCursor(PostmortemDebugTarget* target)
|
||||
: target_(target) {
|
||||
executor_.reset(new Executor(this));
|
||||
}
|
||||
|
||||
PostmortemCursor::~PostmortemCursor() { executor_.reset(); }
|
||||
|
||||
bool PostmortemCursor::can_step() const {
|
||||
// TODO(benvanik): check trace flags.
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostmortemCursor::Continue(Thread* thread) {
|
||||
auto cmd = std::make_unique<ContinueCommand>();
|
||||
cmd->thread = thread;
|
||||
executor_->IssueCommand(std::move(cmd));
|
||||
}
|
||||
|
||||
void PostmortemCursor::ContinueTo(uint32_t address, Thread* thread) {}
|
||||
|
||||
void PostmortemCursor::ContinueToNextCall(Thread* thread) {}
|
||||
|
||||
void PostmortemCursor::ContinueToReturn(Thread* thread) {}
|
||||
|
||||
void PostmortemCursor::ContinueUntil(
|
||||
const std::function<bool(protocol::EventType, uint8_t*)> predicate,
|
||||
Thread* thread) {}
|
||||
|
||||
void PostmortemCursor::Break() {}
|
||||
|
||||
} // namespace xdb
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_POSTMORTEM_CURSOR_H_
|
||||
#define XDB_POSTMORTEM_CURSOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <xdb/cursor.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class PostmortemDebugTarget;
|
||||
|
||||
class PostmortemCursor : public Cursor {
|
||||
public:
|
||||
PostmortemCursor(PostmortemDebugTarget* target);
|
||||
~PostmortemCursor() override;
|
||||
|
||||
bool can_step() const override;
|
||||
|
||||
void Continue(Thread* thread = nullptr) override;
|
||||
void ContinueTo(uint32_t address, Thread* thread = nullptr) override;
|
||||
void ContinueToNextCall(Thread* thread = nullptr) override;
|
||||
void ContinueToReturn(Thread* thread = nullptr) override;
|
||||
void ContinueUntil(
|
||||
const std::function<bool(protocol::EventType, uint8_t*)> predicate,
|
||||
Thread* thread = nullptr) override;
|
||||
void Break() override;
|
||||
|
||||
private:
|
||||
class Executor;
|
||||
|
||||
PostmortemDebugTarget* target_;
|
||||
std::unique_ptr<Executor> executor_;
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_POSTMORTEM_CURSOR_H_
|
@ -1,199 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/postmortem_debug_target.h>
|
||||
|
||||
#include <xdb/postmortem_cursor.h>
|
||||
#include <xenia/logging.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
using xdb::protocol::EventType;
|
||||
|
||||
PostmortemDebugTarget::PostmortemDebugTarget()
|
||||
: file_(nullptr),
|
||||
file_mapping_(nullptr),
|
||||
trace_base_(0),
|
||||
process_start_event_(nullptr),
|
||||
process_exit_event_(nullptr) {}
|
||||
|
||||
PostmortemDebugTarget::~PostmortemDebugTarget() {
|
||||
if (trace_base_) {
|
||||
UnmapViewOfFile(trace_base_);
|
||||
}
|
||||
CloseHandle(file_mapping_);
|
||||
CloseHandle(file_);
|
||||
}
|
||||
|
||||
bool PostmortemDebugTarget::LoadTrace(const std::wstring& path,
|
||||
const std::wstring& content_path) {
|
||||
file_ = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY, nullptr);
|
||||
if (!file_) {
|
||||
XELOGE("Could not open trace file for writing");
|
||||
return false;
|
||||
}
|
||||
|
||||
file_mapping_ =
|
||||
CreateFileMapping(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (!file_mapping_) {
|
||||
XELOGE("Could not create trace file mapping");
|
||||
return false;
|
||||
}
|
||||
|
||||
trace_base_ = reinterpret_cast<const uint8_t*>(
|
||||
MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0));
|
||||
if (!trace_base_) {
|
||||
XELOGE("Could not map view of trace file");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the process start event - it should be near the top and we need it for
|
||||
// path lookup.
|
||||
const uint8_t* ptr = trace_base_ + 8;
|
||||
EventType event_type;
|
||||
while ((event_type = xe::load<EventType>(ptr)) != EventType::END_OF_STREAM) {
|
||||
switch (event_type) {
|
||||
case EventType::PROCESS_START: {
|
||||
process_start_event_ = protocol::ProcessStartEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (process_start_event_) {
|
||||
break;
|
||||
}
|
||||
ptr += protocol::kEventSizes[static_cast<uint8_t>(event_type)];
|
||||
}
|
||||
|
||||
bool initialized_filesystem = false;
|
||||
if (!content_path.empty()) {
|
||||
initialized_filesystem = InitializeFileSystem(content_path);
|
||||
} else {
|
||||
// If no path was provided just use what's in the trace.
|
||||
auto trace_content_path =
|
||||
xe::to_wstring(std::string(process_start_event_->launch_path));
|
||||
initialized_filesystem = InitializeFileSystem(trace_content_path);
|
||||
}
|
||||
if (!initialized_filesystem) {
|
||||
XELOGE("Unable to initialize filesystem.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PostmortemDebugTarget::Prepare() {
|
||||
std::atomic<bool> cancelled(false);
|
||||
return Prepare(cancelled);
|
||||
}
|
||||
|
||||
bool PostmortemDebugTarget::Prepare(std::atomic<bool>& cancelled) {
|
||||
// TODO(benvanik): scan file, build indicies, etc.
|
||||
|
||||
const uint8_t* ptr = trace_base_ + 8;
|
||||
EventType event_type;
|
||||
while ((event_type = xe::load<EventType>(ptr)) != EventType::END_OF_STREAM) {
|
||||
switch (event_type) {
|
||||
case EventType::PROCESS_START: {
|
||||
assert_true(process_start_event_ ==
|
||||
protocol::ProcessStartEvent::Get(ptr));
|
||||
break;
|
||||
}
|
||||
case EventType::PROCESS_EXIT: {
|
||||
process_exit_event_ = protocol::ProcessExitEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::MODULE_LOAD: {
|
||||
auto ev = protocol::ModuleLoadEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::MODULE_UNLOAD: {
|
||||
auto ev = protocol::ModuleUnloadEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_CREATE: {
|
||||
auto ev = protocol::ThreadCreateEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_INFO: {
|
||||
auto ev = protocol::ThreadInfoEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::THREAD_EXIT: {
|
||||
auto ev = protocol::ThreadExitEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::FUNCTION_COMPILED: {
|
||||
auto ev = protocol::FunctionCompiledEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::OUTPUT_STRING: {
|
||||
auto ev = protocol::OutputStringEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::KERNEL_CALL: {
|
||||
auto ev = protocol::KernelCallEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::KERNEL_CALL_RETURN: {
|
||||
auto ev = protocol::KernelCallReturnEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::USER_CALL: {
|
||||
auto ev = protocol::UserCallEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::USER_CALL_RETURN: {
|
||||
auto ev = protocol::UserCallReturnEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR: {
|
||||
auto ev = protocol::InstrEvent::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R8: {
|
||||
auto ev = protocol::InstrEventR8::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R8_R8: {
|
||||
auto ev = protocol::InstrEventR8R8::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R8_R16: {
|
||||
auto ev = protocol::InstrEventR8R16::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R16: {
|
||||
auto ev = protocol::InstrEventR16::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R16_R8: {
|
||||
auto ev = protocol::InstrEventR16R8::Get(ptr);
|
||||
break;
|
||||
}
|
||||
case EventType::INSTR_R16_R16: {
|
||||
auto ev = protocol::InstrEventR16R16::Get(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptr += protocol::kEventSizes[static_cast<uint8_t>(event_type)];
|
||||
};
|
||||
|
||||
trace_length_ = ptr - trace_base_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Cursor> PostmortemDebugTarget::CreateCursor() {
|
||||
auto cursor = std::make_unique<PostmortemCursor>(this);
|
||||
return std::unique_ptr<Cursor>(cursor.release());
|
||||
}
|
||||
|
||||
} // namespace xdb
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_POSTMORTEM_DEBUG_TARGET_H_
|
||||
#define XDB_POSTMORTEM_DEBUG_TARGET_H_
|
||||
|
||||
// TODO(benvanik): abstract mapping type.
|
||||
#include <Windows.h>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include <xdb/debug_target.h>
|
||||
#include <xdb/protocol.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class PostmortemDebugTarget : public DebugTarget {
|
||||
public:
|
||||
PostmortemDebugTarget();
|
||||
~PostmortemDebugTarget() override;
|
||||
|
||||
const uint8_t* trace_base() const { return trace_base_ + 8; }
|
||||
size_t trace_length() const { return trace_length_; }
|
||||
|
||||
bool LoadTrace(const std::wstring& path,
|
||||
const std::wstring& content_path = L"");
|
||||
|
||||
bool Prepare();
|
||||
bool Prepare(std::atomic<bool>& cancelled);
|
||||
|
||||
std::unique_ptr<Cursor> CreateCursor() override;
|
||||
|
||||
private:
|
||||
HANDLE file_;
|
||||
HANDLE file_mapping_;
|
||||
const uint8_t* trace_base_;
|
||||
size_t trace_length_;
|
||||
|
||||
const protocol::ProcessStartEvent* process_start_event_;
|
||||
const protocol::ProcessExitEvent* process_exit_event_;
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_POSTMORTEM_DEBUG_TARGET_H_
|
@ -1,253 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_PROTOCOL_H_
|
||||
#define XDB_PROTOCOL_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "xenia/base/atomic.h"
|
||||
#include "xenia/base/vec128.h"
|
||||
|
||||
namespace xdb {
|
||||
namespace protocol {
|
||||
|
||||
using vec128_t = xe::vec128_t;
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
enum class EventType : uint8_t {
|
||||
END_OF_STREAM = 0,
|
||||
|
||||
PROCESS_START,
|
||||
PROCESS_EXIT,
|
||||
MODULE_LOAD,
|
||||
MODULE_UNLOAD,
|
||||
THREAD_CREATE,
|
||||
THREAD_INFO,
|
||||
THREAD_EXIT,
|
||||
|
||||
FUNCTION_COMPILED,
|
||||
|
||||
OUTPUT_STRING,
|
||||
|
||||
KERNEL_CALL,
|
||||
KERNEL_CALL_RETURN,
|
||||
USER_CALL,
|
||||
USER_CALL_RETURN,
|
||||
|
||||
INSTR,
|
||||
INSTR_R8,
|
||||
INSTR_R8_R8,
|
||||
INSTR_R8_R16,
|
||||
INSTR_R16,
|
||||
INSTR_R16_R8,
|
||||
INSTR_R16_R16,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Event {
|
||||
static T* Append(uint64_t trace_base) {
|
||||
if (!trace_base) {
|
||||
return nullptr;
|
||||
}
|
||||
uint64_t ptr = xe::atomic_exchange_add(
|
||||
sizeof(T), reinterpret_cast<uint64_t*>(trace_base));
|
||||
return reinterpret_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
static const T* Get(const void* ptr) {
|
||||
return reinterpret_cast<const T*>(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
struct ProcessStartEvent : public Event<ProcessStartEvent> {
|
||||
EventType type;
|
||||
uint64_t membase;
|
||||
char launch_path[256];
|
||||
};
|
||||
|
||||
struct ProcessExitEvent : public Event<ProcessExitEvent> {
|
||||
EventType type;
|
||||
};
|
||||
|
||||
struct ModuleLoadEvent : public Event<ModuleLoadEvent> {
|
||||
EventType type;
|
||||
uint32_t module_id;
|
||||
};
|
||||
|
||||
struct ModuleUnloadEvent : public Event<ModuleUnloadEvent> {
|
||||
EventType type;
|
||||
uint32_t module_id;
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
uint64_t lr;
|
||||
uint64_t ctr;
|
||||
uint32_t xer;
|
||||
uint32_t cr[8];
|
||||
uint32_t fpscr;
|
||||
uint32_t vscr;
|
||||
uint64_t gpr[32];
|
||||
double fpr[32];
|
||||
xe::vec128_t vr[128];
|
||||
};
|
||||
|
||||
struct ThreadCreateEvent : public Event<ThreadCreateEvent> {
|
||||
EventType type;
|
||||
uint16_t thread_id;
|
||||
Registers registers;
|
||||
};
|
||||
|
||||
struct ThreadInfoEvent : public Event<ThreadInfoEvent> {
|
||||
EventType type;
|
||||
uint16_t thread_id;
|
||||
};
|
||||
|
||||
struct ThreadExitEvent : public Event<ThreadExitEvent> {
|
||||
EventType type;
|
||||
uint16_t thread_id;
|
||||
};
|
||||
|
||||
struct FunctionCompiledEvent : public Event<FunctionCompiledEvent> {
|
||||
EventType type;
|
||||
uint8_t _reserved;
|
||||
uint16_t flags; // RECOMPILED? user/extern? etc
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
// timing?
|
||||
};
|
||||
|
||||
struct OutputStringEvent : public Event<OutputStringEvent> {
|
||||
EventType type;
|
||||
uint16_t thread_id;
|
||||
// ?
|
||||
};
|
||||
|
||||
struct KernelCallEvent : public Event<KernelCallEvent> {
|
||||
EventType type;
|
||||
uint8_t _reserved;
|
||||
uint16_t thread_id;
|
||||
uint16_t module_id;
|
||||
uint16_t ordinal;
|
||||
};
|
||||
struct KernelCallReturnEvent : public Event<KernelCallReturnEvent> {
|
||||
EventType type;
|
||||
uint8_t _reserved;
|
||||
uint16_t thread_id;
|
||||
};
|
||||
|
||||
struct UserCallEvent : public Event<UserCallEvent> {
|
||||
EventType type;
|
||||
uint8_t call_type; // TAIL?
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
};
|
||||
struct UserCallReturnEvent : public Event<UserCallReturnEvent> {
|
||||
EventType type;
|
||||
uint8_t _reserved;
|
||||
uint16_t thread_id;
|
||||
};
|
||||
|
||||
struct InstrEvent : public Event<InstrEvent> {
|
||||
EventType type;
|
||||
uint8_t _reserved;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
};
|
||||
struct InstrEventR8 : public Event<InstrEventR8> {
|
||||
EventType type;
|
||||
uint8_t dest_reg;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
uint64_t dest_value;
|
||||
};
|
||||
struct InstrEventR8R8 : public Event<InstrEventR8R8> {
|
||||
EventType type;
|
||||
uint8_t _reserved0;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
uint8_t dest_reg_0;
|
||||
uint8_t dest_reg_1;
|
||||
uint16_t _reserved1;
|
||||
uint64_t dest_value_0;
|
||||
uint64_t dest_value_1;
|
||||
};
|
||||
struct InstrEventR8R16 : public Event<InstrEventR8R16> {
|
||||
EventType type;
|
||||
uint8_t _reserved0;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
uint8_t dest_reg_0;
|
||||
uint8_t dest_reg_1;
|
||||
uint16_t _reserved1;
|
||||
uint64_t dest_value_0;
|
||||
vec128_t dest_value_1;
|
||||
};
|
||||
struct InstrEventR16 : public Event<InstrEventR16> {
|
||||
EventType type;
|
||||
uint8_t dest_reg;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
vec128_t dest_value;
|
||||
};
|
||||
struct InstrEventR16R8 : public Event<InstrEventR16R8> {
|
||||
EventType type;
|
||||
uint8_t _reserved0;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
uint8_t dest_reg_0;
|
||||
uint8_t dest_reg_1;
|
||||
uint16_t _reserved1;
|
||||
vec128_t dest_value_0;
|
||||
uint64_t dest_value_1;
|
||||
};
|
||||
struct InstrEventR16R16 : public Event<InstrEventR16R16> {
|
||||
EventType type;
|
||||
uint8_t _reserved0;
|
||||
uint16_t thread_id;
|
||||
uint32_t address;
|
||||
uint8_t dest_reg_0;
|
||||
uint8_t dest_reg_1;
|
||||
uint16_t _reserved1;
|
||||
vec128_t dest_value_0;
|
||||
vec128_t dest_value_1;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
// Matches the EventType ordering to allow for quick event size checks.
|
||||
const size_t kEventSizes[] = {
|
||||
0,
|
||||
sizeof(protocol::ProcessStartEvent),
|
||||
sizeof(protocol::ProcessExitEvent),
|
||||
sizeof(protocol::ModuleLoadEvent),
|
||||
sizeof(protocol::ModuleUnloadEvent),
|
||||
sizeof(protocol::ThreadCreateEvent),
|
||||
sizeof(protocol::ThreadInfoEvent),
|
||||
sizeof(protocol::ThreadExitEvent),
|
||||
sizeof(protocol::FunctionCompiledEvent),
|
||||
sizeof(protocol::OutputStringEvent),
|
||||
sizeof(protocol::KernelCallEvent),
|
||||
sizeof(protocol::KernelCallReturnEvent),
|
||||
sizeof(protocol::UserCallEvent),
|
||||
sizeof(protocol::UserCallReturnEvent),
|
||||
sizeof(protocol::InstrEvent),
|
||||
sizeof(protocol::InstrEventR8),
|
||||
sizeof(protocol::InstrEventR8R8),
|
||||
sizeof(protocol::InstrEventR8R16),
|
||||
sizeof(protocol::InstrEventR16),
|
||||
sizeof(protocol::InstrEventR16R8),
|
||||
sizeof(protocol::InstrEventR16R16),
|
||||
};
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_PROTOCOL_H_
|
@ -1,24 +0,0 @@
|
||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'cursor.cc',
|
||||
'cursor.h',
|
||||
'debug_target.cc',
|
||||
'debug_target.h',
|
||||
'module.cc',
|
||||
'module.h',
|
||||
'postmortem_cursor.cc',
|
||||
'postmortem_cursor.h',
|
||||
'postmortem_debug_target.cc',
|
||||
'postmortem_debug_target.h',
|
||||
'protocol.h',
|
||||
'thread.cc',
|
||||
'thread.h',
|
||||
'xdb.cc',
|
||||
'xdb.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'sym/sources.gypi',
|
||||
],
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/sym/map_symbol_database.h>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
Symbol* MapSymbolDatabase::Lookup(uint32_t address) { return nullptr; }
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_SYM_MAP_SYMBOL_DATABASE_H_
|
||||
#define XDB_SYM_MAP_SYMBOL_DATABASE_H_
|
||||
|
||||
#include <xdb/sym/symbol_database.h>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
class MapSymbolDatabase : public SymbolDatabase {
|
||||
public:
|
||||
Symbol* Lookup(uint32_t address) override;
|
||||
};
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_SYM_MAP_SYMBOL_DATABASE_H_
|
@ -1,14 +0,0 @@
|
||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'map_symbol_database.cc',
|
||||
'map_symbol_database.h',
|
||||
'symbol_database.cc',
|
||||
'symbol_database.h',
|
||||
'symbol_provider.cc',
|
||||
'symbol_provider.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
],
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/sym/symbol_database.h>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
//
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
@ -1,50 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_SYM_SYMBOL_DATABASE_H_
|
||||
#define XDB_SYM_SYMBOL_DATABASE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
class ObjectFile {
|
||||
public:
|
||||
std::string library;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
enum class SymbolType {
|
||||
FUNCTION,
|
||||
VARIABLE,
|
||||
};
|
||||
|
||||
class Symbol {
|
||||
public:
|
||||
uint32_t address;
|
||||
ObjectFile* object_file;
|
||||
std::string name;
|
||||
SymbolType type;
|
||||
bool is_inlined;
|
||||
};
|
||||
|
||||
class SymbolDatabase {
|
||||
public:
|
||||
virtual Symbol* Lookup(uint32_t address) = 0;
|
||||
|
||||
protected:
|
||||
SymbolDatabase() = default;
|
||||
};
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_SYM_SYMBOL_DATABASE_H_
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/sym/symbol_provider.h>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
void SymbolProvider::AddSearchPath(const std::string& path) {
|
||||
//
|
||||
}
|
||||
|
||||
std::unique_ptr<SymbolDatabase> SymbolProvider::LoadDatabase(
|
||||
const std::string& module_path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_SYM_SYMBOL_PROVIDER_H_
|
||||
#define XDB_SYM_SYMBOL_PROVIDER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <xdb/sym/symbol_database.h>
|
||||
|
||||
namespace xdb {
|
||||
namespace sym {
|
||||
|
||||
class SymbolProvider {
|
||||
public:
|
||||
SymbolProvider() = default;
|
||||
|
||||
void AddSearchPath(const std::string& path);
|
||||
|
||||
std::unique_ptr<SymbolDatabase> LoadDatabase(const std::string& module_path);
|
||||
};
|
||||
|
||||
} // namespace sym
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_SYM_SYMBOL_PROVIDER_H_
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/thread.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
//
|
||||
|
||||
} // namespace xdb
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_THREAD_H_
|
||||
#define XDB_THREAD_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
uint16_t thread_id;
|
||||
// name
|
||||
// etc
|
||||
};
|
||||
|
||||
} // namespace xdb
|
||||
|
||||
#endif // XDB_THREAD_H_
|
@ -1,16 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <xdb/xdb.h>
|
||||
|
||||
namespace xdb {
|
||||
|
||||
void test() {}
|
||||
|
||||
} // namespace xdb
|
@ -1,17 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 XDB_H_
|
||||
#define XDB_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/emulator.h>
|
||||
#include <xenia/xbox.h>
|
||||
|
||||
#endif // XDB_H_
|
@ -10,6 +10,7 @@
|
||||
#include "xenia/cpu/backend/x64/x64_emitter.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/atomic.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/vec128.h"
|
||||
@ -25,7 +26,6 @@
|
||||
#include "xenia/cpu/symbol_info.h"
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/profiling.h"
|
||||
#include "xdb/protocol.h"
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
@ -161,19 +161,6 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
||||
mov(rdx, qword[rcx + 8]); // membase
|
||||
}
|
||||
|
||||
uint64_t trace_base = runtime_->memory()->trace_base();
|
||||
if (trace_base && trace_flags_ & TRACE_USER_CALLS) {
|
||||
mov(rax, trace_base);
|
||||
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallEvent)));
|
||||
lock();
|
||||
xadd(qword[rax], r8);
|
||||
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL) |
|
||||
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
|
||||
mov(qword[r8], rax);
|
||||
EmitGetCurrentThreadId();
|
||||
mov(word[r8 + 2], ax);
|
||||
}
|
||||
|
||||
// Body.
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
@ -188,16 +175,6 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
||||
const Instr* instr = block->instr_head;
|
||||
while (instr) {
|
||||
const Instr* new_tail = instr;
|
||||
|
||||
// Special handling of TRACE_SOURCE.
|
||||
if (instr->opcode == &OPCODE_TRACE_SOURCE_info) {
|
||||
if (trace_flags_ & TRACE_SOURCE) {
|
||||
EmitTraceSource(instr);
|
||||
}
|
||||
instr = instr->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SelectSequence(*this, instr, &new_tail)) {
|
||||
// No sequence found!
|
||||
assert_always();
|
||||
@ -238,129 +215,12 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
|
||||
source_map_count_++;
|
||||
}
|
||||
|
||||
void X64Emitter::EmitTraceSource(const Instr* instr) {
|
||||
uint64_t trace_base = runtime_->memory()->trace_base();
|
||||
if (!trace_base || !(trace_flags_ & TRACE_SOURCE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(benvanik): make this a function call to some append fn.
|
||||
|
||||
uint8_t dest_reg_0 = instr->flags & 0xFF;
|
||||
uint8_t dest_reg_1 = instr->flags >> 8;
|
||||
|
||||
xdb::protocol::EventType event_type;
|
||||
size_t event_size = 0;
|
||||
if (dest_reg_0 == 100) {
|
||||
event_type = xdb::protocol::EventType::INSTR;
|
||||
event_size = sizeof(xdb::protocol::InstrEvent);
|
||||
} else if (dest_reg_1 == 100) {
|
||||
if (dest_reg_0 & (1 << 7)) {
|
||||
event_type = xdb::protocol::EventType::INSTR_R16;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR16);
|
||||
} else {
|
||||
event_type = xdb::protocol::EventType::INSTR_R8;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR8);
|
||||
}
|
||||
} else {
|
||||
if (dest_reg_0 & (1 << 7) && dest_reg_1 & (1 << 7)) {
|
||||
event_type = xdb::protocol::EventType::INSTR_R16_R16;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR16R16);
|
||||
} else if (dest_reg_0 & (1 << 7) && !(dest_reg_1 & (1 << 7))) {
|
||||
event_type = xdb::protocol::EventType::INSTR_R16_R8;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR16R8);
|
||||
} else if (!(dest_reg_0 & (1 << 7)) && dest_reg_1 & (1 << 7)) {
|
||||
event_type = xdb::protocol::EventType::INSTR_R8_R16;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR8R16);
|
||||
} else if (!(dest_reg_0 & (1 << 7)) && !(dest_reg_1 & (1 << 7))) {
|
||||
event_type = xdb::protocol::EventType::INSTR_R8_R8;
|
||||
event_size = sizeof(xdb::protocol::InstrEventR8R8);
|
||||
}
|
||||
}
|
||||
assert_not_zero(event_size);
|
||||
|
||||
mov(rax, trace_base);
|
||||
mov(r8d, static_cast<uint32_t>(event_size));
|
||||
lock();
|
||||
xadd(qword[rax], r8);
|
||||
// r8 is now the pointer where we can write our event.
|
||||
|
||||
// Write the header, which is the same for everything (pretty much).
|
||||
// Some event types ignore the dest reg, and that's fine.
|
||||
uint64_t qword_0 = static_cast<uint64_t>(event_type) |
|
||||
(static_cast<uint64_t>(dest_reg_0) << 8) |
|
||||
(instr->src1.offset << 32);
|
||||
mov(rax, qword_0);
|
||||
mov(qword[r8], rax);
|
||||
|
||||
// Write thread ID.
|
||||
EmitGetCurrentThreadId();
|
||||
mov(word[r8 + 2], ax);
|
||||
|
||||
switch (event_type) {
|
||||
default:
|
||||
case xdb::protocol::EventType::INSTR:
|
||||
break;
|
||||
case xdb::protocol::EventType::INSTR_R8:
|
||||
case xdb::protocol::EventType::INSTR_R16:
|
||||
if (dest_reg_0 & (1 << 7)) {
|
||||
EmitTraceSourceAppendValue(instr->src2.value, 8);
|
||||
} else {
|
||||
EmitTraceSourceAppendValue(instr->src2.value, 8);
|
||||
}
|
||||
break;
|
||||
case xdb::protocol::EventType::INSTR_R8_R8:
|
||||
case xdb::protocol::EventType::INSTR_R8_R16:
|
||||
case xdb::protocol::EventType::INSTR_R16_R8:
|
||||
case xdb::protocol::EventType::INSTR_R16_R16:
|
||||
mov(word[r8 + 8], dest_reg_0 | static_cast<uint16_t>(dest_reg_1 << 8));
|
||||
size_t offset = 8;
|
||||
if (dest_reg_0 & (1 << 7)) {
|
||||
EmitTraceSourceAppendValue(instr->src2.value, offset);
|
||||
offset += 16;
|
||||
} else {
|
||||
EmitTraceSourceAppendValue(instr->src2.value, offset);
|
||||
offset += 8;
|
||||
}
|
||||
if (dest_reg_1 & (1 << 7)) {
|
||||
EmitTraceSourceAppendValue(instr->src3.value, offset);
|
||||
offset += 16;
|
||||
} else {
|
||||
EmitTraceSourceAppendValue(instr->src3.value, offset);
|
||||
offset += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void X64Emitter::EmitTraceSourceAppendValue(const Value* value,
|
||||
size_t r8_offset) {
|
||||
//
|
||||
}
|
||||
|
||||
void X64Emitter::EmitGetCurrentThreadId() {
|
||||
// rcx must point to context. We could fetch from the stack if needed.
|
||||
mov(ax, word[rcx + runtime_->frontend()->context_info()->thread_id_offset()]);
|
||||
}
|
||||
|
||||
void X64Emitter::EmitTraceUserCallReturn() {
|
||||
auto trace_base = runtime_->memory()->trace_base();
|
||||
if (!trace_base || !(trace_flags_ & TRACE_USER_CALLS)) {
|
||||
return;
|
||||
}
|
||||
mov(rdx, rax);
|
||||
mov(rax, trace_base);
|
||||
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallReturnEvent)));
|
||||
lock();
|
||||
xadd(qword[rax], r8);
|
||||
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL_RETURN) |
|
||||
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
|
||||
mov(qword[r8], rax);
|
||||
EmitGetCurrentThreadId();
|
||||
mov(word[r8 + 2], ax);
|
||||
mov(rax, rdx);
|
||||
ReloadEDX();
|
||||
}
|
||||
void X64Emitter::EmitTraceUserCallReturn() {}
|
||||
|
||||
void X64Emitter::DebugBreak() {
|
||||
// TODO(benvanik): notify debugger.
|
||||
@ -628,23 +488,6 @@ void X64Emitter::CallExtern(const hir::Instr* instr,
|
||||
const FunctionInfo* symbol_info) {
|
||||
assert_true(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
|
||||
|
||||
uint64_t trace_base = runtime_->memory()->trace_base();
|
||||
if (trace_base & trace_flags_ & TRACE_EXTERN_CALLS) {
|
||||
mov(rax, trace_base);
|
||||
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallEvent)));
|
||||
lock();
|
||||
xadd(qword[rax], r8);
|
||||
// TODO(benvanik): get module/ordinal.
|
||||
uint32_t module_id = 0;
|
||||
uint32_t ordinal = 0;
|
||||
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL) |
|
||||
(static_cast<uint64_t>(0) << 8) | (module_id << 16) |
|
||||
(ordinal));
|
||||
mov(qword[r8], rax);
|
||||
EmitGetCurrentThreadId();
|
||||
mov(word[r8 + 2], ax);
|
||||
}
|
||||
|
||||
if (!symbol_info->extern_handler()) {
|
||||
CallNative(UndefinedCallExtern, reinterpret_cast<uint64_t>(symbol_info));
|
||||
} else {
|
||||
@ -662,19 +505,6 @@ void X64Emitter::CallExtern(const hir::Instr* instr,
|
||||
ReloadEDX();
|
||||
// rax = host return
|
||||
}
|
||||
if (trace_base && trace_flags_ & TRACE_EXTERN_CALLS) {
|
||||
mov(rax, trace_base);
|
||||
mov(r8d,
|
||||
static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallReturnEvent)));
|
||||
lock();
|
||||
xadd(qword[rax], r8);
|
||||
mov(rax,
|
||||
static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL_RETURN) |
|
||||
(static_cast<uint64_t>(0) << 8) | (0));
|
||||
mov(qword[r8], rax);
|
||||
EmitGetCurrentThreadId();
|
||||
mov(word[r8 + 2], ax);
|
||||
}
|
||||
}
|
||||
|
||||
void X64Emitter::CallNative(void* fn) {
|
||||
|
@ -183,8 +183,6 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||
protected:
|
||||
void* Emplace(size_t stack_size);
|
||||
int Emit(hir::HIRBuilder* builder, size_t& out_stack_size);
|
||||
void EmitTraceSource(const hir::Instr* instr);
|
||||
void EmitTraceSourceAppendValue(const hir::Value* value, size_t r8_offset);
|
||||
void EmitGetCurrentThreadId();
|
||||
void EmitTraceUserCallReturn();
|
||||
|
||||
|
@ -12,11 +12,6 @@
|
||||
|
||||
#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_string(load_module_map);
|
||||
|
||||
DECLARE_string(dump_path);
|
||||
|
@ -10,13 +10,6 @@
|
||||
#include "xenia/cpu/cpu-private.h"
|
||||
|
||||
// Debugging:
|
||||
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 "
|
||||
|
@ -27,15 +27,6 @@ enum DebugInfoFlags {
|
||||
DEBUG_INFO_ALL_DISASM = 0xFFFF,
|
||||
};
|
||||
|
||||
enum TraceFlags {
|
||||
TRACE_NONE = 0,
|
||||
TRACE_EXTERN_CALLS = (1 << 0),
|
||||
TRACE_USER_CALLS = (1 << 1),
|
||||
TRACE_SOURCE = (1 << 2),
|
||||
TRACE_SOURCE_VALUES = (1 << 3),
|
||||
TRACE_FUNCTION_GENERATION = (1 << 4),
|
||||
};
|
||||
|
||||
typedef struct SourceMapEntry_s {
|
||||
uint32_t source_offset; // Original source address/offset.
|
||||
uint64_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b)
|
||||
|
@ -139,30 +139,6 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
|
||||
// DebugBreak();
|
||||
// TraceInvalidInstruction(i);
|
||||
}
|
||||
|
||||
if (flags & EMIT_TRACE_SOURCE) {
|
||||
if (flags & EMIT_TRACE_SOURCE_VALUES) {
|
||||
switch (trace_info_.dest_count) {
|
||||
case 0:
|
||||
TraceSource(i.address);
|
||||
break;
|
||||
case 1:
|
||||
TraceSource(i.address, trace_info_.dests[0].reg,
|
||||
trace_info_.dests[0].value);
|
||||
break;
|
||||
case 2:
|
||||
TraceSource(i.address, trace_info_.dests[0].reg,
|
||||
trace_info_.dests[0].value, trace_info_.dests[1].reg,
|
||||
trace_info_.dests[1].value);
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(trace_info_.dest_count);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
TraceSource(i.address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Finalize();
|
||||
|
@ -35,10 +35,6 @@ class PPCHIRBuilder : public hir::HIRBuilder {
|
||||
enum EmitFlags {
|
||||
// Emit comment nodes.
|
||||
EMIT_DEBUG_COMMENTS = 1 << 0,
|
||||
// Emit TraceSource nodes.
|
||||
EMIT_TRACE_SOURCE = 1 << 1,
|
||||
// Emit TraceSource nodes with the resulting values of the operations.
|
||||
EMIT_TRACE_SOURCE_VALUES = EMIT_TRACE_SOURCE | (1 << 2),
|
||||
};
|
||||
int Emit(FunctionInfo* symbol_info, uint32_t flags);
|
||||
|
||||
|
@ -108,7 +108,7 @@ static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) {
|
||||
|
||||
typedef struct {
|
||||
InstrType* type;
|
||||
uint64_t address;
|
||||
uint32_t address;
|
||||
|
||||
union {
|
||||
uint32_t code;
|
||||
|
@ -134,11 +134,6 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||
if (debug_info) {
|
||||
emit_flags |= PPCHIRBuilder::EMIT_DEBUG_COMMENTS;
|
||||
}
|
||||
if (trace_flags & TRACE_SOURCE_VALUES) {
|
||||
emit_flags |= PPCHIRBuilder::EMIT_TRACE_SOURCE_VALUES;
|
||||
} else if (trace_flags & TRACE_SOURCE) {
|
||||
emit_flags |= PPCHIRBuilder::EMIT_TRACE_SOURCE;
|
||||
}
|
||||
int result = builder_->Emit(symbol_info, emit_flags);
|
||||
if (result) {
|
||||
return result;
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "xenia/cpu/function.h"
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/cpu/debugger.h"
|
||||
#include "xenia/cpu/symbol_info.h"
|
||||
@ -75,18 +74,9 @@ int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||
|
||||
int result = 0;
|
||||
|
||||
uint64_t trace_base = thread_state->memory()->trace_base();
|
||||
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
|
||||
auto handler = symbol_info_->extern_handler();
|
||||
|
||||
if (trace_base && true) {
|
||||
auto ev = xdb::protocol::KernelCallEvent::Append(trace_base);
|
||||
ev->type = xdb::protocol::EventType::KERNEL_CALL;
|
||||
ev->thread_id = thread_state->thread_id();
|
||||
ev->module_id = 0;
|
||||
ev->ordinal = 0;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler(thread_state->context(), symbol_info_->extern_arg0(),
|
||||
symbol_info_->extern_arg1());
|
||||
@ -95,28 +85,8 @@ int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||
symbol_info_->name().c_str());
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (trace_base && true) {
|
||||
auto ev = xdb::protocol::KernelCallReturnEvent::Append(trace_base);
|
||||
ev->type = xdb::protocol::EventType::KERNEL_CALL_RETURN;
|
||||
ev->thread_id = thread_state->thread_id();
|
||||
}
|
||||
} else {
|
||||
if (trace_base && true) {
|
||||
auto ev = xdb::protocol::UserCallEvent::Append(trace_base);
|
||||
ev->type = xdb::protocol::EventType::USER_CALL;
|
||||
ev->call_type = 0; // ?
|
||||
ev->thread_id = thread_state->thread_id();
|
||||
ev->address = static_cast<uint32_t>(symbol_info_->address());
|
||||
}
|
||||
|
||||
CallImpl(thread_state, return_address);
|
||||
|
||||
if (trace_base && true) {
|
||||
auto ev = xdb::protocol::UserCallReturnEvent::Append(trace_base);
|
||||
ev->type = xdb::protocol::EventType::USER_CALL_RETURN;
|
||||
ev->thread_id = thread_state->thread_id();
|
||||
}
|
||||
}
|
||||
|
||||
if (original_thread_state != thread_state) {
|
||||
|
@ -640,34 +640,12 @@ void HIRBuilder::Nop() {
|
||||
i->src1.value = i->src2.value = i->src3.value = NULL;
|
||||
}
|
||||
|
||||
void HIRBuilder::SourceOffset(uint64_t offset) {
|
||||
void HIRBuilder::SourceOffset(uint32_t offset) {
|
||||
Instr* i = AppendInstr(OPCODE_SOURCE_OFFSET_info, 0);
|
||||
i->src1.offset = offset;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
}
|
||||
|
||||
void HIRBuilder::TraceSource(uint64_t offset) {
|
||||
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, 100 | (100 << 8));
|
||||
i->src1.offset = offset;
|
||||
i->set_src2(LoadZero(INT64_TYPE));
|
||||
i->set_src3(LoadZero(INT64_TYPE));
|
||||
}
|
||||
|
||||
void HIRBuilder::TraceSource(uint64_t offset, uint8_t index, Value* value) {
|
||||
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, index | (100 << 8));
|
||||
i->src1.offset = offset;
|
||||
i->set_src2(value);
|
||||
i->set_src3(LoadZero(INT64_TYPE));
|
||||
}
|
||||
|
||||
void HIRBuilder::TraceSource(uint64_t offset, uint8_t index_0, Value* value_0,
|
||||
uint8_t index_1, Value* value_1) {
|
||||
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, index_0 | (index_1 << 8));
|
||||
i->src1.offset = offset;
|
||||
i->set_src2(value_0);
|
||||
i->set_src3(value_1);
|
||||
}
|
||||
|
||||
void HIRBuilder::DebugBreak() {
|
||||
Instr* i = AppendInstr(OPCODE_DEBUG_BREAK_info, 0);
|
||||
i->src1.value = i->src2.value = i->src3.value = NULL;
|
||||
|
@ -68,11 +68,7 @@ class HIRBuilder {
|
||||
|
||||
void Nop();
|
||||
|
||||
void SourceOffset(uint64_t offset);
|
||||
void TraceSource(uint64_t offset);
|
||||
void TraceSource(uint64_t offset, uint8_t index, Value* value);
|
||||
void TraceSource(uint64_t offset, uint8_t index_0, Value* value_0,
|
||||
uint8_t index_1, Value* value_1);
|
||||
void SourceOffset(uint32_t offset);
|
||||
|
||||
// trace info/etc
|
||||
void DebugBreak();
|
||||
|
@ -109,7 +109,6 @@ enum Opcode {
|
||||
OPCODE_COMMENT,
|
||||
OPCODE_NOP,
|
||||
OPCODE_SOURCE_OFFSET,
|
||||
OPCODE_TRACE_SOURCE,
|
||||
OPCODE_DEBUG_BREAK,
|
||||
OPCODE_DEBUG_BREAK_TRUE,
|
||||
OPCODE_TRAP,
|
||||
|
@ -26,12 +26,6 @@ DEFINE_OPCODE(
|
||||
OPCODE_SIG_X_O,
|
||||
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_TRACE_SOURCE,
|
||||
"trace_source",
|
||||
OPCODE_SIG_X_O_V_V,
|
||||
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
OPCODE_DEBUG_BREAK,
|
||||
"debug_break",
|
||||
|
@ -72,21 +72,6 @@ int Processor::Setup() {
|
||||
|
||||
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 Runtime(memory_, export_resolver_, debug_info_flags, trace_flags);
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/cpu/frontend/ppc_frontend.h"
|
||||
#include "xenia/cpu/module.h"
|
||||
@ -254,16 +253,6 @@ int Runtime::DemandFunction(FunctionInfo* symbol_info,
|
||||
}
|
||||
symbol_info->set_function(function);
|
||||
|
||||
auto trace_base = memory()->trace_base();
|
||||
if (trace_base && trace_flags_ & TRACE_FUNCTION_GENERATION) {
|
||||
auto ev = xdb::protocol::FunctionCompiledEvent::Append(trace_base);
|
||||
ev->type = xdb::protocol::EventType::FUNCTION_COMPILED;
|
||||
ev->flags = 0;
|
||||
ev->address = static_cast<uint32_t>(symbol_info->address());
|
||||
ev->length =
|
||||
static_cast<uint32_t>(symbol_info->end_address() - ev->address);
|
||||
}
|
||||
|
||||
// Before we give the symbol back to the rest, let the debugger know.
|
||||
debugger_->OnFunctionDefined(symbol_info, function);
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/cpu/runtime.h"
|
||||
@ -100,30 +99,5 @@ ThreadState* ThreadState::Get() { return thread_state_; }
|
||||
|
||||
uint32_t ThreadState::GetThreadID() { return thread_state_->thread_id_; }
|
||||
|
||||
void ThreadState::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));
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
@ -14,12 +14,6 @@
|
||||
#include "xenia/cpu/thread_state.h"
|
||||
#include "xenia/memory.h"
|
||||
|
||||
namespace xdb {
|
||||
namespace protocol {
|
||||
struct Registers;
|
||||
} // namespace protocol
|
||||
} // namespace xdb
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
@ -50,8 +44,6 @@ class ThreadState {
|
||||
static ThreadState* Get();
|
||||
static uint32_t GetThreadID();
|
||||
|
||||
void WriteRegisters(xdb::protocol::Registers* registers);
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
Memory* memory_;
|
||||
|
@ -1,79 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 <gflags/gflags.h>
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/memory.h"
|
||||
#include "xenia/base/string.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) {
|
||||
auto file_path = xe::to_wstring(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.
|
||||
xe::store<uint64_t>(trace_base_, trace_base() + 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace xe
|
@ -1,44 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/base/platform.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_
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "xenia/emulator.h"
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
#include "xenia/apu/apu.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/string.h"
|
||||
@ -39,13 +38,6 @@ Emulator::Emulator(const std::wstring& 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;
|
||||
}
|
||||
|
||||
debug_agent_.reset();
|
||||
|
||||
xam_.reset();
|
||||
xboxkrnl_.reset();
|
||||
kernel_state_.reset();
|
||||
@ -75,19 +67,12 @@ X_STATUS Emulator::Setup() {
|
||||
main_window_ = std::make_unique<ui::MainWindow>(this);
|
||||
main_window_->Start();
|
||||
|
||||
debug_agent_.reset(new DebugAgent(this));
|
||||
result = debug_agent_->Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create memory system first, as it is required for other systems.
|
||||
memory_ = std::make_unique<Memory>();
|
||||
result = memory_->Initialize();
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
memory_->set_trace_base(debug_agent_->trace_base());
|
||||
|
||||
// Shared export resolver used to attach and query for HLE exports.
|
||||
export_resolver_ = std::make_unique<xe::cpu::ExportResolver>();
|
||||
@ -200,15 +185,6 @@ X_STATUS Emulator::LaunchSTFSTitle(const std::wstring& path) {
|
||||
|
||||
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||
const std::string& module_path) {
|
||||
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
|
||||
if (ev) {
|
||||
ev->type = xdb::protocol::EventType::PROCESS_START;
|
||||
ev->membase = reinterpret_cast<uint64_t>(memory()->virtual_membase());
|
||||
auto path_length =
|
||||
xe::to_string(path).copy(ev->launch_path, sizeof(ev->launch_path) - 1);
|
||||
ev->launch_path[path_length] = 0;
|
||||
}
|
||||
|
||||
return xboxkrnl_->LaunchModule(module_path.c_str());
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "xenia/debug_agent.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/ui/main_window.h"
|
||||
@ -55,8 +54,6 @@ class Emulator {
|
||||
|
||||
Memory* memory() const { return memory_.get(); }
|
||||
|
||||
DebugAgent* debug_agent() const { return debug_agent_.get(); }
|
||||
|
||||
cpu::Processor* processor() const { return processor_.get(); }
|
||||
apu::AudioSystem* audio_system() const { return audio_system_.get(); }
|
||||
gpu::GraphicsSystem* graphics_system() const {
|
||||
@ -89,8 +86,6 @@ class Emulator {
|
||||
|
||||
std::unique_ptr<Memory> memory_;
|
||||
|
||||
std::unique_ptr<DebugAgent> debug_agent_;
|
||||
|
||||
std::unique_ptr<cpu::Processor> processor_;
|
||||
std::unique_ptr<apu::AudioSystem> audio_system_;
|
||||
std::unique_ptr<gpu::GraphicsSystem> graphics_system_;
|
||||
|
@ -9,8 +9,6 @@
|
||||
|
||||
#include "xenia/kernel/objects/xmodule.h"
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
@ -32,22 +30,10 @@ XModule::XModule(KernelState* kernel_state, const std::string& 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);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
|
||||
#include "xdb/protocol.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/threading.h"
|
||||
@ -63,12 +62,6 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -208,13 +201,6 @@ 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;
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ Memory::Memory()
|
||||
physical_membase_(nullptr),
|
||||
reserve_address_(0),
|
||||
reserve_value_(0),
|
||||
trace_base_(0),
|
||||
mapping_(0),
|
||||
mapping_base_(nullptr) {
|
||||
system_page_size_ = uint32_t(xe::page_size());
|
||||
|
@ -76,9 +76,6 @@ class Memory {
|
||||
inline uint64_t* reserve_address() { return &reserve_address_; }
|
||||
inline uint64_t* reserve_value() { return &reserve_value_; }
|
||||
|
||||
uint64_t trace_base() const { return trace_base_; }
|
||||
void set_trace_base(uint64_t value) { trace_base_ = value; }
|
||||
|
||||
// TODO(benvanik): make poly memory utils for these.
|
||||
void Zero(uint32_t address, uint32_t size);
|
||||
void Fill(uint32_t address, uint32_t size, uint8_t value);
|
||||
@ -118,7 +115,6 @@ class Memory {
|
||||
uint8_t* physical_membase_;
|
||||
uint64_t reserve_address_;
|
||||
uint64_t reserve_value_;
|
||||
uint64_t trace_base_;
|
||||
|
||||
HANDLE mapping_;
|
||||
uint8_t* mapping_base_;
|
||||
|
@ -1,8 +1,6 @@
|
||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'debug_agent.cc',
|
||||
'debug_agent.h',
|
||||
'emulator.cc',
|
||||
'emulator.h',
|
||||
'memory.cc',
|
||||
|
21
xb.bat
21
xb.bat
@ -464,20 +464,15 @@ IF %CLANG_FORMAT%=="" (
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
SET ANY_ERRORS=0
|
||||
IF %ALL% NEQ 1 (
|
||||
ECHO.
|
||||
ECHO ^> git-clang-format
|
||||
CMD /c python third_party/clang-format/git-clang-format --binary=%CLANG_FORMAT% --commit=HEAD
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: clang-format failed - ensure all files are staged
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
) ELSE (
|
||||
SET ANY_ERRORS=0
|
||||
ECHO.
|
||||
ECHO ^> clang-format (all)
|
||||
PUSHD src
|
||||
FOR /R %%G in (*.cc *.c *.h *.inl) DO (
|
||||
ECHO ^> clang-format %%G
|
||||
@ -487,12 +482,12 @@ IF %ALL% NEQ 1 (
|
||||
)
|
||||
)
|
||||
POPD
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: one or more clang-format calls failed
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
)
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: 1+ clang-format calls failed - ensure all files are staged
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
|
Loading…
Reference in New Issue
Block a user