parent
02696f8dc4
commit
4f9e6b0547
|
@ -0,0 +1,37 @@
|
|||
# Debugger
|
||||
|
||||
## Protocol
|
||||
|
||||
Framed messages:
|
||||
|
||||
```
|
||||
[4b type] (0=request, 1=notification, etc)
|
||||
[4b content source id]
|
||||
[4b request/response id]
|
||||
[4b size]
|
||||
[payload]
|
||||
```
|
||||
|
||||
## Content Sources
|
||||
|
||||
### `xe::dbg::sources::MemorySource`
|
||||
|
||||
[ ] Paged view into memory
|
||||
[ ] Search operations
|
||||
[ ] Live streaming updates
|
||||
[ ] Writes
|
||||
|
||||
### `xe::dbg::sources::ProcessorSource`
|
||||
|
||||
[ ] Thread list
|
||||
[ ] State read/write (per thread)
|
||||
[ ] Modules
|
||||
[ ] Statistics
|
||||
[ ] Basic control (pause/resume)
|
||||
[ ] Breakpoints/checkpoints/traces
|
||||
[ ] Trace stream
|
||||
|
||||
### `xe::dbg::sources::ModuleSource`
|
||||
|
||||
[ ] Paged view into all symbols
|
||||
[ ] Get function contents (data, disasm, llvm, x86, etc)
|
|
@ -18,17 +18,22 @@ namespace xe {
|
|||
namespace dbg {
|
||||
|
||||
|
||||
class Debugger;
|
||||
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client();
|
||||
Client(Debugger* debugger);
|
||||
virtual ~Client();
|
||||
|
||||
virtual int Setup() = 0;
|
||||
|
||||
void OnMessage(const uint8_t* data, size_t length);
|
||||
void Write(uint8_t* buffer, size_t length);
|
||||
virtual void Write(uint8_t** buffers, size_t* lengths, size_t count) = 0;
|
||||
|
||||
protected:
|
||||
Debugger* debugger_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -22,20 +22,17 @@ namespace dbg {
|
|||
|
||||
class ContentSource {
|
||||
public:
|
||||
enum Type {
|
||||
kTypeIndexed,
|
||||
};
|
||||
|
||||
ContentSource(Type type);
|
||||
ContentSource(Debugger* debugger, uint32_t source_id);
|
||||
virtual ~ContentSource();
|
||||
|
||||
Type type();
|
||||
uint32_t source_id();
|
||||
|
||||
virtual int DispatchRequest(Client* client,
|
||||
const uint8_t* data, size_t length) = 0;
|
||||
virtual int Dispatch(Client* client, uint8_t type, uint32_t request_id,
|
||||
const uint8_t* data, size_t length) = 0;
|
||||
|
||||
protected:
|
||||
Type type_;
|
||||
Debugger* debugger_;
|
||||
uint32_t source_id_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <xenia/core.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace xe {
|
||||
|
@ -30,20 +31,24 @@ public:
|
|||
Debugger(xe_pal_ref pal);
|
||||
virtual ~Debugger();
|
||||
|
||||
void RegisterContentSource(std::string& name, ContentSource* content_source);
|
||||
void RegisterContentSource(ContentSource* content_source);
|
||||
|
||||
int Startup();
|
||||
|
||||
void Broadcast(uint32_t source_id, const uint8_t* data, size_t length);
|
||||
|
||||
private:
|
||||
int DispatchRequest(Client* client, const char* source_name,
|
||||
const uint8_t* data, size_t length);
|
||||
void AddClient(Client* client);
|
||||
void RemoveClient(Client* client);
|
||||
int Dispatch(Client* client, const uint8_t* data, size_t length);
|
||||
|
||||
friend class Client;
|
||||
|
||||
private:
|
||||
xe_pal_ref pal_;
|
||||
auto_ptr<Listener> listener_;
|
||||
std::map<char*, ContentSource*> content_sources_;
|
||||
std::vector<Client*> clients_;
|
||||
std::map<uint32_t, ContentSource*> content_sources_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_DBG_INDEXED_CONTENT_SOURCE_H_
|
||||
#define XENIA_KERNEL_DBG_INDEXED_CONTENT_SOURCE_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
#include <xenia/dbg/content_source.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace dbg {
|
||||
|
||||
|
||||
class Client;
|
||||
|
||||
|
||||
class IndexedContentSource : public ContentSource {
|
||||
public:
|
||||
IndexedContentSource();
|
||||
virtual ~IndexedContentSource();
|
||||
|
||||
int DispatchRequest(Client* client, const uint8_t* data, size_t length);
|
||||
|
||||
protected:
|
||||
virtual int RequestIndex(Client* client, uint64_t req_id) = 0;
|
||||
virtual int RequestRange(Client* client, uint64_t req_id,
|
||||
uint64_t start_index, uint64_t end_index) = 0;
|
||||
virtual int RequestEntry(Client* client, uint64_t req_id, uint64_t index) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace dbg
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_DBG_INDEXED_CONTENT_SOURCE_H_
|
|
@ -9,15 +9,24 @@
|
|||
|
||||
#include <xenia/dbg/client.h>
|
||||
|
||||
#include <xenia/dbg/debugger.h>
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::dbg;
|
||||
|
||||
|
||||
Client::Client() {
|
||||
Client::Client(Debugger* debugger) :
|
||||
debugger_(debugger) {
|
||||
debugger_->AddClient(this);
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
debugger_->RemoveClient(this);
|
||||
}
|
||||
|
||||
void Client::OnMessage(const uint8_t* data, size_t length) {
|
||||
debugger_->Dispatch(this, data, length);
|
||||
}
|
||||
|
||||
void Client::Write(uint8_t* buffer, size_t length) {
|
||||
|
|
|
@ -14,14 +14,13 @@ using namespace xe;
|
|||
using namespace xe::dbg;
|
||||
|
||||
|
||||
ContentSource::ContentSource(Type type) :
|
||||
type_(type) {
|
||||
ContentSource::ContentSource(Debugger* debugger, uint32_t source_id) :
|
||||
debugger_(debugger), source_id_(source_id) {
|
||||
}
|
||||
|
||||
ContentSource::~ContentSource() {
|
||||
}
|
||||
|
||||
|
||||
ContentSource::Type ContentSource::type() {
|
||||
return type_;
|
||||
uint32_t ContentSource::source_id() {
|
||||
return source_id_;
|
||||
}
|
||||
|
|
|
@ -30,13 +30,18 @@ Debugger::Debugger(xe_pal_ref pal) {
|
|||
pal_ = xe_pal_retain(pal);
|
||||
|
||||
listener_ = auto_ptr<Listener>(new WsListener(
|
||||
pal_, FLAGS_remote_debug_port));
|
||||
this, pal_, FLAGS_remote_debug_port));
|
||||
}
|
||||
|
||||
Debugger::~Debugger() {
|
||||
for (std::map<char*, ContentSource*>::iterator it = content_sources_.begin();
|
||||
it != content_sources_.end(); ++it) {
|
||||
xe_free(it->first);
|
||||
for (std::vector<Client*>::iterator it = clients_.begin();
|
||||
it != clients_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
clients_.clear();
|
||||
|
||||
for (std::map<uint32_t, ContentSource*>::iterator it =
|
||||
content_sources_.begin(); it != content_sources_.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
content_sources_.clear();
|
||||
|
@ -44,10 +49,9 @@ Debugger::~Debugger() {
|
|||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
void Debugger::RegisterContentSource(std::string& name,
|
||||
ContentSource* content_source) {
|
||||
content_sources_.insert(std::pair<char*, ContentSource*>(
|
||||
xestrdupa(name.c_str()), content_source));
|
||||
void Debugger::RegisterContentSource(ContentSource* content_source) {
|
||||
content_sources_.insert(std::pair<uint32_t, ContentSource*>(
|
||||
content_source->source_id(), content_source));
|
||||
}
|
||||
|
||||
int Debugger::Startup() {
|
||||
|
@ -69,12 +73,54 @@ int Debugger::Startup() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Debugger::DispatchRequest(Client* client, const char* source_name,
|
||||
const uint8_t* data, size_t length) {
|
||||
std::map<char*, ContentSource*>::iterator it =
|
||||
content_sources_.find((char*)source_name);
|
||||
void Debugger::Broadcast(uint32_t source_id,
|
||||
const uint8_t* data, size_t length) {
|
||||
uint32_t header[] = {
|
||||
0x00000001,
|
||||
source_id,
|
||||
0,
|
||||
length,
|
||||
};
|
||||
uint8_t* buffers[] = {
|
||||
(uint8_t*)header,
|
||||
(uint8_t*)data,
|
||||
};
|
||||
size_t lengths[] = {
|
||||
sizeof(header),
|
||||
length,
|
||||
};
|
||||
for (std::vector<Client*>::iterator it = clients_.begin();
|
||||
it != clients_.end(); ++it) {
|
||||
Client* client = *it;
|
||||
client->Write(buffers, lengths, XECOUNT(buffers));
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::AddClient(Client* client) {
|
||||
clients_.push_back(client);
|
||||
}
|
||||
|
||||
void Debugger::RemoveClient(Client* client) {
|
||||
for (std::vector<Client*>::iterator it = clients_.begin();
|
||||
it != clients_.end(); ++it) {
|
||||
if (*it == client) {
|
||||
clients_.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Debugger::Dispatch(Client* client, const uint8_t* data, size_t length) {
|
||||
uint32_t type = XEGETUINT32LE(data + 0);
|
||||
uint32_t source_id = XEGETUINT32LE(data + 4);
|
||||
uint32_t request_id = XEGETUINT32LE(data + 8);
|
||||
uint32_t size = XEGETUINT32LE(data + 12);
|
||||
|
||||
std::map<uint32_t, ContentSource*>::iterator it =
|
||||
content_sources_.find(source_id);
|
||||
if (it == content_sources_.end()) {
|
||||
XELOGW(XT("Content source %d not found, ignoring message"), source_id);
|
||||
return 1;
|
||||
}
|
||||
return it->second->DispatchRequest(client, data, length);
|
||||
return it->second->Dispatch(client, type, request_id, data + 16, size);
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/dbg/indexed_content_source.h>
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::dbg;
|
||||
|
||||
|
||||
IndexedContentSource::IndexedContentSource() :
|
||||
ContentSource(kTypeIndexed) {
|
||||
}
|
||||
|
||||
IndexedContentSource::~IndexedContentSource() {
|
||||
}
|
||||
|
||||
int IndexedContentSource::DispatchRequest(Client* client,
|
||||
const uint8_t* data, size_t length) {
|
||||
//
|
||||
return 1;
|
||||
}
|
|
@ -14,7 +14,8 @@ using namespace xe;
|
|||
using namespace xe::dbg;
|
||||
|
||||
|
||||
Listener::Listener(xe_pal_ref pal) {
|
||||
Listener::Listener(Debugger* debugger, xe_pal_ref pal) :
|
||||
debugger_(debugger) {
|
||||
pal_ = xe_pal_retain(pal);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,16 +18,20 @@ namespace xe {
|
|||
namespace dbg {
|
||||
|
||||
|
||||
class Debugger;
|
||||
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
Listener(xe_pal_ref pal);
|
||||
Listener(Debugger* debugger, xe_pal_ref pal);
|
||||
virtual ~Listener();
|
||||
|
||||
virtual int Setup() = 0;
|
||||
virtual int WaitForClient() = 0;
|
||||
|
||||
protected:
|
||||
xe_pal_ref pal_;
|
||||
Debugger* debugger_;
|
||||
xe_pal_ref pal_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
'client.cc',
|
||||
'content_source.cc',
|
||||
'debugger.cc',
|
||||
'indexed_content_source.cc',
|
||||
'listener.cc',
|
||||
'ws_client.cc',
|
||||
'ws_listener.cc',
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "dbg/ws_client.h"
|
||||
|
||||
#include <xenia/dbg/debugger.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -26,8 +28,8 @@ using namespace xe;
|
|||
using namespace xe::dbg;
|
||||
|
||||
|
||||
WsClient::WsClient(int socket_id) :
|
||||
Client(),
|
||||
WsClient::WsClient(Debugger* debugger, int socket_id) :
|
||||
Client(debugger),
|
||||
socket_id_(socket_id) {
|
||||
mutex_ = xe_mutex_alloc(1000);
|
||||
|
||||
|
@ -65,9 +67,24 @@ int WsClient::Setup() {
|
|||
setsockopt(socket_id_, IPPROTO_TCP, TCP_NODELAY,
|
||||
&opt_value, sizeof(opt_value));
|
||||
|
||||
// launch thread/etc
|
||||
EventThread();
|
||||
// TODO(benvanik): win32 support - put simple threads in PAL
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_t thread_handle;
|
||||
int result_code = pthread_create(
|
||||
&thread_handle,
|
||||
&attr,
|
||||
&StartCallbackPthreads,
|
||||
this);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return result_code;
|
||||
}
|
||||
|
||||
void* WsClient::StartCallbackPthreads(void* param) {
|
||||
WsClient* thread = reinterpret_cast<WsClient*>(param);
|
||||
thread->EventThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -126,27 +143,18 @@ void WsClientOnMsgCallback(wslay_event_context_ptr ctx,
|
|||
return;
|
||||
}
|
||||
|
||||
WsClient* client = reinterpret_cast<WsClient*>(user_data);
|
||||
switch (arg->opcode) {
|
||||
case WSLAY_TEXT_FRAME:
|
||||
// arg->msg, arg->msg_length
|
||||
XELOGW(XT("Text frame ignored; use binary messages"));
|
||||
break;
|
||||
case WSLAY_BINARY_FRAME:
|
||||
// arg->msg, arg->msg_length
|
||||
client->OnMessage(arg->msg, arg->msg_length);
|
||||
break;
|
||||
default:
|
||||
// Unknown opcode - some frame stuff?
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(benvanik): dispatch
|
||||
|
||||
// WsClient* client = reinterpret_cast<WsClient*>(user_data);
|
||||
// char hello[] = "HELLO";
|
||||
// size_t len = sizeof(hello);
|
||||
// uint8_t* bs[] = {(uint8_t*)&hello};
|
||||
// size_t lens[] = {len};
|
||||
// client->Write((uint8_t**)bs, lens, 1);
|
||||
// printf("on msg %d, %ld\n", arg->opcode, arg->msg_length);
|
||||
}
|
||||
|
||||
std::string EncodeBase64(const uint8_t* input, size_t length) {
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace dbg {
|
|||
|
||||
class WsClient : public Client {
|
||||
public:
|
||||
WsClient(int socket_id);
|
||||
WsClient(Debugger* debugger, int socket_id);
|
||||
virtual ~WsClient();
|
||||
|
||||
int socket_id();
|
||||
|
@ -37,6 +37,8 @@ public:
|
|||
virtual void Write(uint8_t** buffers, size_t* lengths, size_t count);
|
||||
|
||||
private:
|
||||
static void* StartCallbackPthreads(void* param);
|
||||
|
||||
int PerformHandshake();
|
||||
void EventThread();
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ using namespace xe;
|
|||
using namespace xe::dbg;
|
||||
|
||||
|
||||
WsListener::WsListener(xe_pal_ref pal, uint32_t port) :
|
||||
Listener(pal),
|
||||
WsListener::WsListener(Debugger* debugger, xe_pal_ref pal, uint32_t port) :
|
||||
Listener(debugger, pal),
|
||||
port_(port) {
|
||||
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ int WsListener::WaitForClient() {
|
|||
|
||||
// Create the client object.
|
||||
// Note that the client will delete itself when done.
|
||||
WsClient* client = new WsClient(client_socket_id);
|
||||
WsClient* client = new WsClient(debugger_, client_socket_id);
|
||||
if (client->Setup()) {
|
||||
// Client failed to setup - abort.
|
||||
return 1;
|
||||
|
|
|
@ -20,9 +20,12 @@ namespace xe {
|
|||
namespace dbg {
|
||||
|
||||
|
||||
class Debugger;
|
||||
|
||||
|
||||
class WsListener : public Listener {
|
||||
public:
|
||||
WsListener(xe_pal_ref pal, uint32_t port);
|
||||
WsListener(Debugger* debugger, xe_pal_ref pal, uint32_t port);
|
||||
virtual ~WsListener();
|
||||
|
||||
virtual int Setup();
|
||||
|
|
Loading…
Reference in New Issue