Skip to content

Commit

Permalink
More WIP.
Browse files Browse the repository at this point in the history
  • Loading branch information
SpartanJ committed Dec 16, 2024
1 parent d2dabdf commit 75490bf
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 17 deletions.
168 changes: 161 additions & 7 deletions src/tools/ecode/plugins/debugger/dap/debuggerclientdap.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
#include "debuggerclientdap.hpp"
#include "messages.hpp"
#include <eepp/core/string.hpp>
#include <eepp/system/log.hpp>

namespace ecode {
using namespace EE::System;

namespace ecode::dap {

constexpr int MAX_HEADER_SIZE = 1 << 16;

DebuggerClientDap::DebuggerClientDap( std::unique_ptr<Bus>&& bus ) : mBus( std::move( bus ) ) {}

void DebuggerClientDap::makeRequest( const std::string& command, const nlohmann::json& arguments,
std::function<void()> onFinish ) {
nlohmann::json json_cmd = {
{ "seq", mIdx.load() },
{ "type", "request" },
{ "command", command },
{ "arguments", arguments.empty() ? nlohmann::json::object() : arguments } };

std::string cmd = json_cmd.dump();

Log::instance()->writel( mDebug ? LogLevel::Info : LogLevel::Debug, cmd );

std::string msg( String::format( "Content-Length: %zu\r\n\r\n%s", cmd.size(), cmd ) );
mBus->write( msg.data(), msg.size() );

if ( onFinish )
mCommandQueue[mIdx] = onFinish;

mIdx.fetch_add( 1, std::memory_order_relaxed );
}

bool DebuggerClientDap::hasBreakpoint( const std::string& path, size_t line ) {
return false;
}
Expand All @@ -17,30 +45,156 @@ bool DebuggerClientDap::removeBreakpoint( const std::string& path, size_t line )
}

bool DebuggerClientDap::start() {
return mBus->start();
bool started = mBus->start();
if ( started )
mBus->startAsyncRead( [this]( const char* bytes, size_t n ) { asyncRead( bytes, n ); } );
mStarted = started;
return started;
}

void DebuggerClientDap::asyncRead( const char* bytes, size_t n ) {
std::string_view read( bytes, n );
mBuffer += read;

while ( true ) {
const auto info = readHeader();
if ( !info )
break;
const auto data = mBuffer.substr( info->payloadStart, info->payloadLength );
if ( data.size() < info->payloadLength )
break;
mBuffer.erase( 0, info->payloadStart + info->payloadLength );

#ifndef EE_DEBUG
try {
#endif
auto message = json::parse( data );

if ( mDebug )
Log::debug( message.dump() );

processProtocolMessage( message );
#ifndef EE_DEBUG
} catch ( const json::exception& e ) {
Log::error( "DebuggerClientDap::asyncRead: JSON bad format: %s", e.what() );
}
#endif
}
}

void DebuggerClientDap::processProtocolMessage( const nlohmann::json& msg ) {
const auto type = msg.value( DAP_TYPE, "" );

if ( DAP_RESPONSE == type ) {
processResponse( msg );
} else if ( DAP_EVENT == type ) {
processEvent( msg );
} else {
Log::warning( "DebuggerClientDap::processProtocolMessage: unknown, empty or unexpected "
"ProtocolMessage::%s (%s)",
DAP_TYPE, type );
}
}

void DebuggerClientDap::processResponse( const nlohmann::json& msg ) {}

void DebuggerClientDap::processEvent( const nlohmann::json& msg ) {}

std::optional<DebuggerClientDap::HeaderInfo> DebuggerClientDap::readHeader() {
Uint64 length = std::string::npos;
Uint64 start = 0;
Uint64 end = std::string::npos;

auto discardExploredBuffer = [this, length, start, end]() mutable {
mBuffer.erase( 0, end );
length = end = std::string::npos;
start = 0;
};

while ( true ) {
end = mBuffer.find( DAP_SEP, start );
if ( end == std::string::npos ) {
if ( mBuffer.size() > MAX_HEADER_SIZE )
mBuffer.clear();
length = std::string::npos;
break; // PENDING
}

const auto header = mBuffer.substr( start, end - start );
end += DAP_SEP_SIZE;

// header block separator
if ( header.size() == 0 ) {
if ( length < 0 ) {
// unexpected end of header
Log::error( "DebuggerClientDap::readHeader unexpected end of header block" );
discardExploredBuffer();
continue;
}
break; // END HEADER (length>0, end>0)
}

// parse field
const auto sep = header.find_first_of( ":" );
if ( sep == std::string::npos ) {
Log::error( "DebuggerClientDap::readHeader cannot parse header field: ", header );
discardExploredBuffer();
continue; // CONTINUE HEADER
}

// parse content-length
if ( String::startsWith( header, DAP_CONTENT_LENGTH ) ) {
std::string lengthStr( header.substr( sep + 1, header.size() - sep ) );
Uint64 length;
if ( !String::fromString( length, lengthStr ) ) {
Log::error( "DebuggerClientDap::readHeader invalid value: ", header );
discardExploredBuffer();
continue; // CONTINUE HEADER
}
}

start = end;
}

if ( length < 0 )
return std::nullopt;

return HeaderInfo{ .payloadStart = end, .payloadLength = length };
}

bool DebuggerClientDap::attach() {
return false;
}

bool DebuggerClientDap::started() const {
return mStarted;
}

bool DebuggerClientDap::cont( int threadId ) {
return false;
}

bool DebuggerClientDap::pause( int threadId ) {
return false;
}

bool DebuggerClientDap::next( int threadId ) {
return false;
}

bool DebuggerClientDap::cont() {
bool DebuggerClientDap::goTo( int threadId, int targetId ) {
return false;
}

bool DebuggerClientDap::stepInto() {
bool DebuggerClientDap::stepInto( int threadId ) {
return false;
}

bool DebuggerClientDap::stepOver() {
bool DebuggerClientDap::stepOver( int threadId ) {
return false;
}

bool DebuggerClientDap::stepOut() {
bool DebuggerClientDap::stepOut( int threadId ) {
return false;
}

Expand All @@ -60,4 +214,4 @@ bool DebuggerClientDap::completed() {
return false;
}

} // namespace ecode
} // namespace ecode::dap
46 changes: 40 additions & 6 deletions src/tools/ecode/plugins/debugger/dap/debuggerclientdap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

#include "../bus.hpp"
#include "../debuggerclient.hpp"
#include <atomic>
#include <eepp/config.hpp>

namespace ecode {
using namespace EE;

namespace ecode::dap {

class DebuggerClientDap : public DebuggerClient {
public:
Expand All @@ -21,13 +25,19 @@ class DebuggerClientDap : public DebuggerClient {

bool started() const;

bool cont();
bool cont( int threadId );

bool pause( int threadId ) = 0;

bool next( int threadId ) = 0;

bool stepInto();
bool goTo( int threadId, int targetId ) = 0;

bool stepOver();
bool stepInto( int threadId );

bool stepOut();
bool stepOver( int threadId );

bool stepOut( int threadId );

bool halt();

Expand All @@ -39,6 +49,30 @@ class DebuggerClientDap : public DebuggerClient {

protected:
std::unique_ptr<Bus> mBus;
UnorderedMap<std::string, UnorderedSet<int>> mBreakpoints;
std::atomic<Uint64> mIdx{ 1 };
Uint64 mThreadId{ 1 };
bool mDebug{ true };
bool mStarted{ false };
UnorderedMap<Uint64, std::function<void()>> mCommandQueue;
std::string mBuffer;

void makeRequest( const std::string& command, const nlohmann::json& arguments,
std::function<void()> onFinish = nullptr );

void asyncRead( const char* bytes, size_t n );

void processProtocolMessage( const nlohmann::json& msg );

void processResponse( const nlohmann::json& msg );

void processEvent( const nlohmann::json& msg );

struct HeaderInfo {
Uint64 payloadStart;
Uint64 payloadLength;
};
std::optional<HeaderInfo> readHeader();
};

} // namespace ecode
} // namespace ecode::dap
14 changes: 10 additions & 4 deletions src/tools/ecode/plugins/debugger/debuggerclient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ class DebuggerClient {

virtual bool started() const = 0;

virtual bool cont() = 0;
virtual bool cont( int threadId ) = 0;

virtual bool stepInto() = 0;
virtual bool pause( int threadId ) = 0;

virtual bool stepOver() = 0;
virtual bool next( int threadId ) = 0;

virtual bool stepOut() = 0;
virtual bool goTo( int threadId, int targetId ) = 0;

virtual bool stepInto( int threadId ) = 0;

virtual bool stepOver( int threadId ) = 0;

virtual bool stepOut( int threadId ) = 0;

virtual bool halt() = 0;

Expand Down

0 comments on commit 75490bf

Please sign in to comment.