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