#ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_RNBREMOTE_H
#define LLDB_TOOLS_DEBUGSERVER_SOURCE_RNBREMOTE_H
#include "DNB.h"
#include "PThreadMutex.h"
#include "RNBContext.h"
#include "RNBDefs.h"
#include "RNBSocket.h"
#include <deque>
#include <map>
#include <string>
#include <vector>
class RNBSocket;
class RNBContext;
class PThreadEvents;
enum event_loop_mode { debug_nub, gdb_remote_protocol, done };
enum class compression_types { zlib_deflate, lz4, lzma, lzfse, none };
class RNBRemote {
public:
enum PacketEnum {
invalid_packet = 0,
ack,
nack,
halt,
use_extended_mode,
why_halted,
set_argv,
set_bp,
cont,
continue_with_sig,
detach,
read_general_regs,
write_general_regs,
set_thread,
step_inferior_one_cycle,
signal_and_step_inf_one_cycle,
kill,
read_memory,
write_memory,
read_register,
write_register,
restart,
single_step,
single_step_with_sig,
search_mem_backwards,
thread_alive_p,
vattach,
vattachwait,
vattachorwait,
vattachname,
vcont,
vcont_list_actions,
read_data_from_memory,
write_data_to_memory,
insert_mem_bp,
remove_mem_bp,
insert_hardware_bp,
remove_hardware_bp,
insert_write_watch_bp,
remove_write_watch_bp,
insert_read_watch_bp,
remove_read_watch_bp,
insert_access_watch_bp,
remove_access_watch_bp,
query_monitor,
query_current_thread_id,
query_get_pid,
query_echo,
query_thread_ids_first,
query_thread_ids_subsequent,
query_thread_extra_info,
query_thread_stop_info,
query_image_offsets,
query_symbol_lookup,
query_launch_success,
query_register_info,
query_shlib_notify_info_addr,
query_step_packet_supported,
query_supported_features,
query_vattachorwait_supported,
query_sync_thread_state_supported,
query_host_info,
query_gdb_server_version,
query_process_info,
json_query_thread_extended_info,
json_query_get_loaded_dynamic_libraries_infos,
json_query_threads_info,
json_query_get_shared_cache_info,
pass_signals_to_inferior,
start_noack_mode,
prefix_reg_packets_with_tid,
set_logging_mode,
set_ignored_exceptions,
set_max_packet_size,
set_max_payload_size,
set_environment_variable,
set_environment_variable_hex,
set_launch_arch,
set_disable_aslr,
set_stdin,
set_stdout,
set_stderr,
set_working_dir,
set_list_threads_in_stop_reply,
sync_thread_state,
memory_region_info,
get_profile_data,
set_enable_profiling,
enable_compression,
watchpoint_support_info,
allocate_memory,
deallocate_memory,
set_process_event,
save_register_state,
restore_register_state,
speed_test,
set_detach_on_error,
query_transfer,
json_query_dyld_process_state,
enable_error_strings,
unknown_type
};
typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p);
RNBRemote();
~RNBRemote();
void Initialize();
bool InitializeRegisters(bool force = false);
rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL);
rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL);
nub_thread_t GetContinueThread() const { return m_continue_thread; }
void SetContinueThread(nub_thread_t tid) { m_continue_thread = tid; }
nub_thread_t GetCurrentThread() const {
if (m_thread == 0 || m_thread == (nub_thread_t)-1)
return DNBProcessGetCurrentThread(m_ctx.ProcessID());
return m_thread;
}
void SetCurrentThread(nub_thread_t tid) {
DNBProcessSetCurrentThread(m_ctx.ProcessID(), tid);
m_thread = tid;
}
static void *ThreadFunctionReadRemoteData(void *arg);
void StartReadRemoteDataThread();
void StopReadRemoteDataThread();
void NotifyThatProcessStopped(void);
rnb_err_t HandlePacket_A(const char *p);
rnb_err_t HandlePacket_H(const char *p);
rnb_err_t HandlePacket_qC(const char *p);
rnb_err_t HandlePacket_qRcmd(const char *p);
rnb_err_t HandlePacket_qGetPid(const char *p);
rnb_err_t HandlePacket_qEcho(const char *p);
rnb_err_t HandlePacket_qLaunchSuccess(const char *p);
rnb_err_t HandlePacket_qRegisterInfo(const char *p);
rnb_err_t HandlePacket_qShlibInfoAddr(const char *p);
rnb_err_t HandlePacket_qStepPacketSupported(const char *p);
rnb_err_t HandlePacket_qVAttachOrWaitSupported(const char *p);
rnb_err_t HandlePacket_qSyncThreadStateSupported(const char *p);
rnb_err_t HandlePacket_qThreadInfo(const char *p);
rnb_err_t HandlePacket_jThreadExtendedInfo(const char *p);
rnb_err_t HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p);
rnb_err_t HandlePacket_jThreadsInfo(const char *p);
rnb_err_t HandlePacket_jGetSharedCacheInfo(const char *p);
rnb_err_t HandlePacket_qThreadExtraInfo(const char *p);
rnb_err_t HandlePacket_qThreadStopInfo(const char *p);
rnb_err_t HandlePacket_qHostInfo(const char *p);
rnb_err_t HandlePacket_qGDBServerVersion(const char *p);
rnb_err_t HandlePacket_qProcessInfo(const char *p);
rnb_err_t HandlePacket_qSymbol(const char *p);
rnb_err_t HandlePacket_QEnableErrorStrings(const char *p);
rnb_err_t HandlePacket_QStartNoAckMode(const char *p);
rnb_err_t HandlePacket_QThreadSuffixSupported(const char *p);
rnb_err_t HandlePacket_QSetLogging(const char *p);
rnb_err_t HandlePacket_QSetIgnoredExceptions(const char *p);
rnb_err_t HandlePacket_QSetDisableASLR(const char *p);
rnb_err_t HandlePacket_QSetSTDIO(const char *p);
rnb_err_t HandlePacket_QSetWorkingDir(const char *p);
rnb_err_t HandlePacket_QSetMaxPayloadSize(const char *p);
rnb_err_t HandlePacket_QSetMaxPacketSize(const char *p);
rnb_err_t HandlePacket_QEnvironment(const char *p);
rnb_err_t HandlePacket_QEnvironmentHexEncoded(const char *p);
rnb_err_t HandlePacket_QLaunchArch(const char *p);
rnb_err_t HandlePacket_QListThreadsInStopReply(const char *p);
rnb_err_t HandlePacket_QSyncThreadState(const char *p);
rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID(const char *p);
rnb_err_t HandlePacket_QSetProcessEvent(const char *p);
rnb_err_t HandlePacket_last_signal(const char *p);
rnb_err_t HandlePacket_m(const char *p);
rnb_err_t HandlePacket_M(const char *p);
rnb_err_t HandlePacket_x(const char *p);
rnb_err_t HandlePacket_X(const char *p);
rnb_err_t HandlePacket_g(const char *p);
rnb_err_t HandlePacket_G(const char *p);
rnb_err_t HandlePacket_z(const char *p);
rnb_err_t HandlePacket_T(const char *p);
rnb_err_t HandlePacket_p(const char *p);
rnb_err_t HandlePacket_P(const char *p);
rnb_err_t HandlePacket_c(const char *p);
rnb_err_t HandlePacket_C(const char *p);
rnb_err_t HandlePacket_D(const char *p);
rnb_err_t HandlePacket_k(const char *p);
rnb_err_t HandlePacket_s(const char *p);
rnb_err_t HandlePacket_S(const char *p);
rnb_err_t HandlePacket_qSupported(const char *p);
rnb_err_t HandlePacket_v(const char *p);
rnb_err_t HandlePacket_UNIMPLEMENTED(const char *p);
rnb_err_t HandlePacket_ILLFORMED(const char *file, int line, const char *p,
const char *description);
rnb_err_t HandlePacket_AllocateMemory(const char *p);
rnb_err_t HandlePacket_DeallocateMemory(const char *p);
rnb_err_t HandlePacket_SaveRegisterState(const char *p);
rnb_err_t HandlePacket_RestoreRegisterState(const char *p);
rnb_err_t HandlePacket_MemoryRegionInfo(const char *p);
rnb_err_t HandlePacket_GetProfileData(const char *p);
rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p);
rnb_err_t HandlePacket_QEnableCompression(const char *p);
rnb_err_t HandlePacket_WatchpointSupportInfo(const char *p);
rnb_err_t HandlePacket_qSpeedTest(const char *p);
rnb_err_t HandlePacket_qXfer(const char *p);
rnb_err_t HandlePacket_stop_process(const char *p);
rnb_err_t HandlePacket_QSetDetachOnError(const char *p);
rnb_err_t HandlePacket_jGetDyldProcessState(const char *p);
rnb_err_t SendStopReplyPacketForThread(nub_thread_t tid);
rnb_err_t SendHexEncodedBytePacket(const char *header, const void *buf,
size_t buf_len, const char *footer);
rnb_err_t SendSTDOUTPacket(char *buf, nub_size_t buf_size);
rnb_err_t SendSTDERRPacket(char *buf, nub_size_t buf_size);
void FlushSTDIO();
void SendAsyncProfileData();
rnb_err_t SendAsyncProfileDataPacket(char *buf, nub_size_t buf_size);
rnb_err_t SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary);
RNBContext &Context() { return m_ctx; }
RNBSocket &Comm() { return m_comm; }
private:
RNBRemote(const RNBRemote &) = delete;
protected:
rnb_err_t GetCommData();
void CommDataReceived(const std::string &data);
struct Packet {
typedef std::vector<Packet> collection;
typedef collection::iterator iterator;
typedef collection::const_iterator const_iterator;
PacketEnum type;
HandlePacketCallback normal;
HandlePacketCallback async;
std::string abbrev;
std::string printable_name;
bool IsPlatformPacket() const {
switch (type) {
case set_logging_mode:
case query_host_info:
return true;
default:
break;
}
return false;
}
Packet()
: type(invalid_packet), normal(NULL), async(NULL), abbrev(),
printable_name() {}
Packet(PacketEnum in_type, HandlePacketCallback in_normal,
HandlePacketCallback in_async, const char *in_abbrev,
const char *in_printable_name)
: type(in_type), normal(in_normal), async(in_async), abbrev(in_abbrev),
printable_name(in_printable_name) {}
};
struct DispatchQueueOffsets {
uint16_t dqo_version;
uint16_t dqo_label;
uint16_t dqo_label_size;
uint16_t dqo_flags;
uint16_t dqo_flags_size;
uint16_t dqo_serialnum;
uint16_t dqo_serialnum_size;
uint16_t dqo_width;
uint16_t dqo_width_size;
uint16_t dqo_running;
uint16_t dqo_running_size;
uint16_t dqo_suspend_cnt;
uint16_t dqo_suspend_cnt_size;
uint16_t dqo_target_queue;
uint16_t dqo_target_queue_size;
uint16_t
dqo_priority;
uint16_t dqo_priority_size;
DispatchQueueOffsets() { Clear(); }
void Clear() {
dqo_version = UINT16_MAX;
dqo_label = UINT16_MAX;
dqo_label_size = UINT16_MAX;
dqo_flags = UINT16_MAX;
dqo_flags_size = UINT16_MAX;
dqo_serialnum = UINT16_MAX;
dqo_serialnum_size = UINT16_MAX;
dqo_width = UINT16_MAX;
dqo_width_size = UINT16_MAX;
dqo_running = UINT16_MAX;
dqo_running_size = UINT16_MAX;
dqo_suspend_cnt = UINT16_MAX;
dqo_suspend_cnt_size = UINT16_MAX;
dqo_target_queue = UINT16_MAX;
dqo_target_queue_size = UINT16_MAX;
dqo_priority = UINT16_MAX;
dqo_priority_size = UINT16_MAX;
}
bool IsValid() const { return dqo_version != UINT16_MAX; }
void GetThreadQueueInfo(nub_process_t pid, nub_addr_t dispatch_qaddr,
nub_addr_t &dispatch_queue_t,
std::string &queue_name, uint64_t &queue_width,
uint64_t &queue_serialnum) const;
};
rnb_err_t GetPacket(std::string &packet_data, RNBRemote::Packet &packet_info,
bool wait);
rnb_err_t SendPacket(const std::string &);
rnb_err_t SendErrorPacket(std::string errcode,
const std::string &errmsg = "");
std::string CompressString(const std::string &);
void CreatePacketTable();
rnb_err_t GetPacketPayload(std::string &);
nub_thread_t ExtractThreadIDFromThreadSuffix(const char *p);
void EnableCompressionNextSendPacket(compression_types);
compression_types GetCompressionType();
const DispatchQueueOffsets *GetDispatchQueueOffsets();
JSONGenerator::ObjectSP
GetJSONThreadsInfo(bool threads_with_valid_stop_info_only);
RNBContext m_ctx;
RNBSocket m_comm;
std::string m_arch;
nub_thread_t m_continue_thread;
nub_thread_t m_thread;
PThreadMutex m_mutex;
DispatchQueueOffsets m_dispatch_queue_offsets;
nub_addr_t m_dispatch_queue_offsets_addr;
uint32_t m_qSymbol_index;
uint32_t m_packets_recvd;
Packet::collection m_packets;
std::deque<std::string> m_rx_packets;
std::string m_rx_partial_data;
pthread_t m_rx_pthread;
uint32_t
m_max_payload_size;
bool m_extended_mode;
bool m_noack_mode;
bool m_thread_suffix_supported;
bool m_list_threads_in_stop_reply;
size_t m_compression_minsize;
bool m_enable_compression_next_send_packet;
compression_types m_compression_mode;
bool m_enable_error_strings;
};
(e.g. EXC_BAD_ACCESS) to the fake BSD signal numbers that gdb uses
in include/gdb/signals.h (e.g. TARGET_EXC_BAD_ACCESS). These hard
coded values for TARGET_EXC_BAD_ACCESS et al must match the gdb
values in its include/gdb/signals.h. */
#define TARGET_EXC_BAD_ACCESS 0x91
#define TARGET_EXC_BAD_INSTRUCTION 0x92
#define TARGET_EXC_ARITHMETIC 0x93
#define TARGET_EXC_EMULATION 0x94
#define TARGET_EXC_SOFTWARE 0x95
#define TARGET_EXC_BREAKPOINT 0x96
at a time with a random gdb. This bufsize constant is only specifying
how many bytes gdb can *receive* from debugserver -- it tells us nothing
about how many bytes gdb might try to send in a single packet. */
#define DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE 399
#endif