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 ®_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, ¤tRightDict);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, ®ion_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 ®) {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 ®: 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, ®ion_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