Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1 | //===-- RNBRemote.h ---------------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Created by Greg Clayton on 12/12/07. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef __RNBRemote_h__ |
| 15 | #define __RNBRemote_h__ |
| 16 | |
| 17 | #include "RNBDefs.h" |
| 18 | #include "DNB.h" |
| 19 | #include "RNBContext.h" |
| 20 | #include "RNBSocket.h" |
| 21 | #include "PThreadMutex.h" |
| 22 | #include <string> |
| 23 | #include <vector> |
| 24 | #include <deque> |
| 25 | #include <map> |
| 26 | |
| 27 | class RNBSocket; |
| 28 | class RNBContext; |
| 29 | class PThreadEvents; |
| 30 | |
| 31 | enum event_loop_mode { debug_nub, gdb_remote_protocol, done }; |
| 32 | |
| 33 | class RNBRemote |
| 34 | { |
| 35 | public: |
| 36 | |
| 37 | typedef enum { |
| 38 | invalid_packet = 0, |
| 39 | ack, // '+' |
| 40 | nack, // '-' |
| 41 | halt, // ^C (async halt) |
| 42 | use_extended_mode, // '!' |
| 43 | why_halted, // '?' |
| 44 | set_argv, // 'A' |
| 45 | set_bp, // 'B' |
| 46 | cont, // 'c' |
| 47 | continue_with_sig, // 'C' |
| 48 | detach, // 'D' |
| 49 | read_general_regs, // 'g' |
| 50 | write_general_regs, // 'G' |
| 51 | set_thread, // 'H' |
| 52 | step_inferior_one_cycle, // 'i' |
| 53 | signal_and_step_inf_one_cycle, // 'I' |
| 54 | kill, // 'k' |
| 55 | read_memory, // 'm' |
| 56 | write_memory, // 'M' |
| 57 | read_register, // 'p' |
| 58 | write_register, // 'P' |
| 59 | restart, // 'R' |
| 60 | single_step, // 's' |
| 61 | single_step_with_sig, // 'S' |
| 62 | search_mem_backwards, // 't' |
| 63 | thread_alive_p, // 'T' |
Greg Clayton | c1d3775 | 2010-10-18 01:45:30 +0000 | [diff] [blame^] | 64 | vattach, // 'vAttach;pid' |
| 65 | vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes |
| 66 | vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 67 | vcont, // 'vCont' |
| 68 | vcont_list_actions, // 'vCont?' |
| 69 | write_data_to_memory, // 'X' |
| 70 | insert_mem_bp, // 'Z0' |
| 71 | remove_mem_bp, // 'z0' |
| 72 | insert_hardware_bp, // 'Z1' |
| 73 | remove_hardware_bp, // 'z1' |
| 74 | insert_write_watch_bp, // 'Z2' |
| 75 | remove_write_watch_bp, // 'z2' |
| 76 | insert_read_watch_bp, // 'Z3' |
| 77 | remove_read_watch_bp, // 'z3' |
| 78 | insert_access_watch_bp, // 'Z4' |
| 79 | remove_access_watch_bp, // 'z4' |
| 80 | |
| 81 | query_current_thread_id, // 'qC' |
| 82 | query_memory_crc, // 'qCRC:' |
| 83 | query_thread_ids_first, // 'qfThreadInfo' |
| 84 | query_thread_ids_subsequent, // 'qsThreadInfo' |
| 85 | query_thread_extra_info, // 'qThreadExtraInfo' |
| 86 | query_thread_stop_info, // 'qThreadStopInfo' |
| 87 | query_image_offsets, // 'qOffsets' |
| 88 | query_symbol_lookup, // 'gSymbols' |
| 89 | query_launch_success, // 'qLaunchSuccess' |
| 90 | query_register_info, // 'qRegisterInfo' |
| 91 | query_shlib_notify_info_addr, // 'qShlibInfoAddr' |
| 92 | query_step_packet_supported, // 'qStepPacketSupported' |
| 93 | query_host_info, // 'qHostInfo' |
| 94 | pass_signals_to_inferior, // 'QPassSignals' |
| 95 | start_noack_mode, // 'QStartNoAckMode' |
| 96 | set_logging_mode, // 'QSetLogging:' |
| 97 | set_max_packet_size, // 'QSetMaxPacketSize:' |
| 98 | set_max_payload_size, // 'QSetMaxPayloadSize:' |
| 99 | set_environment_variable, // 'QEnvironment:' |
Greg Clayton | 0a7f75f | 2010-09-09 06:32:46 +0000 | [diff] [blame] | 100 | set_disable_aslr, // 'QSetDisableASLR:' |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 101 | allocate_memory, // '_M' |
| 102 | deallocate_memory, // '_m' |
| 103 | |
| 104 | unknown_type, |
| 105 | } PacketEnum; |
| 106 | |
| 107 | typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p); |
| 108 | |
| 109 | RNBRemote(bool use_native_regs); |
| 110 | ~RNBRemote(); |
| 111 | |
| 112 | static void InitializeRegisters (int use_native); |
| 113 | |
| 114 | rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL); |
| 115 | rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL); |
| 116 | |
| 117 | nub_thread_t GetContinueThread () const |
| 118 | { |
| 119 | return m_continue_thread; |
| 120 | } |
| 121 | |
| 122 | void SetContinueThread (nub_thread_t tid) |
| 123 | { |
| 124 | m_continue_thread = tid; |
| 125 | } |
| 126 | |
| 127 | nub_thread_t GetCurrentThread () const |
| 128 | { |
| 129 | if (m_thread == 0 || m_thread == -1) |
| 130 | return DNBProcessGetCurrentThread (m_ctx.ProcessID()); |
| 131 | return m_thread; |
| 132 | } |
| 133 | |
| 134 | void SetCurrentThread (nub_thread_t tid) |
| 135 | { |
| 136 | DNBProcessSetCurrentThread (m_ctx.ProcessID(), tid); |
| 137 | m_thread = tid; |
| 138 | } |
| 139 | |
| 140 | static void* ThreadFunctionReadRemoteData(void *arg); |
| 141 | void StartReadRemoteDataThread (); |
| 142 | void StopReadRemoteDataThread (); |
| 143 | |
| 144 | void NotifyThatProcessStopped (void); |
| 145 | |
| 146 | rnb_err_t HandlePacket_A (const char *p); |
| 147 | rnb_err_t HandlePacket_H (const char *p); |
| 148 | rnb_err_t HandlePacket_qC (const char *p); |
| 149 | rnb_err_t HandlePacket_qLaunchSuccess (const char *p); |
| 150 | rnb_err_t HandlePacket_qRegisterInfo (const char *p); |
| 151 | rnb_err_t HandlePacket_qShlibInfoAddr (const char *p); |
| 152 | rnb_err_t HandlePacket_qStepPacketSupported (const char *p); |
| 153 | rnb_err_t HandlePacket_qThreadInfo (const char *p); |
| 154 | rnb_err_t HandlePacket_qThreadExtraInfo (const char *p); |
| 155 | rnb_err_t HandlePacket_qThreadStopInfo (const char *p); |
| 156 | rnb_err_t HandlePacket_qHostInfo (const char *p); |
| 157 | rnb_err_t HandlePacket_Q (const char *p); |
| 158 | rnb_err_t HandlePacket_last_signal (const char *p); |
| 159 | rnb_err_t HandlePacket_m (const char *p); |
| 160 | rnb_err_t HandlePacket_M (const char *p); |
| 161 | rnb_err_t HandlePacket_X (const char *p); |
| 162 | rnb_err_t HandlePacket_g (const char *p); |
| 163 | rnb_err_t HandlePacket_G (const char *p); |
| 164 | rnb_err_t HandlePacket_z (const char *p); |
| 165 | rnb_err_t HandlePacket_T (const char *p); |
| 166 | rnb_err_t HandlePacket_p (const char *p); |
| 167 | rnb_err_t HandlePacket_P (const char *p); |
| 168 | rnb_err_t HandlePacket_c (const char *p); |
| 169 | rnb_err_t HandlePacket_C (const char *p); |
| 170 | rnb_err_t HandlePacket_D (const char *p); |
| 171 | rnb_err_t HandlePacket_k (const char *p); |
| 172 | rnb_err_t HandlePacket_s (const char *p); |
| 173 | rnb_err_t HandlePacket_S (const char *p); |
| 174 | rnb_err_t HandlePacket_v (const char *p); |
| 175 | rnb_err_t HandlePacket_UNIMPLEMENTED (const char *p); |
| 176 | rnb_err_t HandlePacket_ILLFORMED (const char *description); |
| 177 | rnb_err_t HandlePacket_AllocateMemory (const char *p); |
| 178 | rnb_err_t HandlePacket_DeallocateMemory (const char *p); |
| 179 | |
| 180 | rnb_err_t HandlePacket_stop_process (const char *p); |
| 181 | |
| 182 | rnb_err_t SendStopReplyPacketForThread (nub_thread_t tid); |
| 183 | rnb_err_t SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer); |
| 184 | rnb_err_t SendSTDOUTPacket (char *buf, nub_size_t buf_size); |
| 185 | rnb_err_t SendSTDERRPacket (char *buf, nub_size_t buf_size); |
| 186 | void FlushSTDIO (); |
| 187 | |
| 188 | RNBContext& Context() { return m_ctx; } |
| 189 | RNBSocket& Comm() { return m_comm; } |
| 190 | |
| 191 | private: |
| 192 | // Outlaw some contructors |
| 193 | RNBRemote (const RNBRemote &); |
| 194 | |
| 195 | protected: |
| 196 | |
| 197 | static void |
| 198 | InitializeNativeRegisters (); |
| 199 | |
| 200 | rnb_err_t GetCommData (); |
| 201 | void CommDataReceived(const std::string& data); |
| 202 | struct Packet |
| 203 | { |
| 204 | typedef std::vector<Packet> collection; |
| 205 | typedef collection::iterator iterator; |
| 206 | typedef collection::const_iterator const_iterator; |
| 207 | PacketEnum type; |
| 208 | HandlePacketCallback normal; // Function to call when inferior is halted |
| 209 | HandlePacketCallback async; // Function to call when inferior is running |
| 210 | std::string abbrev; |
| 211 | std::string printable_name; |
| 212 | Packet() : |
| 213 | type(invalid_packet), |
| 214 | normal (NULL), |
| 215 | async (NULL), |
| 216 | abbrev (), |
| 217 | printable_name () |
| 218 | { |
| 219 | } |
| 220 | |
| 221 | Packet( PacketEnum in_type, |
| 222 | HandlePacketCallback in_normal, |
| 223 | HandlePacketCallback in_async, |
| 224 | const char *in_abbrev, |
| 225 | const char *in_printable_name) : |
| 226 | type (in_type), |
| 227 | normal (in_normal), |
| 228 | async (in_async), |
| 229 | abbrev (in_abbrev), |
| 230 | printable_name (in_printable_name) |
| 231 | { |
| 232 | } |
| 233 | }; |
| 234 | |
| 235 | rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait); |
| 236 | rnb_err_t SendPacket (const std::string &); |
| 237 | |
| 238 | void CreatePacketTable (); |
| 239 | rnb_err_t GetPacketPayload (std::string &); |
| 240 | |
| 241 | // gdb can send multiple Z/z packets for the same address and |
| 242 | // these calls must be ref counted. |
Johnny Chen | fa15024 | 2010-09-28 16:34:56 +0000 | [diff] [blame] | 243 | struct Breakpoint |
Chris Lattner | 24943d2 | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 244 | { |
| 245 | Breakpoint(nub_break_t breakID) : |
| 246 | m_breakID(breakID), |
| 247 | m_refCount(1) |
| 248 | { |
| 249 | } |
| 250 | |
| 251 | Breakpoint() : |
| 252 | m_breakID(INVALID_NUB_BREAK_ID), |
| 253 | m_refCount(0) |
| 254 | { |
| 255 | } |
| 256 | |
| 257 | Breakpoint(const Breakpoint& rhs) : |
| 258 | m_breakID(rhs.m_breakID), |
| 259 | m_refCount(rhs.m_refCount) |
| 260 | { |
| 261 | } |
| 262 | |
| 263 | nub_break_t BreakID() const { return m_breakID; } |
| 264 | uint32_t RefCount() const { return m_refCount; } |
| 265 | void Release() { if (m_refCount > 0) --m_refCount; } |
| 266 | void Retain() { ++m_refCount; } |
| 267 | |
| 268 | nub_break_t m_breakID; |
| 269 | uint32_t m_refCount; |
| 270 | }; |
| 271 | typedef std::map<nub_addr_t, Breakpoint> BreakpointMap; |
| 272 | typedef BreakpointMap::iterator BreakpointMapIter; |
| 273 | typedef BreakpointMap::const_iterator BreakpointMapConstIter; |
| 274 | RNBContext m_ctx; // process context |
| 275 | RNBSocket m_comm; // communication port |
| 276 | bool m_extended_mode; // are we in extended mode? |
| 277 | bool m_noack_mode; // are we in no-ack mode? |
| 278 | nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all |
| 279 | nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all |
| 280 | PThreadMutex m_mutex; // Mutex that protects |
| 281 | uint32_t m_packets_recvd; |
| 282 | Packet::collection m_packets; |
| 283 | std::deque<std::string> m_rx_packets; |
| 284 | std::string m_rx_partial_data; // For packets that may come in more than one batch, anything left over can be left here |
| 285 | pthread_t m_rx_pthread; |
| 286 | BreakpointMap m_breakpoints; |
| 287 | BreakpointMap m_watchpoints; |
| 288 | uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb |
| 289 | bool m_use_native_regs; |
| 290 | }; |
| 291 | |
| 292 | /* We translate the /usr/include/mach/exception_types.h exception types |
| 293 | (e.g. EXC_BAD_ACCESS) to the fake BSD signal numbers that gdb uses |
| 294 | in include/gdb/signals.h (e.g. TARGET_EXC_BAD_ACCESS). These hard |
| 295 | coded values for TARGET_EXC_BAD_ACCESS et al must match the gdb |
| 296 | values in its include/gdb/signals.h. */ |
| 297 | |
| 298 | #define TARGET_EXC_BAD_ACCESS 0x91 |
| 299 | #define TARGET_EXC_BAD_INSTRUCTION 0x92 |
| 300 | #define TARGET_EXC_ARITHMETIC 0x93 |
| 301 | #define TARGET_EXC_EMULATION 0x94 |
| 302 | #define TARGET_EXC_SOFTWARE 0x95 |
| 303 | #define TARGET_EXC_BREAKPOINT 0x96 |
| 304 | |
| 305 | /* Generally speaking, you can't assume gdb can receive more than 399 bytes |
| 306 | at a time with a random gdb. This bufsize constant is only specifying |
| 307 | how many bytes gdb can *receive* from debugserver -- it tells us nothing |
| 308 | about how many bytes gdb might try to send in a single packet. */ |
| 309 | #define DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE 399 |
| 310 | |
| 311 | #endif // #ifndef __RNBRemote_h__ |