polserver/pol-core/pol/dap/handles.cpp
Kevin Eady 686090d950
Introduce DAP Debugger (#608)
* Add cppdap debugger library and simple server (#508)

* Add cppdap library

* Add cppdap server

* fixup cmake scripts for windows

* Enable caching of cppdap on GitHub actions

* Fix CMake for cppdap target

* Wait 1s for session close before thread ends

* Address review comments
- Remove unnecessary use of wait_for
- Fix wait_for method

* Do not use SocketClientThread for cppdap clients

* Address review comments
- Cleanup object ownership

* Add authorization and event handling (#510)

* Add authorization and event handling [WIP]

* Use std::weak_ptr; Only allow one debugger conn

* Only attach debugger if dbg file exists

* Cleanup weak_ptr; Fix listeners; Add handler stubs

* Address review comments
- PolLock on uoexec and weakptr access
- Use make_shared when creating client thread

* Add ExecutorDebugListener on_destroy callback

* Use cppdap sockets instead of clib sockets

* Update cppdap repository to 2703cf4

* Implement server address binding

* Update cppdap repository to eeca5ce

* Fix warnings

* Use weak_from_this

* Fix stalled executors on disconnect

* Fix stalled executors on re-attach

* Clear uoexec weakptr on all debugger detaches

* Move server to gamestate

* move DapDebugServer into Network namespace

* move DapDebugServer into GameState for storage

* Move DapDebugServer into NetworkManager

* Fix missing memory include

* Add more events (#513)

* Add more events

* Implement dbg_step_out

* Fix breakpoint clearing

* Add even more events (#515)

* add launch request

* Add custom `processes` command

* fixup loop

* Refactoring to move handlers to member functions

* Add VariablesRequest and ScopesRequest

* use std::varaint for Handles

* add pollocks

* refactor Handles to new file

* move custom messages to proto.h

* move clientthread

* some formatting / cleanup

* Add missing PolLock

* move dap variables creation to Handles

* appobj members

* rename ClientThread to DebugClientThread

* rename LaunchRequest args to arg

* Fix compiler error on size_t

* Add support for EvaluateRequest and SetVariableRequest (#519)

* Update grammar for evaluateUnit

* Cleanup various compiler code

* Add support for EvaluateRequest
Only supports values, variables, element access, member access

* Add report clearing to reinitialize state

* Add support for SetVariableRequest

* Fix CI build errors

* Move ExpressionEvaluator to Bscript

* Fix formatting

* Fix include

* Refactor global and frame variable references

* Encapsulate Executor debugging environment; Fix step over (#524)

* Fix step over

* Some cleanup of executor
- Remove unused debug states
- Rename members for consistency

* move debugging environment to new class

* Move instruction inspection to class

* Cleanup slashes on Windows; Add Executor state to processes response (#527)

* Fix backspaces in script names on Windows

* Fix compilation warnings with data loss

* Use boost::icontains for string comparison

* Add Executor state to processes response

* Updates for libfmt

* Fix tests; Fix cppdap build for Mac universal binary (#607)

* fix tests

* fix cppdap build for mac universal binary

* Update cppdap to 2a4c7cf

* Add tests; Modify launch behavior to not stop at entry (redo) (#609)

* Remove unused setExceptionBreakpoints handler

* Add debugger tests

* Launching a script should not set attaching state

* Add launch tests

* Do not check for connection in debugger tests

* Rename `program` to `script` in protocol structs

* Fix launch stopAtEntry; quote string var values

* Fix compilation error on Windows

* Add configfiles doc entry

* Various fixes for finishing touches; Add core-changes (#610)

* switch cmake projects

* simple docs

* cmake move make_directory

* Fix launch request with relative, absolute, package paths

* make relative paths as absolute in source request

* Add true, false, uninit to ExpressionEvaluator

* Re-add setExceptionBreakpoints to avoid unhandled message errors

* Better debug thread logging with instance numbers

* launched scripts should terminate on disconnect (according to DAP spec)

* Properly handle exited event in client thread

* Add core-changes

* Address Discord comments
- Mention vscode-escript in core-changes
- Re-add "cppdap already built" in cmake

* change cmake escriptgrammarlib visibility to public
2024-01-28 09:49:55 +01:00

207 lines
5.5 KiB
C++

#include "handles.h"
#include "../../bscript/eprog.h"
#include "../uoexec.h"
namespace Pol
{
namespace Network
{
namespace DAP
{
using namespace Bscript;
Handles::Handles() : _nextHandle( START_HANDLE ) {}
void Handles::reset()
{
_nextHandle = START_HANDLE;
_handleMap.clear();
}
int Handles::create( const Reference& value )
{
int handle = _nextHandle++;
_handleMap.insert( { handle, value } );
return handle;
}
Reference* Handles::get( int handle )
{
auto iter = _handleMap.find( handle );
if ( iter != _handleMap.end() )
{
return &iter->second;
}
return nullptr;
}
BObjectRef Handles::set_index_or_member( const BObjectRef& objref, const std::string& key,
BObjectRef& value )
{
auto impptr = objref->impptr();
if ( impptr != nullptr )
{
if ( impptr->isa( BObjectImp::OTStruct ) )
{
BStruct* bstruct = static_cast<BStruct*>( impptr );
bstruct->addMember( key.c_str(), value );
return value;
}
else if ( impptr->isa( BObjectImp::OTDictionary ) )
{
BDictionary* dict = static_cast<BDictionary*>( impptr );
dict->addMember( key.c_str(), value );
return value;
}
else if ( impptr->isa( BObjectImp::OTArray ) )
{
ObjArray* objarr = static_cast<ObjArray*>( impptr );
auto index = strtoul( key.c_str(), nullptr, 0 );
objarr->ref_arr.at( index ) = value;
return value;
}
else if ( impptr->isa( BObjectImp::OTApplicObj ) )
{
impptr->set_member( key.c_str(), value->impptr(), true );
return impptr->get_member( key.c_str() );
}
}
return BObjectRef( UninitObject::create() );
}
dap::array<dap::Variable> Handles::to_variables( const BObjectRef& objref )
{
dap::array<dap::Variable> variables;
auto impptr = objref->impptr();
if ( impptr != nullptr )
{
if ( impptr->isa( BObjectImp::OTStruct ) )
{
BStruct* bstruct = static_cast<BStruct*>( impptr );
for ( const auto& content : bstruct->contents() )
{
dap::Variable current_var;
current_var.name = content.first;
set_response_details( content.second, current_var );
variables.push_back( current_var );
}
}
else if ( impptr->isa( BObjectImp::OTDictionary ) )
{
BDictionary* dict = static_cast<BDictionary*>( impptr );
for ( const auto& content : dict->contents() )
{
dap::Variable current_var;
current_var.name = content.first->getStringRep();
set_response_details( content.second, current_var );
variables.push_back( current_var );
}
}
else if ( impptr->isa( BObjectImp::OTArray ) )
{
ObjArray* objarr = static_cast<ObjArray*>( impptr );
size_t index = 1;
for ( const auto& content : objarr->ref_arr )
{
dap::Variable current_var;
current_var.name = Clib::tostring( index++ );
set_response_details( content, current_var );
variables.push_back( current_var );
}
}
else if ( impptr->isa( BObjectImp::OTApplicObj ) )
{
for ( int i = 0; i < Bscript::n_objmembers; ++i )
{
const auto& object_member = Bscript::object_members[i];
auto member_value = impptr->get_member_id( object_member.id );
if ( !member_value->isa( BObjectImp::BObjectType::OTUninit ) )
{
dap::Variable variable;
variable.name = object_member.code;
set_response_details( member_value, variable );
variables.push_back( variable );
}
}
std::sort( variables.begin(), variables.end(),
[]( const auto& a, const auto& b ) { return a.name < b.name; } );
}
}
return variables;
}
FrameReference::FrameReference( Core::UOExecutor* uoexec, Bscript::EScriptProgram* _script,
size_t frameId )
: contents()
{
if ( frameId > uoexec->ControlStack.size() )
{
throw std::runtime_error( "Invalid frame id" );
}
std::vector<BObjectRefVec*> upperLocals2 = uoexec->upperLocals2;
std::vector<ReturnContext> stack = uoexec->ControlStack;
unsigned int PC;
{
ReturnContext rc;
rc.PC = uoexec->PC;
rc.ValueStackDepth = static_cast<unsigned int>( uoexec->ValueStack.size() );
stack.push_back( rc );
}
upperLocals2.push_back( uoexec->Locals2 );
auto currentFrameId = stack.size();
while ( --currentFrameId, !stack.empty() )
{
ReturnContext& rc = stack.back();
BObjectRefVec* Locals2 = upperLocals2.back();
PC = rc.PC;
stack.pop_back();
upperLocals2.pop_back();
if ( frameId != currentFrameId )
{
continue;
}
size_t left = Locals2->size();
unsigned block = _script->dbg_ins_blocks[PC];
while ( left )
{
while ( left <= _script->blocks[block].parentvariables )
{
block = _script->blocks[block].parentblockidx;
}
const EPDbgBlock& progblock = _script->blocks[block];
size_t varidx = left - 1 - progblock.parentvariables;
left--;
contents[progblock.localvarnames[varidx]] = &( *Locals2 )[left];
}
}
}
GlobalReference::GlobalReference( Core::UOExecutor* uoexec, Bscript::EScriptProgram* _script )
: contents()
{
BObjectRefVec::iterator itr = uoexec->Globals2.begin(), end = uoexec->Globals2.end();
for ( unsigned idx = 0; itr != end; ++itr, ++idx )
{
if ( _script->globalvarnames.size() > idx )
{
contents[_script->globalvarnames[idx]] = &( *itr );
}
}
}
} // namespace DAP
} // namespace Network
} // namespace Pol