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 {
|
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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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/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) {
|
||||||
|
|
|
@ -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_;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue