Experimenting with xdb API, starting on compare tool.
This commit is contained in:
parent
3de39aaf10
commit
1a39f5bd06
|
@ -249,7 +249,6 @@ int Translate_SOURCE_OFFSET(TranslationContext& ctx, Instr* i) {
|
||||||
|
|
||||||
// TODO(benvanik): dispatch of register forms.
|
// TODO(benvanik): dispatch of register forms.
|
||||||
uint32_t IntCode_TRACE_SOURCE(IntCodeState& ics, const IntCode* i) {
|
uint32_t IntCode_TRACE_SOURCE(IntCodeState& ics, const IntCode* i) {
|
||||||
// TODO(benvanik): append to active trace writer.
|
|
||||||
uint64_t trace_base = ics.thread_state->memory()->trace_base();
|
uint64_t trace_base = ics.thread_state->memory()->trace_base();
|
||||||
if (trace_base) {
|
if (trace_base) {
|
||||||
auto ev = xdb::protocol::InstrEvent::Append(trace_base);
|
auto ev = xdb::protocol::InstrEvent::Append(trace_base);
|
||||||
|
@ -323,7 +322,7 @@ uint32_t IntCode_TRAP(IntCodeState& ics, const IntCode* i) {
|
||||||
switch (i->flags) {
|
switch (i->flags) {
|
||||||
case 20:
|
case 20:
|
||||||
// 0x0FE00014 is a 'debug print' where r3 = buffer r4 = length
|
// 0x0FE00014 is a 'debug print' where r3 = buffer r4 = length
|
||||||
break;
|
return IA_NEXT;
|
||||||
case 22:
|
case 22:
|
||||||
// Always trap?
|
// Always trap?
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,6 +20,9 @@ namespace alloy {
|
||||||
|
|
||||||
// TODO(benvanik): go lockfree, and don't hold the lock while emitting.
|
// TODO(benvanik): go lockfree, and don't hold the lock while emitting.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Delegate;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Delegate {
|
class Delegate {
|
||||||
public:
|
public:
|
||||||
|
@ -30,16 +33,6 @@ class Delegate {
|
||||||
listeners_.push_back(listener);
|
listeners_.push_back(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveListener(Listener const& listener) {
|
|
||||||
std::lock_guard<std::mutex> guard(lock_);
|
|
||||||
for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
|
|
||||||
if (it == listener) {
|
|
||||||
listeners_.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveAllListeners() {
|
void RemoveAllListeners() {
|
||||||
std::lock_guard<std::mutex> guard(lock_);
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
listeners_.clear();
|
listeners_.clear();
|
||||||
|
@ -57,6 +50,33 @@ class Delegate {
|
||||||
std::vector<Listener> listeners_;
|
std::vector<Listener> listeners_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class Delegate<void> {
|
||||||
|
public:
|
||||||
|
typedef std::function<void()> Listener;
|
||||||
|
|
||||||
|
void AddListener(Listener const& listener) {
|
||||||
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
|
listeners_.push_back(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveAllListeners() {
|
||||||
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
|
listeners_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()() {
|
||||||
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
|
for (auto& listener : listeners_) {
|
||||||
|
listener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex lock_;
|
||||||
|
std::vector<Listener> listeners_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace alloy
|
} // namespace alloy
|
||||||
|
|
||||||
#endif // ALLOY_DELEGATE_H_
|
#endif // ALLOY_DELEGATE_H_
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 <alloy/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
|
||||||
|
|
||||||
|
alloy::Delegate<void> end_of_stream;
|
||||||
|
|
||||||
|
std::vector<Module*> modules();
|
||||||
|
std::vector<Thread*> threads();
|
||||||
|
|
||||||
|
alloy::Delegate<Module*> module_loaded;
|
||||||
|
alloy::Delegate<Module*> module_unloaded;
|
||||||
|
alloy::Delegate<Thread*> thread_created;
|
||||||
|
alloy::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_
|
|
@ -27,4 +27,16 @@ bool DebugTarget::InitializeFileSystem(const std::wstring& path) {
|
||||||
return true;
|
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
|
} // namespace xdb
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
#ifndef XDB_DEBUG_TARGET_H_
|
#ifndef XDB_DEBUG_TARGET_H_
|
||||||
#define 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>
|
#include <xenia/kernel/fs/filesystem.h>
|
||||||
|
|
||||||
namespace xdb {
|
namespace xdb {
|
||||||
|
@ -20,12 +26,23 @@ class DebugTarget {
|
||||||
|
|
||||||
xe::kernel::fs::FileSystem* file_system() const { return file_system_.get(); }
|
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:
|
protected:
|
||||||
DebugTarget() = default;
|
DebugTarget() = default;
|
||||||
|
|
||||||
bool InitializeFileSystem(const std::wstring& path);
|
bool InitializeFileSystem(const std::wstring& path);
|
||||||
|
|
||||||
std::unique_ptr<xe::kernel::fs::FileSystem> file_system_;
|
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
|
} // namespace xdb
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_
|
|
@ -0,0 +1,181 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 = poly::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
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_
|
|
@ -10,37 +10,13 @@
|
||||||
#include <xdb/postmortem_debug_target.h>
|
#include <xdb/postmortem_debug_target.h>
|
||||||
|
|
||||||
#include <poly/poly.h>
|
#include <poly/poly.h>
|
||||||
|
#include <xdb/postmortem_cursor.h>
|
||||||
#include <xenia/logging.h>
|
#include <xenia/logging.h>
|
||||||
|
|
||||||
namespace xdb {
|
namespace xdb {
|
||||||
|
|
||||||
using xdb::protocol::EventType;
|
using xdb::protocol::EventType;
|
||||||
|
|
||||||
// Matches the EventType ordering to allow for quick event size checks.
|
|
||||||
const size_t event_sizes[] = {
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
|
|
||||||
PostmortemDebugTarget::PostmortemDebugTarget()
|
PostmortemDebugTarget::PostmortemDebugTarget()
|
||||||
: file_(nullptr),
|
: file_(nullptr),
|
||||||
file_mapping_(nullptr),
|
file_mapping_(nullptr),
|
||||||
|
@ -66,8 +42,8 @@ bool PostmortemDebugTarget::LoadTrace(const std::wstring& path,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_mapping_ = CreateFileMapping(file_, nullptr, PAGE_READONLY, 0, 0,
|
file_mapping_ =
|
||||||
L"Local\\xenia_xdb_trace");
|
CreateFileMapping(file_, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||||
if (!file_mapping_) {
|
if (!file_mapping_) {
|
||||||
XELOGE("Could not create trace file mapping");
|
XELOGE("Could not create trace file mapping");
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,7 +71,7 @@ bool PostmortemDebugTarget::LoadTrace(const std::wstring& path,
|
||||||
if (process_start_event_) {
|
if (process_start_event_) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ptr += event_sizes[static_cast<uint8_t>(event_type)];
|
ptr += protocol::kEventSizes[static_cast<uint8_t>(event_type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initialized_filesystem = false;
|
bool initialized_filesystem = false;
|
||||||
|
@ -129,7 +105,8 @@ bool PostmortemDebugTarget::Prepare(std::atomic<bool>& cancelled) {
|
||||||
EventType::END_OF_STREAM) {
|
EventType::END_OF_STREAM) {
|
||||||
switch (event_type) {
|
switch (event_type) {
|
||||||
case EventType::PROCESS_START: {
|
case EventType::PROCESS_START: {
|
||||||
process_start_event_ = protocol::ProcessStartEvent::Get(ptr);
|
assert_true(process_start_event_ ==
|
||||||
|
protocol::ProcessStartEvent::Get(ptr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EventType::PROCESS_EXIT: {
|
case EventType::PROCESS_EXIT: {
|
||||||
|
@ -209,10 +186,17 @@ bool PostmortemDebugTarget::Prepare(std::atomic<bool>& cancelled) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptr += event_sizes[static_cast<uint8_t>(event_type)];
|
ptr += protocol::kEventSizes[static_cast<uint8_t>(event_type)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trace_length_ = ptr - trace_base_;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Cursor> PostmortemDebugTarget::CreateCursor() {
|
||||||
|
auto cursor = std::make_unique<PostmortemCursor>(this);
|
||||||
|
return std::unique_ptr<Cursor>(cursor.release());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xdb
|
} // namespace xdb
|
||||||
|
|
|
@ -25,16 +25,22 @@ class PostmortemDebugTarget : public DebugTarget {
|
||||||
PostmortemDebugTarget();
|
PostmortemDebugTarget();
|
||||||
~PostmortemDebugTarget() override;
|
~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,
|
bool LoadTrace(const std::wstring& path,
|
||||||
const std::wstring& content_path = L"");
|
const std::wstring& content_path = L"");
|
||||||
|
|
||||||
bool Prepare();
|
bool Prepare();
|
||||||
bool Prepare(std::atomic<bool>& cancelled);
|
bool Prepare(std::atomic<bool>& cancelled);
|
||||||
|
|
||||||
|
std::unique_ptr<Cursor> CreateCursor() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HANDLE file_;
|
HANDLE file_;
|
||||||
HANDLE file_mapping_;
|
HANDLE file_mapping_;
|
||||||
const uint8_t* trace_base_;
|
const uint8_t* trace_base_;
|
||||||
|
size_t trace_length_;
|
||||||
|
|
||||||
const protocol::ProcessStartEvent* process_start_event_;
|
const protocol::ProcessStartEvent* process_start_event_;
|
||||||
const protocol::ProcessExitEvent* process_exit_event_;
|
const protocol::ProcessExitEvent* process_exit_event_;
|
||||||
|
|
|
@ -77,14 +77,9 @@ struct ProcessExitEvent : public Event<ProcessExitEvent> {
|
||||||
EventType type;
|
EventType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ModuleInfo {
|
|
||||||
uint32_t module_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModuleLoadEvent : public Event<ModuleLoadEvent> {
|
struct ModuleLoadEvent : public Event<ModuleLoadEvent> {
|
||||||
EventType type;
|
EventType type;
|
||||||
uint32_t module_id;
|
uint32_t module_id;
|
||||||
ModuleInfo module_info;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ModuleUnloadEvent : public Event<ModuleUnloadEvent> {
|
struct ModuleUnloadEvent : public Event<ModuleUnloadEvent> {
|
||||||
|
@ -227,6 +222,31 @@ struct InstrEventR16R16 : public Event<InstrEventR16R16> {
|
||||||
|
|
||||||
#pragma pack(pop)
|
#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 protocol
|
||||||
} // namespace xdb
|
} // namespace xdb
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'cursor.cc',
|
||||||
|
'cursor.h',
|
||||||
'debug_target.cc',
|
'debug_target.cc',
|
||||||
'debug_target.h',
|
'debug_target.h',
|
||||||
|
'module.cc',
|
||||||
|
'module.h',
|
||||||
|
'postmortem_cursor.cc',
|
||||||
|
'postmortem_cursor.h',
|
||||||
'postmortem_debug_target.cc',
|
'postmortem_debug_target.cc',
|
||||||
'postmortem_debug_target.h',
|
'postmortem_debug_target.h',
|
||||||
'protocol.h',
|
'protocol.h',
|
||||||
|
'thread.cc',
|
||||||
|
'thread.h',
|
||||||
'xdb.cc',
|
'xdb.cc',
|
||||||
'xdb.h',
|
'xdb.h',
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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
|
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_
|
|
@ -13,7 +13,32 @@ namespace xdb {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
MainFrame::MainFrame(std::unique_ptr<DebugTarget> debug_target)
|
MainFrame::MainFrame(std::unique_ptr<DebugTarget> debug_target)
|
||||||
: MainFrameBase(nullptr), debug_target_(std::move(debug_target)) {}
|
: MainFrameBase(nullptr), debug_target_(std::move(debug_target)) {
|
||||||
|
cursor_ = std::move(debug_target_->CreateCursor());
|
||||||
|
cursor_->end_of_stream.AddListener([]() {
|
||||||
|
XELOGI("eos");
|
||||||
|
});
|
||||||
|
cursor_->module_loaded.AddListener([](Module* module) {
|
||||||
|
//
|
||||||
|
XELOGI("mod load");
|
||||||
|
});
|
||||||
|
cursor_->module_unloaded.AddListener([](Module* module) {
|
||||||
|
//
|
||||||
|
XELOGI("mod unload");
|
||||||
|
});
|
||||||
|
cursor_->thread_created.AddListener([](Thread* thread) {
|
||||||
|
//
|
||||||
|
XELOGI("thread create");
|
||||||
|
});
|
||||||
|
cursor_->thread_exited.AddListener([](Thread* thread) {
|
||||||
|
//
|
||||||
|
XELOGI("thread exit");
|
||||||
|
});
|
||||||
|
cursor_->Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainFrame::OnIdle(wxIdleEvent& event) {
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xdb
|
} // namespace xdb
|
||||||
|
|
|
@ -23,10 +23,11 @@ class MainFrame : public MainFrameBase {
|
||||||
MainFrame(std::unique_ptr<DebugTarget> debug_target);
|
MainFrame(std::unique_ptr<DebugTarget> debug_target);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//
|
void OnIdle(wxIdleEvent& event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<DebugTarget> debug_target_;
|
std::unique_ptr<DebugTarget> debug_target_;
|
||||||
|
std::unique_ptr<Cursor> cursor_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
<event name="OnEraseBackground"></event>
|
<event name="OnEraseBackground"></event>
|
||||||
<event name="OnHibernate"></event>
|
<event name="OnHibernate"></event>
|
||||||
<event name="OnIconize"></event>
|
<event name="OnIconize"></event>
|
||||||
<event name="OnIdle"></event>
|
<event name="OnIdle">OnIdle</event>
|
||||||
<event name="OnKeyDown"></event>
|
<event name="OnKeyDown"></event>
|
||||||
<event name="OnKeyUp"></event>
|
<event name="OnKeyUp"></event>
|
||||||
<event name="OnKillFocus"></event>
|
<event name="OnKillFocus"></event>
|
||||||
|
@ -536,7 +536,7 @@
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="Dialog" expanded="1">
|
<object class="Dialog" expanded="0">
|
||||||
<property name="aui_managed">0</property>
|
<property name="aui_managed">0</property>
|
||||||
<property name="aui_manager_style"></property>
|
<property name="aui_manager_style"></property>
|
||||||
<property name="bg"></property>
|
<property name="bg"></property>
|
||||||
|
@ -598,16 +598,16 @@
|
||||||
<event name="OnSetFocus"></event>
|
<event name="OnSetFocus"></event>
|
||||||
<event name="OnSize"></event>
|
<event name="OnSize"></event>
|
||||||
<event name="OnUpdateUI"></event>
|
<event name="OnUpdateUI"></event>
|
||||||
<object class="wxBoxSizer" expanded="1">
|
<object class="wxBoxSizer" expanded="0">
|
||||||
<property name="minimum_size"></property>
|
<property name="minimum_size"></property>
|
||||||
<property name="name">root_panel_outer</property>
|
<property name="name">root_panel_outer</property>
|
||||||
<property name="orient">wxVERTICAL</property>
|
<property name="orient">wxVERTICAL</property>
|
||||||
<property name="permission">none</property>
|
<property name="permission">none</property>
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="0">
|
||||||
<property name="border">10</property>
|
<property name="border">10</property>
|
||||||
<property name="flag">wxEXPAND | wxALL</property>
|
<property name="flag">wxEXPAND | wxALL</property>
|
||||||
<property name="proportion">1</property>
|
<property name="proportion">1</property>
|
||||||
<object class="wxPanel" expanded="1">
|
<object class="wxPanel" expanded="0">
|
||||||
<property name="BottomDockable">1</property>
|
<property name="BottomDockable">1</property>
|
||||||
<property name="LeftDockable">1</property>
|
<property name="LeftDockable">1</property>
|
||||||
<property name="RightDockable">1</property>
|
<property name="RightDockable">1</property>
|
||||||
|
@ -681,7 +681,7 @@
|
||||||
<event name="OnSetFocus"></event>
|
<event name="OnSetFocus"></event>
|
||||||
<event name="OnSize"></event>
|
<event name="OnSize"></event>
|
||||||
<event name="OnUpdateUI"></event>
|
<event name="OnUpdateUI"></event>
|
||||||
<object class="wxFlexGridSizer" expanded="1">
|
<object class="wxFlexGridSizer" expanded="0">
|
||||||
<property name="cols">1</property>
|
<property name="cols">1</property>
|
||||||
<property name="flexible_direction">wxVERTICAL</property>
|
<property name="flexible_direction">wxVERTICAL</property>
|
||||||
<property name="growablecols">0</property>
|
<property name="growablecols">0</property>
|
||||||
|
@ -693,11 +693,11 @@
|
||||||
<property name="permission">none</property>
|
<property name="permission">none</property>
|
||||||
<property name="rows">0</property>
|
<property name="rows">0</property>
|
||||||
<property name="vgap">0</property>
|
<property name="vgap">0</property>
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="0">
|
||||||
<property name="border">5</property>
|
<property name="border">5</property>
|
||||||
<property name="flag">wxALL</property>
|
<property name="flag">wxALL</property>
|
||||||
<property name="proportion">0</property>
|
<property name="proportion">0</property>
|
||||||
<object class="wxStaticText" expanded="1">
|
<object class="wxStaticText" expanded="0">
|
||||||
<property name="BottomDockable">1</property>
|
<property name="BottomDockable">1</property>
|
||||||
<property name="LeftDockable">1</property>
|
<property name="LeftDockable">1</property>
|
||||||
<property name="RightDockable">1</property>
|
<property name="RightDockable">1</property>
|
||||||
|
@ -776,11 +776,11 @@
|
||||||
<event name="OnUpdateUI"></event>
|
<event name="OnUpdateUI"></event>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="0">
|
||||||
<property name="border">5</property>
|
<property name="border">5</property>
|
||||||
<property name="flag">wxEXPAND</property>
|
<property name="flag">wxEXPAND</property>
|
||||||
<property name="proportion">0</property>
|
<property name="proportion">0</property>
|
||||||
<object class="wxFlexGridSizer" expanded="1">
|
<object class="wxFlexGridSizer" expanded="0">
|
||||||
<property name="cols">2</property>
|
<property name="cols">2</property>
|
||||||
<property name="flexible_direction">wxBOTH</property>
|
<property name="flexible_direction">wxBOTH</property>
|
||||||
<property name="growablecols">1</property>
|
<property name="growablecols">1</property>
|
||||||
|
@ -1138,11 +1138,11 @@
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="sizeritem" expanded="1">
|
<object class="sizeritem" expanded="0">
|
||||||
<property name="border">0</property>
|
<property name="border">0</property>
|
||||||
<property name="flag">wxEXPAND</property>
|
<property name="flag">wxEXPAND</property>
|
||||||
<property name="proportion">1</property>
|
<property name="proportion">1</property>
|
||||||
<object class="wxStdDialogButtonSizer" expanded="1">
|
<object class="wxStdDialogButtonSizer" expanded="0">
|
||||||
<property name="Apply">0</property>
|
<property name="Apply">0</property>
|
||||||
<property name="Cancel">1</property>
|
<property name="Cancel">1</property>
|
||||||
<property name="ContextHelp">0</property>
|
<property name="ContextHelp">0</property>
|
||||||
|
|
|
@ -40,10 +40,16 @@ MainFrameBase::MainFrameBase( wxWindow* parent, wxWindowID id, const wxString& t
|
||||||
|
|
||||||
m_mgr.Update();
|
m_mgr.Update();
|
||||||
this->Centre( wxBOTH );
|
this->Centre( wxBOTH );
|
||||||
|
|
||||||
|
// Connect Events
|
||||||
|
this->Connect( wxEVT_IDLE, wxIdleEventHandler( MainFrameBase::OnIdle ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
MainFrameBase::~MainFrameBase()
|
MainFrameBase::~MainFrameBase()
|
||||||
{
|
{
|
||||||
|
// Disconnect Events
|
||||||
|
this->Disconnect( wxEVT_IDLE, wxIdleEventHandler( MainFrameBase::OnIdle ) );
|
||||||
|
|
||||||
m_mgr.UnInit();
|
m_mgr.UnInit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,10 @@ namespace xdb
|
||||||
wxAuiNotebook* notebook_;
|
wxAuiNotebook* notebook_;
|
||||||
wxPanel* m_panel3;
|
wxPanel* m_panel3;
|
||||||
wxPanel* m_panel4;
|
wxPanel* m_panel4;
|
||||||
|
|
||||||
|
// Virtual event handlers, overide them in your derived class
|
||||||
|
virtual void OnIdle( wxIdleEvent& event ) { event.Skip(); }
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{
|
{
|
||||||
'includes': [
|
'includes': [
|
||||||
'alloy-sandbox/alloy-sandbox.gypi',
|
'alloy-sandbox/alloy-sandbox.gypi',
|
||||||
|
'xenia-compare/xenia-compare.gypi',
|
||||||
'xenia-debug/xenia-debug.gypi',
|
'xenia-debug/xenia-debug.gypi',
|
||||||
'xenia-run/xenia-run.gypi',
|
'xenia-run/xenia-run.gypi',
|
||||||
#'xenia-test/xenia-test.gypi',
|
#'xenia-test/xenia-test.gypi',
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 <memory>
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
#include <poly/poly.h>
|
||||||
|
#include <xdb/postmortem_debug_target.h>
|
||||||
|
#include <xdb/xdb.h>
|
||||||
|
|
||||||
|
DEFINE_string(trace_file_left, "", "Trace file to compare (original).");
|
||||||
|
DEFINE_string(trace_file_right, "", "Trace file to compare (new).");
|
||||||
|
|
||||||
|
namespace xc {
|
||||||
|
|
||||||
|
using xdb::PostmortemDebugTarget;
|
||||||
|
|
||||||
|
int main(int argc, xechar_t** argv) {
|
||||||
|
// Create platform abstraction layer.
|
||||||
|
xe_pal_options_t pal_options;
|
||||||
|
xe_zero_struct(&pal_options, sizeof(pal_options));
|
||||||
|
if (xe_pal_init(pal_options)) {
|
||||||
|
XEFATAL("Failed to initialize PAL");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto left_target = std::make_unique<PostmortemDebugTarget>();
|
||||||
|
if (!left_target->LoadTrace(poly::to_wstring(FLAGS_trace_file_left))) {
|
||||||
|
XEFATAL("Unable to load left trace file: %s",
|
||||||
|
FLAGS_trace_file_left.c_str());
|
||||||
|
}
|
||||||
|
auto right_target = std::make_unique<PostmortemDebugTarget>();
|
||||||
|
if (!right_target->LoadTrace(poly::to_wstring(FLAGS_trace_file_right))) {
|
||||||
|
XEFATAL("Unable to load right trace file: %s",
|
||||||
|
FLAGS_trace_file_right.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xc
|
||||||
|
|
||||||
|
// TODO(benvanik): move main thunk into poly
|
||||||
|
// ehhh
|
||||||
|
XE_MAIN_WINDOW_THUNK(xc::main, L"xenia-compare", "xenia-compare");
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Copyright 2014 Ben Vanik. All Rights Reserved.
|
||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'xenia-compare',
|
||||||
|
'type': 'executable',
|
||||||
|
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCLinkerTool': {
|
||||||
|
'SubSystem': '2'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'dependencies': [
|
||||||
|
'xdb',
|
||||||
|
'xenia',
|
||||||
|
],
|
||||||
|
|
||||||
|
'include_dirs': [
|
||||||
|
'.',
|
||||||
|
],
|
||||||
|
|
||||||
|
'sources': [
|
||||||
|
'xenia-compare.cc',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
Loading…
Reference in New Issue