RNBRemote.h 18.1 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  Created by Greg Clayton on 12/12/07.
//
//===----------------------------------------------------------------------===//

#ifndef __RNBRemote_h__
#define __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,                          // ^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?'
    read_data_from_memory,  // 'x'
    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_monitor,                                 // 'qRcmd'
    query_current_thread_id,                       // 'qC'
    query_get_pid,                                 // 'qGetPid'
    query_echo,                                    // 'qEcho'
    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,                           // 'qSymbol'
    query_launch_success,                          // 'qLaunchSuccess'
    query_register_info,                           // 'qRegisterInfo'
    query_shlib_notify_info_addr,                  // 'qShlibInfoAddr'
    query_step_packet_supported,                   // 'qStepPacketSupported'
    query_supported_features,                      // 'qSupported'
    query_vattachorwait_supported,                 // 'qVAttachOrWaitSupported'
    query_sync_thread_state_supported,             // 'QSyncThreadState'
    query_host_info,                               // 'qHostInfo'
    query_gdb_server_version,                      // 'qGDBServerVersion'
    query_process_info,                            // 'qProcessInfo'
    json_query_thread_extended_info,               // 'jThreadExtendedInfo'
    json_query_get_loaded_dynamic_libraries_infos, // 'jGetLoadedDynamicLibrariesInfos'
    json_query_threads_info,                       // 'jThreadsInfo'
    json_query_get_shared_cache_info,              // 'jGetSharedCacheInfo'
    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,               // 'QSetEnableAsyncProfiling'
    enable_compression,                 // 'QEnableCompression:'
    watchpoint_support_info,            // 'qWatchpointSupportInfo:'
    allocate_memory,                    // '_M'
    deallocate_memory,                  // '_m'
    set_process_event,                  // 'QSetProcessEvent:'
    save_register_state,                // '_g'
    restore_register_state,             // '_G'
    speed_test,                         // 'qSpeedTest:'
    set_detach_on_error,                // 'QSetDetachOnError:'
    query_transfer,                     // 'qXfer:'
    query_supported_async_json_packets, // 'QSupportedAsyncJSONPackets'
    configure_darwin_log,               // 'ConfigureDarwinLog:'
    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_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_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_qStructuredDataPlugins(const char *p);
  rnb_err_t HandlePacket_QConfigureDarwinLog(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);
  void SendAsyncDarwinLogData();
  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; // 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) {}
  };

  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; // version 5 and later, starting with Mac OS X
                              // 10.10/iOS 8
    uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS
                                   // X 10.10/iOS 8
    uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X
                               // 10.10/iOS 8
    uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS
                                    // X 10.10/iOS 8
    uint16_t
        dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8
    uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X
                                // 10.10/iOS 8

    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 &);
  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; // 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
  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; // For packets that may come in more than one
                                 // batch, anything left over can be left here
  pthread_t m_rx_pthread;
  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_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;

  size_t m_compression_minsize; // only packets larger than this size will be
                                // compressed
  bool m_enable_compression_next_send_packet;

  compression_types m_compression_mode;
};

/* 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__