| //===-- RNBRemote.h ---------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Created by Greg Clayton on 12/12/07. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef __RNBRemote_h__ |
| #define __RNBRemote_h__ |
| |
| #include "RNBDefs.h" |
| #include "DNB.h" |
| #include "RNBContext.h" |
| #include "RNBSocket.h" |
| #include "PThreadMutex.h" |
| #include <string> |
| #include <vector> |
| #include <deque> |
| #include <map> |
| |
| class RNBSocket; |
| class RNBContext; |
| class PThreadEvents; |
| |
| enum event_loop_mode { debug_nub, gdb_remote_protocol, done }; |
| |
| class RNBRemote |
| { |
| public: |
| |
| typedef enum { |
| invalid_packet = 0, |
| ack, // '+' |
| nack, // '-' |
| halt, // ^C (async halt) |
| use_extended_mode, // '!' |
| why_halted, // '?' |
| set_argv, // 'A' |
| set_bp, // 'B' |
| cont, // 'c' |
| continue_with_sig, // 'C' |
| detach, // 'D' |
| read_general_regs, // 'g' |
| write_general_regs, // 'G' |
| set_thread, // 'H' |
| step_inferior_one_cycle, // 'i' |
| signal_and_step_inf_one_cycle, // 'I' |
| kill, // 'k' |
| read_memory, // 'm' |
| write_memory, // 'M' |
| read_register, // 'p' |
| write_register, // 'P' |
| restart, // 'R' |
| single_step, // 's' |
| single_step_with_sig, // 'S' |
| search_mem_backwards, // 't' |
| thread_alive_p, // 'T' |
| vattach, // 'vAttach;pid' |
| vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes |
| vattachorwait, // 'vAttachOrWait:XX...' where XX is one or more hex encoded process name ASCII bytes |
| vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes |
| vcont, // 'vCont' |
| vcont_list_actions, // 'vCont?' |
| write_data_to_memory, // 'X' |
| insert_mem_bp, // 'Z0' |
| remove_mem_bp, // 'z0' |
| insert_hardware_bp, // 'Z1' |
| remove_hardware_bp, // 'z1' |
| insert_write_watch_bp, // 'Z2' |
| remove_write_watch_bp, // 'z2' |
| insert_read_watch_bp, // 'Z3' |
| remove_read_watch_bp, // 'z3' |
| insert_access_watch_bp, // 'Z4' |
| remove_access_watch_bp, // 'z4' |
| |
| query_current_thread_id, // 'qC' |
| query_get_pid, // 'qGetPid' |
| query_memory_crc, // 'qCRC:' |
| query_thread_ids_first, // 'qfThreadInfo' |
| query_thread_ids_subsequent, // 'qsThreadInfo' |
| query_thread_extra_info, // 'qThreadExtraInfo' |
| query_thread_stop_info, // 'qThreadStopInfo' |
| query_image_offsets, // 'qOffsets' |
| query_symbol_lookup, // 'gSymbols' |
| query_launch_success, // 'qLaunchSuccess' |
| query_register_info, // 'qRegisterInfo' |
| query_shlib_notify_info_addr, // 'qShlibInfoAddr' |
| query_step_packet_supported, // 'qStepPacketSupported' |
| query_vattachorwait_supported, // 'qVAttachOrWaitSupported' |
| query_sync_thread_state_supported,// 'QSyncThreadState' |
| query_host_info, // 'qHostInfo' |
| query_process_info, // 'qProcessInfo' |
| pass_signals_to_inferior, // 'QPassSignals' |
| start_noack_mode, // 'QStartNoAckMode' |
| prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID |
| set_logging_mode, // 'QSetLogging:' |
| set_max_packet_size, // 'QSetMaxPacketSize:' |
| set_max_payload_size, // 'QSetMaxPayloadSize:' |
| set_environment_variable, // 'QEnvironment:' |
| set_environment_variable_hex, // 'QEnvironmentHexEncoded:' |
| set_launch_arch, // 'QLaunchArch:' |
| set_disable_aslr, // 'QSetDisableASLR:' |
| set_stdin, // 'QSetSTDIN:' |
| set_stdout, // 'QSetSTDOUT:' |
| set_stderr, // 'QSetSTDERR:' |
| set_working_dir, // 'QSetWorkingDir:' |
| set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:' |
| sync_thread_state, // 'QSyncThreadState:' |
| memory_region_info, // 'qMemoryRegionInfo:' |
| get_profile_data, // 'qGetProfileData' |
| set_enable_profiling, // 'QSetAsyncEnableProfiling' |
| watchpoint_support_info, // 'qWatchpointSupportInfo:' |
| allocate_memory, // '_M' |
| deallocate_memory, // '_m' |
| |
| unknown_type |
| } PacketEnum; |
| |
| typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p); |
| |
| RNBRemote (); |
| ~RNBRemote (); |
| |
| void Initialize(); |
| |
| bool InitializeRegisters (); |
| |
| 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 == -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_qGetPid (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_qThreadExtraInfo (const char *p); |
| rnb_err_t HandlePacket_qThreadStopInfo (const char *p); |
| rnb_err_t HandlePacket_qHostInfo (const char *p); |
| rnb_err_t HandlePacket_qProcessInfo (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_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_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_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_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_MemoryRegionInfo (const char *p); |
| rnb_err_t HandlePacket_GetProfileData(const char *p); |
| rnb_err_t HandlePacket_SetAsyncEnableProfiling(const char *p); |
| rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p); |
| |
| rnb_err_t HandlePacket_stop_process (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); |
| |
| RNBContext& Context() { return m_ctx; } |
| RNBSocket& Comm() { return m_comm; } |
| |
| void |
| SetUseNativeRegisters (bool b) |
| { |
| m_use_native_regs = b; |
| } |
| private: |
| // Outlaw some contructors |
| RNBRemote (const RNBRemote &); |
| |
| 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; // Function to call when inferior is halted |
| HandlePacketCallback async; // Function to call when inferior is running |
| 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) |
| { |
| } |
| }; |
| |
| rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait); |
| rnb_err_t SendPacket (const std::string &); |
| |
| void CreatePacketTable (); |
| rnb_err_t GetPacketPayload (std::string &); |
| |
| nub_thread_t |
| ExtractThreadIDFromThreadSuffix (const char *p); |
| |
| // gdb can send multiple Z/z packets for the same address and |
| // these calls must be ref counted. |
| struct Breakpoint |
| { |
| Breakpoint(nub_break_t breakID) : |
| m_breakID(breakID), |
| m_refCount(1) |
| { |
| } |
| |
| Breakpoint() : |
| m_breakID(INVALID_NUB_BREAK_ID), |
| m_refCount(0) |
| { |
| } |
| |
| Breakpoint(const Breakpoint& rhs) : |
| m_breakID(rhs.m_breakID), |
| m_refCount(rhs.m_refCount) |
| { |
| } |
| |
| nub_break_t BreakID() const { return m_breakID; } |
| uint32_t RefCount() const { return m_refCount; } |
| void Release() { if (m_refCount > 0) --m_refCount; } |
| void Retain() { ++m_refCount; } |
| |
| nub_break_t m_breakID; |
| uint32_t m_refCount; |
| }; |
| typedef std::map<nub_addr_t, Breakpoint> BreakpointMap; |
| typedef BreakpointMap::iterator BreakpointMapIter; |
| typedef BreakpointMap::const_iterator BreakpointMapConstIter; |
| RNBContext m_ctx; // process context |
| RNBSocket m_comm; // communication port |
| std::string m_arch; |
| nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all |
| nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all |
| PThreadMutex m_mutex; // Mutex that protects |
| uint32_t m_packets_recvd; |
| Packet::collection m_packets; |
| std::deque<std::string> m_rx_packets; |
| std::string m_rx_partial_data; // For packets that may come in more than one batch, anything left over can be left here |
| pthread_t m_rx_pthread; |
| BreakpointMap m_breakpoints; |
| BreakpointMap m_watchpoints; |
| uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb |
| bool m_extended_mode; // are we in extended mode? |
| bool m_noack_mode; // are we in no-ack mode? |
| bool m_use_native_regs; // Use native registers by querying DNB layer for register definitions? |
| bool m_thread_suffix_supported; // Set to true if the 'p', 'P', 'g', and 'G' packets should be prefixed with the thread ID and colon: |
| // "$pRR;thread:TTTT;" instead of "$pRR" |
| // "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV" |
| // "$g;thread:TTTT" instead of "$g" |
| // "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV" |
| bool m_list_threads_in_stop_reply; |
| }; |
| |
| /* We translate the /usr/include/mach/exception_types.h exception types |
| (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 |
| |
| /* Generally speaking, you can't assume gdb can receive more than 399 bytes |
| 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 // #ifndef __RNBRemote_h__ |