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 {
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_;
};

View File

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

View File

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

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/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) {

View File

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

View File

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

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;
Listener::Listener(xe_pal_ref pal) {
Listener::Listener(Debugger* debugger, xe_pal_ref pal) :
debugger_(debugger) {
pal_ = xe_pal_retain(pal);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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