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

source code of lldb/tools/debugserver/source/RNBRemote.cpp