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

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