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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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