#pragma once #include #include #include #include "TargetDescriptor.hpp" #include "GdbDebugServerConfig.hpp" #include "Connection.hpp" #include "Feature.hpp" #include "ProgrammingSession.hpp" #include "RangeSteppingSession.hpp" #include "src/Targets/TargetMemory.hpp" #include "src/Targets/TargetBreakpoint.hpp" #include "src/Services/TargetControllerService.hpp" namespace DebugServer::Gdb { class DebugSession { public: /** * The connection serving this debug session. */ Connection connection; /** * A set of all GDB features supported for this debug session, along with any optional values (some GDB * features can be specified with a value, such as Feature::PACKET_SIZE). */ std::set>> supportedFeatures; /** * The current server configuration. * * TODO: I think this should be moved out of the DebugSession struct and passed into CommandPacket::handle() * function. Review after v1.1.0. */ const GdbDebugServerConfig& serverConfig; /** * During a debug session, we can set two types of breakpoints: internal and external. * * - Internal breakpoints are set by Bloom's GDB server, for reasons that are specific to Bloom's internals. * For example, we use internal breakpoints to facilitate range stepping sessions, where we place * intercepting breakpoints in places where we suspect the target will leave the stepping range. * * - External breakpoints are requested by the connected client (GDB), typically on behalf of the user. * Sometimes GDB will set some internal breakpoints of its own, but from our perspective these are considered * to be external breakpoints. * * We track internal and external breakpoints separately. */ std::map internalBreakpointsByAddress; std::map externalBreakpointsByAddress; /** * When the GDB client is waiting for the target to halt, this is set to true so we know when to notify the * client. */ bool waitingForBreak = false; bool pendingInterrupt = false; /** * When the user attempts to program the target via GDB's 'load' command, GDB will send a number of * FlashWrite (vFlashWrite) packets to Bloom. We group the data in these packets and flush it all at once, upon * receiving a FlashDone (vFlashDone) packet. * * The grouped data is held in a ProgrammingSession object, against the active debug session. Once the data has * been flushed, the ProgrammingSession object is destroyed. * * See the ProgrammingSession struct and GDB RSP documentation for more. * * This member holds the current (if any) ProgrammingSession object. It should only be populated during * programming. */ std::optional programmingSession = std::nullopt; /** * When we're range stepping, we maintain a range stepping session, which holds all info related to that * particular range stepping session. * * This member should only be populated during a range stepping session. */ std::optional activeRangeSteppingSession = std::nullopt; DebugSession( Connection&& connection, const std::set>>& supportedFeatures, const GdbDebugServerConfig& serverConfig ); DebugSession(const DebugSession& other) = delete; DebugSession(DebugSession&& other) = delete; DebugSession& operator = (const DebugSession& other) = delete; DebugSession& operator = (DebugSession&& other) = delete; virtual ~DebugSession(); virtual void setInternalBreakpoint( Targets::TargetMemoryAddress address, Services::TargetControllerService& targetControllerService ); virtual void removeInternalBreakpoint( Targets::TargetMemoryAddress address, Services::TargetControllerService& targetControllerService ); virtual void setExternalBreakpoint( Targets::TargetMemoryAddress address, Services::TargetControllerService& targetControllerService ); virtual void removeExternalBreakpoint( Targets::TargetMemoryAddress address, Services::TargetControllerService& targetControllerService ); virtual void startRangeSteppingSession( RangeSteppingSession&& session, Services::TargetControllerService& targetControllerService ); virtual void terminateRangeSteppingSession( Services::TargetControllerService& targetControllerService ); }; }