brintos

brintos / llvm-project-archived public Read only

0
0
Text · 227.6 KiB · 11b9371 Raw
6605 lines · cpp
1//===-- RNBRemote.cpp -------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  Created by Greg Clayton on 12/12/07.10//11//===----------------------------------------------------------------------===//12 13#include "RNBRemote.h"14 15#include <bsm/audit.h>16#include <bsm/audit_session.h>17#include <cerrno>18#include <csignal>19#include <libproc.h>20#include <mach-o/loader.h>21#include <mach/exception_types.h>22#include <mach/mach_vm.h>23#include <mach/task_info.h>24#include <memory>25#if __has_include(<os/security_config.h>)26#include <os/security_config.h>27#endif28#include <pwd.h>29#include <string>30#include <sys/stat.h>31#include <sys/sysctl.h>32#include <unistd.h>33 34#if defined(__APPLE__)35#include <pthread.h>36#include <sched.h>37#endif38 39#include "DNB.h"40#include "DNBDataRef.h"41#include "DNBLog.h"42#include "DNBThreadResumeActions.h"43#include "JSON.h"44#include "JSONGenerator.h"45#include "MacOSX/Genealogy.h"46#include "OsLogger.h"47#include "RNBContext.h"48#include "RNBServices.h"49#include "RNBSocket.h"50#include "StdStringExtractor.h"51 52#include <compression.h>53 54#include <TargetConditionals.h>55#include <algorithm>56#include <iomanip>57#include <memory>58#include <sstream>59#include <unordered_set>60 61#include <CoreFoundation/CoreFoundation.h>62#include <Security/Security.h>63 64// constants65 66static const std::string OS_LOG_EVENTS_KEY_NAME("events");67static const std::string JSON_ASYNC_TYPE_KEY_NAME("type");68 69// std::iostream formatting macros70#define RAW_HEXBASE std::setfill('0') << std::hex << std::right71#define HEXBASE '0' << 'x' << RAW_HEXBASE72#define RAWHEX8(x) RAW_HEXBASE << std::setw(2) << ((uint32_t)((uint8_t)x))73#define RAWHEX16 RAW_HEXBASE << std::setw(4)74#define RAWHEX32 RAW_HEXBASE << std::setw(8)75#define RAWHEX64 RAW_HEXBASE << std::setw(16)76#define HEX8(x) HEXBASE << std::setw(2) << ((uint32_t)(x))77#define HEX16 HEXBASE << std::setw(4)78#define HEX32 HEXBASE << std::setw(8)79#define HEX64 HEXBASE << std::setw(16)80#define RAW_HEX(x) RAW_HEXBASE << std::setw(sizeof(x) * 2) << (x)81#define HEX(x) HEXBASE << std::setw(sizeof(x) * 2) << (x)82#define RAWHEX_SIZE(x, sz) RAW_HEXBASE << std::setw((sz)) << (x)83#define HEX_SIZE(x, sz) HEXBASE << std::setw((sz)) << (x)84#define STRING_WIDTH(w) std::setfill(' ') << std::setw(w)85#define LEFT_STRING_WIDTH(s, w)                                                \86  std::left << std::setfill(' ') << std::setw(w) << (s) << std::right87#define DECIMAL std::dec << std::setfill(' ')88#define DECIMAL_WIDTH(w) DECIMAL << std::setw(w)89#define FLOAT(n, d)                                                            \90  std::setfill(' ') << std::setw((n) + (d) + 1) << std::setprecision(d)        \91                    << std::showpoint << std::fixed92#define INDENT_WITH_SPACES(iword_idx)                                          \93  std::setfill(' ') << std::setw((iword_idx)) << ""94#define INDENT_WITH_TABS(iword_idx)                                            \95  std::setfill('\t') << std::setw((iword_idx)) << ""96 97// If `ch` is a meta character as per the binary packet convention in the98// gdb-remote protocol, quote it and write it into `stream`, otherwise write it99// as is.100static void binary_encode_char(std::ostringstream &stream, char ch) {101  if (ch == '#' || ch == '$' || ch == '}' || ch == '*') {102    stream.put('}');103    stream.put(ch ^ 0x20);104  } else {105    stream.put(ch);106  }107}108 109// Equivalent to calling binary_encode_char for every element of `data`.110static void binary_encode_data_vector(std::ostringstream &stream,111                                      std::vector<uint8_t> data) {112  for (auto ch : data)113    binary_encode_char(stream, ch);114}115 116// Quote any meta characters in a std::string as per the binary117// packet convention in the gdb-remote protocol.118static std::string binary_encode_string(const std::string &s) {119  std::ostringstream stream;120  for (char ch : s)121    binary_encode_char(stream, ch);122  return stream.str();123}124 125// Decode a single hex character and return the hex value as a number or126// -1 if "ch" is not a hex character.127static inline int xdigit_to_sint(char ch) {128  if (ch >= 'a' && ch <= 'f')129    return 10 + ch - 'a';130  if (ch >= 'A' && ch <= 'F')131    return 10 + ch - 'A';132  if (ch >= '0' && ch <= '9')133    return ch - '0';134  return -1;135}136 137// Decode a single hex ASCII byte. Return -1 on failure, a value 0-255138// on success.139static inline int decoded_hex_ascii_char(const char *p) {140  const int hi_nibble = xdigit_to_sint(p[0]);141  if (hi_nibble == -1)142    return -1;143  const int lo_nibble = xdigit_to_sint(p[1]);144  if (lo_nibble == -1)145    return -1;146  return (uint8_t)((hi_nibble << 4) + lo_nibble);147}148 149// Decode a hex ASCII string back into a string150static std::string decode_hex_ascii_string(const char *p,151                                           uint32_t max_length = UINT32_MAX) {152  std::string arg;153  if (p) {154    for (const char *c = p; ((c - p) / 2) < max_length; c += 2) {155      int ch = decoded_hex_ascii_char(c);156      if (ch == -1)157        break;158      else159        arg.push_back(ch);160    }161  }162  return arg;163}164 165static uint64_t decode_uint64(const char *p, int base, char **end = nullptr,166                              uint64_t fail_value = 0) {167  nub_addr_t addr = strtoull(p, end, 16);168  if (addr == 0 && errno != 0)169    return fail_value;170  return addr;171}172 173/// Attempts to parse a prefix of `number_str` as a uint64_t. If174/// successful, the number is returned and the prefix is dropped from175/// `number_str`.176static std::optional<uint64_t> extract_u64(std::string_view &number_str) {177  char *str_end = nullptr;178  errno = 0;179  uint64_t number = strtoull(number_str.data(), &str_end, 16);180  if (errno != 0)181    return std::nullopt;182  assert(str_end);183  number_str.remove_prefix(str_end - number_str.data());184  return number;185}186 187static void append_hex_value(std::ostream &ostrm, const void *buf,188                             size_t buf_size, bool swap) {189  int i;190  const uint8_t *p = (const uint8_t *)buf;191  if (swap) {192    for (i = static_cast<int>(buf_size) - 1; i >= 0; i--)193      ostrm << RAWHEX8(p[i]);194  } else {195    for (size_t i = 0; i < buf_size; i++)196      ostrm << RAWHEX8(p[i]);197  }198}199 200static std::string cstring_to_asciihex_string(const char *str) {201  std::string hex_str;202  hex_str.reserve(strlen(str) * 2);203  while (str && *str) {204    uint8_t c = *str++;205    char hexbuf[5];206    snprintf(hexbuf, sizeof(hexbuf), "%02x", c);207    hex_str += hexbuf;208  }209  return hex_str;210}211 212static void append_hexified_string(std::ostream &ostrm,213                                   const std::string &string) {214  size_t string_size = string.size();215  const char *string_buf = string.c_str();216  for (size_t i = 0; i < string_size; i++) {217    ostrm << RAWHEX8(*(string_buf + i));218  }219}220 221/// Returns true if `str` starts with `prefix`.222static bool starts_with(std::string_view str, std::string_view prefix) {223  return str.substr(0, prefix.size()) == prefix;224}225 226/// Splits `list_str` into multiple string_views separated by `,`.227static std::vector<std::string_view>228parse_comma_separated_list(std::string_view list_str) {229  std::vector<std::string_view> list;230  while (!list_str.empty()) {231    auto pos = list_str.find(',');232    list.push_back(list_str.substr(0, pos));233    if (pos == list_str.npos)234      break;235    list_str.remove_prefix(pos + 1);236  }237  return list;238}239 240// from System.framework/Versions/B/PrivateHeaders/sys/codesign.h241extern "C" {242#define CS_OPS_STATUS 0       /* return status */243#define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */244int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);245 246// from rootless.h247bool rootless_allows_task_for_pid(pid_t pid);248 249// from sys/csr.h250typedef uint32_t csr_config_t;251#define CSR_ALLOW_TASK_FOR_PID (1 << 2)252int csr_check(csr_config_t mask);253}254 255RNBRemote::RNBRemote()256    : m_ctx(), m_comm(), m_arch(), m_continue_thread(-1), m_thread(-1),257      m_mutex(), m_dispatch_queue_offsets(),258      m_dispatch_queue_offsets_addr(INVALID_NUB_ADDRESS),259      m_qSymbol_index(UINT32_MAX), m_packets_recvd(0), m_packets(),260      m_rx_packets(), m_rx_partial_data(), m_rx_pthread(0),261      m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4),262      m_extended_mode(false), m_noack_mode(false),263      m_thread_suffix_supported(false), m_list_threads_in_stop_reply(false),264      m_compression_minsize(384), m_enable_compression_next_send_packet(false),265      m_compression_mode(compression_types::none),266      m_enable_error_strings(false) {267  DNBLogThreadedIf(LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);268  CreatePacketTable();269}270 271RNBRemote::~RNBRemote() {272  DNBLogThreadedIf(LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);273  StopReadRemoteDataThread();274}275 276void RNBRemote::CreatePacketTable() {277  // Step required to add new packets:278  // 1 - Add new enumeration to RNBRemote::PacketEnum279  // 2 - Create the RNBRemote::HandlePacket_ function if a new function is280  // needed281  // 3 - Register the Packet definition with any needed callbacks in this282  // function283  //          - If no response is needed for a command, then use NULL for the284  //          normal callback285  //          - If the packet is not supported while the target is running, use286  //          NULL for the async callback287  // 4 - If the packet is a standard packet (starts with a '$' character288  //      followed by the payload and then '#' and checksum, then you are done289  //      else go on to step 5290  // 5 - if the packet is a fixed length packet:291  //      - modify the switch statement for the first character in the payload292  //        in RNBRemote::CommDataReceived so it doesn't reject the new packet293  //        type as invalid294  //      - modify the switch statement for the first character in the payload295  //        in RNBRemote::GetPacketPayload and make sure the payload of the296  //        packet297  //        is returned correctly298 299  std::vector<Packet> &t = m_packets;300  t.push_back(Packet(ack, NULL, NULL, "+", "ACK"));301  t.push_back(Packet(nack, NULL, NULL, "-", "!ACK"));302  t.push_back(Packet(read_memory, &RNBRemote::HandlePacket_m, NULL, "m",303                     "Read memory"));304  t.push_back(Packet(read_register, &RNBRemote::HandlePacket_p, NULL, "p",305                     "Read one register"));306  // Careful: this *must* come before the `M` packet, as debugserver matches307  // packet prefixes against known packet names. Inverting the order would match308  // `MultiMemRead` as an `M` packet.309  t.push_back(Packet(multi_mem_read, &RNBRemote::HandlePacket_MultiMemRead,310                     NULL, "MultiMemRead", "Read multiple memory addresses"));311  t.push_back(Packet(write_memory, &RNBRemote::HandlePacket_M, NULL, "M",312                     "Write memory"));313  t.push_back(Packet(write_register, &RNBRemote::HandlePacket_P, NULL, "P",314                     "Write one register"));315  t.push_back(Packet(insert_mem_bp, &RNBRemote::HandlePacket_z, NULL, "Z0",316                     "Insert memory breakpoint"));317  t.push_back(Packet(remove_mem_bp, &RNBRemote::HandlePacket_z, NULL, "z0",318                     "Remove memory breakpoint"));319  t.push_back(Packet(single_step, &RNBRemote::HandlePacket_s, NULL, "s",320                     "Single step"));321  t.push_back(Packet(cont, &RNBRemote::HandlePacket_c, NULL, "c", "continue"));322  t.push_back(Packet(single_step_with_sig, &RNBRemote::HandlePacket_S, NULL,323                     "S", "Single step with signal"));324  t.push_back(325      Packet(set_thread, &RNBRemote::HandlePacket_H, NULL, "H", "Set thread"));326  t.push_back(Packet(halt, &RNBRemote::HandlePacket_last_signal,327                     &RNBRemote::HandlePacket_stop_process, "\x03", "^C"));328  //  t.push_back (Packet (use_extended_mode,329  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "!", "Use extended mode"));330  t.push_back(Packet(why_halted, &RNBRemote::HandlePacket_last_signal, NULL,331                     "?", "Why did target halt"));332  t.push_back(333      Packet(set_argv, &RNBRemote::HandlePacket_A, NULL, "A", "Set argv"));334  //  t.push_back (Packet (set_bp,335  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "B", "Set/clear336  //  breakpoint"));337  t.push_back(Packet(continue_with_sig, &RNBRemote::HandlePacket_C, NULL, "C",338                     "Continue with signal"));339  t.push_back(Packet(detach, &RNBRemote::HandlePacket_D, NULL, "D",340                     "Detach gdb from remote system"));341  //  t.push_back (Packet (step_inferior_one_cycle,342  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "i", "Step inferior by one343  //  clock cycle"));344  //  t.push_back (Packet (signal_and_step_inf_one_cycle,345  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "I", "Signal inferior, then346  //  step one clock cycle"));347  t.push_back(Packet(kill, &RNBRemote::HandlePacket_k, NULL, "k", "Kill"));348  //  t.push_back (Packet (restart,349  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "R", "Restart inferior"));350  //  t.push_back (Packet (search_mem_backwards,351  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "t", "Search memory352  //  backwards"));353  t.push_back(Packet(thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T",354                     "Is thread alive"));355  t.push_back(Packet(query_supported_features,356                     &RNBRemote::HandlePacket_qSupported, NULL, "qSupported",357                     "Query about supported features"));358  t.push_back(Packet(vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach",359                     "Attach to a new process"));360  t.push_back(Packet(vattachwait, &RNBRemote::HandlePacket_v, NULL,361                     "vAttachWait",362                     "Wait for a process to start up then attach to it"));363  t.push_back(Packet(vattachorwait, &RNBRemote::HandlePacket_v, NULL,364                     "vAttachOrWait", "Attach to the process or if it doesn't "365                                      "exist, wait for the process to start up "366                                      "then attach to it"));367  t.push_back(Packet(vattachname, &RNBRemote::HandlePacket_v, NULL,368                     "vAttachName", "Attach to an existing process by name"));369  t.push_back(Packet(vcont_list_actions, &RNBRemote::HandlePacket_v, NULL,370                     "vCont;", "Verbose resume with thread actions"));371  t.push_back(Packet(vcont_list_actions, &RNBRemote::HandlePacket_v, NULL,372                     "vCont?",373                     "List valid continue-with-thread-actions actions"));374  t.push_back(Packet(read_data_from_memory, &RNBRemote::HandlePacket_x, NULL,375                     "x", "Read data from memory"));376  t.push_back(Packet(write_data_to_memory, &RNBRemote::HandlePacket_X, NULL,377                     "X", "Write data to memory"));378  t.push_back(Packet(insert_hardware_bp, &RNBRemote::HandlePacket_z, NULL, "Z1",379                     "Insert hardware breakpoint"));380  t.push_back(Packet(remove_hardware_bp, &RNBRemote::HandlePacket_z, NULL, "z1",381                     "Remove hardware breakpoint"));382  t.push_back(Packet(insert_write_watch_bp, &RNBRemote::HandlePacket_z, NULL,383                     "Z2", "Insert write watchpoint"));384  t.push_back(Packet(remove_write_watch_bp, &RNBRemote::HandlePacket_z, NULL,385                     "z2", "Remove write watchpoint"));386  t.push_back(Packet(insert_read_watch_bp, &RNBRemote::HandlePacket_z, NULL,387                     "Z3", "Insert read watchpoint"));388  t.push_back(Packet(remove_read_watch_bp, &RNBRemote::HandlePacket_z, NULL,389                     "z3", "Remove read watchpoint"));390  t.push_back(Packet(insert_access_watch_bp, &RNBRemote::HandlePacket_z, NULL,391                     "Z4", "Insert access watchpoint"));392  t.push_back(Packet(remove_access_watch_bp, &RNBRemote::HandlePacket_z, NULL,393                     "z4", "Remove access watchpoint"));394  t.push_back(Packet(query_monitor, &RNBRemote::HandlePacket_qRcmd, NULL,395                     "qRcmd", "Monitor command"));396  t.push_back(Packet(query_current_thread_id, &RNBRemote::HandlePacket_qC, NULL,397                     "qC", "Query current thread ID"));398  t.push_back(Packet(query_echo, &RNBRemote::HandlePacket_qEcho, NULL, "qEcho:",399                     "Echo the packet back to allow the debugger to sync up "400                     "with this server"));401  t.push_back(Packet(query_get_pid, &RNBRemote::HandlePacket_qGetPid, NULL,402                     "qGetPid", "Query process id"));403  t.push_back(Packet(query_thread_ids_first,404                     &RNBRemote::HandlePacket_qThreadInfo, NULL, "qfThreadInfo",405                     "Get list of active threads (first req)"));406  t.push_back(Packet(query_thread_ids_subsequent,407                     &RNBRemote::HandlePacket_qThreadInfo, NULL, "qsThreadInfo",408                     "Get list of active threads (subsequent req)"));409  // APPLE LOCAL: qThreadStopInfo410  // syntax: qThreadStopInfoTTTT411  //  TTTT is hex thread ID412  t.push_back(Packet(query_thread_stop_info,413                     &RNBRemote::HandlePacket_qThreadStopInfo, NULL,414                     "qThreadStopInfo",415                     "Get detailed info on why the specified thread stopped"));416  t.push_back(Packet(query_thread_extra_info,417                     &RNBRemote::HandlePacket_qThreadExtraInfo, NULL,418                     "qThreadExtraInfo", "Get printable status of a thread"));419  //  t.push_back (Packet (query_image_offsets,420  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qOffsets", "Report offset421  //  of loaded program"));422  t.push_back(Packet(423      query_launch_success, &RNBRemote::HandlePacket_qLaunchSuccess, NULL,424      "qLaunchSuccess", "Report the success or failure of the launch attempt"));425  t.push_back(426      Packet(query_register_info, &RNBRemote::HandlePacket_qRegisterInfo, NULL,427             "qRegisterInfo",428             "Dynamically discover remote register context information."));429  t.push_back(Packet(430      query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr,431      NULL, "qShlibInfoAddr", "Returns the address that contains info needed "432                              "for getting shared library notifications"));433  t.push_back(Packet(query_step_packet_supported,434                     &RNBRemote::HandlePacket_qStepPacketSupported, NULL,435                     "qStepPacketSupported",436                     "Replys with OK if the 's' packet is supported."));437  t.push_back(438      Packet(query_vattachorwait_supported,439             &RNBRemote::HandlePacket_qVAttachOrWaitSupported, NULL,440             "qVAttachOrWaitSupported",441             "Replys with OK if the 'vAttachOrWait' packet is supported."));442  t.push_back(443      Packet(query_sync_thread_state_supported,444             &RNBRemote::HandlePacket_qSyncThreadStateSupported, NULL,445             "qSyncThreadStateSupported",446             "Replys with OK if the 'QSyncThreadState:' packet is supported."));447  t.push_back(Packet(448      query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo",449      "Replies with multiple 'key:value;' tuples appended to each other."));450  t.push_back(Packet(451      query_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion,452      NULL, "qGDBServerVersion",453      "Replies with multiple 'key:value;' tuples appended to each other."));454  t.push_back(Packet(455      query_process_info, &RNBRemote::HandlePacket_qProcessInfo, NULL,456      "qProcessInfo",457      "Replies with multiple 'key:value;' tuples appended to each other."));458  t.push_back(Packet(459      query_symbol_lookup, &RNBRemote::HandlePacket_qSymbol, NULL, "qSymbol:",460      "Notify that host debugger is ready to do symbol lookups"));461  t.push_back(Packet(enable_error_strings,462                     &RNBRemote::HandlePacket_QEnableErrorStrings, NULL,463                     "QEnableErrorStrings",464                     "Tell " DEBUGSERVER_PROGRAM_NAME465                     " it can append descriptive error messages in replies."));466  t.push_back(Packet(json_query_thread_extended_info,467                     &RNBRemote::HandlePacket_jThreadExtendedInfo, NULL,468                     "jThreadExtendedInfo",469                     "Replies with JSON data of thread extended information."));470  t.push_back(Packet(json_query_get_loaded_dynamic_libraries_infos,471                     &RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos,472                     NULL, "jGetLoadedDynamicLibrariesInfos",473                     "Replies with JSON data of all the shared libraries "474                     "loaded in this process."));475  t.push_back(476      Packet(json_query_threads_info, &RNBRemote::HandlePacket_jThreadsInfo,477             NULL, "jThreadsInfo",478             "Replies with JSON data with information about all threads."));479  t.push_back(Packet(json_query_get_shared_cache_info,480                     &RNBRemote::HandlePacket_jGetSharedCacheInfo, NULL,481                     "jGetSharedCacheInfo", "Replies with JSON data about the "482                                            "location and uuid of the shared "483                                            "cache in the inferior process."));484  t.push_back(Packet(start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode,485                     NULL, "QStartNoAckMode",486                     "Request that " DEBUGSERVER_PROGRAM_NAME487                     " stop acking remote protocol packets"));488  t.push_back(Packet(prefix_reg_packets_with_tid,489                     &RNBRemote::HandlePacket_QThreadSuffixSupported, NULL,490                     "QThreadSuffixSupported",491                     "Check if thread specific packets (register packets 'g', "492                     "'G', 'p', and 'P') support having the thread ID appended "493                     "to the end of the command"));494  t.push_back(Packet(set_logging_mode, &RNBRemote::HandlePacket_QSetLogging,495                     NULL, "QSetLogging:", "Turn on log channels in debugserver"));496  t.push_back(Packet(set_ignored_exceptions, &RNBRemote::HandlePacket_QSetIgnoredExceptions,497                     NULL, "QSetIgnoredExceptions:", "Set the exception types "498                                           "debugserver won't wait for, allowing "499                                           "them to be turned into the equivalent "500                                           "BSD signals by the normal means."));501  t.push_back(Packet(502      set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize, NULL,503      "QSetMaxPacketSize:",504      "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle"));505  t.push_back(Packet(506      set_max_payload_size, &RNBRemote::HandlePacket_QSetMaxPayloadSize, NULL,507      "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME508                             " the max sized payload gdb can handle"));509  t.push_back(510      Packet(set_environment_variable, &RNBRemote::HandlePacket_QEnvironment,511             NULL, "QEnvironment:",512             "Add an environment variable to the inferior's environment"));513  t.push_back(514      Packet(set_environment_variable_hex,515             &RNBRemote::HandlePacket_QEnvironmentHexEncoded, NULL,516             "QEnvironmentHexEncoded:",517             "Add an environment variable to the inferior's environment"));518  t.push_back(Packet(set_launch_arch, &RNBRemote::HandlePacket_QLaunchArch,519                     NULL, "QLaunchArch:", "Set the architecture to use when "520                                           "launching a process for hosts that "521                                           "can run multiple architecture "522                                           "slices from universal files."));523  t.push_back(Packet(set_disable_aslr, &RNBRemote::HandlePacket_QSetDisableASLR,524                     NULL, "QSetDisableASLR:",525                     "Set whether to disable ASLR when launching the process "526                     "with the set argv ('A') packet"));527  t.push_back(Packet(set_stdin, &RNBRemote::HandlePacket_QSetSTDIO, NULL,528                     "QSetSTDIN:", "Set the standard input for a process to be "529                                   "launched with the 'A' packet"));530  t.push_back(Packet(set_stdout, &RNBRemote::HandlePacket_QSetSTDIO, NULL,531                     "QSetSTDOUT:", "Set the standard output for a process to "532                                    "be launched with the 'A' packet"));533  t.push_back(Packet(set_stderr, &RNBRemote::HandlePacket_QSetSTDIO, NULL,534                     "QSetSTDERR:", "Set the standard error for a process to "535                                    "be launched with the 'A' packet"));536  t.push_back(Packet(set_working_dir, &RNBRemote::HandlePacket_QSetWorkingDir,537                     NULL, "QSetWorkingDir:", "Set the working directory for a "538                                              "process to be launched with the "539                                              "'A' packet"));540  t.push_back(Packet(set_list_threads_in_stop_reply,541                     &RNBRemote::HandlePacket_QListThreadsInStopReply, NULL,542                     "QListThreadsInStopReply",543                     "Set if the 'threads' key should be added to the stop "544                     "reply packets with a list of all thread IDs."));545  t.push_back(Packet(546      sync_thread_state, &RNBRemote::HandlePacket_QSyncThreadState, NULL,547      "QSyncThreadState:", "Do whatever is necessary to make sure 'thread' is "548                           "in a safe state to call functions on."));549  //  t.push_back (Packet (pass_signals_to_inferior,550  //  &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify551  //  which signals are passed to the inferior"));552  t.push_back(Packet(allocate_memory, &RNBRemote::HandlePacket_AllocateMemory,553                     NULL, "_M", "Allocate memory in the inferior process."));554  t.push_back(Packet(deallocate_memory,555                     &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m",556                     "Deallocate memory in the inferior process."));557  t.push_back(Packet(558      save_register_state, &RNBRemote::HandlePacket_SaveRegisterState, NULL,559      "QSaveRegisterState", "Save the register state for the current thread "560                            "and return a decimal save ID."));561  t.push_back(Packet(restore_register_state,562                     &RNBRemote::HandlePacket_RestoreRegisterState, NULL,563                     "QRestoreRegisterState:",564                     "Restore the register state given a save ID previously "565                     "returned from a call to QSaveRegisterState."));566  t.push_back(Packet(567      memory_region_info, &RNBRemote::HandlePacket_MemoryRegionInfo, NULL,568      "qMemoryRegionInfo", "Return size and attributes of a memory region that "569                           "contains the given address"));570  t.push_back(Packet(get_memory_tags, &RNBRemote::HandlePacket_qMemTags, NULL,571                     "qMemTags", "Return tags for a region of memory"));572  t.push_back(Packet(get_profile_data, &RNBRemote::HandlePacket_GetProfileData,573                     NULL, "qGetProfileData",574                     "Return profiling data of the current target."));575  t.push_back(Packet(set_enable_profiling,576                     &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL,577                     "QSetEnableAsyncProfiling",578                     "Enable or disable the profiling of current target."));579  t.push_back(Packet(enable_compression,580                     &RNBRemote::HandlePacket_QEnableCompression, NULL,581                     "QEnableCompression:",582                     "Enable compression for the remainder of the connection"));583  t.push_back(Packet(watchpoint_support_info,584                     &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL,585                     "qWatchpointSupportInfo",586                     "Return the number of supported hardware watchpoints"));587  t.push_back(Packet(set_process_event,588                     &RNBRemote::HandlePacket_QSetProcessEvent, NULL,589                     "QSetProcessEvent:", "Set a process event, to be passed "590                                          "to the process, can be set before "591                                          "the process is started, or after."));592  t.push_back(593      Packet(set_detach_on_error, &RNBRemote::HandlePacket_QSetDetachOnError,594             NULL, "QSetDetachOnError:",595             "Set whether debugserver will detach (1) or kill (0) from the "596             "process it is controlling if it loses connection to lldb."));597  t.push_back(Packet(598      speed_test, &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:",599      "Test the maximum speed at which packet can be sent/received."));600  t.push_back(Packet(query_transfer, &RNBRemote::HandlePacket_qXfer, NULL,601                     "qXfer:", "Support the qXfer packet."));602  t.push_back(Packet(json_query_dyld_process_state,603                     &RNBRemote::HandlePacket_jGetDyldProcessState, NULL,604                     "jGetDyldProcessState",605                     "Query the process state from dyld."));606}607 608void RNBRemote::FlushSTDIO() {609  if (m_ctx.HasValidProcessID()) {610    nub_process_t pid = m_ctx.ProcessID();611    char buf[256];612    nub_size_t count;613    do {614      count = DNBProcessGetAvailableSTDOUT(pid, buf, sizeof(buf));615      if (count > 0) {616        SendSTDOUTPacket(buf, count);617      }618    } while (count > 0);619 620    do {621      count = DNBProcessGetAvailableSTDERR(pid, buf, sizeof(buf));622      if (count > 0) {623        SendSTDERRPacket(buf, count);624      }625    } while (count > 0);626  }627}628 629void RNBRemote::SendAsyncProfileData() {630  if (m_ctx.HasValidProcessID()) {631    nub_process_t pid = m_ctx.ProcessID();632    char buf[1024];633    nub_size_t count;634    do {635      count = DNBProcessGetAvailableProfileData(pid, buf, sizeof(buf));636      if (count > 0) {637        SendAsyncProfileDataPacket(buf, count);638      }639    } while (count > 0);640  }641}642 643rnb_err_t RNBRemote::SendHexEncodedBytePacket(const char *header,644                                              const void *buf, size_t buf_len,645                                              const char *footer) {646  std::ostringstream packet_sstrm;647  // Append the header cstr if there was one648  if (header && header[0])649    packet_sstrm << header;650  nub_size_t i;651  const uint8_t *ubuf8 = (const uint8_t *)buf;652  for (i = 0; i < buf_len; i++) {653    packet_sstrm << RAWHEX8(ubuf8[i]);654  }655  // Append the footer cstr if there was one656  if (footer && footer[0])657    packet_sstrm << footer;658 659  return SendPacket(packet_sstrm.str());660}661 662rnb_err_t RNBRemote::SendSTDOUTPacket(char *buf, nub_size_t buf_size) {663  if (buf_size == 0)664    return rnb_success;665  return SendHexEncodedBytePacket("O", buf, buf_size, NULL);666}667 668rnb_err_t RNBRemote::SendSTDERRPacket(char *buf, nub_size_t buf_size) {669  if (buf_size == 0)670    return rnb_success;671  return SendHexEncodedBytePacket("O", buf, buf_size, NULL);672}673 674// This makes use of asynchronous bit 'A' in the gdb remote protocol.675rnb_err_t RNBRemote::SendAsyncProfileDataPacket(char *buf,676                                                nub_size_t buf_size) {677  if (buf_size == 0)678    return rnb_success;679 680  std::string packet("A");681  packet.append(buf, buf_size);682  return SendPacket(packet);683}684 685rnb_err_t686RNBRemote::SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary) {687  std::ostringstream stream;688  // We're choosing something that is easy to spot if we somehow get one689  // of these coming out at the wrong time (i.e. when the remote side690  // is not waiting for a process control completion response).691  stream << "JSON-async:";692  dictionary.DumpBinaryEscaped(stream);693  return SendPacket(stream.str());694}695 696// Given a std::string packet contents to send, possibly encode/compress it.697// If compression is enabled, the returned std::string will be in one of two698// forms:699//700//    N<original packet contents uncompressed>701//    C<size of original decompressed packet>:<packet compressed with the702//    requested compression scheme>703//704// If compression is not requested, the original packet contents are returned705 706std::string RNBRemote::CompressString(const std::string &orig) {707  std::string compressed;708  compression_types compression_type = GetCompressionType();709  if (compression_type != compression_types::none) {710    bool compress_this_packet = false;711 712    if (orig.size() > m_compression_minsize) {713      compress_this_packet = true;714    }715 716    if (compress_this_packet) {717      const size_t encoded_data_buf_size = orig.size() + 128;718      std::vector<uint8_t> encoded_data(encoded_data_buf_size);719      size_t compressed_size = 0;720 721      // Allocate a scratch buffer for libcompression the first722      // time we see a different compression type; reuse it in 723      // all compression_encode_buffer calls so it doesn't need724      // to allocate / free its own scratch buffer each time.725      // This buffer will only be freed when compression type726      // changes; otherwise it will persist until debugserver727      // exit.728 729      static compression_types g_libcompress_scratchbuf_type = compression_types::none;730      static void *g_libcompress_scratchbuf = nullptr;731 732      if (g_libcompress_scratchbuf_type != compression_type) {733        if (g_libcompress_scratchbuf) {734          free (g_libcompress_scratchbuf);735          g_libcompress_scratchbuf = nullptr;736        }737        size_t scratchbuf_size = 0;738        switch (compression_type) {739          case compression_types::lz4: 740            scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZ4_RAW);741            break;742          case compression_types::zlib_deflate: 743            scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_ZLIB);744            break;745          case compression_types::lzma: 746            scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZMA);747            break;748          case compression_types::lzfse: 749            scratchbuf_size = compression_encode_scratch_buffer_size (COMPRESSION_LZFSE);750            break;751          default:752            break;753        }754        if (scratchbuf_size > 0) {755          g_libcompress_scratchbuf = (void*) malloc (scratchbuf_size);756          g_libcompress_scratchbuf_type = compression_type;757        }758      }759 760      if (compression_type == compression_types::lz4) {761        compressed_size = compression_encode_buffer(762            encoded_data.data(), encoded_data_buf_size,763            (const uint8_t *)orig.c_str(), orig.size(), 764            g_libcompress_scratchbuf,765            COMPRESSION_LZ4_RAW);766      }767      if (compression_type == compression_types::zlib_deflate) {768        compressed_size = compression_encode_buffer(769            encoded_data.data(), encoded_data_buf_size,770            (const uint8_t *)orig.c_str(), orig.size(), 771            g_libcompress_scratchbuf,772            COMPRESSION_ZLIB);773      }774      if (compression_type == compression_types::lzma) {775        compressed_size = compression_encode_buffer(776            encoded_data.data(), encoded_data_buf_size,777            (const uint8_t *)orig.c_str(), orig.size(), 778            g_libcompress_scratchbuf,779            COMPRESSION_LZMA);780      }781      if (compression_type == compression_types::lzfse) {782        compressed_size = compression_encode_buffer(783            encoded_data.data(), encoded_data_buf_size,784            (const uint8_t *)orig.c_str(), orig.size(), 785            g_libcompress_scratchbuf,786            COMPRESSION_LZFSE);787      }788 789      if (compressed_size > 0) {790        compressed.clear();791        compressed.reserve(compressed_size);792        compressed = "C";793        char numbuf[16];794        snprintf(numbuf, sizeof(numbuf), "%zu:", orig.size());795        numbuf[sizeof(numbuf) - 1] = '\0';796        compressed.append(numbuf);797 798        for (size_t i = 0; i < compressed_size; i++) {799          uint8_t byte = encoded_data[i];800          if (byte == '#' || byte == '$' || byte == '}' || byte == '*' ||801              byte == '\0') {802            compressed.push_back(0x7d);803            compressed.push_back(byte ^ 0x20);804          } else {805            compressed.push_back(byte);806          }807        }808      } else {809        compressed = "N" + orig;810      }811    } else {812      compressed = "N" + orig;813    }814  } else {815    compressed = orig;816  }817 818  return compressed;819}820 821rnb_err_t RNBRemote::SendPacket(const std::string &s) {822  DNBLogThreadedIf(LOG_RNB_MAX, "%8d RNBRemote::%s (%s) called",823                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),824                   __FUNCTION__, s.c_str());825 826  std::string s_compressed = CompressString(s);827 828  std::string sendpacket = "$" + s_compressed + "#";829  int cksum = 0;830  char hexbuf[5];831 832  if (m_noack_mode) {833    sendpacket += "00";834  } else {835    for (size_t i = 0; i != s_compressed.size(); ++i)836      cksum += s_compressed[i];837    snprintf(hexbuf, sizeof hexbuf, "%02x", cksum & 0xff);838    sendpacket += hexbuf;839  }840 841  rnb_err_t err = m_comm.Write(sendpacket.c_str(), sendpacket.size());842  if (err != rnb_success)843    return err;844 845  if (m_noack_mode)846    return rnb_success;847 848  std::string reply;849  RNBRemote::Packet packet;850  err = GetPacket(reply, packet, true);851 852  if (err != rnb_success) {853    DNBLogThreadedIf(LOG_RNB_REMOTE,854                     "%8d RNBRemote::%s (%s) got error trying to get reply...",855                     (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),856                     __FUNCTION__, sendpacket.c_str());857    return err;858  }859 860  DNBLogThreadedIf(LOG_RNB_MAX, "%8d RNBRemote::%s (%s) got reply: '%s'",861                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),862                   __FUNCTION__, sendpacket.c_str(), reply.c_str());863 864  if (packet.type == ack)865    return rnb_success;866 867  // Should we try to resend the packet at this layer?868  //  if (packet.command == nack)869  return rnb_err;870}871 872rnb_err_t RNBRemote::SendErrorPacket(std::string errcode,873                                     const std::string &errmsg) {874  if (m_enable_error_strings && !errmsg.empty()) {875    errcode += ";";876    errcode += cstring_to_asciihex_string(errmsg.c_str());877  }878  return SendPacket(errcode);879}880 881/* Get a packet via gdb remote protocol.882 Strip off the prefix/suffix, verify the checksum to make sure883 a valid packet was received, send an ACK if they match.  */884 885rnb_err_t RNBRemote::GetPacketPayload(std::string &return_packet) {886  // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s called",887  // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);888 889  {890    std::lock_guard<std::mutex> guard(m_mutex);891    if (m_rx_packets.empty()) {892      // Only reset the remote command available event if we have no more893      // packets894      m_ctx.Events().ResetEvents(RNBContext::event_read_packet_available);895      // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s error: no packets896      // available...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),897      // __FUNCTION__);898      return rnb_err;899    }900 901    // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s has %u queued packets",902    // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__,903    // m_rx_packets.size());904    return_packet.swap(m_rx_packets.front());905    m_rx_packets.pop_front();906 907    if (m_rx_packets.empty()) {908      // Reset the remote command available event if we have no more packets909      m_ctx.Events().ResetEvents(RNBContext::event_read_packet_available);910    }911  }912 913  // DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s: '%s'",914  // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__,915  // return_packet.c_str());916 917  switch (return_packet[0]) {918  case '+':919  case '-':920  case '\x03':921    break;922 923  case '$': {924    long packet_checksum = 0;925    if (!m_noack_mode) {926      for (size_t i = return_packet.size() - 2; i < return_packet.size(); ++i) {927        char checksum_char = tolower(return_packet[i]);928        if (!isxdigit(checksum_char)) {929          m_comm.Write("-", 1);930          DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s error: packet "931                                           "with invalid checksum characters: "932                                           "%s",933                           (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),934                           __FUNCTION__, return_packet.c_str());935          return rnb_err;936        }937      }938      packet_checksum =939          strtol(&return_packet[return_packet.size() - 2], NULL, 16);940    }941 942    return_packet.erase(0, 1);                     // Strip the leading '$'943    return_packet.erase(return_packet.size() - 3); // Strip the #XX checksum944 945    if (!m_noack_mode) {946      // Compute the checksum947      int computed_checksum = 0;948      for (std::string::iterator it = return_packet.begin();949           it != return_packet.end(); ++it) {950        computed_checksum += *it;951      }952 953      if (packet_checksum == (computed_checksum & 0xff)) {954        // DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for955        // '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),956        // __FUNCTION__, return_packet.c_str());957        m_comm.Write("+", 1);958      } else {959        DNBLogThreadedIf(960            LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s' (error: "961                            "packet checksum mismatch  (0x%2.2lx != 0x%2.2x))",962            (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__,963            return_packet.c_str(), packet_checksum, computed_checksum);964        m_comm.Write("-", 1);965        return rnb_err;966      }967    }968  } break;969 970  default:971    DNBLogThreadedIf(LOG_RNB_REMOTE,972                     "%8u RNBRemote::%s tossing unexpected packet???? %s",973                     (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),974                     __FUNCTION__, return_packet.c_str());975    if (!m_noack_mode)976      m_comm.Write("-", 1);977    return rnb_err;978  }979 980  return rnb_success;981}982 983rnb_err_t RNBRemote::HandlePacket_UNIMPLEMENTED(const char *p) {984  DNBLogThreadedIf(LOG_RNB_MAX, "%8u RNBRemote::%s(\"%s\")",985                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),986                   __FUNCTION__, p ? p : "NULL");987  return SendPacket("");988}989 990rnb_err_t RNBRemote::HandlePacket_ILLFORMED(const char *file, int line,991                                            const char *p,992                                            const char *description) {993  DNBLogThreadedIf(LOG_RNB_PACKETS, "%8u %s:%i ILLFORMED: '%s' (%s)",994                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), file,995                   line, __FUNCTION__, p);996  return SendErrorPacket("E03");997}998 999rnb_err_t RNBRemote::GetPacket(std::string &packet_payload,1000                               RNBRemote::Packet &packet_info, bool wait) {1001  std::string payload;1002  rnb_err_t err = GetPacketPayload(payload);1003  if (err != rnb_success) {1004    PThreadEvent &events = m_ctx.Events();1005    nub_event_t set_events = events.GetEventBits();1006    // TODO: add timeout version of GetPacket?? We would then need to pass1007    // that timeout value along to DNBProcessTimedWaitForEvent.1008    if (!wait || ((set_events & RNBContext::event_read_thread_running) == 0))1009      return err;1010 1011    const nub_event_t events_to_wait_for =1012        RNBContext::event_read_packet_available |1013        RNBContext::event_read_thread_exiting;1014 1015    while ((set_events = events.WaitForSetEvents(events_to_wait_for)) != 0) {1016      if (set_events & RNBContext::event_read_packet_available) {1017        // Try the queue again now that we got an event1018        err = GetPacketPayload(payload);1019        if (err == rnb_success)1020          break;1021      }1022 1023      if (set_events & RNBContext::event_read_thread_exiting)1024        err = rnb_not_connected;1025 1026      if (err == rnb_not_connected)1027        return err;1028    }1029    while (err == rnb_err)1030      ;1031 1032    if (set_events == 0)1033      err = rnb_not_connected;1034  }1035 1036  if (err == rnb_success) {1037    Packet::iterator it;1038    for (it = m_packets.begin(); it != m_packets.end(); ++it) {1039      if (payload.compare(0, it->abbrev.size(), it->abbrev) == 0)1040        break;1041    }1042 1043    // A packet we don't have an entry for. This can happen when we1044    // get a packet that we don't know about or support. We just reply1045    // accordingly and go on.1046    if (it == m_packets.end()) {1047      DNBLogThreadedIf(LOG_RNB_PACKETS, "unimplemented packet: '%s'",1048                       payload.c_str());1049      HandlePacket_UNIMPLEMENTED(payload.c_str());1050      return rnb_err;1051    } else {1052      packet_info = *it;1053      packet_payload = payload;1054    }1055  }1056  return err;1057}1058 1059rnb_err_t RNBRemote::HandleAsyncPacket(PacketEnum *type) {1060  DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s",1061                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1062                   __FUNCTION__);1063  static DNBTimer g_packetTimer(true);1064  rnb_err_t err = rnb_err;1065  std::string packet_data;1066  RNBRemote::Packet packet_info;1067  err = GetPacket(packet_data, packet_info, false);1068 1069  if (err == rnb_success) {1070    if (!packet_data.empty() && isprint(packet_data[0]))1071      DNBLogThreadedIf(LOG_RNB_REMOTE | LOG_RNB_PACKETS,1072                       "HandleAsyncPacket (\"%s\");", packet_data.c_str());1073    else1074      DNBLogThreadedIf(LOG_RNB_REMOTE | LOG_RNB_PACKETS,1075                       "HandleAsyncPacket (%s);",1076                       packet_info.printable_name.c_str());1077 1078    HandlePacketCallback packet_callback = packet_info.async;1079    if (packet_callback != NULL) {1080      if (type != NULL)1081        *type = packet_info.type;1082      return (this->*packet_callback)(packet_data.c_str());1083    }1084  }1085 1086  return err;1087}1088 1089rnb_err_t RNBRemote::HandleReceivedPacket(PacketEnum *type) {1090  static DNBTimer g_packetTimer(true);1091 1092  rnb_err_t err = rnb_err;1093  std::string packet_data;1094  RNBRemote::Packet packet_info;1095  err = GetPacket(packet_data, packet_info, false);1096 1097  if (err == rnb_success) {1098    DNBLogThreadedIf(LOG_RNB_REMOTE, "HandleReceivedPacket (\"%s\");",1099                     packet_data.c_str());1100    HandlePacketCallback packet_callback = packet_info.normal;1101    if (packet_callback != NULL) {1102      if (type != NULL)1103        *type = packet_info.type;1104      return (this->*packet_callback)(packet_data.c_str());1105    } else {1106      // Do not fall through to end of this function, if we have valid1107      // packet_info and it has a NULL callback, then we need to respect1108      // that it may not want any response or anything to be done.1109      return err;1110    }1111  }1112  return rnb_err;1113}1114 1115void RNBRemote::CommDataReceived(const std::string &new_data) {1116  //  DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called",1117  //  (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);1118 1119  // Put the packet data into the buffer in a thread safe fashion1120  std::lock_guard<std::mutex> guard(m_mutex);1121 1122  std::string data;1123  // See if we have any left over data from a previous call to this1124  // function?1125  if (!m_rx_partial_data.empty()) {1126    // We do, so lets start with that data1127    data.swap(m_rx_partial_data);1128  }1129  // Append the new incoming data1130  data += new_data;1131 1132  // Parse up the packets into gdb remote packets1133  size_t idx = 0;1134  const size_t data_size = data.size();1135 1136  while (idx < data_size) {1137    // end_idx must be one past the last valid packet byte. Start1138    // it off with an invalid value that is the same as the current1139    // index.1140    size_t end_idx = idx;1141 1142    switch (data[idx]) {1143    case '+':            // Look for ack1144    case '-':            // Look for cancel1145    case '\x03':         // ^C to halt target1146      end_idx = idx + 1; // The command is one byte long...1147      break;1148 1149    case '$':1150      // Look for a standard gdb packet?1151      end_idx = data.find('#', idx + 1);1152      if (end_idx == std::string::npos || end_idx + 3 > data_size) {1153        end_idx = std::string::npos;1154      } else {1155        // Add two for the checksum bytes and 1 to point to the1156        // byte just past the end of this packet1157        end_idx += 3;1158      }1159      break;1160 1161    default:1162      break;1163    }1164 1165    if (end_idx == std::string::npos) {1166      // Not all data may be here for the packet yet, save it for1167      // next time through this function.1168      m_rx_partial_data += data.substr(idx);1169      // DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s saving data for1170      // later[%u, npos):1171      // '%s'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1172      // __FUNCTION__, idx, m_rx_partial_data.c_str());1173      idx = end_idx;1174    } else if (idx < end_idx) {1175      m_packets_recvd++;1176      // Hack to get rid of initial '+' ACK???1177      if (m_packets_recvd == 1 && (end_idx == idx + 1) && data[idx] == '+') {1178        // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s throwing first1179        // ACK away....[%u, npos):1180        // '+'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1181        // __FUNCTION__, idx);1182      } else {1183        // We have a valid packet...1184        m_rx_packets.push_back(data.substr(idx, end_idx - idx));1185        DNBLogThreadedIf(LOG_RNB_PACKETS, "getpkt: %s",1186                         m_rx_packets.back().c_str());1187      }1188      idx = end_idx;1189    } else {1190      DNBLogThreadedIf(LOG_RNB_MAX, "%8d RNBRemote::%s tossing junk byte at %c",1191                       (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1192                       __FUNCTION__, data[idx]);1193      idx = idx + 1;1194    }1195  }1196 1197  if (!m_rx_packets.empty()) {1198    // Let the main thread know we have received a packet1199 1200    // DNBLogThreadedIf (LOG_RNB_EVENTS, "%8d RNBRemote::%s   called1201    // events.SetEvent(RNBContext::event_read_packet_available)",1202    // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);1203    PThreadEvent &events = m_ctx.Events();1204    events.SetEvents(RNBContext::event_read_packet_available);1205  }1206}1207 1208rnb_err_t RNBRemote::GetCommData() {1209  //  DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called",1210  //  (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__);1211  std::string comm_data;1212  rnb_err_t err = m_comm.Read(comm_data);1213  if (err == rnb_success) {1214    if (!comm_data.empty())1215      CommDataReceived(comm_data);1216  }1217  return err;1218}1219 1220void RNBRemote::StartReadRemoteDataThread() {1221  DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s called",1222                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1223                   __FUNCTION__);1224  PThreadEvent &events = m_ctx.Events();1225  if ((events.GetEventBits() & RNBContext::event_read_thread_running) == 0) {1226    events.ResetEvents(RNBContext::event_read_thread_exiting);1227    int err = ::pthread_create(&m_rx_pthread, NULL,1228                               ThreadFunctionReadRemoteData, this);1229    if (err == 0) {1230      // Our thread was successfully kicked off, wait for it to1231      // set the started event so we can safely continue1232      events.WaitForSetEvents(RNBContext::event_read_thread_running);1233    } else {1234      events.ResetEvents(RNBContext::event_read_thread_running);1235      events.SetEvents(RNBContext::event_read_thread_exiting);1236    }1237  }1238}1239 1240void RNBRemote::StopReadRemoteDataThread() {1241  DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s called",1242                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),1243                   __FUNCTION__);1244  PThreadEvent &events = m_ctx.Events();1245  if ((events.GetEventBits() & RNBContext::event_read_thread_running) ==1246      RNBContext::event_read_thread_running) {1247    DNBLog("debugserver about to shut down packet communications to lldb.");1248    m_comm.Disconnect(true);1249    struct timespec timeout_abstime;1250    DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);1251 1252    // Wait for 2 seconds for the remote data thread to exit1253    if (events.WaitForSetEvents(RNBContext::event_read_thread_exiting,1254                                &timeout_abstime) == 0) {1255      // Kill the remote data thread???1256    }1257  }1258}1259 1260void *RNBRemote::ThreadFunctionReadRemoteData(void *arg) {1261  // Keep a shared pointer reference so this doesn't go away on us before the1262  // thread is killed.1263  DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread starting...",1264                   __FUNCTION__, arg);1265  RNBRemoteSP remoteSP(g_remoteSP);1266  if (remoteSP.get() != NULL) {1267 1268#if defined(__APPLE__)1269    pthread_setname_np("read gdb-remote packets thread");1270#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)1271    struct sched_param thread_param;1272    int thread_sched_policy;1273    if (pthread_getschedparam(pthread_self(), &thread_sched_policy,1274                              &thread_param) == 0) {1275      thread_param.sched_priority = 47;1276      pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);1277    }1278#endif1279#endif1280 1281    RNBRemote *remote = remoteSP.get();1282    PThreadEvent &events = remote->Context().Events();1283    events.SetEvents(RNBContext::event_read_thread_running);1284    // START: main receive remote command thread loop1285    bool done = false;1286    while (!done) {1287      rnb_err_t err = remote->GetCommData();1288 1289      switch (err) {1290      case rnb_success:1291        break;1292 1293      case rnb_err:1294        DNBLogThreadedIf(LOG_RNB_REMOTE,1295                         "RNBSocket::GetCommData returned error %u", err);1296        done = true;1297        break;1298 1299      case rnb_not_connected:1300        DNBLogThreadedIf(LOG_RNB_REMOTE,1301                         "RNBSocket::GetCommData returned not connected...");1302        done = true;1303        break;1304      }1305    }1306    // START: main receive remote command thread loop1307    events.ResetEvents(RNBContext::event_read_thread_running);1308    events.SetEvents(RNBContext::event_read_thread_exiting);1309  }1310  DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread exiting...",1311                   __FUNCTION__, arg);1312  return NULL;1313}1314 1315// If we fail to get back a valid CPU type for the remote process,1316// make a best guess for the CPU type based on the currently running1317// debugserver binary -- the debugger may not handle the case of an1318// un-specified process CPU type correctly.1319 1320static cpu_type_t best_guess_cpu_type() {1321#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)1322  if (sizeof(char *) == 8) {1323    return CPU_TYPE_ARM64;1324  } else {1325#if defined (__ARM64_ARCH_8_32__)1326    return CPU_TYPE_ARM64_32;1327#endif1328    return CPU_TYPE_ARM;1329  }1330#elif defined(__i386__) || defined(__x86_64__)1331  if (sizeof(char *) == 8) {1332    return CPU_TYPE_X86_64;1333  } else {1334    return CPU_TYPE_I386;1335  }1336#endif1337  return 0;1338}1339 1340/* Read the bytes in STR which are GDB Remote Protocol binary encoded bytes1341 (8-bit bytes).1342 This encoding uses 0x7d ('}') as an escape character for1343 0x7d ('}'), 0x23 ('#'), 0x24 ('$'), 0x2a ('*').1344 LEN is the number of bytes to be processed.  If a character is escaped,1345 it is 2 characters for LEN.  A LEN of -1 means decode-until-nul-byte1346 (end of string).  */1347static std::vector<uint8_t> decode_binary_data(const char *str, size_t len) {1348  std::vector<uint8_t> bytes;1349  if (len == 0) {1350    return bytes;1351  }1352  if (len == (size_t)-1)1353    len = strlen(str);1354 1355  while (len--) {1356    unsigned char c = *str++;1357    if (c == 0x7d && len > 0) {1358      len--;1359      c = *str++ ^ 0x20;1360    }1361    bytes.push_back(c);1362  }1363  return bytes;1364}1365 1366// If the value side of a key-value pair in JSON is a string,1367// and that string has a " character in it, the " character must1368// be escaped.1369static std::string json_string_quote_metachars(const std::string &s) {1370  if (s.find('"') == std::string::npos)1371    return s;1372 1373  std::string output;1374  const size_t s_size = s.size();1375  const char *s_chars = s.c_str();1376  for (size_t i = 0; i < s_size; i++) {1377    unsigned char ch = *(s_chars + i);1378    if (ch == '"') {1379      output.push_back('\\');1380    }1381    output.push_back(ch);1382  }1383  return output;1384}1385 1386typedef struct register_map_entry {1387  uint32_t debugserver_regnum; // debugserver register number1388  uint32_t offset; // Offset in bytes into the register context data with no1389                   // padding between register values1390  DNBRegisterInfo nub_info; // debugnub register info1391  std::vector<uint32_t> value_regnums;1392  std::vector<uint32_t> invalidate_regnums;1393} register_map_entry_t;1394 1395// If the notion of registers differs from what is handed out by the1396// architecture, then flavors can be defined here.1397 1398static std::vector<register_map_entry_t> g_dynamic_register_map;1399static register_map_entry_t *g_reg_entries = NULL;1400static size_t g_num_reg_entries = 0;1401 1402void RNBRemote::Initialize() { DNBInitialize(); }1403 1404bool RNBRemote::InitializeRegisters(bool force) {1405  pid_t pid = m_ctx.ProcessID();1406  if (pid == INVALID_NUB_PROCESS)1407    return false;1408 1409  DNBLogThreadedIf(1410      LOG_RNB_PROC,1411      "RNBRemote::%s() getting native registers from DNB interface",1412      __FUNCTION__);1413  // Discover the registers by querying the DNB interface and letting it1414  // state the registers that it would like to export. This allows the1415  // registers to be discovered using multiple qRegisterInfo calls to get1416  // all register information after the architecture for the process is1417  // determined.1418  if (force) {1419    g_dynamic_register_map.clear();1420    g_reg_entries = NULL;1421    g_num_reg_entries = 0;1422  }1423 1424  if (g_dynamic_register_map.empty()) {1425    nub_size_t num_reg_sets = 0;1426    const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo(&num_reg_sets);1427 1428    assert(num_reg_sets > 0 && reg_sets != NULL);1429 1430    uint32_t regnum = 0;1431    uint32_t reg_data_offset = 0;1432    typedef std::map<std::string, uint32_t> NameToRegNum;1433    NameToRegNum name_to_regnum;1434    for (nub_size_t set = 0; set < num_reg_sets; ++set) {1435      if (reg_sets[set].registers == NULL)1436        continue;1437 1438      for (uint32_t reg = 0; reg < reg_sets[set].num_registers; ++reg) {1439        register_map_entry_t reg_entry = {1440            regnum++, // register number starts at zero and goes up with no gaps1441            reg_data_offset, // Offset into register context data, no gaps1442                             // between registers1443            reg_sets[set].registers[reg], // DNBRegisterInfo1444            {},1445            {},1446        };1447 1448        name_to_regnum[reg_entry.nub_info.name] = reg_entry.debugserver_regnum;1449 1450        if (reg_entry.nub_info.value_regs == NULL) {1451          reg_data_offset += reg_entry.nub_info.size;1452        }1453 1454        g_dynamic_register_map.push_back(reg_entry);1455      }1456    }1457 1458    // Now we must find any registers whose values are in other registers and1459    // fix up1460    // the offsets since we removed all gaps...1461    for (auto &reg_entry : g_dynamic_register_map) {1462      if (reg_entry.nub_info.value_regs) {1463        uint32_t new_offset = UINT32_MAX;1464        for (size_t i = 0; reg_entry.nub_info.value_regs[i] != NULL; ++i) {1465          const char *name = reg_entry.nub_info.value_regs[i];1466          auto pos = name_to_regnum.find(name);1467          if (pos != name_to_regnum.end()) {1468            regnum = pos->second;1469            reg_entry.value_regnums.push_back(regnum);1470            if (regnum < g_dynamic_register_map.size()) {1471              // The offset for value_regs registers is the offset within the1472              // register with the lowest offset1473              const uint32_t reg_offset =1474                  g_dynamic_register_map[regnum].offset +1475                  reg_entry.nub_info.offset;1476              if (new_offset > reg_offset)1477                new_offset = reg_offset;1478            }1479          }1480        }1481 1482        if (new_offset != UINT32_MAX) {1483          reg_entry.offset = new_offset;1484        } else {1485          DNBLogThreaded("no offset was calculated entry for register %s",1486                         reg_entry.nub_info.name);1487          reg_entry.offset = UINT32_MAX;1488        }1489      }1490 1491      if (reg_entry.nub_info.update_regs) {1492        for (size_t i = 0; reg_entry.nub_info.update_regs[i] != NULL; ++i) {1493          const char *name = reg_entry.nub_info.update_regs[i];1494          auto pos = name_to_regnum.find(name);1495          if (pos != name_to_regnum.end()) {1496            regnum = pos->second;1497            reg_entry.invalidate_regnums.push_back(regnum);1498          }1499        }1500      }1501    }1502 1503    g_reg_entries = g_dynamic_register_map.data();1504    g_num_reg_entries = g_dynamic_register_map.size();1505  }1506  return true;1507}1508 1509/* The inferior has stopped executing; send a packet1510 to gdb to let it know.  */1511 1512void RNBRemote::NotifyThatProcessStopped(void) {1513  RNBRemote::HandlePacket_last_signal(NULL);1514}1515 1516/* 'A arglen,argnum,arg,...'1517 Update the inferior context CTX with the program name and arg1518 list.1519 The documentation for this packet is underwhelming but my best reading1520 of this is that it is a series of (len, position #, arg)'s, one for1521 each argument with "arg" hex encoded (two 0-9a-f chars?).1522 Why we need BOTH a "len" and a hex encoded "arg" is beyond me - either1523 is sufficient to get around the "," position separator escape issue.1524 1525 e.g. our best guess for a valid 'A' packet for "gdb -q a.out" is1526 1527 6,0,676462,4,1,2d71,10,2,612e6f75741528 1529 Note that "argnum" and "arglen" are numbers in base 10.  Again, that's1530 not documented either way but I'm assuming it's so.  */1531 1532rnb_err_t RNBRemote::HandlePacket_A(const char *p) {1533  if (p == NULL || *p == '\0') {1534    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1535                                  "Null packet for 'A' pkt");1536  }1537  p++;1538  if (*p == '\0' || !isdigit(*p)) {1539    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1540                                  "arglen not specified on 'A' pkt");1541  }1542 1543  /* I promise I don't modify it anywhere in this function.  strtoul()'s1544   2nd arg has to be non-const which makes it problematic to step1545   through the string easily.  */1546  char *buf = const_cast<char *>(p);1547 1548  RNBContext &ctx = Context();1549 1550  while (*buf != '\0') {1551    unsigned long arglen, argnum;1552    std::string arg;1553    char *c;1554 1555    errno = 0;1556    arglen = strtoul(buf, &c, 10);1557    if (errno != 0 && arglen == 0) {1558      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1559                                    "arglen not a number on 'A' pkt");1560    }1561    if (*c != ',') {1562      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1563                                    "arglen not followed by comma on 'A' pkt");1564    }1565    buf = c + 1;1566 1567    errno = 0;1568    argnum = strtoul(buf, &c, 10);1569    if (errno != 0 && argnum == 0) {1570      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1571                                    "argnum not a number on 'A' pkt");1572    }1573    if (*c != ',') {1574      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1575                                    "arglen not followed by comma on 'A' pkt");1576    }1577    buf = c + 1;1578 1579    c = buf;1580    buf = buf + arglen;1581    while (c < buf && *c != '\0' && c + 1 < buf && *(c + 1) != '\0') {1582      char smallbuf[3];1583      smallbuf[0] = *c;1584      smallbuf[1] = *(c + 1);1585      smallbuf[2] = '\0';1586 1587      errno = 0;1588      int ch = static_cast<int>(strtoul(smallbuf, NULL, 16));1589      if (errno != 0 && ch == 0) {1590        return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1591                                      "non-hex char in arg on 'A' pkt");1592      }1593 1594      arg.push_back(ch);1595      c += 2;1596    }1597 1598    ctx.PushArgument(arg.c_str());1599    if (*buf == ',')1600      buf++;1601  }1602  SendPacket("OK");1603 1604  return rnb_success;1605}1606 1607/* 'H c t'1608 Set the thread for subsequent actions; 'c' for step/continue ops,1609 'g' for other ops.  -1 means all threads, 0 means any thread.  */1610 1611rnb_err_t RNBRemote::HandlePacket_H(const char *p) {1612  p++; // skip 'H'1613  if (*p != 'c' && *p != 'g') {1614    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1615                                  "Missing 'c' or 'g' type in H packet");1616  }1617 1618  if (!m_ctx.HasValidProcessID()) {1619    // We allow gdb to connect to a server that hasn't started running1620    // the target yet.  gdb still wants to ask questions about it and1621    // freaks out if it gets an error.  So just return OK here.1622  }1623 1624  errno = 0;1625  nub_thread_t tid = strtoul(p + 1, NULL, 16);1626  if (errno != 0 && tid == 0) {1627    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1628                                  "Invalid thread number in H packet");1629  }1630  if (*p == 'c')1631    SetContinueThread(tid);1632  if (*p == 'g')1633    SetCurrentThread(tid);1634 1635  return SendPacket("OK");1636}1637 1638rnb_err_t RNBRemote::HandlePacket_qLaunchSuccess(const char *p) {1639  if (m_ctx.HasValidProcessID() || m_ctx.LaunchStatus().Status() == 0)1640    return SendPacket("OK");1641  std::string status_str;1642  return SendErrorPacket("E89", m_ctx.LaunchStatusAsString(status_str));1643}1644 1645rnb_err_t RNBRemote::HandlePacket_qShlibInfoAddr(const char *p) {1646  if (m_ctx.HasValidProcessID()) {1647    nub_addr_t shlib_info_addr =1648        DNBProcessGetSharedLibraryInfoAddress(m_ctx.ProcessID());1649    if (shlib_info_addr != INVALID_NUB_ADDRESS) {1650      std::ostringstream ostrm;1651      ostrm << RAW_HEXBASE << shlib_info_addr;1652      return SendPacket(ostrm.str());1653    }1654  }1655  return SendErrorPacket("E44");1656}1657 1658rnb_err_t RNBRemote::HandlePacket_qStepPacketSupported(const char *p) {1659  // Normally the "s" packet is mandatory, yet in gdb when using ARM, they1660  // get around the need for this packet by implementing software single1661  // stepping from gdb. Current versions of debugserver do support the "s"1662  // packet, yet some older versions do not. We need a way to tell if this1663  // packet is supported so we can disable software single stepping in gdb1664  // for remote targets (so the "s" packet will get used).1665  return SendPacket("OK");1666}1667 1668rnb_err_t RNBRemote::HandlePacket_qSyncThreadStateSupported(const char *p) {1669  // We support attachOrWait meaning attach if the process exists, otherwise1670  // wait to attach.1671  return SendPacket("OK");1672}1673 1674rnb_err_t RNBRemote::HandlePacket_qVAttachOrWaitSupported(const char *p) {1675  // We support attachOrWait meaning attach if the process exists, otherwise1676  // wait to attach.1677  return SendPacket("OK");1678}1679 1680rnb_err_t RNBRemote::HandlePacket_qThreadStopInfo(const char *p) {1681  p += strlen("qThreadStopInfo");1682  nub_thread_t tid = strtoul(p, 0, 16);1683  return SendStopReplyPacketForThread(tid);1684}1685 1686rnb_err_t RNBRemote::HandlePacket_qThreadInfo(const char *p) {1687  // We allow gdb to connect to a server that hasn't started running1688  // the target yet.  gdb still wants to ask questions about it and1689  // freaks out if it gets an error.  So just return OK here.1690  nub_process_t pid = m_ctx.ProcessID();1691  if (pid == INVALID_NUB_PROCESS)1692    return SendPacket("OK");1693 1694  // Only "qfThreadInfo" and "qsThreadInfo" get into this function so1695  // we only need to check the second byte to tell which is which1696  if (p[1] == 'f') {1697    nub_size_t numthreads = DNBProcessGetNumThreads(pid);1698    std::ostringstream ostrm;1699    ostrm << "m";1700    bool first = true;1701    for (nub_size_t i = 0; i < numthreads; ++i) {1702      if (first)1703        first = false;1704      else1705        ostrm << ",";1706      nub_thread_t th = DNBProcessGetThreadAtIndex(pid, i);1707      ostrm << std::hex << th;1708    }1709    return SendPacket(ostrm.str());1710  } else {1711    return SendPacket("l");1712  }1713}1714 1715rnb_err_t RNBRemote::HandlePacket_qThreadExtraInfo(const char *p) {1716  // We allow gdb to connect to a server that hasn't started running1717  // the target yet.  gdb still wants to ask questions about it and1718  // freaks out if it gets an error.  So just return OK here.1719  nub_process_t pid = m_ctx.ProcessID();1720  if (pid == INVALID_NUB_PROCESS)1721    return SendPacket("OK");1722 1723  /* This is supposed to return a string like 'Runnable' or1724   'Blocked on Mutex'.1725   The returned string is formatted like the "A" packet - a1726   sequence of letters encoded in as 2-hex-chars-per-letter.  */1727  p += strlen("qThreadExtraInfo");1728  if (*p++ != ',')1729    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1730                                  "Illformed qThreadExtraInfo packet");1731  errno = 0;1732  nub_thread_t tid = strtoul(p, NULL, 16);1733  if (errno != 0 && tid == 0) {1734    return HandlePacket_ILLFORMED(1735        __FILE__, __LINE__, p,1736        "Invalid thread number in qThreadExtraInfo packet");1737  }1738 1739  const char *threadInfo = DNBThreadGetInfo(pid, tid);1740  if (threadInfo != NULL && threadInfo[0]) {1741    return SendHexEncodedBytePacket(NULL, threadInfo, strlen(threadInfo), NULL);1742  } else {1743    // "OK" == 4f6b1744    // Return "OK" as a ASCII hex byte stream if things go wrong1745    return SendPacket("4f6b");1746  }1747 1748  return SendPacket("");1749}1750 1751static const char *k_space_delimiters = " \t";1752static void skip_spaces(std::string &line) {1753  if (!line.empty()) {1754    size_t space_pos = line.find_first_not_of(k_space_delimiters);1755    if (space_pos > 0)1756      line.erase(0, space_pos);1757  }1758}1759 1760static std::string get_identifier(std::string &line) {1761  std::string word;1762  skip_spaces(line);1763  const size_t line_size = line.size();1764  size_t end_pos;1765  for (end_pos = 0; end_pos < line_size; ++end_pos) {1766    if (end_pos == 0) {1767      if (isalpha(line[end_pos]) || line[end_pos] == '_')1768        continue;1769    } else if (isalnum(line[end_pos]) || line[end_pos] == '_')1770      continue;1771    break;1772  }1773  word.assign(line, 0, end_pos);1774  line.erase(0, end_pos);1775  return word;1776}1777 1778static std::string get_operator(std::string &line) {1779  std::string op;1780  skip_spaces(line);1781  if (!line.empty()) {1782    if (line[0] == '=') {1783      op = '=';1784      line.erase(0, 1);1785    }1786  }1787  return op;1788}1789 1790static std::string get_value(std::string &line) {1791  std::string value;1792  skip_spaces(line);1793  if (!line.empty()) {1794    value.swap(line);1795  }1796  return value;1797}1798 1799extern void FileLogCallback(void *baton, uint32_t flags, const char *format,1800                            va_list args);1801 1802rnb_err_t RNBRemote::HandlePacket_qRcmd(const char *p) {1803  const char *c = p + strlen("qRcmd,");1804  std::string line;1805  while (c[0] && c[1]) {1806    char smallbuf[3] = {c[0], c[1], '\0'};1807    errno = 0;1808    int ch = static_cast<int>(strtoul(smallbuf, NULL, 16));1809    if (errno != 0 && ch == 0)1810      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,1811                                    "non-hex char in payload of qRcmd packet");1812    line.push_back(ch);1813    c += 2;1814  }1815  if (*c == '\0') {1816    std::string command = get_identifier(line);1817    if (command == "set") {1818      std::string variable = get_identifier(line);1819      std::string op = get_operator(line);1820      std::string value = get_value(line);1821      if (variable == "logfile") {1822        FILE *log_file = fopen(value.c_str(), "w");1823        if (log_file) {1824          DNBLogSetLogCallback(FileLogCallback, log_file);1825          return SendPacket("OK");1826        }1827        return SendErrorPacket("E71");1828      } else if (variable == "logmask") {1829        char *end;1830        errno = 0;1831        uint32_t logmask =1832            static_cast<uint32_t>(strtoul(value.c_str(), &end, 0));1833        if (errno == 0 && end && *end == '\0') {1834          DNBLogSetLogMask(logmask);1835          if (auto log_callback = OsLogger::GetLogFunction())1836            DNBLogSetLogCallback(log_callback, nullptr);1837          return SendPacket("OK");1838        }1839        errno = 0;1840        logmask = static_cast<uint32_t>(strtoul(value.c_str(), &end, 16));1841        if (errno == 0 && end && *end == '\0') {1842          DNBLogSetLogMask(logmask);1843          return SendPacket("OK");1844        }1845        return SendErrorPacket("E72");1846      }1847      return SendErrorPacket("E70");1848    }1849    return SendErrorPacket("E69");1850  }1851  return SendErrorPacket("E73");1852}1853 1854rnb_err_t RNBRemote::HandlePacket_qC(const char *p) {1855  nub_thread_t tid;1856  std::ostringstream rep;1857  // If we haven't run the process yet, we tell the debugger the1858  // pid is 0.  That way it can know to tell use to run later on.1859  if (!m_ctx.HasValidProcessID())1860    tid = 0;1861  else {1862    // Grab the current thread.1863    tid = DNBProcessGetCurrentThread(m_ctx.ProcessID());1864    // Make sure we set the current thread so g and p packets return1865    // the data the gdb will expect.1866    SetCurrentThread(tid);1867  }1868  rep << "QC" << std::hex << tid;1869  return SendPacket(rep.str());1870}1871 1872rnb_err_t RNBRemote::HandlePacket_qEcho(const char *p) {1873  // Just send the exact same packet back that we received to1874  // synchronize the response packets after a previous packet1875  // timed out. This allows the debugger to get back on track1876  // with responses after a packet timeout.1877  return SendPacket(p);1878}1879 1880rnb_err_t RNBRemote::HandlePacket_qGetPid(const char *p) {1881  nub_process_t pid;1882  std::ostringstream rep;1883  // If we haven't run the process yet, we tell the debugger the1884  // pid is 0.  That way it can know to tell use to run later on.1885  if (m_ctx.HasValidProcessID())1886    pid = m_ctx.ProcessID();1887  else1888    pid = 0;1889  rep << std::hex << pid;1890  return SendPacket(rep.str());1891}1892 1893rnb_err_t RNBRemote::HandlePacket_qRegisterInfo(const char *p) {1894  if (g_num_reg_entries == 0)1895    InitializeRegisters();1896 1897  p += strlen("qRegisterInfo");1898 1899  nub_size_t num_reg_sets = 0;1900  const DNBRegisterSetInfo *reg_set_info = DNBGetRegisterSetInfo(&num_reg_sets);1901  uint32_t reg_num = static_cast<uint32_t>(strtoul(p, 0, 16));1902 1903  if (reg_num < g_num_reg_entries) {1904    const register_map_entry_t *reg_entry = &g_reg_entries[reg_num];1905    std::ostringstream ostrm;1906    if (reg_entry->nub_info.name)1907      ostrm << "name:" << reg_entry->nub_info.name << ';';1908    if (reg_entry->nub_info.alt)1909      ostrm << "alt-name:" << reg_entry->nub_info.alt << ';';1910 1911    ostrm << "bitsize:" << std::dec << reg_entry->nub_info.size * 8 << ';';1912    ostrm << "offset:" << std::dec << reg_entry->offset << ';';1913 1914    switch (reg_entry->nub_info.type) {1915    case Uint:1916      ostrm << "encoding:uint;";1917      break;1918    case Sint:1919      ostrm << "encoding:sint;";1920      break;1921    case IEEE754:1922      ostrm << "encoding:ieee754;";1923      break;1924    case Vector:1925      ostrm << "encoding:vector;";1926      break;1927    }1928 1929    switch (reg_entry->nub_info.format) {1930    case Binary:1931      ostrm << "format:binary;";1932      break;1933    case Decimal:1934      ostrm << "format:decimal;";1935      break;1936    case Hex:1937      ostrm << "format:hex;";1938      break;1939    case Float:1940      ostrm << "format:float;";1941      break;1942    case VectorOfSInt8:1943      ostrm << "format:vector-sint8;";1944      break;1945    case VectorOfUInt8:1946      ostrm << "format:vector-uint8;";1947      break;1948    case VectorOfSInt16:1949      ostrm << "format:vector-sint16;";1950      break;1951    case VectorOfUInt16:1952      ostrm << "format:vector-uint16;";1953      break;1954    case VectorOfSInt32:1955      ostrm << "format:vector-sint32;";1956      break;1957    case VectorOfUInt32:1958      ostrm << "format:vector-uint32;";1959      break;1960    case VectorOfFloat32:1961      ostrm << "format:vector-float32;";1962      break;1963    case VectorOfUInt128:1964      ostrm << "format:vector-uint128;";1965      break;1966    };1967 1968    if (reg_set_info && reg_entry->nub_info.set < num_reg_sets)1969      ostrm << "set:" << reg_set_info[reg_entry->nub_info.set].name << ';';1970 1971    if (reg_entry->nub_info.reg_ehframe != INVALID_NUB_REGNUM)1972      ostrm << "ehframe:" << std::dec << reg_entry->nub_info.reg_ehframe << ';';1973 1974    if (reg_entry->nub_info.reg_dwarf != INVALID_NUB_REGNUM)1975      ostrm << "dwarf:" << std::dec << reg_entry->nub_info.reg_dwarf << ';';1976 1977    switch (reg_entry->nub_info.reg_generic) {1978    case GENERIC_REGNUM_FP:1979      ostrm << "generic:fp;";1980      break;1981    case GENERIC_REGNUM_PC:1982      ostrm << "generic:pc;";1983      break;1984    case GENERIC_REGNUM_SP:1985      ostrm << "generic:sp;";1986      break;1987    case GENERIC_REGNUM_RA:1988      ostrm << "generic:ra;";1989      break;1990    case GENERIC_REGNUM_FLAGS:1991      ostrm << "generic:flags;";1992      break;1993    case GENERIC_REGNUM_ARG1:1994      ostrm << "generic:arg1;";1995      break;1996    case GENERIC_REGNUM_ARG2:1997      ostrm << "generic:arg2;";1998      break;1999    case GENERIC_REGNUM_ARG3:2000      ostrm << "generic:arg3;";2001      break;2002    case GENERIC_REGNUM_ARG4:2003      ostrm << "generic:arg4;";2004      break;2005    case GENERIC_REGNUM_ARG5:2006      ostrm << "generic:arg5;";2007      break;2008    case GENERIC_REGNUM_ARG6:2009      ostrm << "generic:arg6;";2010      break;2011    case GENERIC_REGNUM_ARG7:2012      ostrm << "generic:arg7;";2013      break;2014    case GENERIC_REGNUM_ARG8:2015      ostrm << "generic:arg8;";2016      break;2017    default:2018      break;2019    }2020 2021    if (!reg_entry->value_regnums.empty()) {2022      ostrm << "container-regs:";2023      for (size_t i = 0, n = reg_entry->value_regnums.size(); i < n; ++i) {2024        if (i > 0)2025          ostrm << ',';2026        ostrm << RAW_HEXBASE << reg_entry->value_regnums[i];2027      }2028      ostrm << ';';2029    }2030 2031    if (!reg_entry->invalidate_regnums.empty()) {2032      ostrm << "invalidate-regs:";2033      for (size_t i = 0, n = reg_entry->invalidate_regnums.size(); i < n; ++i) {2034        if (i > 0)2035          ostrm << ',';2036        ostrm << RAW_HEXBASE << reg_entry->invalidate_regnums[i];2037      }2038      ostrm << ';';2039    }2040 2041    return SendPacket(ostrm.str());2042  }2043  return SendErrorPacket("E45");2044}2045 2046/* This expects a packet formatted like2047 2048 QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE;2049 2050 with the "QSetLogging:" already removed from the start.  Maybe in the2051 future this packet will include other keyvalue pairs like2052 2053 QSetLogging:bitmask=LOG_ALL;mode=asl;2054 */2055 2056static rnb_err_t set_logging(const char *p) {2057  int bitmask = 0;2058  while (p && *p != '\0') {2059    if (strncmp(p, "bitmask=", sizeof("bitmask=") - 1) == 0) {2060      p += sizeof("bitmask=") - 1;2061      while (p && *p != '\0' && *p != ';') {2062        if (*p == '|')2063          p++;2064 2065        // to regenerate the LOG_ entries (not including the LOG_RNB entries)2066        // $ for logname in `grep '^#define LOG_' DNBDefs.h | egrep -v2067        // 'LOG_HI|LOG_LO' | awk '{print $2}'`2068        // do2069        //   echo "                else if (strncmp (p, \"$logname\", sizeof2070        //   (\"$logname\") - 1) == 0)"2071        //   echo "                {"2072        //   echo "                    p += sizeof (\"$logname\") - 1;"2073        //   echo "                    bitmask |= $logname;"2074        //   echo "                }"2075        // done2076        if (strncmp(p, "LOG_VERBOSE", sizeof("LOG_VERBOSE") - 1) == 0) {2077          p += sizeof("LOG_VERBOSE") - 1;2078          bitmask |= LOG_VERBOSE;2079        } else if (strncmp(p, "LOG_PROCESS", sizeof("LOG_PROCESS") - 1) == 0) {2080          p += sizeof("LOG_PROCESS") - 1;2081          bitmask |= LOG_PROCESS;2082        } else if (strncmp(p, "LOG_THREAD", sizeof("LOG_THREAD") - 1) == 0) {2083          p += sizeof("LOG_THREAD") - 1;2084          bitmask |= LOG_THREAD;2085        } else if (strncmp(p, "LOG_EXCEPTIONS", sizeof("LOG_EXCEPTIONS") - 1) ==2086                   0) {2087          p += sizeof("LOG_EXCEPTIONS") - 1;2088          bitmask |= LOG_EXCEPTIONS;2089        } else if (strncmp(p, "LOG_SHLIB", sizeof("LOG_SHLIB") - 1) == 0) {2090          p += sizeof("LOG_SHLIB") - 1;2091          bitmask |= LOG_SHLIB;2092        } else if (strncmp(p, "LOG_MEMORY_DATA_SHORT",2093                           sizeof("LOG_MEMORY_DATA_SHORT") - 1) == 0) {2094          p += sizeof("LOG_MEMORY_DATA_SHORT") - 1;2095          bitmask |= LOG_MEMORY_DATA_SHORT;2096        } else if (strncmp(p, "LOG_MEMORY_DATA_LONG",2097                           sizeof("LOG_MEMORY_DATA_LONG") - 1) == 0) {2098          p += sizeof("LOG_MEMORY_DATA_LONG") - 1;2099          bitmask |= LOG_MEMORY_DATA_LONG;2100        } else if (strncmp(p, "LOG_MEMORY_PROTECTIONS",2101                           sizeof("LOG_MEMORY_PROTECTIONS") - 1) == 0) {2102          p += sizeof("LOG_MEMORY_PROTECTIONS") - 1;2103          bitmask |= LOG_MEMORY_PROTECTIONS;2104        } else if (strncmp(p, "LOG_MEMORY", sizeof("LOG_MEMORY") - 1) == 0) {2105          p += sizeof("LOG_MEMORY") - 1;2106          bitmask |= LOG_MEMORY;2107        } else if (strncmp(p, "LOG_BREAKPOINTS",2108                           sizeof("LOG_BREAKPOINTS") - 1) == 0) {2109          p += sizeof("LOG_BREAKPOINTS") - 1;2110          bitmask |= LOG_BREAKPOINTS;2111        } else if (strncmp(p, "LOG_EVENTS", sizeof("LOG_EVENTS") - 1) == 0) {2112          p += sizeof("LOG_EVENTS") - 1;2113          bitmask |= LOG_EVENTS;2114        } else if (strncmp(p, "LOG_WATCHPOINTS",2115                           sizeof("LOG_WATCHPOINTS") - 1) == 0) {2116          p += sizeof("LOG_WATCHPOINTS") - 1;2117          bitmask |= LOG_WATCHPOINTS;2118        } else if (strncmp(p, "LOG_STEP", sizeof("LOG_STEP") - 1) == 0) {2119          p += sizeof("LOG_STEP") - 1;2120          bitmask |= LOG_STEP;2121        } else if (strncmp(p, "LOG_TASK", sizeof("LOG_TASK") - 1) == 0) {2122          p += sizeof("LOG_TASK") - 1;2123          bitmask |= LOG_TASK;2124        } else if (strncmp(p, "LOG_ALL", sizeof("LOG_ALL") - 1) == 0) {2125          p += sizeof("LOG_ALL") - 1;2126          bitmask |= LOG_ALL;2127        } else if (strncmp(p, "LOG_DEFAULT", sizeof("LOG_DEFAULT") - 1) == 0) {2128          p += sizeof("LOG_DEFAULT") - 1;2129          bitmask |= LOG_DEFAULT;2130        }2131        // end of auto-generated entries2132 2133        else if (strncmp(p, "LOG_NONE", sizeof("LOG_NONE") - 1) == 0) {2134          p += sizeof("LOG_NONE") - 1;2135          bitmask = 0;2136        } else if (strncmp(p, "LOG_RNB_MINIMAL",2137                           sizeof("LOG_RNB_MINIMAL") - 1) == 0) {2138          p += sizeof("LOG_RNB_MINIMAL") - 1;2139          bitmask |= LOG_RNB_MINIMAL;2140        } else if (strncmp(p, "LOG_RNB_MEDIUM", sizeof("LOG_RNB_MEDIUM") - 1) ==2141                   0) {2142          p += sizeof("LOG_RNB_MEDIUM") - 1;2143          bitmask |= LOG_RNB_MEDIUM;2144        } else if (strncmp(p, "LOG_RNB_MAX", sizeof("LOG_RNB_MAX") - 1) == 0) {2145          p += sizeof("LOG_RNB_MAX") - 1;2146          bitmask |= LOG_RNB_MAX;2147        } else if (strncmp(p, "LOG_RNB_COMM", sizeof("LOG_RNB_COMM") - 1) ==2148                   0) {2149          p += sizeof("LOG_RNB_COMM") - 1;2150          bitmask |= LOG_RNB_COMM;2151        } else if (strncmp(p, "LOG_RNB_REMOTE", sizeof("LOG_RNB_REMOTE") - 1) ==2152                   0) {2153          p += sizeof("LOG_RNB_REMOTE") - 1;2154          bitmask |= LOG_RNB_REMOTE;2155        } else if (strncmp(p, "LOG_RNB_EVENTS", sizeof("LOG_RNB_EVENTS") - 1) ==2156                   0) {2157          p += sizeof("LOG_RNB_EVENTS") - 1;2158          bitmask |= LOG_RNB_EVENTS;2159        } else if (strncmp(p, "LOG_RNB_PROC", sizeof("LOG_RNB_PROC") - 1) ==2160                   0) {2161          p += sizeof("LOG_RNB_PROC") - 1;2162          bitmask |= LOG_RNB_PROC;2163        } else if (strncmp(p, "LOG_RNB_PACKETS",2164                           sizeof("LOG_RNB_PACKETS") - 1) == 0) {2165          p += sizeof("LOG_RNB_PACKETS") - 1;2166          bitmask |= LOG_RNB_PACKETS;2167        } else if (strncmp(p, "LOG_RNB_ALL", sizeof("LOG_RNB_ALL") - 1) == 0) {2168          p += sizeof("LOG_RNB_ALL") - 1;2169          bitmask |= LOG_RNB_ALL;2170        } else if (strncmp(p, "LOG_RNB_DEFAULT",2171                           sizeof("LOG_RNB_DEFAULT") - 1) == 0) {2172          p += sizeof("LOG_RNB_DEFAULT") - 1;2173          bitmask |= LOG_RNB_DEFAULT;2174        } else if (strncmp(p, "LOG_DARWIN_LOG", sizeof("LOG_DARWIN_LOG") - 1) ==2175                   0) {2176          p += sizeof("LOG_DARWIN_LOG") - 1;2177          bitmask |= LOG_DARWIN_LOG;2178        } else if (strncmp(p, "LOG_RNB_NONE", sizeof("LOG_RNB_NONE") - 1) ==2179                   0) {2180          p += sizeof("LOG_RNB_NONE") - 1;2181          bitmask = 0;2182        } else {2183          /* Unrecognized logging bit; ignore it.  */2184          const char *c = strchr(p, '|');2185          if (c) {2186            p = c;2187          } else {2188            c = strchr(p, ';');2189            if (c) {2190              p = c;2191            } else {2192              // Improperly terminated word; just go to end of str2193              p = strchr(p, '\0');2194            }2195          }2196        }2197      }2198      // Did we get a properly formatted logging bitmask?2199      if (p && *p == ';') {2200        // Enable DNB logging.2201        // Use the existing log callback if one was already configured.2202        if (!DNBLogGetLogCallback()) {2203          if (auto log_callback = OsLogger::GetLogFunction())2204            DNBLogSetLogCallback(log_callback, nullptr);2205        }2206 2207        // Update logging to use the configured log channel bitmask.2208        DNBLogSetLogMask(bitmask);2209        p++;2210      }2211    }2212// We're not going to support logging to a file for now.  All logging2213// goes through ASL or the previously arranged log callback.2214#if 02215        else if (strncmp (p, "mode=", sizeof ("mode=") - 1) == 0)2216        {2217            p += sizeof ("mode=") - 1;2218            if (strncmp (p, "asl;", sizeof ("asl;") - 1) == 0)2219            {2220                DNBLogToASL ();2221                p += sizeof ("asl;") - 1;2222            }2223            else if (strncmp (p, "file;", sizeof ("file;") - 1) == 0)2224            {2225                DNBLogToFile ();2226                p += sizeof ("file;") - 1;2227            }2228            else2229            {2230                // Ignore unknown argument2231                const char *c = strchr (p, ';');2232                if (c)2233                    p = c + 1;2234                else2235                    p = strchr (p, '\0');2236            }2237        }2238        else if (strncmp (p, "filename=", sizeof ("filename=") - 1) == 0)2239        {2240            p += sizeof ("filename=") - 1;2241            const char *c = strchr (p, ';');2242            if (c == NULL)2243            {2244                c = strchr (p, '\0');2245                continue;2246            }2247            char *fn = (char *) alloca (c - p + 1);2248            strlcpy (fn, p, c - p);2249            fn[c - p] = '\0';2250 2251            // A file name of "asl" is special and is another way to indicate2252            // that logging should be done via ASL, not by file.2253            if (strcmp (fn, "asl") == 0)2254            {2255                DNBLogToASL ();2256            }2257            else2258            {2259                FILE *f = fopen (fn, "w");2260                if (f)2261                {2262                    DNBLogSetLogFile (f);2263                    DNBEnableLogging (f, DNBLogGetLogMask ());2264                    DNBLogToFile ();2265                }2266            }2267            p = c + 1;2268        }2269#endif /* #if 0 to enforce ASL logging only.  */2270    else {2271      // Ignore unknown argument2272      const char *c = strchr(p, ';');2273      if (c)2274        p = c + 1;2275      else2276        p = strchr(p, '\0');2277    }2278  }2279 2280  return rnb_success;2281}2282 2283rnb_err_t RNBRemote::HandlePacket_QSetIgnoredExceptions(const char *p) {2284  // We can't set the ignored exceptions if we have a running process:2285  if (m_ctx.HasValidProcessID())2286    return SendErrorPacket("E35");2287 2288  p += sizeof("QSetIgnoredExceptions:") - 1;2289  bool success = true;2290  while(1) {2291    const char *bar  = strchr(p, '|');2292    if (bar == nullptr) {2293      success = m_ctx.AddIgnoredException(p);2294      break;2295    } else {2296      std::string exc_str(p, bar - p);2297      if (exc_str.empty()) {2298        success = false;2299        break;2300      }2301 2302      success = m_ctx.AddIgnoredException(exc_str.c_str());2303      if (!success)2304        break;2305      p = bar + 1;2306    }2307  }2308  if (success)2309    return SendPacket("OK");2310  else2311    return SendErrorPacket("E36");2312}2313 2314rnb_err_t RNBRemote::HandlePacket_QThreadSuffixSupported(const char *p) {2315  m_thread_suffix_supported = true;2316  return SendPacket("OK");2317}2318 2319rnb_err_t RNBRemote::HandlePacket_QStartNoAckMode(const char *p) {2320  // Send the OK packet first so the correct checksum is appended...2321  rnb_err_t result = SendPacket("OK");2322  m_noack_mode = true;2323  return result;2324}2325 2326rnb_err_t RNBRemote::HandlePacket_QSetLogging(const char *p) {2327  p += sizeof("QSetLogging:") - 1;2328  rnb_err_t result = set_logging(p);2329  if (result == rnb_success)2330    return SendPacket("OK");2331  else2332    return SendErrorPacket("E35");2333}2334 2335rnb_err_t RNBRemote::HandlePacket_QSetDisableASLR(const char *p) {2336  extern int g_disable_aslr;2337  p += sizeof("QSetDisableASLR:") - 1;2338  switch (*p) {2339  case '0':2340    g_disable_aslr = 0;2341    break;2342  case '1':2343    g_disable_aslr = 1;2344    break;2345  default:2346    return SendErrorPacket("E56");2347  }2348  return SendPacket("OK");2349}2350 2351rnb_err_t RNBRemote::HandlePacket_QSetSTDIO(const char *p) {2352  // Only set stdin/out/err if we don't already have a process2353  if (!m_ctx.HasValidProcessID()) {2354    bool success = false;2355    // Check the seventh character since the packet will be one of:2356    // QSetSTDIN2357    // QSetSTDOUT2358    // QSetSTDERR2359    StdStringExtractor packet(p);2360    packet.SetFilePos(7);2361    char ch = packet.GetChar();2362    while (packet.GetChar() != ':')2363      /* Do nothing. */;2364 2365    switch (ch) {2366    case 'I': // STDIN2367      packet.GetHexByteString(m_ctx.GetSTDIN());2368      success = !m_ctx.GetSTDIN().empty();2369      break;2370 2371    case 'O': // STDOUT2372      packet.GetHexByteString(m_ctx.GetSTDOUT());2373      success = !m_ctx.GetSTDOUT().empty();2374      break;2375 2376    case 'E': // STDERR2377      packet.GetHexByteString(m_ctx.GetSTDERR());2378      success = !m_ctx.GetSTDERR().empty();2379      break;2380 2381    default:2382      break;2383    }2384    if (success)2385      return SendPacket("OK");2386    return SendErrorPacket("E57");2387  }2388  return SendErrorPacket("E58");2389}2390 2391rnb_err_t RNBRemote::HandlePacket_QSetWorkingDir(const char *p) {2392  // Only set the working directory if we don't already have a process2393  if (!m_ctx.HasValidProcessID()) {2394    StdStringExtractor packet(p += sizeof("QSetWorkingDir:") - 1);2395    if (packet.GetHexByteString(m_ctx.GetWorkingDir())) {2396      struct stat working_dir_stat;2397      if (::stat(m_ctx.GetWorkingDirPath(), &working_dir_stat) == -1) {2398        m_ctx.GetWorkingDir().clear();2399        return SendErrorPacket("E61"); // Working directory doesn't exist...2400      } else if ((working_dir_stat.st_mode & S_IFMT) == S_IFDIR) {2401        return SendPacket("OK");2402      } else {2403        m_ctx.GetWorkingDir().clear();2404        return SendErrorPacket("E62"); // Working directory isn't a directory...2405      }2406    }2407    return SendErrorPacket("E59"); // Invalid path2408  }2409  return SendPacket(2410      "E60"); // Already had a process, too late to set working dir2411}2412 2413rnb_err_t RNBRemote::HandlePacket_QSyncThreadState(const char *p) {2414  if (!m_ctx.HasValidProcessID()) {2415    // We allow gdb to connect to a server that hasn't started running2416    // the target yet.  gdb still wants to ask questions about it and2417    // freaks out if it gets an error.  So just return OK here.2418    return SendPacket("OK");2419  }2420 2421  errno = 0;2422  p += strlen("QSyncThreadState:");2423  nub_thread_t tid = strtoul(p, NULL, 16);2424  if (errno != 0 && tid == 0) {2425    return HandlePacket_ILLFORMED(2426        __FILE__, __LINE__, p,2427        "Invalid thread number in QSyncThreadState packet");2428  }2429  if (DNBProcessSyncThreadState(m_ctx.ProcessID(), tid))2430    return SendPacket("OK");2431  else2432    return SendErrorPacket("E61");2433}2434 2435rnb_err_t RNBRemote::HandlePacket_QSetDetachOnError(const char *p) {2436  p += sizeof("QSetDetachOnError:") - 1;2437  bool should_detach = true;2438  switch (*p) {2439  case '0':2440    should_detach = false;2441    break;2442  case '1':2443    should_detach = true;2444    break;2445  default:2446    return HandlePacket_ILLFORMED(2447        __FILE__, __LINE__, p,2448        "Invalid value for QSetDetachOnError - should be 0 or 1");2449    break;2450  }2451 2452  m_ctx.SetDetachOnError(should_detach);2453  return SendPacket("OK");2454}2455 2456rnb_err_t RNBRemote::HandlePacket_QListThreadsInStopReply(const char *p) {2457  // If this packet is received, it allows us to send an extra key/value2458  // pair in the stop reply packets where we will list all of the thread IDs2459  // separated by commas:2460  //2461  //  "threads:10a,10b,10c;"2462  //2463  // This will get included in the stop reply packet as something like:2464  //2465  //  "T11thread:10a;00:00000000;01:00010203:threads:10a,10b,10c;"2466  //2467  // This can save two packets on each stop: qfThreadInfo/qsThreadInfo and2468  // speed things up a bit.2469  //2470  // Send the OK packet first so the correct checksum is appended...2471  rnb_err_t result = SendPacket("OK");2472  m_list_threads_in_stop_reply = true;2473 2474  return result;2475}2476 2477rnb_err_t RNBRemote::HandlePacket_QSetMaxPayloadSize(const char *p) {2478  /* The number of characters in a packet payload that gdb is2479   prepared to accept.  The packet-start char, packet-end char,2480   2 checksum chars and terminating null character are not included2481   in this size.  */2482  p += sizeof("QSetMaxPayloadSize:") - 1;2483  errno = 0;2484  uint32_t size = static_cast<uint32_t>(strtoul(p, NULL, 16));2485  if (errno != 0 && size == 0) {2486    return HandlePacket_ILLFORMED(2487        __FILE__, __LINE__, p, "Invalid length in QSetMaxPayloadSize packet");2488  }2489  m_max_payload_size = size;2490  return SendPacket("OK");2491}2492 2493rnb_err_t RNBRemote::HandlePacket_QSetMaxPacketSize(const char *p) {2494  /* This tells us the largest packet that gdb can handle.2495   i.e. the size of gdb's packet-reading buffer.2496   QSetMaxPayloadSize is preferred because it is less ambiguous.  */2497  p += sizeof("QSetMaxPacketSize:") - 1;2498  errno = 0;2499  uint32_t size = static_cast<uint32_t>(strtoul(p, NULL, 16));2500  if (errno != 0 && size == 0) {2501    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,2502                                  "Invalid length in QSetMaxPacketSize packet");2503  }2504  m_max_payload_size = size - 5;2505  return SendPacket("OK");2506}2507 2508rnb_err_t RNBRemote::HandlePacket_QEnvironment(const char *p) {2509  /* This sets the environment for the target program.  The packet is of the2510   form:2511 2512   QEnvironment:VARIABLE=VALUE2513 2514   */2515 2516  DNBLogThreadedIf(2517      LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"",2518      (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p);2519 2520  p += sizeof("QEnvironment:") - 1;2521  RNBContext &ctx = Context();2522 2523  ctx.PushEnvironment(p);2524  return SendPacket("OK");2525}2526 2527rnb_err_t RNBRemote::HandlePacket_QEnvironmentHexEncoded(const char *p) {2528  /* This sets the environment for the target program.  The packet is of the2529     form:2530 2531      QEnvironmentHexEncoded:VARIABLE=VALUE2532 2533      The VARIABLE=VALUE part is sent hex-encoded so characters like '#' with2534     special2535      meaning in the remote protocol won't break it.2536  */2537 2538  DNBLogThreadedIf(LOG_RNB_REMOTE,2539                   "%8u RNBRemote::%s Handling QEnvironmentHexEncoded: \"%s\"",2540                   (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),2541                   __FUNCTION__, p);2542 2543  p += sizeof("QEnvironmentHexEncoded:") - 1;2544 2545  std::string arg;2546  const char *c;2547  c = p;2548  while (*c != '\0') {2549    if (*(c + 1) == '\0') {2550      return HandlePacket_ILLFORMED(2551          __FILE__, __LINE__, p,2552          "non-hex char in arg on 'QEnvironmentHexEncoded' pkt");2553    }2554    char smallbuf[3];2555    smallbuf[0] = *c;2556    smallbuf[1] = *(c + 1);2557    smallbuf[2] = '\0';2558    errno = 0;2559    int ch = static_cast<int>(strtoul(smallbuf, NULL, 16));2560    if (errno != 0 && ch == 0) {2561      return HandlePacket_ILLFORMED(2562          __FILE__, __LINE__, p,2563          "non-hex char in arg on 'QEnvironmentHexEncoded' pkt");2564    }2565    arg.push_back(ch);2566    c += 2;2567  }2568 2569  RNBContext &ctx = Context();2570  if (arg.length() > 0)2571    ctx.PushEnvironment(arg.c_str());2572 2573  return SendPacket("OK");2574}2575 2576rnb_err_t RNBRemote::HandlePacket_QLaunchArch(const char *p) {2577  p += sizeof("QLaunchArch:") - 1;2578  if (DNBSetArchitecture(p))2579    return SendPacket("OK");2580  return SendErrorPacket("E63");2581}2582 2583rnb_err_t RNBRemote::HandlePacket_QSetProcessEvent(const char *p) {2584  p += sizeof("QSetProcessEvent:") - 1;2585  // If the process is running, then send the event to the process, otherwise2586  // store it in the context.2587  if (Context().HasValidProcessID()) {2588    if (DNBProcessSendEvent(Context().ProcessID(), p))2589      return SendPacket("OK");2590    else2591      return SendErrorPacket("E80");2592  } else {2593    Context().PushProcessEvent(p);2594  }2595  return SendPacket("OK");2596}2597 2598// If a fail_value is provided, a correct-length reply is always provided,2599// even if the register cannot be read right now on this thread.2600static bool register_value_in_hex_fixed_width(2601    std::ostream &ostrm, nub_process_t pid, nub_thread_t tid,2602    const register_map_entry_t *reg, const DNBRegisterValue *reg_value_ptr,2603    std::optional<uint8_t> fail_value) {2604  if (reg != NULL) {2605    std::unique_ptr<DNBRegisterValue> reg_value =2606        std::make_unique<DNBRegisterValue>();2607    if (reg_value_ptr == NULL) {2608      if (DNBThreadGetRegisterValueByID(pid, tid, reg->nub_info.set,2609                                        reg->nub_info.reg, reg_value.get()))2610        reg_value_ptr = reg_value.get();2611    }2612 2613    if (reg_value_ptr) {2614      append_hex_value(ostrm, reg_value_ptr->value.v_uint8, reg->nub_info.size,2615                       false);2616      return true;2617    }2618    if (!fail_value || reg->nub_info.size == 0)2619      return false;2620 2621    // Pad out the reply to the correct size to maintain correct offsets,2622    // even if we could not read the register value.2623    std::vector<uint8_t> fail_result(reg->nub_info.size, *fail_value);2624    append_hex_value(ostrm, fail_result.data(), fail_result.size(), false);2625    return true;2626  }2627  return false;2628}2629 2630static void debugserver_regnum_with_fixed_width_hex_register_value(2631    std::ostream &ostrm, nub_process_t pid, nub_thread_t tid,2632    const register_map_entry_t *reg, const DNBRegisterValue *reg_value_ptr,2633    std::optional<uint8_t> fail_value) {2634  // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX2635  // gdb register number, and VVVVVVVV is the correct number of hex bytes2636  // as ASCII for the register value.2637  if (reg != NULL) {2638    ostrm << RAWHEX8(reg->debugserver_regnum) << ':';2639    register_value_in_hex_fixed_width(ostrm, pid, tid, reg, reg_value_ptr,2640                                      fail_value);2641    ostrm << ';';2642  }2643}2644 2645void RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo(2646    nub_process_t pid, nub_addr_t dispatch_qaddr, nub_addr_t &dispatch_queue_t,2647    std::string &queue_name, uint64_t &queue_width,2648    uint64_t &queue_serialnum) const {2649  queue_name.clear();2650  queue_width = 0;2651  queue_serialnum = 0;2652 2653  if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS &&2654      dispatch_qaddr != 0) {2655    dispatch_queue_t = DNBProcessMemoryReadPointer(pid, dispatch_qaddr);2656    if (dispatch_queue_t) {2657      queue_width = DNBProcessMemoryReadInteger(2658          pid, dispatch_queue_t + dqo_width, dqo_width_size, 0);2659      queue_serialnum = DNBProcessMemoryReadInteger(2660          pid, dispatch_queue_t + dqo_serialnum, dqo_serialnum_size, 0);2661 2662      if (dqo_version >= 4) {2663        // libdispatch versions 4+, pointer to dispatch name is in the2664        // queue structure.2665        nub_addr_t pointer_to_label_address = dispatch_queue_t + dqo_label;2666        nub_addr_t label_addr =2667            DNBProcessMemoryReadPointer(pid, pointer_to_label_address);2668        if (label_addr)2669          queue_name = DNBProcessMemoryReadCString(pid, label_addr);2670      } else {2671        // libdispatch versions 1-3, dispatch name is a fixed width char array2672        // in the queue structure.2673        queue_name = DNBProcessMemoryReadCStringFixed(2674            pid, dispatch_queue_t + dqo_label, dqo_label_size);2675      }2676    }2677  }2678}2679 2680struct StackMemory {2681  uint8_t bytes[2 * sizeof(nub_addr_t)];2682  nub_size_t length;2683};2684typedef std::map<nub_addr_t, StackMemory> StackMemoryMap;2685 2686static void ReadStackMemory(nub_process_t pid, nub_thread_t tid,2687                            StackMemoryMap &stack_mmap,2688                            uint32_t backtrace_limit = 256) {2689  std::unique_ptr<DNBRegisterValue> reg_value =2690      std::make_unique<DNBRegisterValue>();2691  if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC,2692                                    GENERIC_REGNUM_FP, reg_value.get())) {2693    uint32_t frame_count = 0;2694    uint64_t fp = 0;2695    if (reg_value->info.size == 4)2696      fp = reg_value->value.uint32;2697    else2698      fp = reg_value->value.uint64;2699    while (fp != 0) {2700      // Make sure we never recurse more than 256 times so we don't recurse too2701      // far or2702      // store up too much memory in the expedited cache2703      if (++frame_count > backtrace_limit)2704        break;2705 2706      const nub_size_t read_size = reg_value->info.size * 2;2707      StackMemory stack_memory;2708      stack_memory.length = read_size;2709      if (DNBProcessMemoryRead(pid, fp, read_size, stack_memory.bytes) !=2710          read_size)2711        break;2712      // Make sure we don't try to put the same stack memory in more than once2713      if (stack_mmap.find(fp) != stack_mmap.end())2714        break;2715      // Put the entry into the cache2716      stack_mmap[fp] = stack_memory;2717      // Dereference the frame pointer to get to the previous frame pointer2718      if (reg_value->info.size == 4)2719        fp = ((uint32_t *)stack_memory.bytes)[0];2720      else2721        fp = ((uint64_t *)stack_memory.bytes)[0];2722    }2723  }2724}2725 2726rnb_err_t RNBRemote::SendStopReplyPacketForThread(nub_thread_t tid) {2727  const nub_process_t pid = m_ctx.ProcessID();2728  if (pid == INVALID_NUB_PROCESS)2729    return SendErrorPacket("E50");2730 2731  struct DNBThreadStopInfo tid_stop_info;2732 2733  /* Fill the remaining space in this packet with as many registers2734   as we can stuff in there.  */2735 2736  if (DNBThreadGetStopReason(pid, tid, &tid_stop_info)) {2737    const bool did_exec = tid_stop_info.reason == eStopTypeExec;2738    if (did_exec) {2739      RNBRemote::InitializeRegisters(true);2740 2741      // Reset any symbols that need resetting when we exec2742      m_dispatch_queue_offsets_addr = INVALID_NUB_ADDRESS;2743      m_dispatch_queue_offsets.Clear();2744    }2745 2746    std::ostringstream ostrm;2747    // Output the T packet with the thread2748    ostrm << 'T';2749    int signum = tid_stop_info.details.signal.signo;2750    DNBLogThreadedIf(2751        LOG_RNB_PROC, "%8d %s got signal signo = %u, exc_type = %u",2752        (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__,2753        signum, tid_stop_info.details.exception.type);2754 2755    // Translate any mach exceptions to gdb versions, unless they are2756    // common exceptions like a breakpoint or a soft signal.2757    switch (tid_stop_info.details.exception.type) {2758    default:2759      signum = 0;2760      break;2761    case EXC_BREAKPOINT:2762      signum = SIGTRAP;2763      break;2764    case EXC_BAD_ACCESS:2765      signum = TARGET_EXC_BAD_ACCESS;2766      break;2767    case EXC_BAD_INSTRUCTION:2768      signum = TARGET_EXC_BAD_INSTRUCTION;2769      break;2770    case EXC_ARITHMETIC:2771      signum = TARGET_EXC_ARITHMETIC;2772      break;2773    case EXC_EMULATION:2774      signum = TARGET_EXC_EMULATION;2775      break;2776    case EXC_SOFTWARE:2777      if (tid_stop_info.details.exception.data_count == 2 &&2778          tid_stop_info.details.exception.data[0] == EXC_SOFT_SIGNAL)2779        signum = static_cast<int>(tid_stop_info.details.exception.data[1]);2780      else2781        signum = TARGET_EXC_SOFTWARE;2782      break;2783    }2784 2785    ostrm << RAWHEX8(signum & 0xff);2786 2787    ostrm << std::hex << "thread:" << tid << ';';2788 2789    const char *thread_name = DNBThreadGetName(pid, tid);2790    if (thread_name && thread_name[0]) {2791      size_t thread_name_len = strlen(thread_name);2792 2793      if (::strcspn(thread_name, "$#+-;:") == thread_name_len)2794        ostrm << std::hex << "name:" << thread_name << ';';2795      else {2796        // the thread name contains special chars, send as hex bytes2797        ostrm << std::hex << "hexname:";2798        const uint8_t *u_thread_name = (const uint8_t *)thread_name;2799        for (size_t i = 0; i < thread_name_len; i++)2800          ostrm << RAWHEX8(u_thread_name[i]);2801        ostrm << ';';2802      }2803    }2804 2805    // If a 'QListThreadsInStopReply' was sent to enable this feature, we2806    // will send all thread IDs back in the "threads" key whose value is2807    // a list of hex thread IDs separated by commas:2808    //  "threads:10a,10b,10c;"2809    // This will save the debugger from having to send a pair of qfThreadInfo2810    // and qsThreadInfo packets, but it also might take a lot of room in the2811    // stop reply packet, so it must be enabled only on systems where there2812    // are no limits on packet lengths.2813    if (m_list_threads_in_stop_reply) {2814      const nub_size_t numthreads = DNBProcessGetNumThreads(pid);2815      if (numthreads > 0) {2816        std::vector<uint64_t> pc_values;2817        ostrm << std::hex << "threads:";2818        for (nub_size_t i = 0; i < numthreads; ++i) {2819          nub_thread_t th = DNBProcessGetThreadAtIndex(pid, i);2820          if (i > 0)2821            ostrm << ',';2822          ostrm << std::hex << th;2823          DNBRegisterValue pc_regval;2824          if (DNBThreadGetRegisterValueByID(pid, th, REGISTER_SET_GENERIC,2825                                            GENERIC_REGNUM_PC, &pc_regval)) {2826            uint64_t pc = INVALID_NUB_ADDRESS;2827            if (pc_regval.value.uint64 != INVALID_NUB_ADDRESS) {2828              if (pc_regval.info.size == 4) {2829                pc = pc_regval.value.uint32;2830              } else if (pc_regval.info.size == 8) {2831                pc = pc_regval.value.uint64;2832              }2833              if (pc != INVALID_NUB_ADDRESS) {2834                pc_values.push_back(pc);2835              }2836            }2837          }2838        }2839        ostrm << ';';2840 2841        // If we failed to get any of the thread pc values, the size of our2842        // vector will not2843        // be the same as the # of threads.  Don't provide any expedited thread2844        // pc values in2845        // that case.  This should not happen.2846        if (pc_values.size() == numthreads) {2847          ostrm << std::hex << "thread-pcs:";2848          for (nub_size_t i = 0; i < numthreads; ++i) {2849            if (i > 0)2850              ostrm << ',';2851            ostrm << std::hex << pc_values[i];2852          }2853          ostrm << ';';2854        }2855      }2856 2857      // Include JSON info that describes the stop reason for any threads2858      // that actually have stop reasons. We use the new "jstopinfo" key2859      // whose values is hex ascii JSON that contains the thread IDs2860      // thread stop info only for threads that have stop reasons. Only send2861      // this if we have more than one thread otherwise this packet has all2862      // the info it needs.2863      if (numthreads > 1) {2864        const bool threads_with_valid_stop_info_only = true;2865        JSONGenerator::ObjectSP threads_info_sp =2866            GetJSONThreadsInfo(threads_with_valid_stop_info_only);2867        if (threads_info_sp) {2868          ostrm << std::hex << "jstopinfo:";2869          std::ostringstream json_strm;2870          threads_info_sp->Dump(json_strm);2871          threads_info_sp->Clear();2872          append_hexified_string(ostrm, json_strm.str());2873          ostrm << ';';2874        }2875      }2876    }2877 2878    if (g_num_reg_entries == 0)2879      InitializeRegisters();2880 2881    nub_size_t num_reg_sets = 0;2882    const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo(&num_reg_sets);2883 2884    std::unique_ptr<DNBRegisterValue> reg_value =2885        std::make_unique<DNBRegisterValue>();2886    for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) {2887      int regset = g_reg_entries[reg].nub_info.set;2888      bool include_reg = false;2889      // Expedite interesting register sets, all registers not2890      // contained in other registers2891      if (g_reg_entries[reg].nub_info.value_regs == nullptr &&2892          (strcmp("General Purpose Registers", reg_sets[regset].name) == 0 ||2893           strcmp("Exception State Registers", reg_sets[regset].name) == 0))2894        include_reg = true;2895      // Include the SME state registers2896      if (strcmp("svcr", g_reg_entries[reg].nub_info.name) == 0 ||2897          strcmp("tpidr2", g_reg_entries[reg].nub_info.name) == 0 ||2898          strcmp("svl", g_reg_entries[reg].nub_info.name) == 0)2899        include_reg = true;2900 2901      if (include_reg) {2902        if (!DNBThreadGetRegisterValueByID(pid, tid, regset,2903                                           g_reg_entries[reg].nub_info.reg,2904                                           reg_value.get()))2905          continue;2906 2907        debugserver_regnum_with_fixed_width_hex_register_value(2908            ostrm, pid, tid, &g_reg_entries[reg], reg_value.get(),2909            std::nullopt);2910      }2911    }2912 2913    if (did_exec) {2914      ostrm << "reason:exec;";2915    } else if (tid_stop_info.reason == eStopTypeWatchpoint) {2916      ostrm << "reason:watchpoint;";2917      ostrm << "description:";2918      std::ostringstream wp_desc;2919      wp_desc << tid_stop_info.details.watchpoint.addr << " ";2920      wp_desc << tid_stop_info.details.watchpoint.hw_idx << " ";2921      wp_desc << tid_stop_info.details.watchpoint.mach_exception_addr;2922      append_hexified_string(ostrm, wp_desc.str());2923      ostrm << ";";2924 2925      // Temporarily, print all of the fields we've parsed out of the ESR2926      // on a watchpoint exception.  Normally this is something we would2927      // log for LOG_WATCHPOINTS only, but this was implemented from the2928      // ARM ARM spec and hasn't been exercised on real hardware that can2929      // set most of these fields yet.  It may need to be debugged in the2930      // future, so include all of these purely for debugging by reading2931      // the packet logs; lldb isn't using these fields.2932      ostrm << "watch_addr:" << std::hex2933            << tid_stop_info.details.watchpoint.addr << ";";2934      ostrm << "me_watch_addr:" << std::hex2935            << tid_stop_info.details.watchpoint.mach_exception_addr << ";";2936      ostrm << "wp_hw_idx:" << std::hex2937            << tid_stop_info.details.watchpoint.hw_idx << ";";2938      if (tid_stop_info.details.watchpoint.esr_fields_set) {2939        ostrm << "wp_esr_iss:" << std::hex2940              << tid_stop_info.details.watchpoint.esr_fields.iss << ";";2941        ostrm << "wp_esr_wpt:" << std::hex2942              << tid_stop_info.details.watchpoint.esr_fields.wpt << ";";2943        ostrm << "wp_esr_wptv:"2944              << tid_stop_info.details.watchpoint.esr_fields.wptv << ";";2945        ostrm << "wp_esr_wpf:"2946              << tid_stop_info.details.watchpoint.esr_fields.wpf << ";";2947        ostrm << "wp_esr_fnp:"2948              << tid_stop_info.details.watchpoint.esr_fields.fnp << ";";2949        ostrm << "wp_esr_vncr:"2950              << tid_stop_info.details.watchpoint.esr_fields.vncr << ";";2951        ostrm << "wp_esr_fnv:"2952              << tid_stop_info.details.watchpoint.esr_fields.fnv << ";";2953        ostrm << "wp_esr_cm:" << tid_stop_info.details.watchpoint.esr_fields.cm2954              << ";";2955        ostrm << "wp_esr_wnr:"2956              << tid_stop_info.details.watchpoint.esr_fields.wnr << ";";2957        ostrm << "wp_esr_dfsc:" << std::hex2958              << tid_stop_info.details.watchpoint.esr_fields.dfsc << ";";2959      }2960    } else if (tid_stop_info.details.exception.type) {2961      ostrm << "metype:" << std::hex << tid_stop_info.details.exception.type2962            << ';';2963      ostrm << "mecount:" << std::hex2964            << tid_stop_info.details.exception.data_count << ';';2965      for (nub_size_t i = 0; i < tid_stop_info.details.exception.data_count;2966           ++i)2967        ostrm << "medata:" << std::hex2968              << tid_stop_info.details.exception.data[i] << ';';2969    }2970 2971    // Add expedited stack memory so stack backtracing doesn't need to read2972    // anything from the2973    // frame pointer chain.2974    StackMemoryMap stack_mmap;2975    ReadStackMemory(pid, tid, stack_mmap, 2);2976    if (!stack_mmap.empty()) {2977      for (const auto &stack_memory : stack_mmap) {2978        ostrm << "memory:" << HEXBASE << stack_memory.first << '=';2979        append_hex_value(ostrm, stack_memory.second.bytes,2980                         stack_memory.second.length, false);2981        ostrm << ';';2982      }2983    }2984 2985    return SendPacket(ostrm.str());2986  }2987  return SendErrorPacket("E51");2988}2989 2990/* '?'2991 The stop reply packet - tell gdb what the status of the inferior is.2992 Often called the questionmark_packet.  */2993 2994rnb_err_t RNBRemote::HandlePacket_last_signal(const char *unused) {2995  if (!m_ctx.HasValidProcessID()) {2996    // Inferior is not yet specified/running2997    return SendErrorPacket("E02");2998  }2999 3000  nub_process_t pid = m_ctx.ProcessID();3001  nub_state_t pid_state = DNBProcessGetState(pid);3002 3003  switch (pid_state) {3004  case eStateAttaching:3005  case eStateLaunching:3006  case eStateRunning:3007  case eStateStepping:3008  case eStateDetached:3009    return rnb_success; // Ignore3010 3011  case eStateSuspended:3012  case eStateStopped:3013  case eStateCrashed: {3014    nub_thread_t tid = DNBProcessGetCurrentThread(pid);3015    // Make sure we set the current thread so g and p packets return3016    // the data the gdb will expect.3017    SetCurrentThread(tid);3018 3019    SendStopReplyPacketForThread(tid);3020  } break;3021 3022  case eStateInvalid:3023  case eStateUnloaded:3024  case eStateExited: {3025    char pid_exited_packet[16] = "";3026    int pid_status = 0;3027    // Process exited with exit status3028    if (!DNBProcessGetExitStatus(pid, &pid_status))3029      pid_status = 0;3030 3031    if (pid_status) {3032      if (WIFEXITED(pid_status))3033        snprintf(pid_exited_packet, sizeof(pid_exited_packet), "W%02x",3034                 WEXITSTATUS(pid_status));3035      else if (WIFSIGNALED(pid_status))3036        snprintf(pid_exited_packet, sizeof(pid_exited_packet), "X%02x",3037                 WTERMSIG(pid_status));3038      else if (WIFSTOPPED(pid_status))3039        snprintf(pid_exited_packet, sizeof(pid_exited_packet), "S%02x",3040                 WSTOPSIG(pid_status));3041    }3042 3043    // If we have an empty exit packet, lets fill one in to be safe.3044    if (!pid_exited_packet[0]) {3045      strlcpy(pid_exited_packet, "W00", sizeof(pid_exited_packet) - 1);3046      pid_exited_packet[sizeof(pid_exited_packet) - 1] = '\0';3047    }3048 3049    const char *exit_info = DNBProcessGetExitInfo(pid);3050    if (exit_info != NULL && *exit_info != '\0') {3051      std::ostringstream exit_packet;3052      exit_packet << pid_exited_packet;3053      exit_packet << ';';3054      exit_packet << RAW_HEXBASE << "description";3055      exit_packet << ':';3056      for (size_t i = 0; exit_info[i] != '\0'; i++)3057        exit_packet << RAWHEX8(exit_info[i]);3058      exit_packet << ';';3059      return SendPacket(exit_packet.str());3060    } else3061      return SendPacket(pid_exited_packet);3062  } break;3063  }3064  return rnb_success;3065}3066 3067rnb_err_t RNBRemote::HandlePacket_M(const char *p) {3068  if (p == NULL || p[0] == '\0' || strlen(p) < 3) {3069    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short M packet");3070  }3071 3072  char *c;3073  p++;3074  errno = 0;3075  nub_addr_t addr = strtoull(p, &c, 16);3076  if (errno != 0 && addr == 0) {3077    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3078                                  "Invalid address in M packet");3079  }3080  if (*c != ',') {3081    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3082                                  "Comma sep missing in M packet");3083  }3084 3085  /* Advance 'p' to the length part of the packet.  */3086  p += (c - p) + 1;3087 3088  errno = 0;3089  unsigned long length = strtoul(p, &c, 16);3090  if (errno != 0 && length == 0) {3091    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3092                                  "Invalid length in M packet");3093  }3094  if (length == 0) {3095    return SendPacket("OK");3096  }3097 3098  if (*c != ':') {3099    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3100                                  "Missing colon in M packet");3101  }3102  /* Advance 'p' to the data part of the packet.  */3103  p += (c - p) + 1;3104 3105  size_t datalen = strlen(p);3106  if (datalen & 0x1) {3107    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3108                                  "Uneven # of hex chars for data in M packet");3109  }3110  if (datalen == 0) {3111    return SendPacket("OK");3112  }3113 3114  uint8_t *buf = (uint8_t *)alloca(datalen / 2);3115  uint8_t *i = buf;3116 3117  while (*p != '\0' && *(p + 1) != '\0') {3118    char hexbuf[3];3119    hexbuf[0] = *p;3120    hexbuf[1] = *(p + 1);3121    hexbuf[2] = '\0';3122    errno = 0;3123    uint8_t byte = strtoul(hexbuf, NULL, 16);3124    if (errno != 0 && byte == 0) {3125      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3126                                    "Invalid hex byte in M packet");3127    }3128    *i++ = byte;3129    p += 2;3130  }3131 3132  nub_size_t wrote =3133      DNBProcessMemoryWrite(m_ctx.ProcessID(), addr, length, buf);3134  if (wrote != length)3135    return SendErrorPacket("E09");3136  else3137    return SendPacket("OK");3138}3139 3140rnb_err_t RNBRemote::HandlePacket_m(const char *p) {3141  if (p == NULL || p[0] == '\0' || strlen(p) < 3) {3142    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short m packet");3143  }3144 3145  char *c;3146  p++;3147  errno = 0;3148  nub_addr_t addr = strtoull(p, &c, 16);3149  if (errno != 0 && addr == 0) {3150    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3151                                  "Invalid address in m packet");3152  }3153  if (*c != ',') {3154    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3155                                  "Comma sep missing in m packet");3156  }3157 3158  /* Advance 'p' to the length part of the packet.  */3159  p += (c - p) + 1;3160 3161  errno = 0;3162  auto length = strtoul(p, NULL, 16);3163  if (errno != 0 && length == 0) {3164    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3165                                  "Invalid length in m packet");3166  }3167  if (length == 0) {3168    return SendPacket("");3169  }3170 3171  std::string buf(length, '\0');3172  if (buf.empty()) {3173    return SendErrorPacket("E78");3174  }3175  nub_size_t bytes_read =3176      DNBProcessMemoryRead(m_ctx.ProcessID(), addr, buf.size(), &buf[0]);3177  if (bytes_read == 0) {3178    return SendErrorPacket("E08");3179  }3180 3181  // "The reply may contain fewer bytes than requested if the server was able3182  //  to read only part of the region of memory."3183  length = bytes_read;3184 3185  std::ostringstream ostrm;3186  for (unsigned long i = 0; i < length; i++)3187    ostrm << RAWHEX8(buf[i]);3188  return SendPacket(ostrm.str());3189}3190 3191rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {3192  const std::string_view packet_name("MultiMemRead:");3193  std::string_view packet(p);3194 3195  if (!starts_with(packet, packet_name))3196    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3197                                  "Invalid MultiMemRead packet prefix");3198 3199  packet.remove_prefix(packet_name.size());3200 3201  const std::string_view ranges_prefix("ranges:");3202  if (!starts_with(packet, ranges_prefix))3203    return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),3204                                  "Missing 'ranges' in MultiMemRead packet");3205  packet.remove_prefix(ranges_prefix.size());3206 3207  std::vector<std::pair<nub_addr_t, std::size_t>> ranges;3208 3209  // Ranges should have the form: <addr>,<size>[,<addr>,<size>]*;3210  auto end_of_ranges_pos = packet.find(';');3211  if (end_of_ranges_pos == packet.npos)3212    return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),3213                                  "MultiMemRead missing end of ranges marker");3214 3215  std::vector<std::string_view> numbers_list =3216      parse_comma_separated_list(packet.substr(0, end_of_ranges_pos));3217  packet.remove_prefix(end_of_ranges_pos + 1);3218 3219  // Ranges are pairs, so the number of elements must be even.3220  if (numbers_list.size() % 2 == 1)3221    return HandlePacket_ILLFORMED(3222        __FILE__, __LINE__, p,3223        "MultiMemRead has an odd number of numbers for the ranges");3224 3225  for (unsigned idx = 0; idx < numbers_list.size(); idx += 2) {3226    std::optional<uint64_t> maybe_addr = extract_u64(numbers_list[idx]);3227    std::optional<uint64_t> maybe_length = extract_u64(numbers_list[idx + 1]);3228    if (!maybe_addr || !maybe_length)3229      return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),3230                                    "Invalid MultiMemRead range");3231    // A sanity check that the packet requested is not too large or a negative3232    // number.3233    if (*maybe_length > 4 * 1024 * 1024)3234      return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),3235                                    "MultiMemRead length is too large");3236 3237    ranges.emplace_back(*maybe_addr, *maybe_length);3238  }3239 3240  if (ranges.empty())3241    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3242                                  "MultiMemRead has an empty range list");3243 3244  if (!packet.empty())3245    return HandlePacket_ILLFORMED(3246        __FILE__, __LINE__, p, "MultiMemRead packet has unrecognized fields");3247 3248  std::vector<std::vector<uint8_t>> buffers;3249  buffers.reserve(ranges.size());3250  for (auto [base_addr, length] : ranges) {3251    buffers.emplace_back(length, 0);3252    nub_size_t bytes_read = DNBProcessMemoryRead(m_ctx.ProcessID(), base_addr,3253                                                 length, buffers.back().data());3254    buffers.back().resize(bytes_read);3255  }3256 3257  std::ostringstream reply_stream;3258  bool first = true;3259  for (const std::vector<uint8_t> &buffer : buffers) {3260    reply_stream << (first ? "" : ",") << std::hex << buffer.size();3261    first = false;3262  }3263  reply_stream << ';';3264 3265  for (const std::vector<uint8_t> &buffer : buffers)3266    binary_encode_data_vector(reply_stream, buffer);3267 3268  return SendPacket(reply_stream.str());3269}3270 3271// Read memory, sent it up as binary data.3272// Usage:  xADDR,LEN3273// ADDR and LEN are both base 16.3274 3275// Responds with 'OK' for zero-length request3276// or3277//3278// DATA3279//3280// where DATA is the binary data payload.3281 3282rnb_err_t RNBRemote::HandlePacket_x(const char *p) {3283  if (p == NULL || p[0] == '\0' || strlen(p) < 3) {3284    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short X packet");3285  }3286 3287  char *c;3288  p++;3289  errno = 0;3290  nub_addr_t addr = strtoull(p, &c, 16);3291  if (errno != 0) {3292    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3293                                  "Invalid address in X packet");3294  }3295  if (*c != ',') {3296    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3297                                  "Comma sep missing in X packet");3298  }3299 3300  /* Advance 'p' to the number of bytes to be read.  */3301  p += (c - p) + 1;3302 3303  errno = 0;3304  auto length = strtoul(p, NULL, 16);3305  if (errno != 0) {3306    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3307                                  "Invalid length in x packet");3308  }3309 3310  // zero length read means this is a test of whether that packet is implemented3311  // or not.3312  if (length == 0) {3313    return SendPacket("OK");3314  }3315 3316  std::vector<uint8_t> buf(length);3317 3318  if (buf.capacity() != length) {3319    return SendErrorPacket("E79");3320  }3321  nub_size_t bytes_read =3322      DNBProcessMemoryRead(m_ctx.ProcessID(), addr, buf.size(), &buf[0]);3323  if (bytes_read == 0) {3324    return SendErrorPacket("E80");3325  }3326 3327  buf.resize(bytes_read);3328  std::ostringstream ostrm;3329  binary_encode_data_vector(ostrm, buf);3330 3331  return SendPacket(ostrm.str());3332}3333 3334rnb_err_t RNBRemote::HandlePacket_X(const char *p) {3335  if (p == NULL || p[0] == '\0' || strlen(p) < 3) {3336    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short X packet");3337  }3338 3339  char *c;3340  p++;3341  errno = 0;3342  nub_addr_t addr = strtoull(p, &c, 16);3343  if (errno != 0 && addr == 0) {3344    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3345                                  "Invalid address in X packet");3346  }3347  if (*c != ',') {3348    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3349                                  "Comma sep missing in X packet");3350  }3351 3352  /* Advance 'p' to the length part of the packet.  NB this is the length of the3353     packet3354     including any escaped chars.  The data payload may be a little bit smaller3355     after3356     decoding.  */3357  p += (c - p) + 1;3358 3359  errno = 0;3360  auto length = strtoul(p, NULL, 16);3361  if (errno != 0 && length == 0) {3362    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3363                                  "Invalid length in X packet");3364  }3365 3366  // I think gdb sends a zero length write request to test whether this3367  // packet is accepted.3368  if (length == 0) {3369    return SendPacket("OK");3370  }3371 3372  std::vector<uint8_t> data = decode_binary_data(c, -1);3373  std::vector<uint8_t>::const_iterator it;3374  uint8_t *buf = (uint8_t *)alloca(data.size());3375  uint8_t *i = buf;3376  for (it = data.begin(); it != data.end(); ++it) {3377    *i++ = *it;3378  }3379 3380  nub_size_t wrote =3381      DNBProcessMemoryWrite(m_ctx.ProcessID(), addr, data.size(), buf);3382  if (wrote != data.size())3383    return SendErrorPacket("E08");3384  return SendPacket("OK");3385}3386 3387static bool RNBRemoteShouldCancelCallback(void *not_used) {3388  RNBRemoteSP remoteSP(g_remoteSP);3389  if (remoteSP.get() != NULL) {3390    RNBRemote *remote = remoteSP.get();3391    return !remote->Comm().IsConnected();3392  }3393  return true;3394}3395 3396// FORMAT: _MXXXXXX,PPP3397//      XXXXXX: big endian hex chars3398//      PPP: permissions can be any combo of r w x chars3399//3400// RESPONSE: XXXXXX3401//      XXXXXX: hex address of the newly allocated memory3402//      EXX: error code3403//3404// EXAMPLES:3405//      _M123000,rw3406//      _M123000,rwx3407//      _M123000,xw3408 3409rnb_err_t RNBRemote::HandlePacket_AllocateMemory(const char *p) {3410  StdStringExtractor packet(p);3411  packet.SetFilePos(2); // Skip the "_M"3412 3413  nub_addr_t size = packet.GetHexMaxU64(StdStringExtractor::BigEndian, 0);3414  if (size != 0) {3415    if (packet.GetChar() == ',') {3416      uint32_t permissions = 0;3417      char ch;3418      bool success = true;3419      while (success && (ch = packet.GetChar()) != '\0') {3420        switch (ch) {3421        case 'r':3422          permissions |= eMemoryPermissionsReadable;3423          break;3424        case 'w':3425          permissions |= eMemoryPermissionsWritable;3426          break;3427        case 'x':3428          permissions |= eMemoryPermissionsExecutable;3429          break;3430        default:3431          success = false;3432          break;3433        }3434      }3435 3436      if (success) {3437        nub_addr_t addr =3438            DNBProcessMemoryAllocate(m_ctx.ProcessID(), size, permissions);3439        if (addr != INVALID_NUB_ADDRESS) {3440          std::ostringstream ostrm;3441          ostrm << RAW_HEXBASE << addr;3442          return SendPacket(ostrm.str());3443        }3444      }3445    }3446  }3447  return SendErrorPacket("E53");3448}3449 3450// FORMAT: _mXXXXXX3451//      XXXXXX: address that was previously allocated3452//3453// RESPONSE: XXXXXX3454//      OK: address was deallocated3455//      EXX: error code3456//3457// EXAMPLES:3458//      _m1230003459 3460rnb_err_t RNBRemote::HandlePacket_DeallocateMemory(const char *p) {3461  StdStringExtractor packet(p);3462  packet.SetFilePos(2); // Skip the "_m"3463  nub_addr_t addr =3464      packet.GetHexMaxU64(StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS);3465 3466  if (addr != INVALID_NUB_ADDRESS) {3467    if (DNBProcessMemoryDeallocate(m_ctx.ProcessID(), addr))3468      return SendPacket("OK");3469  }3470  return SendErrorPacket("E54");3471}3472 3473// FORMAT: QSaveRegisterState;thread:TTTT;  (when thread suffix is supported)3474// FORMAT: QSaveRegisterState               (when thread suffix is NOT3475// supported)3476//      TTTT: thread ID in hex3477//3478// RESPONSE:3479//      SAVEID: Where SAVEID is a decimal number that represents the save ID3480//              that can be passed back into a "QRestoreRegisterState" packet3481//      EXX: error code3482//3483// EXAMPLES:3484//      QSaveRegisterState;thread:1E34;     (when thread suffix is supported)3485//      QSaveRegisterState                  (when thread suffix is NOT3486//      supported)3487 3488rnb_err_t RNBRemote::HandlePacket_SaveRegisterState(const char *p) {3489  nub_process_t pid = m_ctx.ProcessID();3490  nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p);3491  if (tid == INVALID_NUB_THREAD) {3492    if (m_thread_suffix_supported)3493      return HandlePacket_ILLFORMED(3494          __FILE__, __LINE__, p,3495          "No thread specified in QSaveRegisterState packet");3496    else3497      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3498                                    "No thread was is set with the Hg packet");3499  }3500 3501  // Get the register context size first by calling with NULL buffer3502  const uint32_t save_id = DNBThreadSaveRegisterState(pid, tid);3503  if (save_id != 0) {3504    char response[64];3505    snprintf(response, sizeof(response), "%u", save_id);3506    return SendPacket(response);3507  } else {3508    return SendErrorPacket("E75");3509  }3510}3511// FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT;  (when thread suffix is3512// supported)3513// FORMAT: QRestoreRegisterState:SAVEID               (when thread suffix is NOT3514// supported)3515//      TTTT: thread ID in hex3516//      SAVEID: a decimal number that represents the save ID that was3517//              returned from a call to "QSaveRegisterState"3518//3519// RESPONSE:3520//      OK: successfully restored registers for the specified thread3521//      EXX: error code3522//3523// EXAMPLES:3524//      QRestoreRegisterState:1;thread:1E34;     (when thread suffix is3525//      supported)3526//      QRestoreRegisterState:1                  (when thread suffix is NOT3527//      supported)3528 3529rnb_err_t RNBRemote::HandlePacket_RestoreRegisterState(const char *p) {3530  nub_process_t pid = m_ctx.ProcessID();3531  nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p);3532  if (tid == INVALID_NUB_THREAD) {3533    if (m_thread_suffix_supported)3534      return HandlePacket_ILLFORMED(3535          __FILE__, __LINE__, p,3536          "No thread specified in QSaveRegisterState packet");3537    else3538      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3539                                    "No thread was is set with the Hg packet");3540  }3541 3542  StdStringExtractor packet(p);3543  packet.SetFilePos(3544      strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:"3545  const uint32_t save_id = packet.GetU32(0);3546 3547  if (save_id != 0) {3548    // Get the register context size first by calling with NULL buffer3549    if (DNBThreadRestoreRegisterState(pid, tid, save_id))3550      return SendPacket("OK");3551    else3552      return SendErrorPacket("E77");3553  }3554  return SendErrorPacket("E76");3555}3556 3557static bool GetProcessNameFrom_vAttach(const char *&p,3558                                       std::string &attach_name) {3559  bool return_val = true;3560  while (*p != '\0') {3561    char smallbuf[3];3562    smallbuf[0] = *p;3563    smallbuf[1] = *(p + 1);3564    smallbuf[2] = '\0';3565 3566    errno = 0;3567    int ch = static_cast<int>(strtoul(smallbuf, NULL, 16));3568    if (errno != 0 && ch == 0) {3569      return_val = false;3570      break;3571    }3572 3573    attach_name.push_back(ch);3574    p += 2;3575  }3576  return return_val;3577}3578 3579static bool supports_memory_tagging() {3580  const char *name = "hw.optional.arm.FEAT_MTE4";3581  uint32_t val;3582  size_t len = sizeof(val);3583  int ret = ::sysctlbyname(name, &val, &len, nullptr, 0);3584  if (ret != 0)3585    return false;3586 3587  assert(len == sizeof(val));3588  return val;3589}3590 3591rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) {3592  uint32_t max_packet_size = 128 * 1024; // 128 KiB is a reasonable max packet3593                                         // size--debugger can always use less3594  std::stringstream reply;3595  reply << "qXfer:features:read+;PacketSize=" << std::hex << max_packet_size3596        << ";";3597  reply << "qEcho+;native-signals+;";3598 3599  bool enable_compression = false;3600  (void)enable_compression;3601 3602#if (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1) ||                      \3603    (defined(TARGET_OS_IOS) && TARGET_OS_IOS == 1) ||                          \3604    (defined(TARGET_OS_TV) && TARGET_OS_TV == 1) ||                            \3605    (defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1) ||                    \3606    (defined(TARGET_OS_XR) && TARGET_OS_XR == 1)3607  enable_compression = true;3608#endif3609 3610  if (enable_compression) {3611    reply << "SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;";3612  }3613 3614#if (defined(__arm64__) || defined(__aarch64__))3615  reply << "SupportedWatchpointTypes=aarch64-mask,aarch64-bas;";3616#endif3617#if defined(__x86_64__)3618  reply << "SupportedWatchpointTypes=x86_64;";3619#endif3620 3621  if (supports_memory_tagging())3622    reply << "memory-tagging+;";3623 3624  reply << "MultiMemRead+;";3625  return SendPacket(reply.str().c_str());3626}3627 3628static bool process_does_not_exist (nub_process_t pid) {3629  std::vector<struct kinfo_proc> proc_infos;3630  DNBGetAllInfos (proc_infos);3631  const size_t infos_size = proc_infos.size();3632  for (size_t i = 0; i < infos_size; i++)3633    if (proc_infos[i].kp_proc.p_pid == pid)3634      return false;3635 3636  return true; // process does not exist3637}3638 3639// my_uid and process_uid are only initialized if this function3640// returns true -- that there was a uid mismatch -- and those3641// id's may want to be used in the error message.3642// 3643// NOTE: this should only be called after process_does_not_exist().3644// This sysctl will return uninitialized data if we ask for a pid3645// that doesn't exist.  The alternative would be to fetch all3646// processes and step through to find the one we're looking for3647// (as process_does_not_exist() does).3648static bool attach_failed_due_to_uid_mismatch (nub_process_t pid,3649                                               uid_t &my_uid,3650                                               uid_t &process_uid) {3651  struct kinfo_proc kinfo;3652  int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};3653  size_t len = sizeof(struct kinfo_proc);3654  if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &kinfo, &len, NULL, 0) != 0) {3655    return false; // pid doesn't exist? can't check uid mismatch - it was fine3656  }3657  my_uid = geteuid();3658  if (my_uid == 0)3659    return false; // if we're root, attach didn't fail because of uid mismatch3660  process_uid = kinfo.kp_eproc.e_ucred.cr_uid;3661 3662  // If my uid != the process' uid, then the attach probably failed because3663  // of that.3664  if (my_uid != process_uid)3665    return true;3666  else3667    return false;3668}3669 3670// NOTE: this should only be called after process_does_not_exist().3671// This sysctl will return uninitialized data if we ask for a pid3672// that doesn't exist.  The alternative would be to fetch all3673// processes and step through to find the one we're looking for3674// (as process_does_not_exist() does).3675static bool process_is_already_being_debugged (nub_process_t pid) {3676  if (DNBProcessIsBeingDebugged(pid) && DNBGetParentProcessID(pid) != getpid())3677    return true;3678  else3679    return false;3680}3681 3682// Test if this current login session has a connection to the3683// window server (if it does not have that access, it cannot ask3684// for debug permission by popping up a dialog box and attach3685// may fail outright).3686static bool login_session_has_gui_access () {3687  // I believe this API only works on macOS.3688#if TARGET_OS_OSX == 03689  return true;3690#else3691  auditinfo_addr_t info;3692  getaudit_addr(&info, sizeof(info));3693  if (info.ai_flags & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)3694    return true;3695  else3696    return false;3697#endif3698}3699 3700// Checking for 3701//3702//  {3703//    'class' : 'rule',3704//    'comment' : 'For use by Apple.  WARNING: administrators are advised3705//              not to modify this right.',3706//    'k-of-n' : '1',3707//    'rule' : [3708//      'is-admin',3709//      'is-developer',3710//      'authenticate-developer'3711//    ]3712//  }3713//3714// $ security authorizationdb read system.privilege.taskport.debug3715 3716static bool developer_mode_enabled () {3717  // This API only exists on macOS.3718#if TARGET_OS_OSX == 03719  return true;3720#else3721 CFDictionaryRef currentRightDict = NULL;3722 const char *debug_right = "system.privilege.taskport.debug";3723 // caller must free dictionary initialized by the following3724 OSStatus status = AuthorizationRightGet(debug_right, &currentRightDict);3725 if (status != errAuthorizationSuccess) {3726   // could not check authorization3727   return true;3728 }3729 3730 bool devmode_enabled = true;3731 3732 if (!CFDictionaryContainsKey(currentRightDict, CFSTR("k-of-n"))) {3733   devmode_enabled = false;3734 } else {3735   CFNumberRef item = (CFNumberRef) CFDictionaryGetValue(currentRightDict, CFSTR("k-of-n"));3736   if (item && CFGetTypeID(item) == CFNumberGetTypeID()) {3737      int64_t num = 0;3738      ::CFNumberGetValue(item, kCFNumberSInt64Type, &num);3739      if (num != 1) {3740        devmode_enabled = false;3741      }3742   } else {3743     devmode_enabled = false;3744   }3745 }3746 3747 if (!CFDictionaryContainsKey(currentRightDict, CFSTR("class"))) {3748   devmode_enabled = false;3749 } else {3750   CFStringRef item = (CFStringRef) CFDictionaryGetValue(currentRightDict, CFSTR("class"));3751   if (item && CFGetTypeID(item) == CFStringGetTypeID()) {3752     char tmpbuf[128];3753     if (CFStringGetCString (item, tmpbuf, sizeof(tmpbuf), CFStringGetSystemEncoding())) {3754       tmpbuf[sizeof (tmpbuf) - 1] = '\0';3755       if (strcmp (tmpbuf, "rule") != 0) {3756         devmode_enabled = false;3757       }3758     } else {3759       devmode_enabled = false;3760     }3761   } else {3762     devmode_enabled = false;3763   }3764 }3765 3766 if (!CFDictionaryContainsKey(currentRightDict, CFSTR("rule"))) {3767   devmode_enabled = false;3768 } else {3769   CFArrayRef item = (CFArrayRef) CFDictionaryGetValue(currentRightDict, CFSTR("rule"));3770   if (item && CFGetTypeID(item) == CFArrayGetTypeID()) {3771     int count = ::CFArrayGetCount(item);3772      CFRange range = CFRangeMake (0, count);3773     if (!::CFArrayContainsValue (item, range, CFSTR("is-admin")))3774       devmode_enabled = false;3775     if (!::CFArrayContainsValue (item, range, CFSTR("is-developer")))3776       devmode_enabled = false;3777     if (!::CFArrayContainsValue (item, range, CFSTR("authenticate-developer")))3778       devmode_enabled = false;3779   } else {3780     devmode_enabled = false;3781   }3782 }3783 ::CFRelease(currentRightDict);3784 3785 return devmode_enabled;3786#endif // TARGET_OS_OSX3787}3788 3789/*3790 vAttach;pid3791 3792 Attach to a new process with the specified process ID. pid is a hexadecimal3793 integer3794 identifying the process. If the stub is currently controlling a process, it is3795 killed. The attached process is stopped.This packet is only available in3796 extended3797 mode (see extended mode).3798 3799 Reply:3800 "ENN"                      for an error3801 "Any Stop Reply Packet"     for success3802 */3803 3804rnb_err_t RNBRemote::HandlePacket_v(const char *p) {3805  if (strcmp(p, "vCont;c") == 0) {3806    // Simple continue3807    return RNBRemote::HandlePacket_c("c");3808  } else if (strcmp(p, "vCont;s") == 0) {3809    // Simple step3810    return RNBRemote::HandlePacket_s("s");3811  } else if (strstr(p, "vCont") == p) {3812    DNBThreadResumeActions thread_actions;3813    char *c = const_cast<char *>(p += strlen("vCont"));3814    char *c_end = c + strlen(c);3815    if (*c == '?')3816      return SendPacket("vCont;c;C;s;S");3817 3818    while (c < c_end && *c == ';') {3819      ++c; // Skip the semi-colon3820      DNBThreadResumeAction thread_action;3821      thread_action.tid = INVALID_NUB_THREAD;3822      thread_action.state = eStateInvalid;3823      thread_action.signal = 0;3824      thread_action.addr = INVALID_NUB_ADDRESS;3825 3826      char action = *c++;3827 3828      switch (action) {3829      case 'C':3830        errno = 0;3831        thread_action.signal = static_cast<int>(strtoul(c, &c, 16));3832        if (errno != 0)3833          return HandlePacket_ILLFORMED(3834              __FILE__, __LINE__, p, "Could not parse signal in vCont packet");3835      // Fall through to next case...3836        [[clang::fallthrough]];3837      case 'c':3838        // Continue3839        thread_action.state = eStateRunning;3840        break;3841 3842      case 'S':3843        errno = 0;3844        thread_action.signal = static_cast<int>(strtoul(c, &c, 16));3845        if (errno != 0)3846          return HandlePacket_ILLFORMED(3847              __FILE__, __LINE__, p, "Could not parse signal in vCont packet");3848      // Fall through to next case...3849        [[clang::fallthrough]];3850      case 's':3851        // Step3852        thread_action.state = eStateStepping;3853        break;3854 3855      default:3856        HandlePacket_ILLFORMED(__FILE__, __LINE__, p,3857                               "Unsupported action in vCont packet");3858        break;3859      }3860      if (*c == ':') {3861        errno = 0;3862        thread_action.tid = strtoul(++c, &c, 16);3863        if (errno != 0)3864          return HandlePacket_ILLFORMED(3865              __FILE__, __LINE__, p,3866              "Could not parse thread number in vCont packet");3867      }3868 3869      thread_actions.Append(thread_action);3870    }3871 3872    // If a default action for all other threads wasn't mentioned3873    // then we should stop the threads3874    thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);3875    DNBProcessResume(m_ctx.ProcessID(), thread_actions.GetFirst(),3876                     thread_actions.GetSize());3877    return rnb_success;3878  } else if (strstr(p, "vAttach") == p) {3879    nub_process_t attach_pid =3880        INVALID_NUB_PROCESS; // attach_pid will be set to 0 if the attach fails3881    nub_process_t pid_attaching_to =3882        INVALID_NUB_PROCESS; // pid_attaching_to is the original pid specified3883    char err_str[1024] = {'\0'};3884    std::string attach_name;3885 3886    if (strstr(p, "vAttachWait;") == p) {3887      p += strlen("vAttachWait;");3888      if (!GetProcessNameFrom_vAttach(p, attach_name)) {3889        return HandlePacket_ILLFORMED(3890            __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");3891      }3892      DNBLog("[LaunchAttach] START %d vAttachWait for process name '%s'",3893             getpid(), attach_name.c_str());3894      const bool ignore_existing = true;3895      attach_pid = DNBProcessAttachWait(3896          &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str,3897          sizeof(err_str), RNBRemoteShouldCancelCallback);3898 3899    } else if (strstr(p, "vAttachOrWait;") == p) {3900      p += strlen("vAttachOrWait;");3901      if (!GetProcessNameFrom_vAttach(p, attach_name)) {3902        return HandlePacket_ILLFORMED(3903            __FILE__, __LINE__, p,3904            "non-hex char in arg on 'vAttachOrWait' pkt");3905      }3906      const bool ignore_existing = false;3907      DNBLog("[LaunchAttach] START %d vAttachWaitOrWait for process name "3908             "'%s'",3909             getpid(), attach_name.c_str());3910      attach_pid = DNBProcessAttachWait(3911          &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str,3912          sizeof(err_str), RNBRemoteShouldCancelCallback);3913    } else if (strstr(p, "vAttachName;") == p) {3914      p += strlen("vAttachName;");3915      if (!GetProcessNameFrom_vAttach(p, attach_name)) {3916        return HandlePacket_ILLFORMED(3917            __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt");3918      }3919 3920      DNBLog("[LaunchAttach] START %d vAttachName attach to process name "3921             "'%s'",3922             getpid(), attach_name.c_str());3923      attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL,3924                                          Context().GetIgnoredExceptions(), 3925                                          err_str, sizeof(err_str));3926 3927    } else if (strstr(p, "vAttach;") == p) {3928      p += strlen("vAttach;");3929      char *end = NULL;3930      pid_attaching_to = static_cast<int>(3931          strtoul(p, &end, 16)); // PID will be in hex, so use base 16 to decode3932      if (p != end && *end == '\0') {3933        // Wait at most 30 second for attach3934        struct timespec attach_timeout_abstime;3935        DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0);3936        DNBLog("[LaunchAttach] START %d vAttach to pid %d", getpid(),3937               pid_attaching_to);3938        attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime,3939                                      m_ctx.GetIgnoredExceptions(), 3940                                      err_str, sizeof(err_str));3941      }3942    } else {3943      return HandlePacket_UNIMPLEMENTED(p);3944    }3945 3946    if (attach_pid == INVALID_NUB_PROCESS_ARCH) {3947      DNBLogError("debugserver is x86_64 binary running in translation, attach "3948                  "failed.");3949      return SendErrorPacket("E96", "debugserver is x86_64 binary running in "3950                                    "translation, attach failed.");3951    }3952 3953    if (attach_pid != INVALID_NUB_PROCESS) {3954      if (m_ctx.ProcessID() != attach_pid)3955        m_ctx.SetProcessID(attach_pid);3956      DNBLog("Successfully attached to pid %d", attach_pid);3957      // Send a stop reply packet to indicate we successfully attached!3958      NotifyThatProcessStopped();3959      return rnb_success;3960    } else {3961      DNBLogError("Attach failed");3962      m_ctx.LaunchStatus().SetError(-1, DNBError::Generic);3963      if (err_str[0])3964        m_ctx.LaunchStatus().SetErrorString(err_str);3965      else3966        m_ctx.LaunchStatus().SetErrorString("attach failed");3967 3968      if (pid_attaching_to == INVALID_NUB_PROCESS && !attach_name.empty()) {3969        pid_attaching_to = DNBProcessGetPIDByName(attach_name.c_str());3970      }3971 3972      // attach_pid is INVALID_NUB_PROCESS - we did not succeed in attaching3973      // if the original request, pid_attaching_to, is available, see if we3974      // can figure out why we couldn't attach.  Return an informative error3975      // string to lldb.3976 3977      if (pid_attaching_to != INVALID_NUB_PROCESS) {3978        // The order of these checks is important.  3979        if (process_does_not_exist (pid_attaching_to)) {3980          DNBLogError("Tried to attach to pid that doesn't exist");3981          return SendErrorPacket("E96", "no such process");3982        }3983        if (process_is_already_being_debugged (pid_attaching_to)) {3984          DNBLogError("Tried to attach to process already being debugged");3985          return SendErrorPacket("E96", "tried to attach to "3986                                        "process already being debugged");3987        }3988        uid_t my_uid, process_uid;3989        if (attach_failed_due_to_uid_mismatch (pid_attaching_to, 3990                                               my_uid, process_uid)) {3991          std::string my_username = "uid " + std::to_string (my_uid);3992          std::string process_username = "uid " + std::to_string (process_uid);3993          struct passwd *pw = getpwuid (my_uid);3994          if (pw && pw->pw_name) {3995            my_username = pw->pw_name;3996          }3997          pw = getpwuid (process_uid);3998          if (pw && pw->pw_name) {3999            process_username = pw->pw_name;4000          }4001          DNBLogError("Tried to attach to process with uid mismatch");4002          std::string msg = "tried to attach to process as user '" +4003                            my_username +4004                            "' and process is running "4005                            "as user '" +4006                            process_username + "'";4007          return SendErrorPacket("E96", msg);4008        }4009        if (!login_session_has_gui_access() && !developer_mode_enabled()) {4010          DNBLogError("Developer mode is not enabled and this is a "4011                      "non-interactive session");4012          return SendErrorPacket("E96", "developer mode is "4013                                        "not enabled on this machine "4014                                        "and this is a non-interactive "4015                                        "debug session.");4016        }4017        if (!login_session_has_gui_access()) {4018          DNBLogError("This is a non-interactive session");4019          return SendErrorPacket("E96", "this is a "4020                                        "non-interactive debug session, "4021                                        "cannot get permission to debug "4022                                        "processes.");4023        }4024      }4025 4026      std::string error_explainer = "attach failed";4027      if (err_str[0] != '\0') {4028        // This is not a super helpful message for end users4029        if (strcmp (err_str, "unable to start the exception thread") == 0) {4030          snprintf (err_str, sizeof (err_str) - 1,4031                    "Not allowed to attach to process.  Look in the console "4032                    "messages (Console.app), near the debugserver entries, "4033                    "when the attach failed.  The subsystem that denied "4034                    "the attach permission will likely have logged an "4035                    "informative message about why it was denied.");4036          err_str[sizeof (err_str) - 1] = '\0';4037        }4038        error_explainer += " (";4039        error_explainer += err_str;4040        error_explainer += ")";4041      }4042      DNBLogError("Attach failed: \"%s\".", err_str);4043      return SendErrorPacket("E96", error_explainer);4044    }4045  }4046 4047  // All other failures come through here4048  return HandlePacket_UNIMPLEMENTED(p);4049}4050 4051/* 'T XX' -- status of thread4052 Check if the specified thread is alive.4053 The thread number is in hex?  */4054 4055rnb_err_t RNBRemote::HandlePacket_T(const char *p) {4056  p++;4057  if (p == NULL || *p == '\0') {4058    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4059                                  "No thread specified in T packet");4060  }4061  if (!m_ctx.HasValidProcessID()) {4062    return SendErrorPacket("E15");4063  }4064  errno = 0;4065  nub_thread_t tid = strtoul(p, NULL, 16);4066  if (errno != 0 && tid == 0) {4067    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4068                                  "Could not parse thread number in T packet");4069  }4070 4071  nub_state_t state = DNBThreadGetState(m_ctx.ProcessID(), tid);4072  if (state == eStateInvalid || state == eStateExited ||4073      state == eStateCrashed) {4074    return SendErrorPacket("E16");4075  }4076 4077  return SendPacket("OK");4078}4079 4080rnb_err_t RNBRemote::HandlePacket_z(const char *p) {4081  if (p == NULL || *p == '\0')4082    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4083                                  "No thread specified in z packet");4084 4085  if (!m_ctx.HasValidProcessID())4086    return SendErrorPacket("E15");4087 4088  char packet_cmd = *p++;4089  char break_type = *p++;4090 4091  if (*p++ != ',')4092    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4093                                  "Comma separator missing in z packet");4094 4095  char *c = NULL;4096  nub_process_t pid = m_ctx.ProcessID();4097  errno = 0;4098  nub_addr_t addr = strtoull(p, &c, 16);4099  if (errno != 0 && addr == 0)4100    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4101                                  "Invalid address in z packet");4102  p = c;4103  if (*p++ != ',')4104    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4105                                  "Comma separator missing in z packet");4106 4107  errno = 0;4108  auto byte_size = strtoul(p, &c, 16);4109  if (errno != 0 && byte_size == 0)4110    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4111                                  "Invalid length in z packet");4112 4113  if (packet_cmd == 'Z') {4114    // set4115    switch (break_type) {4116    case '0': // set software breakpoint4117    case '1': // set hardware breakpoint4118    {4119      // gdb can send multiple Z packets for the same address and4120      // these calls must be ref counted.4121      bool hardware = (break_type == '1');4122 4123      if (DNBBreakpointSet(pid, addr, byte_size, hardware)) {4124        // We successfully created a breakpoint, now lets full out4125        // a ref count structure with the breakID and add it to our4126        // map.4127        return SendPacket("OK");4128      } else {4129        // We failed to set the software breakpoint4130        return SendErrorPacket("E09");4131      }4132    } break;4133 4134    case '2': // set write watchpoint4135    case '3': // set read watchpoint4136    case '4': // set access watchpoint4137    {4138      bool hardware = true;4139      uint32_t watch_flags = 0;4140      if (break_type == '2')4141        watch_flags = WATCH_TYPE_WRITE;4142      else if (break_type == '3')4143        watch_flags = WATCH_TYPE_READ;4144      else4145        watch_flags = WATCH_TYPE_READ | WATCH_TYPE_WRITE;4146 4147      if (DNBWatchpointSet(pid, addr, byte_size, watch_flags, hardware)) {4148        return SendPacket("OK");4149      } else {4150        // We failed to set the watchpoint4151        return SendErrorPacket("E09");4152      }4153    } break;4154 4155    default:4156      break;4157    }4158  } else if (packet_cmd == 'z') {4159    // remove4160    switch (break_type) {4161    case '0': // remove software breakpoint4162    case '1': // remove hardware breakpoint4163      if (DNBBreakpointClear(pid, addr)) {4164        return SendPacket("OK");4165      } else {4166        return SendErrorPacket("E08");4167      }4168      break;4169 4170    case '2': // remove write watchpoint4171    case '3': // remove read watchpoint4172    case '4': // remove access watchpoint4173      if (DNBWatchpointClear(pid, addr)) {4174        return SendPacket("OK");4175      } else {4176        return SendErrorPacket("E08");4177      }4178      break;4179 4180    default:4181      break;4182    }4183  }4184  return HandlePacket_UNIMPLEMENTED(p);4185}4186 4187// Extract the thread number from the thread suffix that might be appended to4188// thread specific packets. This will only be enabled if4189// m_thread_suffix_supported4190// is true.4191nub_thread_t RNBRemote::ExtractThreadIDFromThreadSuffix(const char *p) {4192  if (m_thread_suffix_supported) {4193    nub_thread_t tid = INVALID_NUB_THREAD;4194    if (p) {4195      const char *tid_cstr = strstr(p, "thread:");4196      if (tid_cstr) {4197        tid_cstr += strlen("thread:");4198        tid = strtoul(tid_cstr, NULL, 16);4199      }4200    }4201    return tid;4202  }4203  return GetCurrentThread();4204}4205 4206/* 'p XX'4207 print the contents of register X */4208 4209rnb_err_t RNBRemote::HandlePacket_p(const char *p) {4210  if (g_num_reg_entries == 0)4211    InitializeRegisters();4212 4213  if (p == NULL || *p == '\0') {4214    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4215                                  "No thread specified in p packet");4216  }4217  if (!m_ctx.HasValidProcessID()) {4218    return SendErrorPacket("E15");4219  }4220  nub_process_t pid = m_ctx.ProcessID();4221  errno = 0;4222  char *tid_cstr = NULL;4223  uint32_t reg = static_cast<uint32_t>(strtoul(p + 1, &tid_cstr, 16));4224  if (errno != 0 && reg == 0) {4225    return HandlePacket_ILLFORMED(4226        __FILE__, __LINE__, p, "Could not parse register number in p packet");4227  }4228 4229  nub_thread_t tid = ExtractThreadIDFromThreadSuffix(tid_cstr);4230  if (tid == INVALID_NUB_THREAD)4231    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4232                                  "No thread specified in p packet");4233 4234  const register_map_entry_t *reg_entry;4235 4236  if (reg < g_num_reg_entries)4237    reg_entry = &g_reg_entries[reg];4238  else4239    reg_entry = NULL;4240 4241  std::ostringstream ostrm;4242  if (reg_entry == NULL) {4243    DNBLogError(4244        "RNBRemote::HandlePacket_p(%s): unknown register number %u requested\n",4245        p, reg);4246    ostrm << "00000000";4247  } else if (reg_entry->nub_info.reg == (uint32_t)-1) {4248    if (reg_entry->nub_info.size > 0) {4249      std::vector<uint8_t> zeros(reg_entry->nub_info.size, '\0');4250      append_hex_value(ostrm, zeros.data(), zeros.size(), false);4251    }4252  } else {4253    if (!register_value_in_hex_fixed_width(ostrm, pid, tid, reg_entry, NULL,4254                                           std::nullopt))4255      return SendErrorPacket("E97");4256  }4257  return SendPacket(ostrm.str());4258}4259 4260/* 'Pnn=rrrrr'4261 Set register number n to value r.4262 n and r are hex strings.  */4263 4264rnb_err_t RNBRemote::HandlePacket_P(const char *p) {4265  if (g_num_reg_entries == 0)4266    InitializeRegisters();4267 4268  if (p == NULL || *p == '\0') {4269    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Empty P packet");4270  }4271  if (!m_ctx.HasValidProcessID()) {4272    return SendErrorPacket("E28");4273  }4274 4275  nub_process_t pid = m_ctx.ProcessID();4276 4277  StdStringExtractor packet(p);4278 4279  const char cmd_char = packet.GetChar();4280  // Register ID is always in big endian4281  const uint32_t reg = packet.GetHexMaxU32(false, UINT32_MAX);4282  const char equal_char = packet.GetChar();4283 4284  if (cmd_char != 'P')4285    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4286                                  "Improperly formed P packet");4287 4288  if (reg == UINT32_MAX)4289    return SendErrorPacket("E29");4290 4291  if (equal_char != '=')4292    return SendErrorPacket("E30");4293 4294  const register_map_entry_t *reg_entry;4295 4296  if (reg >= g_num_reg_entries)4297    return SendErrorPacket("E47");4298 4299  reg_entry = &g_reg_entries[reg];4300 4301  if (reg_entry->nub_info.set == (uint32_t)-1 &&4302      reg_entry->nub_info.reg == (uint32_t)-1) {4303    DNBLogError(4304        "RNBRemote::HandlePacket_P(%s): unknown register number %u requested\n",4305        p, reg);4306    return SendErrorPacket("E48");4307  }4308 4309  std::unique_ptr<DNBRegisterValue> reg_value =4310      std::make_unique<DNBRegisterValue>();4311  reg_value->info = reg_entry->nub_info;4312  packet.GetHexBytes(reg_value->value.v_sint8, reg_entry->nub_info.size, 0xcc);4313 4314  nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p);4315  if (tid == INVALID_NUB_THREAD)4316    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4317                                  "No thread specified in p packet");4318 4319  if (!DNBThreadSetRegisterValueByID(pid, tid, reg_entry->nub_info.set,4320                                     reg_entry->nub_info.reg,4321                                     reg_value.get())) {4322    return SendErrorPacket("E32");4323  }4324  return SendPacket("OK");4325}4326 4327/* 'c [addr]'4328 Continue, optionally from a specified address. */4329 4330rnb_err_t RNBRemote::HandlePacket_c(const char *p) {4331  const nub_process_t pid = m_ctx.ProcessID();4332 4333  if (pid == INVALID_NUB_PROCESS)4334    return SendErrorPacket("E23");4335 4336  DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateRunning, 0,4337                                  INVALID_NUB_ADDRESS};4338 4339  if (*(p + 1) != '\0') {4340    action.tid = GetContinueThread();4341    errno = 0;4342    action.addr = strtoull(p + 1, NULL, 16);4343    if (errno != 0 && action.addr == 0)4344      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4345                                    "Could not parse address in c packet");4346  }4347 4348  DNBThreadResumeActions thread_actions;4349  thread_actions.Append(action);4350  thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0);4351  if (!DNBProcessResume(pid, thread_actions.GetFirst(),4352                        thread_actions.GetSize()))4353    return SendErrorPacket("E25");4354  // Don't send an "OK" packet; response is the stopped/exited message.4355  return rnb_success;4356}4357 4358rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) {4359  /* This packet will find memory attributes (e.g. readable, writable,4360     executable, stack, jitted code)4361     for the memory region containing a given address and return that4362     information.4363 4364     Users of this packet must be prepared for three results:4365 4366         Region information is returned4367         Region information is unavailable for this address because the address4368     is in unmapped memory4369         Region lookup cannot be performed on this platform or process is not4370     yet launched4371 4372     Examples of use:4373        qMemoryRegionInfo:3a551404374        start:3a50000,size:100000,permissions:rwx4375 4376        qMemoryRegionInfo:04377        error:address in unmapped region4378 4379        qMemoryRegionInfo:3a551140   (on a different platform)4380        error:region lookup cannot be performed4381 4382        qMemoryRegionInfo4383        OK                   // this packet is implemented by the remote nub4384  */4385 4386  p += sizeof("qMemoryRegionInfo") - 1;4387  if (*p == '\0')4388    return SendPacket("OK");4389  if (*p++ != ':')4390    return SendErrorPacket("E67");4391  if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))4392    p += 2;4393 4394  errno = 0;4395  uint64_t address = strtoul(p, NULL, 16);4396  if (errno != 0 && address == 0) {4397    return HandlePacket_ILLFORMED(4398        __FILE__, __LINE__, p, "Invalid address in qMemoryRegionInfo packet");4399  }4400 4401  DNBRegionInfo region_info;4402  DNBProcessMemoryRegionInfo(m_ctx.ProcessID(), address, &region_info);4403  std::ostringstream ostrm;4404 4405  // start:3a50000,size:100000,permissions:rwx4406  ostrm << "start:" << std::hex << region_info.addr << ';';4407 4408  if (region_info.size > 0)4409    ostrm << "size:" << std::hex << region_info.size << ';';4410 4411  if (region_info.permissions) {4412    ostrm << "permissions:";4413 4414    if (region_info.permissions & eMemoryPermissionsReadable)4415      ostrm << 'r';4416    if (region_info.permissions & eMemoryPermissionsWritable)4417      ostrm << 'w';4418    if (region_info.permissions & eMemoryPermissionsExecutable)4419      ostrm << 'x';4420    ostrm << ';';4421 4422    if (!region_info.flags.empty()) {4423      ostrm << "flags:";4424      for (size_t i = 0; i < region_info.flags.size(); i++) {4425        if (i != 0)4426          ostrm << " "; // Separator is whitespace4427        ostrm << region_info.flags[i];4428      }4429      ostrm << ";";4430    }4431 4432    ostrm << "dirty-pages:";4433    if (region_info.dirty_pages.size() > 0) {4434      bool first = true;4435      for (nub_addr_t addr : region_info.dirty_pages) {4436        if (!first)4437          ostrm << ",";4438        first = false;4439        ostrm << std::hex << addr;4440      }4441    }4442    ostrm << ";";4443    if (!region_info.vm_types.empty()) {4444      ostrm << "type:";4445      for (size_t i = 0; i < region_info.vm_types.size(); i++) {4446        if (i)4447          ostrm << ",";4448        ostrm << region_info.vm_types[i];4449      }4450      ostrm << ";";4451    }4452  }4453  return SendPacket(ostrm.str());4454}4455 4456// qMemTags:<hex address>,<hex length>:<hex type>4457rnb_err_t RNBRemote::HandlePacket_qMemTags(const char *p) {4458  nub_process_t pid = m_ctx.ProcessID();4459  if (pid == INVALID_NUB_PROCESS)4460    return SendPacket("OK");4461 4462  StdStringExtractor packet(p);4463  packet.SetFilePos(strlen("qMemTags:"));4464 4465  // Address4466  nub_addr_t addr =4467      packet.GetHexMaxU64(StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS);4468  if (addr == INVALID_NUB_ADDRESS)4469    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4470                                  "Invalid/missing address in qMemTags packet");4471  // ,4472  if (packet.GetChar() != ',')4473    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4474                                  "Invalid qMemTags packet format");4475  // Length4476  uint64_t length = packet.GetHexMaxU64(StdStringExtractor::BigEndian, 0);4477  if (length == 0)4478    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4479                                  "Invalid/missing length in qMemTags packet");4480  // :4481  if (packet.GetChar() != ':')4482    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4483                                  "Invalid qMemTags packet format");4484  // Type4485  // On the LLDB side this is a `int32_t` serialized as (unsigned) hex, which4486  // means negative values will show up as large positive values here.  Right4487  // now, we only support MTE (type 1), so we can ignore this complication.4488  uint32_t type = packet.GetHexMaxU32(StdStringExtractor::BigEndian, 0);4489  if (type != 1 /* MTE */)4490    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4491                                  "Invalid/missing type in qMemTags packet, "4492                                  "only MTE (type 1) is supported");4493  // <EOF>4494  if (packet.GetBytesLeft() != 0)4495    return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4496                                  "Invalid qMemTags packet format");4497 4498  std::vector<uint8_t> tags;4499  bool ok = DNBProcessGetMemoryTags(pid, addr, length, tags);4500  if (!ok)4501    return SendErrorPacket("E91");4502 4503  std::ostringstream ostrm;4504  ostrm << "m"; // Multi part replies4505  for (uint8_t tag : tags) {4506    ostrm << RAWHEX8(tag); // 2 hex chars per tag4507  }4508 4509  return SendPacket(ostrm.str());4510}4511 4512// qGetProfileData;scan_type:0xYYYYYYY4513rnb_err_t RNBRemote::HandlePacket_GetProfileData(const char *p) {4514  nub_process_t pid = m_ctx.ProcessID();4515  if (pid == INVALID_NUB_PROCESS)4516    return SendPacket("OK");4517 4518  StdStringExtractor packet(p += sizeof("qGetProfileData"));4519  DNBProfileDataScanType scan_type = eProfileAll;4520  std::string name;4521  std::string value;4522  while (packet.GetNameColonValue(name, value)) {4523    if (name == "scan_type") {4524      std::istringstream iss(value);4525      uint32_t int_value = 0;4526      if (iss >> std::hex >> int_value) {4527        scan_type = (DNBProfileDataScanType)int_value;4528      }4529    }4530  }4531 4532  std::string data = DNBProcessGetProfileData(pid, scan_type);4533  if (!data.empty()) {4534    return SendPacket(data);4535  } else {4536    return SendPacket("OK");4537  }4538}4539 4540// QSetEnableAsyncProfiling;enable:[0|1]:interval_usec:XXXXXX;scan_type:0xYYYYYYY4541rnb_err_t RNBRemote::HandlePacket_SetEnableAsyncProfiling(const char *p) {4542  nub_process_t pid = m_ctx.ProcessID();4543  if (pid == INVALID_NUB_PROCESS)4544    return SendPacket("OK");4545 4546  StdStringExtractor packet(p += sizeof("QSetEnableAsyncProfiling"));4547  bool enable = false;4548  uint64_t interval_usec = 0;4549  DNBProfileDataScanType scan_type = eProfileAll;4550  std::string name;4551  std::string value;4552  while (packet.GetNameColonValue(name, value)) {4553    if (name == "enable") {4554      enable = strtoul(value.c_str(), NULL, 10) > 0;4555    } else if (name == "interval_usec") {4556      interval_usec = strtoul(value.c_str(), NULL, 10);4557    } else if (name == "scan_type") {4558      std::istringstream iss(value);4559      uint32_t int_value = 0;4560      if (iss >> std::hex >> int_value) {4561        scan_type = (DNBProfileDataScanType)int_value;4562      }4563    }4564  }4565 4566  if (interval_usec == 0) {4567    enable = false;4568  }4569 4570  DNBProcessSetEnableAsyncProfiling(pid, enable, interval_usec, scan_type);4571  return SendPacket("OK");4572}4573 4574// QEnableCompression:type:<COMPRESSION-TYPE>;4575//4576// type: must be a type previously reported by the qXfer:features:4577// SupportedCompressions list4578 4579rnb_err_t RNBRemote::HandlePacket_QEnableCompression(const char *p) {4580  p += sizeof("QEnableCompression:") - 1;4581 4582  if (strstr(p, "type:zlib-deflate;") != nullptr) {4583    EnableCompressionNextSendPacket(compression_types::zlib_deflate);4584    return SendPacket("OK");4585  } else if (strstr(p, "type:lz4;") != nullptr) {4586    EnableCompressionNextSendPacket(compression_types::lz4);4587    return SendPacket("OK");4588  } else if (strstr(p, "type:lzma;") != nullptr) {4589    EnableCompressionNextSendPacket(compression_types::lzma);4590    return SendPacket("OK");4591  } else if (strstr(p, "type:lzfse;") != nullptr) {4592    EnableCompressionNextSendPacket(compression_types::lzfse);4593    return SendPacket("OK");4594  }4595 4596  return SendErrorPacket("E88");4597}4598 4599rnb_err_t RNBRemote::HandlePacket_qSpeedTest(const char *p) {4600  p += strlen("qSpeedTest:response_size:");4601  char *end = NULL;4602  errno = 0;4603  uint64_t response_size = ::strtoul(p, &end, 16);4604  if (errno != 0)4605    return HandlePacket_ILLFORMED(4606        __FILE__, __LINE__, p,4607        "Didn't find response_size value at right offset");4608  else if (*end == ';' && response_size < (4 * 1024 * 1024)) {4609    std::vector<char> buf(response_size + 6, 'a');4610    memcpy(buf.data(), "data:", 5);4611    buf[buf.size() - 1] = '\0';4612    rnb_err_t return_value = SendPacket(buf.data());4613    return return_value;4614  } else {4615    return SendErrorPacket("E79");4616  }4617}4618 4619rnb_err_t RNBRemote::HandlePacket_WatchpointSupportInfo(const char *p) {4620  /* This packet simply returns the number of supported hardware watchpoints.4621 4622     Examples of use:4623        qWatchpointSupportInfo:4624        num:44625 4626        qWatchpointSupportInfo4627        OK                   // this packet is implemented by the remote nub4628  */4629 4630  p += sizeof("qWatchpointSupportInfo") - 1;4631  if (*p == '\0')4632    return SendPacket("OK");4633  if (*p++ != ':')4634    return SendErrorPacket("E67");4635 4636  errno = 0;4637  uint32_t num = DNBWatchpointGetNumSupportedHWP(m_ctx.ProcessID());4638  std::ostringstream ostrm;4639 4640  // size:44641  ostrm << "num:" << std::dec << num << ';';4642  return SendPacket(ostrm.str());4643}4644 4645/* 'C sig [;addr]'4646 Resume with signal sig, optionally at address addr.  */4647 4648rnb_err_t RNBRemote::HandlePacket_C(const char *p) {4649  const nub_process_t pid = m_ctx.ProcessID();4650 4651  if (pid == INVALID_NUB_PROCESS)4652    return SendErrorPacket("E36");4653 4654  DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateRunning, 0,4655                                  INVALID_NUB_ADDRESS};4656  int process_signo = -1;4657  if (*(p + 1) != '\0') {4658    action.tid = GetContinueThread();4659    char *end = NULL;4660    errno = 0;4661    process_signo = static_cast<int>(strtoul(p + 1, &end, 16));4662    if (errno != 0)4663      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4664                                    "Could not parse signal in C packet");4665    else if (*end == ';') {4666      errno = 0;4667      action.addr = strtoull(end + 1, NULL, 16);4668      if (errno != 0 && action.addr == 0)4669        return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4670                                      "Could not parse address in C packet");4671    }4672  }4673 4674  DNBThreadResumeActions thread_actions;4675  thread_actions.Append(action);4676  thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, action.signal);4677  if (!DNBProcessSignal(pid, process_signo))4678    return SendErrorPacket("E52");4679  if (!DNBProcessResume(pid, thread_actions.GetFirst(),4680                        thread_actions.GetSize()))4681    return SendErrorPacket("E38");4682  /* Don't send an "OK" packet; response is the stopped/exited message.  */4683  return rnb_success;4684}4685 4686// 'D' packet4687// Detach from gdb.4688rnb_err_t RNBRemote::HandlePacket_D(const char *p) {4689  if (m_ctx.HasValidProcessID()) {4690    DNBLog("detaching from pid %u due to D packet", m_ctx.ProcessID());4691    if (DNBProcessDetach(m_ctx.ProcessID()))4692      SendPacket("OK");4693    else {4694      DNBLog("error while detaching from pid %u due to D packet",4695             m_ctx.ProcessID());4696      SendErrorPacket("E01");4697    }4698  } else {4699    SendErrorPacket("E04");4700  }4701  return rnb_success;4702}4703 4704/* 'k'4705 Kill the inferior process.  */4706 4707rnb_err_t RNBRemote::HandlePacket_k(const char *p) {4708  DNBLog("Got a 'k' packet, killing the inferior process.");4709  // No response to should be sent to the kill packet4710  if (m_ctx.HasValidProcessID())4711    DNBProcessKill(m_ctx.ProcessID());4712  SendPacket("X09");4713  return rnb_success;4714}4715 4716rnb_err_t RNBRemote::HandlePacket_stop_process(const char *p) {4717//#define TEST_EXIT_ON_INTERRUPT // This should only be uncommented to test4718//exiting on interrupt4719#if defined(TEST_EXIT_ON_INTERRUPT)4720  rnb_err_t err = HandlePacket_k(p);4721  m_comm.Disconnect(true);4722  return err;4723#else4724  if (!DNBProcessInterrupt(m_ctx.ProcessID())) {4725    // If we failed to interrupt the process, then send a stop4726    // reply packet as the process was probably already stopped4727    DNBLogThreaded("RNBRemote::HandlePacket_stop_process() sending extra stop "4728                   "reply because DNBProcessInterrupt returned false");4729    HandlePacket_last_signal(NULL);4730  }4731  return rnb_success;4732#endif4733}4734 4735/* 's'4736 Step the inferior process.  */4737 4738rnb_err_t RNBRemote::HandlePacket_s(const char *p) {4739  const nub_process_t pid = m_ctx.ProcessID();4740  if (pid == INVALID_NUB_PROCESS)4741    return SendErrorPacket("E32");4742 4743  // Hardware supported stepping not supported on arm4744  nub_thread_t tid = GetContinueThread();4745  if (tid == 0 || tid == (nub_thread_t)-1)4746    tid = GetCurrentThread();4747 4748  if (tid == INVALID_NUB_THREAD)4749    return SendErrorPacket("E33");4750 4751  DNBThreadResumeActions thread_actions;4752  thread_actions.AppendAction(tid, eStateStepping);4753 4754  // Make all other threads stop when we are stepping4755  thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);4756  if (!DNBProcessResume(pid, thread_actions.GetFirst(),4757                        thread_actions.GetSize()))4758    return SendErrorPacket("E49");4759  // Don't send an "OK" packet; response is the stopped/exited message.4760  return rnb_success;4761}4762 4763/* 'S sig [;addr]'4764 Step with signal sig, optionally at address addr.  */4765 4766rnb_err_t RNBRemote::HandlePacket_S(const char *p) {4767  const nub_process_t pid = m_ctx.ProcessID();4768  if (pid == INVALID_NUB_PROCESS)4769    return SendErrorPacket("E36");4770 4771  DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateStepping, 0,4772                                  INVALID_NUB_ADDRESS};4773 4774  if (*(p + 1) != '\0') {4775    char *end = NULL;4776    errno = 0;4777    action.signal = static_cast<int>(strtoul(p + 1, &end, 16));4778    if (errno != 0)4779      return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4780                                    "Could not parse signal in S packet");4781    else if (*end == ';') {4782      errno = 0;4783      action.addr = strtoull(end + 1, NULL, 16);4784      if (errno != 0 && action.addr == 0) {4785        return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,4786                                      "Could not parse address in S packet");4787      }4788    }4789  }4790 4791  action.tid = GetContinueThread();4792  if (action.tid == 0 || action.tid == (nub_thread_t)-1)4793    return SendErrorPacket("E40");4794 4795  nub_state_t tstate = DNBThreadGetState(pid, action.tid);4796  if (tstate == eStateInvalid || tstate == eStateExited)4797    return SendErrorPacket("E37");4798 4799  DNBThreadResumeActions thread_actions;4800  thread_actions.Append(action);4801 4802  // Make all other threads stop when we are stepping4803  thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);4804  if (!DNBProcessResume(pid, thread_actions.GetFirst(),4805                        thread_actions.GetSize()))4806    return SendErrorPacket("E39");4807 4808  // Don't send an "OK" packet; response is the stopped/exited message.4809  return rnb_success;4810}4811 4812static const char *GetArchName(const uint32_t cputype,4813                               const uint32_t cpusubtype) {4814  switch (cputype) {4815  case CPU_TYPE_ARM:4816    switch (cpusubtype) {4817    case 5:4818      return "armv4";4819    case 6:4820      return "armv6";4821    case 7:4822      return "armv5t";4823    case 8:4824      return "xscale";4825    case 9:4826      return "armv7";4827    case 10:4828      return "armv7f";4829    case 11:4830      return "armv7s";4831    case 12:4832      return "armv7k";4833    case 14:4834      return "armv6m";4835    case 15:4836      return "armv7m";4837    case 16:4838      return "armv7em";4839    default:4840      return "arm";4841    }4842    break;4843  case CPU_TYPE_ARM64:4844    return "arm64";4845  case CPU_TYPE_ARM64_32:4846    return "arm64_32";4847  case CPU_TYPE_I386:4848    return "i386";4849  case CPU_TYPE_X86_64:4850    switch (cpusubtype) {4851    default:4852      return "x86_64";4853    case 8:4854      return "x86_64h";4855    }4856    break;4857  }4858  return NULL;4859}4860 4861static bool GetHostCPUType(uint32_t &cputype, uint32_t &cpusubtype,4862                           uint32_t &is_64_bit_capable, bool &promoted_to_64) {4863  static uint32_t g_host_cputype = 0;4864  static uint32_t g_host_cpusubtype = 0;4865  static uint32_t g_is_64_bit_capable = 0;4866  static bool g_promoted_to_64 = false;4867 4868  if (g_host_cputype == 0) {4869    g_promoted_to_64 = false;4870    size_t len = sizeof(uint32_t);4871    if (::sysctlbyname("hw.cputype", &g_host_cputype, &len, NULL, 0) == 0) {4872      len = sizeof(uint32_t);4873      if (::sysctlbyname("hw.cpu64bit_capable", &g_is_64_bit_capable, &len,4874                         NULL, 0) == 0) {4875        if (g_is_64_bit_capable && ((g_host_cputype & CPU_ARCH_ABI64) == 0)) {4876          g_promoted_to_64 = true;4877          g_host_cputype |= CPU_ARCH_ABI64;4878        }4879      }4880#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 14881      if (g_host_cputype == CPU_TYPE_ARM64 && sizeof (void*) == 4)4882        g_host_cputype = CPU_TYPE_ARM64_32;4883#endif4884    }4885 4886    len = sizeof(uint32_t);4887    if (::sysctlbyname("hw.cpusubtype", &g_host_cpusubtype, &len, NULL, 0) ==4888        0) {4889      if (g_promoted_to_64 && g_host_cputype == CPU_TYPE_X86_64 &&4890          g_host_cpusubtype == CPU_SUBTYPE_486)4891        g_host_cpusubtype = CPU_SUBTYPE_X86_64_ALL;4892    }4893#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 14894    // on arm64_32 devices, the machine's native cpu type is4895    // CPU_TYPE_ARM64 and subtype is 2 indicating arm64e.4896    // But we change the cputype to CPU_TYPE_ARM64_32 because4897    // the user processes are all ILP32 processes today.4898    // We also need to rewrite the cpusubtype so we vend 4899    // a valid cputype + cpusubtype combination.4900    if (g_host_cputype == CPU_TYPE_ARM64_32)4901      g_host_cpusubtype = CPU_SUBTYPE_ARM64_32_V8;4902#endif4903  }4904 4905  cputype = g_host_cputype;4906  cpusubtype = g_host_cpusubtype;4907  is_64_bit_capable = g_is_64_bit_capable;4908  promoted_to_64 = g_promoted_to_64;4909  return g_host_cputype != 0;4910}4911 4912rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) {4913  std::ostringstream strm;4914 4915  uint32_t cputype = 0;4916  uint32_t cpusubtype = 0;4917  uint32_t is_64_bit_capable = 0;4918  bool promoted_to_64 = false;4919  if (GetHostCPUType(cputype, cpusubtype, is_64_bit_capable, promoted_to_64)) {4920    strm << "cputype:" << std::dec << cputype << ';';4921    strm << "cpusubtype:" << std::dec << cpusubtype << ';';4922  }4923 4924  uint32_t addressing_bits = 0;4925  if (DNBGetAddressingBits(addressing_bits)) {4926    strm << "addressing_bits:" << std::dec << addressing_bits << ';';4927  }4928 4929  // The OS in the triple should be "ios" or "macosx" which doesn't match our4930  // "Darwin" which gets returned from "kern.ostype", so we need to hardcode4931  // this for now.4932  if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM644933      || cputype == CPU_TYPE_ARM64_32) {4934#if defined(TARGET_OS_TV) && TARGET_OS_TV == 14935    strm << "ostype:tvos;";4936#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 14937    strm << "ostype:watchos;";4938#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 14939    strm << "ostype:bridgeos;";4940#elif defined(TARGET_OS_OSX) && TARGET_OS_OSX == 14941    strm << "ostype:macosx;";4942#elif defined(TARGET_OS_XR) && TARGET_OS_XR == 14943    strm << "ostype:xros;";4944#else4945    strm << "ostype:ios;";4946#endif4947 4948    // On armv7 we use "synchronous" watchpoints which means the exception is4949    // delivered before the instruction executes.4950    strm << "watchpoint_exceptions_received:before;";4951  } else {4952    strm << "ostype:macosx;";4953    strm << "watchpoint_exceptions_received:after;";4954  }4955  //    char ostype[64];4956  //    len = sizeof(ostype);4957  //    if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0)4958  //    {4959  //        len = strlen(ostype);4960  //        std::transform (ostype, ostype + len, ostype, tolower);4961  //        strm << "ostype:" << std::dec << ostype << ';';4962  //    }4963 4964  strm << "vendor:apple;";4965 4966  uint64_t major, minor, patch;4967  if (DNBGetOSVersionNumbers(&major, &minor, &patch)) {4968    strm << "os_version:" << major << "." << minor;4969    if (patch != UINT64_MAX)4970      strm << "." << patch;4971    strm << ";";4972  }4973 4974  std::string maccatalyst_version = DNBGetMacCatalystVersionString();4975  if (!maccatalyst_version.empty() &&4976      std::all_of(maccatalyst_version.begin(), maccatalyst_version.end(),4977                  [](char c) { return (c >= '0' && c <= '9') || c == '.'; }))4978    strm << "maccatalyst_version:" << maccatalyst_version << ";";4979 4980#if defined(__LITTLE_ENDIAN__)4981  strm << "endian:little;";4982#elif defined(__BIG_ENDIAN__)4983  strm << "endian:big;";4984#elif defined(__PDP_ENDIAN__)4985  strm << "endian:pdp;";4986#endif4987 4988  if (promoted_to_64)4989    strm << "ptrsize:8;";4990  else4991    strm << "ptrsize:" << std::dec << sizeof(void *) << ';';4992 4993#if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 14994  strm << "default_packet_timeout:10;";4995#endif4996 4997  strm << "vm-page-size:" << std::dec << vm_page_size << ";";4998 4999  return SendPacket(strm.str());5000}5001 5002static void XMLElementStart(std::ostringstream &s, uint32_t indent,5003                            const char *name, bool has_attributes) {5004  if (indent)5005    s << INDENT_WITH_SPACES(indent);5006  s << '<' << name;5007  if (!has_attributes)5008    s << '>' << std::endl;5009}5010 5011static void XMLElementStartEndAttributes(std::ostringstream &s, bool empty) {5012  if (empty)5013    s << '/';5014  s << '>' << std::endl;5015}5016 5017static void XMLElementEnd(std::ostringstream &s, uint32_t indent,5018                          const char *name) {5019  if (indent)5020    s << INDENT_WITH_SPACES(indent);5021  s << '<' << '/' << name << '>' << std::endl;5022}5023 5024static void XMLAttributeString(std::ostringstream &s, const char *name,5025                               const char *value,5026                               const char *default_value = NULL) {5027  if (value) {5028    if (default_value && strcmp(value, default_value) == 0)5029      return; // No need to emit the attribute because it matches the default5030              // value5031    s << ' ' << name << "=\"" << value << "\"";5032  }5033}5034 5035static void XMLAttributeUnsignedDecimal(std::ostringstream &s, const char *name,5036                                        uint64_t value) {5037  s << ' ' << name << "=\"" << DECIMAL << value << "\"";5038}5039 5040static void GenerateTargetXMLRegister(std::ostringstream &s,5041                                      const uint32_t reg_num,5042                                      nub_size_t num_reg_sets,5043                                      const DNBRegisterSetInfo *reg_set_info,5044                                      const register_map_entry_t &reg) {5045  const char *default_lldb_encoding = "uint";5046  const char *lldb_encoding = default_lldb_encoding;5047  const char *gdb_group = "general";5048  const char *default_gdb_type = "int";5049  const char *gdb_type = default_gdb_type;5050  const char *default_lldb_format = "hex";5051  const char *lldb_format = default_lldb_format;5052 5053  switch (reg.nub_info.type) {5054  case Uint:5055    lldb_encoding = "uint";5056    break;5057  case Sint:5058    lldb_encoding = "sint";5059    break;5060  case IEEE754:5061    lldb_encoding = "ieee754";5062    if (reg.nub_info.set > 0)5063      gdb_group = "float";5064    break;5065  case Vector:5066    lldb_encoding = "vector";5067    if (reg.nub_info.set > 0)5068      gdb_group = "vector";5069    break;5070  }5071 5072  switch (reg.nub_info.format) {5073  case Binary:5074    lldb_format = "binary";5075    break;5076  case Decimal:5077    lldb_format = "decimal";5078    break;5079  case Hex:5080    lldb_format = "hex";5081    break;5082  case Float:5083    gdb_type = "float";5084    lldb_format = "float";5085    break;5086  case VectorOfSInt8:5087    gdb_type = "float";5088    lldb_format = "vector-sint8";5089    break;5090  case VectorOfUInt8:5091    gdb_type = "float";5092    lldb_format = "vector-uint8";5093    break;5094  case VectorOfSInt16:5095    gdb_type = "float";5096    lldb_format = "vector-sint16";5097    break;5098  case VectorOfUInt16:5099    gdb_type = "float";5100    lldb_format = "vector-uint16";5101    break;5102  case VectorOfSInt32:5103    gdb_type = "float";5104    lldb_format = "vector-sint32";5105    break;5106  case VectorOfUInt32:5107    gdb_type = "float";5108    lldb_format = "vector-uint32";5109    break;5110  case VectorOfFloat32:5111    gdb_type = "float";5112    lldb_format = "vector-float32";5113    break;5114  case VectorOfUInt128:5115    gdb_type = "float";5116    lldb_format = "vector-uint128";5117    break;5118  };5119 5120  uint32_t indent = 2;5121 5122  XMLElementStart(s, indent, "reg", true);5123  XMLAttributeString(s, "name", reg.nub_info.name);5124  XMLAttributeUnsignedDecimal(s, "regnum", reg_num);5125  XMLAttributeUnsignedDecimal(s, "offset", reg.offset);5126  XMLAttributeUnsignedDecimal(s, "bitsize", reg.nub_info.size * 8);5127  XMLAttributeString(s, "group", gdb_group);5128  XMLAttributeString(s, "type", gdb_type, default_gdb_type);5129  XMLAttributeString(s, "altname", reg.nub_info.alt);5130  XMLAttributeString(s, "encoding", lldb_encoding, default_lldb_encoding);5131  XMLAttributeString(s, "format", lldb_format, default_lldb_format);5132  XMLAttributeUnsignedDecimal(s, "group_id", reg.nub_info.set);5133  if (reg.nub_info.reg_ehframe != INVALID_NUB_REGNUM)5134    XMLAttributeUnsignedDecimal(s, "ehframe_regnum", reg.nub_info.reg_ehframe);5135  if (reg.nub_info.reg_dwarf != INVALID_NUB_REGNUM)5136    XMLAttributeUnsignedDecimal(s, "dwarf_regnum", reg.nub_info.reg_dwarf);5137 5138  const char *lldb_generic = NULL;5139  switch (reg.nub_info.reg_generic) {5140  case GENERIC_REGNUM_FP:5141    lldb_generic = "fp";5142    break;5143  case GENERIC_REGNUM_PC:5144    lldb_generic = "pc";5145    break;5146  case GENERIC_REGNUM_SP:5147    lldb_generic = "sp";5148    break;5149  case GENERIC_REGNUM_RA:5150    lldb_generic = "ra";5151    break;5152  case GENERIC_REGNUM_FLAGS:5153    lldb_generic = "flags";5154    break;5155  case GENERIC_REGNUM_ARG1:5156    lldb_generic = "arg1";5157    break;5158  case GENERIC_REGNUM_ARG2:5159    lldb_generic = "arg2";5160    break;5161  case GENERIC_REGNUM_ARG3:5162    lldb_generic = "arg3";5163    break;5164  case GENERIC_REGNUM_ARG4:5165    lldb_generic = "arg4";5166    break;5167  case GENERIC_REGNUM_ARG5:5168    lldb_generic = "arg5";5169    break;5170  case GENERIC_REGNUM_ARG6:5171    lldb_generic = "arg6";5172    break;5173  case GENERIC_REGNUM_ARG7:5174    lldb_generic = "arg7";5175    break;5176  case GENERIC_REGNUM_ARG8:5177    lldb_generic = "arg8";5178    break;5179  default:5180    break;5181  }5182  XMLAttributeString(s, "generic", lldb_generic);5183 5184  bool empty = reg.value_regnums.empty() && reg.invalidate_regnums.empty();5185  if (!empty) {5186    if (!reg.value_regnums.empty()) {5187      std::ostringstream regnums;5188      bool first = true;5189      regnums << DECIMAL;5190      for (auto regnum : reg.value_regnums) {5191        if (!first)5192          regnums << ',';5193        regnums << regnum;5194        first = false;5195      }5196      XMLAttributeString(s, "value_regnums", regnums.str().c_str());5197    }5198 5199    if (!reg.invalidate_regnums.empty()) {5200      std::ostringstream regnums;5201      bool first = true;5202      regnums << DECIMAL;5203      for (auto regnum : reg.invalidate_regnums) {5204        if (!first)5205          regnums << ',';5206        regnums << regnum;5207        first = false;5208      }5209      XMLAttributeString(s, "invalidate_regnums", regnums.str().c_str());5210    }5211  }5212  XMLElementStartEndAttributes(s, true);5213}5214 5215static void GenerateTargetXMLRegisters(std::ostringstream &s) {5216  nub_size_t num_reg_sets = 0;5217  const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo(&num_reg_sets);5218 5219  uint32_t cputype = DNBGetRegisterCPUType();5220  if (cputype) {5221    XMLElementStart(s, 0, "feature", true);5222    std::ostringstream name_strm;5223    name_strm << "com.apple.debugserver." << GetArchName(cputype, 0);5224    XMLAttributeString(s, "name", name_strm.str().c_str());5225    XMLElementStartEndAttributes(s, false);5226    for (uint32_t reg_num = 0; reg_num < g_num_reg_entries; ++reg_num)5227    //        for (const auto &reg: g_dynamic_register_map)5228    {5229      GenerateTargetXMLRegister(s, reg_num, num_reg_sets, reg_sets,5230                                g_reg_entries[reg_num]);5231    }5232    XMLElementEnd(s, 0, "feature");5233 5234    if (num_reg_sets > 0) {5235      XMLElementStart(s, 0, "groups", false);5236      for (uint32_t set = 1; set < num_reg_sets; ++set) {5237        XMLElementStart(s, 2, "group", true);5238        XMLAttributeUnsignedDecimal(s, "id", set);5239        XMLAttributeString(s, "name", reg_sets[set].name);5240        XMLElementStartEndAttributes(s, true);5241      }5242      XMLElementEnd(s, 0, "groups");5243    }5244  }5245}5246 5247static const char *g_target_xml_header = R"(<?xml version="1.0"?>5248<target version="1.0">)";5249 5250static const char *g_target_xml_footer = "</target>";5251 5252static std::string g_target_xml;5253 5254static void UpdateTargetXML() {5255  std::ostringstream s;5256  s << g_target_xml_header << std::endl;5257 5258  // Set the architecture5259  //5260  // On raw targets (no OS, vendor info), I've seen replies like5261  // <architecture>i386:x86-64</architecture> (for x86_64 systems - from vmware)5262  // <architecture>arm</architecture> (for an unspecified arm device - from a Segger JLink)5263  // For good interop, I'm not sure what's expected here.  e.g. will anyone understand5264  // <architecture>x86_64</architecture> ? Or is i386:x86_64 the expected phrasing?5265  //5266  // s << "<architecture>" << arch "</architecture>" << std::endl;5267 5268  // Set the OSABI5269  // s << "<osabi>abi-name</osabi>"5270 5271  GenerateTargetXMLRegisters(s);5272 5273  s << g_target_xml_footer << std::endl;5274 5275  // Save the XML output in case it gets retrieved in chunks5276  g_target_xml = s.str();5277}5278 5279rnb_err_t RNBRemote::HandlePacket_qXfer(const char *command) {5280  const char *p = command;5281  p += strlen("qXfer:");5282  const char *sep = strchr(p, ':');5283  if (sep) {5284    std::string object(p, sep - p); // "auxv", "backtrace", "features", etc5285    p = sep + 1;5286    sep = strchr(p, ':');5287    if (sep) {5288      std::string rw(p, sep - p); // "read" or "write"5289      p = sep + 1;5290      sep = strchr(p, ':');5291      if (sep) {5292        std::string annex(p, sep - p); // "read" or "write"5293 5294        p = sep + 1;5295        sep = strchr(p, ',');5296        if (sep) {5297          std::string offset_str(p, sep - p); // read the length as a string5298          p = sep + 1;5299          std::string length_str(p); // read the offset as a string5300          char *end = nullptr;5301          const uint64_t offset = strtoul(offset_str.c_str(), &end,5302                                          16); // convert offset_str to a offset5303          if (*end == '\0') {5304            const uint64_t length = strtoul(5305                length_str.c_str(), &end, 16); // convert length_str to a length5306            if (*end == '\0') {5307              if (object == "features" && rw == "read" &&5308                  annex == "target.xml") {5309                std::ostringstream xml_out;5310 5311                if (offset == 0) {5312                  InitializeRegisters(true);5313 5314                  UpdateTargetXML();5315                  if (g_target_xml.empty())5316                    return SendErrorPacket("E83");5317 5318                  if (length > g_target_xml.size()) {5319                    xml_out << 'l'; // No more data5320                    xml_out << binary_encode_string(g_target_xml);5321                  } else {5322                    xml_out << 'm'; // More data needs to be read with a5323                                    // subsequent call5324                    xml_out << binary_encode_string(5325                        std::string(g_target_xml, offset, length));5326                  }5327                } else {5328                  // Retrieving target XML in chunks5329                  if (offset < g_target_xml.size()) {5330                    std::string chunk(g_target_xml, offset, length);5331                    if (chunk.size() < length)5332                      xml_out << 'l'; // No more data5333                    else5334                      xml_out << 'm'; // More data needs to be read with a5335                                      // subsequent call5336                    xml_out << binary_encode_string(chunk.data());5337                  }5338                }5339                return SendPacket(xml_out.str());5340              }5341              // Well formed, put not supported5342              return HandlePacket_UNIMPLEMENTED(command);5343            }5344          }5345        }5346      } else {5347        SendErrorPacket("E85");5348      }5349    } else {5350      SendErrorPacket("E86");5351    }5352  }5353  return SendErrorPacket("E82");5354}5355 5356rnb_err_t RNBRemote::HandlePacket_qGDBServerVersion(const char *p) {5357  std::ostringstream strm;5358 5359#if defined(DEBUGSERVER_PROGRAM_NAME)5360  strm << "name:" DEBUGSERVER_PROGRAM_NAME ";";5361#else5362  strm << "name:debugserver;";5363#endif5364  strm << "version:" << DEBUGSERVER_VERSION_NUM << ";";5365 5366  return SendPacket(strm.str());5367}5368 5369rnb_err_t RNBRemote::HandlePacket_jGetDyldProcessState(const char *p) {5370  const nub_process_t pid = m_ctx.ProcessID();5371  if (pid == INVALID_NUB_PROCESS)5372    return SendErrorPacket("E87");5373 5374  JSONGenerator::ObjectSP dyld_state_sp = DNBGetDyldProcessState(pid);5375  if (dyld_state_sp) {5376    std::ostringstream strm;5377    dyld_state_sp->DumpBinaryEscaped(strm);5378    dyld_state_sp->Clear();5379    if (strm.str().size() > 0)5380      return SendPacket(strm.str());5381  }5382  return SendErrorPacket("E88");5383}5384 5385// A helper function that retrieves a single integer value from5386// a one-level-deep JSON dictionary of key-value pairs.  e.g.5387// jThreadExtendedInfo:{"plo_pthread_tsd_base_address_offset":0,"plo_pthread_tsd_base_offset":224,"plo_pthread_tsd_entry_size":8,"thread":144305}]5388//5389static uint64_t5390get_integer_value_for_key_name_from_json(const char *key,5391                                         const char *json_string) {5392  uint64_t retval = INVALID_NUB_ADDRESS;5393  std::string key_with_quotes = "\"";5394  key_with_quotes += key;5395  key_with_quotes += "\"";5396  const char *c = strstr(json_string, key_with_quotes.c_str());5397  if (c) {5398    c += key_with_quotes.size();5399 5400    while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5401      c++;5402 5403    if (*c == ':') {5404      c++;5405 5406      while (*c != '\0' &&5407             (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5408        c++;5409 5410      errno = 0;5411      retval = strtoul(c, NULL, 10);5412      if (errno != 0) {5413        retval = INVALID_NUB_ADDRESS;5414      }5415    }5416  }5417  return retval;5418}5419 5420// A helper function that retrieves a boolean value from5421// a one-level-deep JSON dictionary of key-value pairs.  e.g.5422// jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}]5423 5424// Returns true if it was able to find the key name, and sets the 'value'5425// argument to the value found.5426 5427static bool get_boolean_value_for_key_name_from_json(const char *key,5428                                                     const char *json_string,5429                                                     bool &value) {5430  std::string key_with_quotes = "\"";5431  key_with_quotes += key;5432  key_with_quotes += "\"";5433  const char *c = strstr(json_string, key_with_quotes.c_str());5434  if (c) {5435    c += key_with_quotes.size();5436 5437    while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5438      c++;5439 5440    if (*c == ':') {5441      c++;5442 5443      while (*c != '\0' &&5444             (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5445        c++;5446 5447      if (strncmp(c, "true", 4) == 0) {5448        value = true;5449        return true;5450      } else if (strncmp(c, "false", 5) == 0) {5451        value = false;5452        return true;5453      }5454    }5455  }5456  return false;5457}5458 5459// A helper function that reads an array of uint64_t's from5460// a one-level-deep JSON dictionary of key-value pairs.  e.g.5461// jGetLoadedDynamicLibrariesInfos:{"solib_addrs":[31345823,7768020384,7310483024]}]5462 5463// Returns true if it was able to find the key name, false if it did not.5464// "ints" will have all integers found in the array appended to it.5465 5466static bool get_array_of_ints_value_for_key_name_from_json(5467    const char *key, const char *json_string, std::vector<uint64_t> &ints) {5468  std::string key_with_quotes = "\"";5469  key_with_quotes += key;5470  key_with_quotes += "\"";5471  const char *c = strstr(json_string, key_with_quotes.c_str());5472  if (c) {5473    c += key_with_quotes.size();5474 5475    while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5476      c++;5477 5478    if (*c == ':') {5479      c++;5480 5481      while (*c != '\0' &&5482             (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5483        c++;5484 5485      if (*c == '[') {5486        c++;5487        while (*c != '\0' &&5488               (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5489          c++;5490        while (true) {5491          if (!isdigit(*c)) {5492            return true;5493          }5494 5495          errno = 0;5496          char *endptr;5497          uint64_t value = strtoul(c, &endptr, 10);5498          if (errno == 0) {5499            ints.push_back(value);5500          } else {5501            break;5502          }5503          if (endptr == c || endptr == nullptr || *endptr == '\0') {5504            break;5505          }5506          c = endptr;5507 5508          while (*c != '\0' &&5509                 (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5510            c++;5511          if (*c == ',')5512            c++;5513          while (*c != '\0' &&5514                 (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))5515            c++;5516          if (*c == ']') {5517            return true;5518          }5519        }5520      }5521    }5522  }5523  return false;5524}5525 5526JSONGenerator::ObjectSP5527RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) {5528  JSONGenerator::ArraySP threads_array_sp;5529  if (m_ctx.HasValidProcessID()) {5530    threads_array_sp = std::make_shared<JSONGenerator::Array>();5531 5532    nub_process_t pid = m_ctx.ProcessID();5533 5534    nub_size_t numthreads = DNBProcessGetNumThreads(pid);5535    for (nub_size_t i = 0; i < numthreads; ++i) {5536      nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, i);5537 5538      struct DNBThreadStopInfo tid_stop_info;5539 5540      const bool stop_info_valid =5541          DNBThreadGetStopReason(pid, tid, &tid_stop_info);5542 5543      // If we are doing stop info only, then we only show threads that have a5544      // valid stop reason5545      if (threads_with_valid_stop_info_only) {5546        if (!stop_info_valid || tid_stop_info.reason == eStopTypeInvalid)5547          continue;5548      }5549 5550      JSONGenerator::DictionarySP thread_dict_sp(5551          new JSONGenerator::Dictionary());5552      thread_dict_sp->AddIntegerItem("tid", tid);5553 5554      std::string reason_value("none");5555 5556      if (stop_info_valid) {5557        switch (tid_stop_info.reason) {5558        case eStopTypeInvalid:5559          break;5560 5561        case eStopTypeSignal:5562          if (tid_stop_info.details.signal.signo != 0) {5563            thread_dict_sp->AddIntegerItem("signal",5564                                           tid_stop_info.details.signal.signo);5565            reason_value = "signal";5566          }5567          break;5568 5569        case eStopTypeException:5570          if (tid_stop_info.details.exception.type != 0) {5571            reason_value = "exception";5572            thread_dict_sp->AddIntegerItem(5573                "metype", tid_stop_info.details.exception.type);5574            JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array());5575            for (nub_size_t i = 0;5576                 i < tid_stop_info.details.exception.data_count; ++i) {5577              medata_array_sp->AddItem(std::make_shared<JSONGenerator::Integer>(5578                  tid_stop_info.details.exception.data[i]));5579            }5580            thread_dict_sp->AddItem("medata", medata_array_sp);5581          }5582          break;5583 5584        case eStopTypeWatchpoint: {5585          reason_value = "watchpoint";5586          thread_dict_sp->AddIntegerItem("watchpoint",5587                                         tid_stop_info.details.watchpoint.addr);5588          thread_dict_sp->AddIntegerItem(5589              "me_watch_addr",5590              tid_stop_info.details.watchpoint.mach_exception_addr);5591          std::ostringstream wp_desc;5592          wp_desc << tid_stop_info.details.watchpoint.addr << " ";5593          wp_desc << tid_stop_info.details.watchpoint.hw_idx << " ";5594          wp_desc << tid_stop_info.details.watchpoint.mach_exception_addr;5595          thread_dict_sp->AddStringItem("description", wp_desc.str());5596        } break;5597 5598        case eStopTypeExec:5599          reason_value = "exec";5600          break;5601        }5602      }5603 5604      thread_dict_sp->AddStringItem("reason", reason_value);5605 5606      if (!threads_with_valid_stop_info_only) {5607        const char *thread_name = DNBThreadGetName(pid, tid);5608        if (thread_name && thread_name[0])5609          thread_dict_sp->AddStringItem("name", thread_name);5610 5611        thread_identifier_info_data_t thread_ident_info;5612        if (DNBThreadGetIdentifierInfo(pid, tid, &thread_ident_info)) {5613          if (thread_ident_info.dispatch_qaddr != 0) {5614            thread_dict_sp->AddIntegerItem("qaddr",5615                                           thread_ident_info.dispatch_qaddr);5616 5617            const DispatchQueueOffsets *dispatch_queue_offsets =5618                GetDispatchQueueOffsets();5619            if (dispatch_queue_offsets) {5620              std::string queue_name;5621              uint64_t queue_width = 0;5622              uint64_t queue_serialnum = 0;5623              nub_addr_t dispatch_queue_t = INVALID_NUB_ADDRESS;5624              dispatch_queue_offsets->GetThreadQueueInfo(5625                  pid, thread_ident_info.dispatch_qaddr, dispatch_queue_t,5626                  queue_name, queue_width, queue_serialnum);5627              if (dispatch_queue_t == 0 && queue_name.empty() &&5628                  queue_serialnum == 0) {5629                thread_dict_sp->AddBooleanItem("associated_with_dispatch_queue",5630                                               false);5631              } else {5632                thread_dict_sp->AddBooleanItem("associated_with_dispatch_queue",5633                                               true);5634              }5635              if (dispatch_queue_t != INVALID_NUB_ADDRESS &&5636                  dispatch_queue_t != 0)5637                thread_dict_sp->AddIntegerItem("dispatch_queue_t",5638                                               dispatch_queue_t);5639              if (!queue_name.empty())5640                thread_dict_sp->AddStringItem("qname", queue_name);5641              if (queue_width == 1)5642                thread_dict_sp->AddStringItem("qkind", "serial");5643              else if (queue_width > 1)5644                thread_dict_sp->AddStringItem("qkind", "concurrent");5645              if (queue_serialnum > 0)5646                thread_dict_sp->AddIntegerItem("qserialnum", queue_serialnum);5647            }5648          }5649        }5650 5651        std::unique_ptr<DNBRegisterValue> reg_value =5652            std::make_unique<DNBRegisterValue>();5653 5654        if (g_reg_entries != NULL) {5655          JSONGenerator::DictionarySP registers_dict_sp(5656              new JSONGenerator::Dictionary());5657 5658          for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) {5659            // Expedite all registers in the first register set that aren't5660            // contained in other registers5661            if (g_reg_entries[reg].nub_info.set == 1 &&5662                g_reg_entries[reg].nub_info.value_regs == NULL) {5663              if (!DNBThreadGetRegisterValueByID(5664                      pid, tid, g_reg_entries[reg].nub_info.set,5665                      g_reg_entries[reg].nub_info.reg, reg_value.get()))5666                continue;5667 5668              std::ostringstream reg_num;5669              reg_num << std::dec << g_reg_entries[reg].debugserver_regnum;5670              // Encode native byte ordered bytes as hex ascii5671              registers_dict_sp->AddBytesAsHexASCIIString(5672                  reg_num.str(), reg_value->value.v_uint8,5673                  g_reg_entries[reg].nub_info.size);5674            }5675          }5676          thread_dict_sp->AddItem("registers", registers_dict_sp);5677        }5678 5679        // Add expedited stack memory so stack backtracing doesn't need to read5680        // anything from the5681        // frame pointer chain.5682        StackMemoryMap stack_mmap;5683        ReadStackMemory(pid, tid, stack_mmap);5684        if (!stack_mmap.empty()) {5685          JSONGenerator::ArraySP memory_array_sp(new JSONGenerator::Array());5686 5687          for (const auto &stack_memory : stack_mmap) {5688            JSONGenerator::DictionarySP stack_memory_sp(5689                new JSONGenerator::Dictionary());5690            stack_memory_sp->AddIntegerItem("address", stack_memory.first);5691            stack_memory_sp->AddBytesAsHexASCIIString(5692                "bytes", stack_memory.second.bytes, stack_memory.second.length);5693            memory_array_sp->AddItem(stack_memory_sp);5694          }5695          thread_dict_sp->AddItem("memory", memory_array_sp);5696        }5697      }5698 5699      threads_array_sp->AddItem(thread_dict_sp);5700    }5701  }5702  return threads_array_sp;5703}5704 5705rnb_err_t RNBRemote::HandlePacket_jThreadsInfo(const char *p) {5706  JSONGenerator::ObjectSP threads_info_sp;5707  std::ostringstream json;5708  std::ostringstream reply_strm;5709  // If we haven't run the process yet, return an error.5710  if (m_ctx.HasValidProcessID()) {5711    const bool threads_with_valid_stop_info_only = false;5712    JSONGenerator::ObjectSP threads_info_sp =5713        GetJSONThreadsInfo(threads_with_valid_stop_info_only);5714 5715    if (threads_info_sp) {5716      std::ostringstream strm;5717      threads_info_sp->DumpBinaryEscaped(strm);5718      threads_info_sp->Clear();5719      if (strm.str().size() > 0)5720        return SendPacket(strm.str());5721    }5722  }5723  return SendErrorPacket("E85");5724}5725 5726rnb_err_t RNBRemote::HandlePacket_jThreadExtendedInfo(const char *p) {5727  nub_process_t pid;5728  std::ostringstream json;5729  // If we haven't run the process yet, return an error.5730  if (!m_ctx.HasValidProcessID()) {5731    return SendErrorPacket("E81");5732  }5733 5734  pid = m_ctx.ProcessID();5735 5736  const char thread_extended_info_str[] = {"jThreadExtendedInfo:{"};5737  if (strncmp(p, thread_extended_info_str,5738              sizeof(thread_extended_info_str) - 1) == 0) {5739    p += strlen(thread_extended_info_str);5740 5741    uint64_t tid = get_integer_value_for_key_name_from_json("thread", p);5742    uint64_t plo_pthread_tsd_base_address_offset =5743        get_integer_value_for_key_name_from_json(5744            "plo_pthread_tsd_base_address_offset", p);5745    uint64_t plo_pthread_tsd_base_offset =5746        get_integer_value_for_key_name_from_json("plo_pthread_tsd_base_offset",5747                                                 p);5748    uint64_t plo_pthread_tsd_entry_size =5749        get_integer_value_for_key_name_from_json("plo_pthread_tsd_entry_size",5750                                                 p);5751    uint64_t dti_qos_class_index =5752        get_integer_value_for_key_name_from_json("dti_qos_class_index", p);5753 5754    if (tid != INVALID_NUB_ADDRESS) {5755      nub_addr_t pthread_t_value = DNBGetPThreadT(pid, tid);5756 5757      uint64_t tsd_address = INVALID_NUB_ADDRESS;5758      if (plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS &&5759          plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS &&5760          plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS) {5761        tsd_address = DNBGetTSDAddressForThread(5762            pid, tid, plo_pthread_tsd_base_address_offset,5763            plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);5764      }5765 5766      bool timed_out = false;5767      Genealogy::ThreadActivitySP thread_activity_sp;5768 5769      // If the pthread_t value is invalid, or if we were able to fetch the5770      // thread's TSD base5771      // and got an invalid value back, then we have a thread in early startup5772      // or shutdown and5773      // it's possible that gathering the genealogy information for this thread5774      // go badly.5775      // Ideally fetching this info for a thread in these odd states shouldn't5776      // matter - but5777      // we've seen some problems with these new SPI and threads in edge-casey5778      // states.5779 5780      double genealogy_fetch_time = 0;5781      if (pthread_t_value != INVALID_NUB_ADDRESS &&5782          tsd_address != INVALID_NUB_ADDRESS) {5783        DNBTimer timer(false);5784        thread_activity_sp = DNBGetGenealogyInfoForThread(pid, tid, timed_out);5785        genealogy_fetch_time = timer.ElapsedMicroSeconds(false) / 1000000.0;5786      }5787 5788      std::unordered_set<uint32_t>5789          process_info_indexes; // an array of the process info #'s seen5790 5791      json << "{";5792 5793      bool need_to_print_comma = false;5794 5795      if (thread_activity_sp && !timed_out) {5796        const Genealogy::Activity *activity =5797            &thread_activity_sp->current_activity;5798        bool need_vouchers_comma_sep = false;5799        json << "\"activity_query_timed_out\":false,";5800        if (genealogy_fetch_time != 0) {5801          //  If we append the floating point value with << we'll get it in5802          //  scientific5803          //  notation.5804          char floating_point_ascii_buffer[64];5805          floating_point_ascii_buffer[0] = '\0';5806          snprintf(floating_point_ascii_buffer,5807                   sizeof(floating_point_ascii_buffer), "%f",5808                   genealogy_fetch_time);5809          if (strlen(floating_point_ascii_buffer) > 0) {5810            if (need_to_print_comma)5811              json << ",";5812            need_to_print_comma = true;5813            json << "\"activity_query_duration\":"5814                 << floating_point_ascii_buffer;5815          }5816        }5817        if (activity->activity_id != 0) {5818          if (need_to_print_comma)5819            json << ",";5820          need_to_print_comma = true;5821          need_vouchers_comma_sep = true;5822          json << "\"activity\":{";5823          json << "\"start\":" << activity->activity_start << ",";5824          json << "\"id\":" << activity->activity_id << ",";5825          json << "\"parent_id\":" << activity->parent_id << ",";5826          json << "\"name\":\""5827               << json_string_quote_metachars(activity->activity_name) << "\",";5828          json << "\"reason\":\""5829               << json_string_quote_metachars(activity->reason) << "\"";5830          json << "}";5831        }5832        if (thread_activity_sp->messages.size() > 0) {5833          need_to_print_comma = true;5834          if (need_vouchers_comma_sep)5835            json << ",";5836          need_vouchers_comma_sep = true;5837          json << "\"trace_messages\":[";5838          bool printed_one_message = false;5839          for (auto iter = thread_activity_sp->messages.begin();5840               iter != thread_activity_sp->messages.end(); ++iter) {5841            if (printed_one_message)5842              json << ",";5843            else5844              printed_one_message = true;5845            json << "{";5846            json << "\"timestamp\":" << iter->timestamp << ",";5847            json << "\"activity_id\":" << iter->activity_id << ",";5848            json << "\"trace_id\":" << iter->trace_id << ",";5849            json << "\"thread\":" << iter->thread << ",";5850            json << "\"type\":" << (int)iter->type << ",";5851            json << "\"process_info_index\":" << iter->process_info_index5852                 << ",";5853            process_info_indexes.insert(iter->process_info_index);5854            json << "\"message\":\""5855                 << json_string_quote_metachars(iter->message) << "\"";5856            json << "}";5857          }5858          json << "]";5859        }5860        if (thread_activity_sp->breadcrumbs.size() == 1) {5861          need_to_print_comma = true;5862          if (need_vouchers_comma_sep)5863            json << ",";5864          need_vouchers_comma_sep = true;5865          json << "\"breadcrumb\":{";5866          for (auto iter = thread_activity_sp->breadcrumbs.begin();5867               iter != thread_activity_sp->breadcrumbs.end(); ++iter) {5868            json << "\"breadcrumb_id\":" << iter->breadcrumb_id << ",";5869            json << "\"activity_id\":" << iter->activity_id << ",";5870            json << "\"timestamp\":" << iter->timestamp << ",";5871            json << "\"name\":\"" << json_string_quote_metachars(iter->name)5872                 << "\"";5873          }5874          json << "}";5875        }5876        if (process_info_indexes.size() > 0) {5877          need_to_print_comma = true;5878          if (need_vouchers_comma_sep)5879            json << ",";5880          need_vouchers_comma_sep = true;5881          bool printed_one_process_info = false;5882          for (auto iter = process_info_indexes.begin();5883               iter != process_info_indexes.end(); ++iter) {5884            if (printed_one_process_info)5885              json << ",";5886            Genealogy::ProcessExecutableInfoSP image_info_sp;5887            uint32_t idx = *iter;5888            image_info_sp = DNBGetGenealogyImageInfo(pid, idx);5889            if (image_info_sp) {5890              if (!printed_one_process_info) {5891                json << "\"process_infos\":[";5892                printed_one_process_info = true;5893              }5894 5895              json << "{";5896              char uuid_buf[37];5897              uuid_unparse_upper(image_info_sp->image_uuid, uuid_buf);5898              json << "\"process_info_index\":" << idx << ",";5899              json << "\"image_path\":\""5900                   << json_string_quote_metachars(image_info_sp->image_path)5901                   << "\",";5902              json << "\"image_uuid\":\"" << uuid_buf << "\"";5903              json << "}";5904            }5905          }5906          if (printed_one_process_info)5907            json << "]";5908        }5909      } else {5910        if (timed_out) {5911          if (need_to_print_comma)5912            json << ",";5913          need_to_print_comma = true;5914          json << "\"activity_query_timed_out\":true";5915          if (genealogy_fetch_time != 0) {5916            //  If we append the floating point value with << we'll get it in5917            //  scientific5918            //  notation.5919            char floating_point_ascii_buffer[64];5920            floating_point_ascii_buffer[0] = '\0';5921            snprintf(floating_point_ascii_buffer,5922                     sizeof(floating_point_ascii_buffer), "%f",5923                     genealogy_fetch_time);5924            if (strlen(floating_point_ascii_buffer) > 0) {5925              json << ",";5926              json << "\"activity_query_duration\":"5927                   << floating_point_ascii_buffer;5928            }5929          }5930        }5931      }5932 5933      if (tsd_address != INVALID_NUB_ADDRESS) {5934        if (need_to_print_comma)5935          json << ",";5936        need_to_print_comma = true;5937        json << "\"tsd_address\":" << tsd_address;5938 5939        if (dti_qos_class_index != 0 && dti_qos_class_index != UINT64_MAX) {5940          ThreadInfo::QoS requested_qos = DNBGetRequestedQoSForThread(5941              pid, tid, tsd_address, dti_qos_class_index);5942          if (requested_qos.IsValid()) {5943            if (need_to_print_comma)5944              json << ",";5945            need_to_print_comma = true;5946            json << "\"requested_qos\":{";5947            json << "\"enum_value\":" << requested_qos.enum_value << ",";5948            json << "\"constant_name\":\""5949                 << json_string_quote_metachars(requested_qos.constant_name)5950                 << "\",";5951            json << "\"printable_name\":\""5952                 << json_string_quote_metachars(requested_qos.printable_name)5953                 << "\"";5954            json << "}";5955          }5956        }5957      }5958 5959      if (pthread_t_value != INVALID_NUB_ADDRESS) {5960        if (need_to_print_comma)5961          json << ",";5962        need_to_print_comma = true;5963        json << "\"pthread_t\":" << pthread_t_value;5964      }5965 5966      nub_addr_t dispatch_queue_t_value = DNBGetDispatchQueueT(pid, tid);5967      if (dispatch_queue_t_value != INVALID_NUB_ADDRESS) {5968        if (need_to_print_comma)5969          json << ",";5970        need_to_print_comma = true;5971        json << "\"dispatch_queue_t\":" << dispatch_queue_t_value;5972      }5973 5974      json << "}";5975      std::string json_quoted = binary_encode_string(json.str());5976      return SendPacket(json_quoted);5977    }5978  }5979  return SendPacket("OK");5980}5981 5982//  This packet may be called in one of two ways:5983//5984//  jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}5985//      Use the new dyld SPI to get a list of all the libraries loaded.5986//      If "report_load_commands":false" is present, only the dyld SPI5987//      provided information (load address, filepath) is returned.5988//      lldb can ask for the mach-o header/load command details in a5989//      separate packet.5990//5991//  jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]}5992//      Use the dyld SPI and Mach-O parsing in memory to get the information5993//      about the libraries loaded at these addresses.5994//5995rnb_err_t5996RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p) {5997  nub_process_t pid;5998  // If we haven't run the process yet, return an error.5999  if (!m_ctx.HasValidProcessID()) {6000    return SendErrorPacket("E83");6001  }6002 6003  pid = m_ctx.ProcessID();6004 6005  const char get_loaded_dynamic_libraries_infos_str[] = {6006      "jGetLoadedDynamicLibrariesInfos:{"};6007  if (strncmp(p, get_loaded_dynamic_libraries_infos_str,6008              sizeof(get_loaded_dynamic_libraries_infos_str) - 1) == 0) {6009    p += strlen(get_loaded_dynamic_libraries_infos_str);6010 6011    JSONGenerator::ObjectSP json_sp;6012 6013    std::vector<uint64_t> macho_addresses;6014    bool fetch_all_solibs = false;6015    bool report_load_commands = true;6016    get_boolean_value_for_key_name_from_json("report_load_commands", p,6017                                             report_load_commands);6018 6019    if (get_boolean_value_for_key_name_from_json("fetch_all_solibs", p,6020                                                 fetch_all_solibs) &&6021        fetch_all_solibs) {6022      json_sp = DNBGetAllLoadedLibrariesInfos(pid, report_load_commands);6023    } else if (get_array_of_ints_value_for_key_name_from_json(6024                   "solib_addresses", p, macho_addresses)) {6025      json_sp = DNBGetLibrariesInfoForAddresses(pid, macho_addresses);6026    }6027 6028    if (json_sp.get()) {6029      std::ostringstream json_str;6030      json_sp->DumpBinaryEscaped(json_str);6031      json_sp->Clear();6032      if (json_str.str().size() > 0) {6033        return SendPacket(json_str.str());6034      } else {6035        SendErrorPacket("E84");6036      }6037    }6038  }6039  return SendPacket("OK");6040}6041 6042// This packet does not currently take any arguments.  So the behavior is6043//    jGetSharedCacheInfo:{}6044//         send information about the inferior's shared cache6045//    jGetSharedCacheInfo:6046//         send "OK" to indicate that this packet is supported6047rnb_err_t RNBRemote::HandlePacket_jGetSharedCacheInfo(const char *p) {6048  nub_process_t pid;6049  // If we haven't run the process yet, return an error.6050  if (!m_ctx.HasValidProcessID()) {6051    return SendErrorPacket("E85");6052  }6053 6054  pid = m_ctx.ProcessID();6055 6056  const char get_shared_cache_info_str[] = {"jGetSharedCacheInfo:{"};6057  if (strncmp(p, get_shared_cache_info_str,6058              sizeof(get_shared_cache_info_str) - 1) == 0) {6059    JSONGenerator::ObjectSP json_sp = DNBGetSharedCacheInfo(pid);6060 6061    if (json_sp.get()) {6062      std::ostringstream json_str;6063      json_sp->DumpBinaryEscaped(json_str);6064      json_sp->Clear();6065      if (json_str.str().size() > 0) {6066        return SendPacket(json_str.str());6067      } else {6068        SendErrorPacket("E86");6069      }6070    }6071  }6072  return SendPacket("OK");6073}6074 6075static bool MachHeaderIsMainExecutable(nub_process_t pid, uint32_t addr_size,6076                                       nub_addr_t mach_header_addr,6077                                       mach_header &mh) {6078  DNBLogThreadedIf(LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, "6079                                 "addr_size = %u, mach_header_addr = "6080                                 "0x%16.16llx)",6081                   pid, addr_size, mach_header_addr);6082  const nub_size_t bytes_read =6083      DNBProcessMemoryRead(pid, mach_header_addr, sizeof(mh), &mh);6084  if (bytes_read == sizeof(mh)) {6085    DNBLogThreadedIf(6086        LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = "6087                      "%u, mach_header_addr = 0x%16.16llx): mh = {\n  magic = "6088                      "0x%8.8x\n  cpu = 0x%8.8x\n  sub = 0x%8.8x\n  filetype = "6089                      "%u\n  ncmds = %u\n  sizeofcmds = 0x%8.8x\n  flags = "6090                      "0x%8.8x }",6091        pid, addr_size, mach_header_addr, mh.magic, mh.cputype, mh.cpusubtype,6092        mh.filetype, mh.ncmds, mh.sizeofcmds, mh.flags);6093    if ((addr_size == 4 && mh.magic == MH_MAGIC) ||6094        (addr_size == 8 && mh.magic == MH_MAGIC_64)) {6095      if (mh.filetype == MH_EXECUTE) {6096        DNBLogThreadedIf(LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = "6097                                       "%u, addr_size = %u, mach_header_addr = "6098                                       "0x%16.16llx) -> this is the "6099                                       "executable!!!",6100                         pid, addr_size, mach_header_addr);6101        return true;6102      }6103    }6104  }6105  return false;6106}6107 6108static nub_addr_t GetMachHeaderForMainExecutable(const nub_process_t pid,6109                                                 const uint32_t addr_size,6110                                                 mach_header &mh) {6111  struct AllImageInfos {6112    uint32_t version;6113    uint32_t dylib_info_count;6114    uint64_t dylib_info_addr;6115  };6116 6117  uint64_t mach_header_addr = 0;6118 6119  const nub_addr_t shlib_addr = DNBProcessGetSharedLibraryInfoAddress(pid);6120  uint8_t bytes[256];6121  nub_size_t bytes_read = 0;6122  DNBDataRef data(bytes, sizeof(bytes), false);6123  DNBDataRef::offset_t offset = 0;6124  data.SetPointerSize(addr_size);6125 6126  // When we are sitting at __dyld_start, the kernel has placed the6127  // address of the mach header of the main executable on the stack. If we6128  // read the SP and dereference a pointer, we might find the mach header6129  // for the executable. We also just make sure there is only 1 thread6130  // since if we are at __dyld_start we shouldn't have multiple threads.6131  if (DNBProcessGetNumThreads(pid) == 1) {6132    nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, 0);6133    if (tid != INVALID_NUB_THREAD) {6134      DNBRegisterValue sp_value;6135      if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC,6136                                        GENERIC_REGNUM_SP, &sp_value)) {6137        uint64_t sp =6138            addr_size == 8 ? sp_value.value.uint64 : sp_value.value.uint32;6139        bytes_read = DNBProcessMemoryRead(pid, sp, addr_size, bytes);6140        if (bytes_read == addr_size) {6141          offset = 0;6142          mach_header_addr = data.GetPointer(&offset);6143          if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh))6144            return mach_header_addr;6145        }6146      }6147    }6148  }6149 6150  // Check the dyld_all_image_info structure for a list of mach header6151  // since it is a very easy thing to check6152  if (shlib_addr != INVALID_NUB_ADDRESS) {6153    bytes_read =6154        DNBProcessMemoryRead(pid, shlib_addr, sizeof(AllImageInfos), bytes);6155    if (bytes_read > 0) {6156      AllImageInfos aii;6157      offset = 0;6158      aii.version = data.Get32(&offset);6159      aii.dylib_info_count = data.Get32(&offset);6160      if (aii.dylib_info_count > 0) {6161        aii.dylib_info_addr = data.GetPointer(&offset);6162        if (aii.dylib_info_addr != 0) {6163          const size_t image_info_byte_size = 3 * addr_size;6164          for (uint32_t i = 0; i < aii.dylib_info_count; ++i) {6165            bytes_read = DNBProcessMemoryRead(pid, aii.dylib_info_addr +6166                                                       i * image_info_byte_size,6167                                              image_info_byte_size, bytes);6168            if (bytes_read != image_info_byte_size)6169              break;6170            offset = 0;6171            mach_header_addr = data.GetPointer(&offset);6172            if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr,6173                                           mh))6174              return mach_header_addr;6175          }6176        }6177      }6178    }6179  }6180 6181  // We failed to find the executable's mach header from the all image6182  // infos and by dereferencing the stack pointer. Now we fall back to6183  // enumerating the memory regions and looking for regions that are6184  // executable.6185  DNBRegionInfo region_info;6186  mach_header_addr = 0;6187  while (DNBProcessMemoryRegionInfo(pid, mach_header_addr, &region_info)) {6188    if (region_info.size == 0)6189      break;6190 6191    if (region_info.permissions & eMemoryPermissionsExecutable) {6192      DNBLogThreadedIf(6193          LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx) permissions = %c%c%c: "6194                        "checking region for executable mach header",6195          region_info.addr, region_info.addr + region_info.size,6196          (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-',6197          (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-',6198          (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-');6199      if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh))6200        return mach_header_addr;6201    } else {6202      DNBLogThreadedIf(6203          LOG_RNB_PROC,6204          "[0x%16.16llx - 0x%16.16llx): permissions = %c%c%c: skipping region",6205          region_info.addr, region_info.addr + region_info.size,6206          (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-',6207          (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-',6208          (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-');6209    }6210    // Set the address to the next mapped region6211    mach_header_addr = region_info.addr + region_info.size;6212  }6213  bzero(&mh, sizeof(mh));6214  return INVALID_NUB_ADDRESS;6215}6216 6217rnb_err_t RNBRemote::HandlePacket_qSymbol(const char *command) {6218  const char *p = command;6219  p += strlen("qSymbol:");6220  const char *sep = strchr(p, ':');6221 6222  std::string symbol_name;6223  std::string symbol_value_str;6224  // Extract the symbol value if there is one6225  if (sep > p)6226    symbol_value_str.assign(p, sep - p);6227  p = sep + 1;6228 6229  if (*p) {6230    // We have a symbol name6231    symbol_name = decode_hex_ascii_string(p);6232    if (!symbol_value_str.empty()) {6233      nub_addr_t symbol_value = decode_uint64(symbol_value_str.c_str(), 16);6234      if (symbol_name == "dispatch_queue_offsets")6235        m_dispatch_queue_offsets_addr = symbol_value;6236    }6237    ++m_qSymbol_index;6238  } else {6239    // No symbol name, set our symbol index to zero so we can6240    // read any symbols that we need6241    m_qSymbol_index = 0;6242  }6243 6244  symbol_name.clear();6245 6246  if (m_qSymbol_index == 0) {6247    if (m_dispatch_queue_offsets_addr == INVALID_NUB_ADDRESS)6248      symbol_name = "dispatch_queue_offsets";6249    else6250      ++m_qSymbol_index;6251  }6252 6253  //    // Lookup next symbol when we have one...6254  //    if (m_qSymbol_index == 1)6255  //    {6256  //    }6257 6258  if (symbol_name.empty()) {6259    // Done with symbol lookups6260    return SendPacket("OK");6261  } else {6262    std::ostringstream reply;6263    reply << "qSymbol:";6264    for (size_t i = 0; i < symbol_name.size(); ++i)6265      reply << RAWHEX8(symbol_name[i]);6266    return SendPacket(reply.str());6267  }6268}6269 6270rnb_err_t RNBRemote::HandlePacket_QEnableErrorStrings(const char *p) {6271  m_enable_error_strings = true;6272  return SendPacket("OK");6273}6274 6275static std::pair<cpu_type_t, cpu_subtype_t>6276GetCPUTypesFromHost(nub_process_t pid) {6277  cpu_type_t cputype = DNBProcessGetCPUType(pid);6278  if (cputype == 0) {6279    DNBLog("Unable to get the process cpu_type, making a best guess.");6280    cputype = best_guess_cpu_type();6281  }6282 6283  bool host_cpu_is_64bit = false;6284  uint32_t is64bit_capable;6285  size_t is64bit_capable_len = sizeof(is64bit_capable);6286  if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable,6287                   &is64bit_capable_len, NULL, 0) == 0)6288    host_cpu_is_64bit = is64bit_capable != 0;6289 6290  uint32_t cpusubtype;6291  size_t cpusubtype_len = sizeof(cpusubtype);6292  if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &cpusubtype_len, NULL, 0) ==6293      0) {6294    // If a process is CPU_TYPE_X86, then ignore the cpusubtype that we detected6295    // from the host and use CPU_SUBTYPE_I386_ALL because we don't want the6296    // CPU_SUBTYPE_X86_ARCH1 or CPU_SUBTYPE_X86_64_H to be used as the cpu6297    // subtype6298    // for i386...6299    if (host_cpu_is_64bit) {6300      if (cputype == CPU_TYPE_X86) {6301        cpusubtype = 3; // CPU_SUBTYPE_I386_ALL6302      } else if (cputype == CPU_TYPE_ARM) {6303        // We can query a process' cputype but we cannot query a process'6304        // cpusubtype.6305        // If the process has cputype CPU_TYPE_ARM, then it is an armv7 (32-bit6306        // process) and we6307        // need to override the host cpusubtype (which is in the6308        // CPU_SUBTYPE_ARM64 subtype namespace)6309        // with a reasonable CPU_SUBTYPE_ARMV7 subtype.6310        cpusubtype = 12; // CPU_SUBTYPE_ARM_V7K6311      }6312    }6313#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 16314    // on arm64_32 devices, the machine's native cpu type is6315    // CPU_TYPE_ARM64 and subtype is 2 indicating arm64e.6316    // But we change the cputype to CPU_TYPE_ARM64_32 because6317    // the user processes are all ILP32 processes today.6318    // We also need to rewrite the cpusubtype so we vend 6319    // a valid cputype + cpusubtype combination.6320    if (cputype == CPU_TYPE_ARM64_32 && cpusubtype == 2)6321      cpusubtype = CPU_SUBTYPE_ARM64_32_V8;6322#endif6323  }6324 6325  return {cputype, cpusubtype};6326}6327 6328static bool ProcessRunningWithMemoryTagging(pid_t pid) {6329#if __has_include(<os/security_config.h>)6330  if (__builtin_available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0,6331                          visionOS 26.0, driverkit 25.0, *)) {6332    os_security_config_t config;6333    int ret = ::os_security_config_get_for_proc(pid, &config);6334    if (ret != 0)6335      return false;6336 6337    return (config & OS_SECURITY_CONFIG_MTE);6338  }6339#endif6340  return false;6341}6342 6343// Note that all numeric values returned by qProcessInfo are hex encoded,6344// including the pid and the cpu type.6345 6346rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) {6347  nub_process_t pid;6348  std::ostringstream rep;6349 6350  // If we haven't run the process yet, return an error.6351  if (!m_ctx.HasValidProcessID())6352    return SendPacket("E68");6353 6354  pid = m_ctx.ProcessID();6355 6356  rep << "pid:" << std::hex << pid << ';';6357 6358  int procpid_mib[4];6359  procpid_mib[0] = CTL_KERN;6360  procpid_mib[1] = KERN_PROC;6361  procpid_mib[2] = KERN_PROC_PID;6362  procpid_mib[3] = pid;6363  struct kinfo_proc proc_kinfo;6364  size_t proc_kinfo_size = sizeof(struct kinfo_proc);6365 6366  if (::sysctl(procpid_mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {6367    if (proc_kinfo_size > 0) {6368      rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';';6369      rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid6370          << ';';6371      rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid6372          << ';';6373      rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid6374          << ';';6375      if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)6376        rep << "effective-gid:" << std::hex6377            << proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';';6378    }6379  }6380 6381  cpu_type_t cputype;6382  cpu_subtype_t cpusubtype;6383  if (auto cputypes = DNBGetMainBinaryCPUTypes(pid))6384    std::tie(cputype, cpusubtype) = *cputypes;6385  else6386    std::tie(cputype, cpusubtype) = GetCPUTypesFromHost(pid);6387 6388  uint32_t addr_size = 0;6389  if (cputype != 0) {6390    rep << "cputype:" << std::hex << cputype << ";";6391    rep << "cpusubtype:" << std::hex << cpusubtype << ';';6392    if (cputype & CPU_ARCH_ABI64)6393      addr_size = 8;6394    else6395      addr_size = 4;6396  }6397 6398  bool os_handled = false;6399  if (addr_size > 0) {6400    rep << "ptrsize:" << std::dec << addr_size << ';';6401#if defined(TARGET_OS_OSX) && TARGET_OS_OSX == 16402    // Try and get the OS type by looking at the load commands in the main6403    // executable and looking for a LC_VERSION_MIN load command. This is the6404    // most reliable way to determine the "ostype" value when on desktop.6405 6406    mach_header mh;6407    nub_addr_t exe_mach_header_addr =6408        GetMachHeaderForMainExecutable(pid, addr_size, mh);6409    if (exe_mach_header_addr != INVALID_NUB_ADDRESS) {6410      uint64_t load_command_addr =6411          exe_mach_header_addr +6412          ((addr_size == 8) ? sizeof(mach_header_64) : sizeof(mach_header));6413      load_command lc;6414      for (uint32_t i = 0; i < mh.ncmds && !os_handled; ++i) {6415        const nub_size_t bytes_read =6416            DNBProcessMemoryRead(pid, load_command_addr, sizeof(lc), &lc);6417        (void)bytes_read;6418 6419        bool is_executable = true;6420        uint32_t major_version, minor_version, patch_version;6421        std::optional<std::string> platform =6422            DNBGetDeploymentInfo(pid, is_executable, lc, load_command_addr,6423                                 major_version, minor_version, patch_version);6424        if (platform) {6425          os_handled = true;6426          rep << "ostype:" << *platform << ";";6427          break;6428        }6429        load_command_addr = load_command_addr + lc.cmdsize;6430      }6431    }6432#endif // TARGET_OS_OSX6433  }6434 6435  // If we weren't able to find the OS in a LC_VERSION_MIN load command, try6436  // to set it correctly by using the cpu type and other tricks6437  if (!os_handled) {6438    // The OS in the triple should be "ios" or "macosx" which doesn't match our6439    // "Darwin" which gets returned from "kern.ostype", so we need to hardcode6440    // this for now.6441    if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM646442        || cputype == CPU_TYPE_ARM64_32) {6443#if defined(TARGET_OS_TV) && TARGET_OS_TV == 16444      rep << "ostype:tvos;";6445#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 16446      rep << "ostype:watchos;";6447#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 16448      rep << "ostype:bridgeos;";6449#elif defined(TARGET_OS_OSX) && TARGET_OS_OSX == 16450      rep << "ostype:macosx;";6451#elif defined(TARGET_OS_XR) && TARGET_OS_XR == 16452      rep << "ostype:xros;";6453#else6454      rep << "ostype:ios;";6455#endif6456    } else {6457      bool is_ios_simulator = false;6458      if (cputype == CPU_TYPE_X86 || cputype == CPU_TYPE_X86_64) {6459        // Check for iOS simulator binaries by getting the process argument6460        // and environment and checking for SIMULATOR_UDID in the environment6461        int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2, (int)pid};6462 6463        uint8_t arg_data[8192];6464        size_t arg_data_size = sizeof(arg_data);6465        if (::sysctl(proc_args_mib, 3, arg_data, &arg_data_size, NULL, 0) ==6466            0) {6467          DNBDataRef data(arg_data, arg_data_size, false);6468          DNBDataRef::offset_t offset = 0;6469          uint32_t argc = data.Get32(&offset);6470          const char *cstr;6471 6472          cstr = data.GetCStr(&offset);6473          if (cstr) {6474            // Skip NULLs6475            while (true) {6476              const char *p = data.PeekCStr(offset);6477              if ((p == NULL) || (*p != '\0'))6478                break;6479              ++offset;6480            }6481            // Now skip all arguments6482            for (uint32_t i = 0; i < argc; ++i) {6483              data.GetCStr(&offset);6484            }6485 6486            // Now iterate across all environment variables6487            while ((cstr = data.GetCStr(&offset))) {6488              if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) ==6489                  0) {6490                is_ios_simulator = true;6491                break;6492              }6493              if (cstr[0] == '\0')6494                break;6495            }6496          }6497        }6498      }6499      if (is_ios_simulator) {6500#if defined(TARGET_OS_TV) && TARGET_OS_TV == 16501        rep << "ostype:tvos;";6502#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 16503        rep << "ostype:watchos;";6504#elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 16505        rep << "ostype:bridgeos;";6506#elif defined(TARGET_OS_XR) && TARGET_OS_XR == 16507        rep << "ostype:xros;";6508#else6509        rep << "ostype:ios;";6510#endif6511      } else {6512        rep << "ostype:macosx;";6513      }6514    }6515  }6516 6517  rep << "vendor:apple;";6518 6519  if (ProcessRunningWithMemoryTagging(pid))6520    rep << "mte:enabled;";6521 6522#if defined(__LITTLE_ENDIAN__)6523  rep << "endian:little;";6524#elif defined(__BIG_ENDIAN__)6525  rep << "endian:big;";6526#elif defined(__PDP_ENDIAN__)6527  rep << "endian:pdp;";6528#endif6529 6530  if (addr_size == 0) {6531#if (defined(__x86_64__) || defined(__i386__)) && defined(x86_THREAD_STATE)6532    nub_thread_t thread = DNBProcessGetCurrentThreadMachPort(pid);6533    kern_return_t kr;6534    x86_thread_state_t gp_regs;6535    mach_msg_type_number_t gp_count = x86_THREAD_STATE_COUNT;6536    kr = thread_get_state(static_cast<thread_act_t>(thread), x86_THREAD_STATE,6537                          (thread_state_t)&gp_regs, &gp_count);6538    if (kr == KERN_SUCCESS) {6539      if (gp_regs.tsh.flavor == x86_THREAD_STATE64)6540        rep << "ptrsize:8;";6541      else6542        rep << "ptrsize:4;";6543    }6544#elif defined(__arm__)6545    rep << "ptrsize:4;";6546#elif (defined(__arm64__) || defined(__aarch64__)) &&                          \6547    defined(ARM_UNIFIED_THREAD_STATE)6548    nub_thread_t thread = DNBProcessGetCurrentThreadMachPort(pid);6549    kern_return_t kr;6550    arm_unified_thread_state_t gp_regs;6551    mach_msg_type_number_t gp_count = ARM_UNIFIED_THREAD_STATE_COUNT;6552    kr = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE,6553                          (thread_state_t)&gp_regs, &gp_count);6554    if (kr == KERN_SUCCESS) {6555      if (gp_regs.ash.flavor == ARM_THREAD_STATE64)6556        rep << "ptrsize:8;";6557      else6558        rep << "ptrsize:4;";6559    }6560#endif6561  }6562 6563  return SendPacket(rep.str());6564}6565 6566const RNBRemote::DispatchQueueOffsets *RNBRemote::GetDispatchQueueOffsets() {6567  if (!m_dispatch_queue_offsets.IsValid() &&6568      m_dispatch_queue_offsets_addr != INVALID_NUB_ADDRESS &&6569      m_ctx.HasValidProcessID()) {6570    nub_process_t pid = m_ctx.ProcessID();6571    nub_size_t bytes_read = DNBProcessMemoryRead(6572        pid, m_dispatch_queue_offsets_addr, sizeof(m_dispatch_queue_offsets),6573        &m_dispatch_queue_offsets);6574    if (bytes_read != sizeof(m_dispatch_queue_offsets))6575      m_dispatch_queue_offsets.Clear();6576  }6577 6578  if (m_dispatch_queue_offsets.IsValid())6579    return &m_dispatch_queue_offsets;6580  else6581    return nullptr;6582}6583 6584void RNBRemote::EnableCompressionNextSendPacket(compression_types type) {6585  m_compression_mode = type;6586  m_enable_compression_next_send_packet = true;6587}6588 6589compression_types RNBRemote::GetCompressionType() {6590  // The first packet we send back to the debugger after a QEnableCompression6591  // request6592  // should be uncompressed -- so we can indicate whether the compression was6593  // enabled6594  // or not via OK / Enn returns.  After that, all packets sent will be using6595  // the6596  // compression protocol.6597 6598  if (m_enable_compression_next_send_packet) {6599    // One time, we send back "None" as our compression type6600    m_enable_compression_next_send_packet = false;6601    return compression_types::none;6602  }6603  return m_compression_mode;6604}6605