More debugger work.

Posix only right now.
This commit is contained in:
Ben Vanik 2013-02-03 00:29:40 -08:00
parent 02696f8dc4
commit 4f9e6b0547
16 changed files with 173 additions and 131 deletions

37
docs/debugger.md Normal file
View File

@ -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)

View File

@ -18,17 +18,22 @@ namespace xe {
namespace dbg { namespace dbg {
class Debugger;
class Client { class Client {
public: public:
Client(); Client(Debugger* debugger);
virtual ~Client(); virtual ~Client();
virtual int Setup() = 0; virtual int Setup() = 0;
void OnMessage(const uint8_t* data, size_t length);
void Write(uint8_t* buffer, size_t length); void Write(uint8_t* buffer, size_t length);
virtual void Write(uint8_t** buffers, size_t* lengths, size_t count) = 0; virtual void Write(uint8_t** buffers, size_t* lengths, size_t count) = 0;
protected: protected:
Debugger* debugger_;
}; };

View File

@ -22,20 +22,17 @@ namespace dbg {
class ContentSource { class ContentSource {
public: public:
enum Type { ContentSource(Debugger* debugger, uint32_t source_id);
kTypeIndexed,
};
ContentSource(Type type);
virtual ~ContentSource(); virtual ~ContentSource();
Type type(); uint32_t source_id();
virtual int DispatchRequest(Client* client, virtual int Dispatch(Client* client, uint8_t type, uint32_t request_id,
const uint8_t* data, size_t length) = 0; const uint8_t* data, size_t length) = 0;
protected: protected:
Type type_; Debugger* debugger_;
uint32_t source_id_;
}; };

View File

@ -14,6 +14,7 @@
#include <xenia/core.h> #include <xenia/core.h>
#include <map> #include <map>
#include <vector>
namespace xe { namespace xe {
@ -30,20 +31,24 @@ public:
Debugger(xe_pal_ref pal); Debugger(xe_pal_ref pal);
virtual ~Debugger(); virtual ~Debugger();
void RegisterContentSource(std::string& name, ContentSource* content_source); void RegisterContentSource(ContentSource* content_source);
int Startup(); int Startup();
void Broadcast(uint32_t source_id, const uint8_t* data, size_t length);
private: private:
int DispatchRequest(Client* client, const char* source_name, void AddClient(Client* client);
const uint8_t* data, size_t length); void RemoveClient(Client* client);
int Dispatch(Client* client, const uint8_t* data, size_t length);
friend class Client; friend class Client;
private: private:
xe_pal_ref pal_; xe_pal_ref pal_;
auto_ptr<Listener> listener_; auto_ptr<Listener> listener_;
std::map<char*, ContentSource*> content_sources_; std::vector<Client*> clients_;
std::map<uint32_t, ContentSource*> content_sources_;
}; };

View File

@ -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_

View File

@ -9,15 +9,24 @@
#include <xenia/dbg/client.h> #include <xenia/dbg/client.h>
#include <xenia/dbg/debugger.h>
using namespace xe; using namespace xe;
using namespace xe::dbg; using namespace xe::dbg;
Client::Client() { Client::Client(Debugger* debugger) :
debugger_(debugger) {
debugger_->AddClient(this);
} }
Client::~Client() { 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) { void Client::Write(uint8_t* buffer, size_t length) {

View File

@ -14,14 +14,13 @@ using namespace xe;
using namespace xe::dbg; using namespace xe::dbg;
ContentSource::ContentSource(Type type) : ContentSource::ContentSource(Debugger* debugger, uint32_t source_id) :
type_(type) { debugger_(debugger), source_id_(source_id) {
} }
ContentSource::~ContentSource() { ContentSource::~ContentSource() {
} }
uint32_t ContentSource::source_id() {
ContentSource::Type ContentSource::type() { return source_id_;
return type_;
} }

View File

@ -30,13 +30,18 @@ Debugger::Debugger(xe_pal_ref pal) {
pal_ = xe_pal_retain(pal); pal_ = xe_pal_retain(pal);
listener_ = auto_ptr<Listener>(new WsListener( listener_ = auto_ptr<Listener>(new WsListener(
pal_, FLAGS_remote_debug_port)); this, pal_, FLAGS_remote_debug_port));
} }
Debugger::~Debugger() { Debugger::~Debugger() {
for (std::map<char*, ContentSource*>::iterator it = content_sources_.begin(); for (std::vector<Client*>::iterator it = clients_.begin();
it != content_sources_.end(); ++it) { it != clients_.end(); ++it) {
xe_free(it->first); delete *it;
}
clients_.clear();
for (std::map<uint32_t, ContentSource*>::iterator it =
content_sources_.begin(); it != content_sources_.end(); ++it) {
delete it->second; delete it->second;
} }
content_sources_.clear(); content_sources_.clear();
@ -44,10 +49,9 @@ Debugger::~Debugger() {
xe_pal_release(pal_); xe_pal_release(pal_);
} }
void Debugger::RegisterContentSource(std::string& name, void Debugger::RegisterContentSource(ContentSource* content_source) {
ContentSource* content_source) { content_sources_.insert(std::pair<uint32_t, ContentSource*>(
content_sources_.insert(std::pair<char*, ContentSource*>( content_source->source_id(), content_source));
xestrdupa(name.c_str()), content_source));
} }
int Debugger::Startup() { int Debugger::Startup() {
@ -69,12 +73,54 @@ int Debugger::Startup() {
return 0; return 0;
} }
int Debugger::DispatchRequest(Client* client, const char* source_name, void Debugger::Broadcast(uint32_t source_id,
const uint8_t* data, size_t length) { const uint8_t* data, size_t length) {
std::map<char*, ContentSource*>::iterator it = uint32_t header[] = {
content_sources_.find((char*)source_name); 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()) { if (it == content_sources_.end()) {
XELOGW(XT("Content source %d not found, ignoring message"), source_id);
return 1; return 1;
} }
return it->second->DispatchRequest(client, data, length); return it->second->Dispatch(client, type, request_id, data + 16, size);
} }

View File

@ -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;
}

View File

@ -14,7 +14,8 @@ using namespace xe;
using namespace xe::dbg; 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); pal_ = xe_pal_retain(pal);
} }

View File

@ -18,16 +18,20 @@ namespace xe {
namespace dbg { namespace dbg {
class Debugger;
class Listener { class Listener {
public: public:
Listener(xe_pal_ref pal); Listener(Debugger* debugger, xe_pal_ref pal);
virtual ~Listener(); virtual ~Listener();
virtual int Setup() = 0; virtual int Setup() = 0;
virtual int WaitForClient() = 0; virtual int WaitForClient() = 0;
protected: protected:
xe_pal_ref pal_; Debugger* debugger_;
xe_pal_ref pal_;
}; };

View File

@ -4,7 +4,6 @@
'client.cc', 'client.cc',
'content_source.cc', 'content_source.cc',
'debugger.cc', 'debugger.cc',
'indexed_content_source.cc',
'listener.cc', 'listener.cc',
'ws_client.cc', 'ws_client.cc',
'ws_listener.cc', 'ws_listener.cc',

View File

@ -9,6 +9,8 @@
#include "dbg/ws_client.h" #include "dbg/ws_client.h"
#include <xenia/dbg/debugger.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -26,8 +28,8 @@ using namespace xe;
using namespace xe::dbg; using namespace xe::dbg;
WsClient::WsClient(int socket_id) : WsClient::WsClient(Debugger* debugger, int socket_id) :
Client(), Client(debugger),
socket_id_(socket_id) { socket_id_(socket_id) {
mutex_ = xe_mutex_alloc(1000); mutex_ = xe_mutex_alloc(1000);
@ -65,9 +67,24 @@ int WsClient::Setup() {
setsockopt(socket_id_, IPPROTO_TCP, TCP_NODELAY, setsockopt(socket_id_, IPPROTO_TCP, TCP_NODELAY,
&opt_value, sizeof(opt_value)); &opt_value, sizeof(opt_value));
// launch thread/etc // TODO(benvanik): win32 support - put simple threads in PAL
EventThread(); 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; return 0;
} }
@ -126,27 +143,18 @@ void WsClientOnMsgCallback(wslay_event_context_ptr ctx,
return; return;
} }
WsClient* client = reinterpret_cast<WsClient*>(user_data);
switch (arg->opcode) { switch (arg->opcode) {
case WSLAY_TEXT_FRAME: case WSLAY_TEXT_FRAME:
// arg->msg, arg->msg_length XELOGW(XT("Text frame ignored; use binary messages"));
break; break;
case WSLAY_BINARY_FRAME: case WSLAY_BINARY_FRAME:
// arg->msg, arg->msg_length client->OnMessage(arg->msg, arg->msg_length);
break; break;
default: default:
// Unknown opcode - some frame stuff? // Unknown opcode - some frame stuff?
break; 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) { std::string EncodeBase64(const uint8_t* input, size_t length) {

View File

@ -27,7 +27,7 @@ namespace dbg {
class WsClient : public Client { class WsClient : public Client {
public: public:
WsClient(int socket_id); WsClient(Debugger* debugger, int socket_id);
virtual ~WsClient(); virtual ~WsClient();
int socket_id(); int socket_id();
@ -37,6 +37,8 @@ public:
virtual void Write(uint8_t** buffers, size_t* lengths, size_t count); virtual void Write(uint8_t** buffers, size_t* lengths, size_t count);
private: private:
static void* StartCallbackPthreads(void* param);
int PerformHandshake(); int PerformHandshake();
void EventThread(); void EventThread();

View File

@ -20,8 +20,8 @@ using namespace xe;
using namespace xe::dbg; using namespace xe::dbg;
WsListener::WsListener(xe_pal_ref pal, uint32_t port) : WsListener::WsListener(Debugger* debugger, xe_pal_ref pal, uint32_t port) :
Listener(pal), Listener(debugger, pal),
port_(port) { port_(port) {
} }
@ -85,7 +85,7 @@ int WsListener::WaitForClient() {
// Create the client object. // Create the client object.
// Note that the client will delete itself when done. // 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()) { if (client->Setup()) {
// Client failed to setup - abort. // Client failed to setup - abort.
return 1; return 1;

View File

@ -20,9 +20,12 @@ namespace xe {
namespace dbg { namespace dbg {
class Debugger;
class WsListener : public Listener { class WsListener : public Listener {
public: public:
WsListener(xe_pal_ref pal, uint32_t port); WsListener(Debugger* debugger, xe_pal_ref pal, uint32_t port);
virtual ~WsListener(); virtual ~WsListener();
virtual int Setup(); virtual int Setup();