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