1 //===-- RNBRemote.cpp -------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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>
20 #include <mach-o/loader.h>
21 #include <mach/exception_types.h>
22 #include <mach/mach_vm.h>
23 #include <mach/task_info.h>
27 #include <sys/sysctl.h>
30 #if defined(__APPLE__)
36 #include "DNBDataRef.h"
38 #include "DNBThreadResumeActions.h"
40 #include "JSONGenerator.h"
41 #include "JSONGenerator.h"
42 #include "MacOSX/Genealogy.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>
56 #include <unordered_set>
58 #include <CoreFoundation/CoreFoundation.h>
59 #include <Security/Security.h>
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)
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.
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')
111 // Decode a single hex ASCII byte. Return -1 on failure, a value 0-255
113 static inline int decoded_hex_ascii_char(const char *p
) {
114 const int hi_nibble
= xdigit_to_sint(p
[0]);
117 const int lo_nibble
= xdigit_to_sint(p
[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
) {
128 for (const char *c
= p
; ((c
- p
) / 2) < max_length
; c
+= 2) {
129 int ch
= decoded_hex_ascii_char(c
);
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)
147 void append_hex_value(std::ostream
&ostrm
, const void *buf
, size_t buf_size
,
150 const uint8_t *p
= (const uint8_t *)buf
;
152 for (i
= static_cast<int>(buf_size
) - 1; i
>= 0; i
--)
153 ostrm
<< RAWHEX8(p
[i
]);
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
) {
162 hex_str
.reserve(strlen(str
) * 2);
163 while (str
&& *str
) {
166 snprintf(hexbuf
, sizeof(hexbuf
), "%02x", c
);
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
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
);
187 bool rootless_allows_task_for_pid(pid_t pid
);
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__
);
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
221 // 3 - Register the Packet definition with any needed callbacks in this
223 // - If no response is needed for a command, then use NULL for the
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
234 // - modify the switch statement for the first character in the payload
235 // in RNBRemote::GetPacketPayload and make sure the payload of the
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",
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",
248 t
.push_back(Packet(write_memory
, &RNBRemote::HandlePacket_M
, NULL
, "M",
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",
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",
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"));
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"));
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
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
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
292 t
.push_back(Packet(thread_alive_p
, &RNBRemote::HandlePacket_T
, NULL
, "T",
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
,
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
,
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
,
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"));
362 query_launch_success
, &RNBRemote::HandlePacket_qLaunchSuccess
, NULL
,
363 "qLaunchSuccess", "Report the success or failure of the launch attempt"));
365 Packet(query_register_info
, &RNBRemote::HandlePacket_qRegisterInfo
, NULL
,
367 "Dynamically discover remote register context information."));
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."));
377 Packet(query_vattachorwait_supported
,
378 &RNBRemote::HandlePacket_qVAttachOrWaitSupported
, NULL
,
379 "qVAttachOrWaitSupported",
380 "Replys with OK if the 'vAttachOrWait' packet is supported."));
382 Packet(query_sync_thread_state_supported
,
383 &RNBRemote::HandlePacket_qSyncThreadStateSupported
, NULL
,
384 "qSyncThreadStateSupported",
385 "Replys with OK if the 'QSyncThreadState:' packet is supported."));
387 query_host_info
, &RNBRemote::HandlePacket_qHostInfo
, NULL
, "qHostInfo",
388 "Replies with multiple 'key:value;' tuples appended to each other."));
390 query_gdb_server_version
, &RNBRemote::HandlePacket_qGDBServerVersion
,
391 NULL
, "qGDBServerVersion",
392 "Replies with multiple 'key:value;' tuples appended to each other."));
394 query_process_info
, &RNBRemote::HandlePacket_qProcessInfo
, NULL
,
396 "Replies with multiple 'key:value;' tuples appended to each other."));
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."));
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."));
441 set_max_packet_size
, &RNBRemote::HandlePacket_QSetMaxPacketSize
, NULL
,
442 "QSetMaxPacketSize:",
443 "Tell " DEBUGSERVER_PROGRAM_NAME
" the max sized packet gdb can handle"));
445 set_max_payload_size
, &RNBRemote::HandlePacket_QSetMaxPayloadSize
, NULL
,
446 "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME
447 " the max sized payload gdb can handle"));
449 Packet(set_environment_variable
, &RNBRemote::HandlePacket_QEnvironment
,
450 NULL
, "QEnvironment:",
451 "Add an environment variable to the inferior's environment"));
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 "
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."));
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."));
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."));
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."));
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."));
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();
551 count
= DNBProcessGetAvailableSTDOUT(pid
, buf
, sizeof(buf
));
553 SendSTDOUTPacket(buf
, count
);
558 count
= DNBProcessGetAvailableSTDERR(pid
, buf
, sizeof(buf
));
560 SendSTDERRPacket(buf
, count
);
566 void RNBRemote::SendAsyncProfileData() {
567 if (m_ctx
.HasValidProcessID()) {
568 nub_process_t pid
= m_ctx
.ProcessID();
572 count
= DNBProcessGetAvailableProfileData(pid
, buf
, sizeof(buf
));
574 SendAsyncProfileDataPacket(buf
, count
);
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
;
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
) {
602 return SendHexEncodedBytePacket("O", buf
, buf_size
, NULL
);
605 rnb_err_t
RNBRemote::SendSTDERRPacket(char *buf
, nub_size_t buf_size
) {
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
) {
617 std::string
packet("A");
618 packet
.append(buf
, buf_size
);
619 return SendPacket(packet
);
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
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
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
);
679 case compression_types::zlib_deflate
:
680 scratchbuf_size
= compression_encode_scratch_buffer_size (COMPRESSION_ZLIB
);
682 case compression_types::lzma
:
683 scratchbuf_size
= compression_encode_scratch_buffer_size (COMPRESSION_LZMA
);
685 case compression_types::lzfse
:
686 scratchbuf_size
= compression_encode_scratch_buffer_size (COMPRESSION_LZFSE
);
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
,
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
,
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
,
726 if (compressed_size
> 0) {
728 compressed
.reserve(compressed_size
);
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
== '*' ||
739 compressed
.push_back(0x7d);
740 compressed
.push_back(byte
^ 0x20);
742 compressed
.push_back(byte
);
746 compressed
= "N" + orig
;
749 compressed
= "N" + orig
;
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
+ "#";
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
)
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());
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
)
804 // Should we try to resend the packet at this layer?
805 // if (packet.command == nack)
809 rnb_err_t
RNBRemote::SendErrorPacket(std::string errcode
,
810 const std::string
&errmsg
) {
811 if (m_enable_error_strings
&& !errmsg
.empty()) {
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
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),
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]) {
861 long packet_checksum
= 0;
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: "
870 (uint32_t)m_comm
.Timer().ElapsedMicroSeconds(true),
871 __FUNCTION__
, return_packet
.c_str());
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
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);
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);
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());
913 m_comm
.Write("-", 1);
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
,
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
) {
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))
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
)
960 if (set_events
& RNBContext::event_read_thread_exiting
)
961 err
= rnb_not_connected
;
963 if (err
== rnb_not_connected
)
966 while (err
== rnb_err
)
970 err
= rnb_not_connected
;
973 if (err
== rnb_success
) {
975 for (it
= m_packets
.begin(); it
!= m_packets
.end(); ++it
) {
976 if (payload
.compare(0, it
->abbrev
.size(), it
->abbrev
) == 0)
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'",
986 HandlePacket_UNIMPLEMENTED(payload
.c_str());
990 packet_payload
= payload
;
996 rnb_err_t
RNBRemote::HandleAsyncPacket(PacketEnum
*type
) {
997 DNBLogThreadedIf(LOG_RNB_REMOTE
, "%8u RNBRemote::%s",
998 (uint32_t)m_comm
.Timer().ElapsedMicroSeconds(true),
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());
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
) {
1018 *type
= packet_info
.type
;
1019 return (this->*packet_callback
)(packet_data
.c_str());
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
) {
1042 *type
= packet_info
.type
;
1043 return (this->*packet_callback
)(packet_data
.c_str());
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.
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
);
1062 // See if we have any left over data from a previous call to this
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
1071 // Parse up the packets into gdb remote packets
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
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...
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
;
1094 // Add two for the checksum bytes and 1 to point to the
1095 // byte just past the end of this packet
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
1110 // '%s'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true),
1111 // __FUNCTION__, idx, m_rx_partial_data.c_str());
1113 } else if (idx
< end_idx
) {
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);
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());
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
]);
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
);
1161 void RNBRemote::StartReadRemoteDataThread() {
1162 DNBLogThreadedIf(LOG_RNB_REMOTE
, "%8u RNBRemote::%s called",
1163 (uint32_t)m_comm
.Timer().ElapsedMicroSeconds(true),
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);
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
);
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),
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...",
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
);
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
1228 rnb_err_t err
= remote
->GetCommData();
1235 DNBLogThreadedIf(LOG_RNB_REMOTE
,
1236 "RNBSocket::GetCommData returned error %u", err
);
1240 case rnb_not_connected
:
1241 DNBLogThreadedIf(LOG_RNB_REMOTE
,
1242 "RNBSocket::GetCommData returned not connected...");
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...",
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
;
1266 #if defined (__ARM64_ARCH_8_32__)
1267 return CPU_TYPE_ARM64_32
;
1269 return CPU_TYPE_ARM
;
1271 #elif defined(__i386__) || defined(__x86_64__)
1272 if (sizeof(char *) == 8) {
1273 return CPU_TYPE_X86_64
;
1275 return CPU_TYPE_I386
;
1281 /* Read the bytes in STR which are GDB Remote Protocol binary encoded 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
1289 std::vector
<uint8_t> decode_binary_data(const char *str
, size_t len
) {
1290 std::vector
<uint8_t> bytes
;
1294 if (len
== (size_t)-1)
1298 unsigned char c
= *str
++;
1299 if (c
== 0x7d && len
> 0) {
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
) {
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);
1322 output
.push_back(ch
);
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
1332 std::string
json_string_quote_metachars(const std::string
&s
) {
1333 if (s
.find('"') == std::string::npos
)
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
);
1342 output
.push_back('\\');
1344 output
.push_back(ch
);
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
)
1374 "RNBRemote::%s() getting native registers from DNB interface",
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
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
)
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
1423 // the offsets since we removed all gaps...
1424 for (auto ®_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
;
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 ®_entry: g_dynamic_register_map)
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);
1475 g_reg_entries
= g_dynamic_register_map
.data();
1476 g_num_reg_entries
= g_dynamic_register_map
.size();
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
);
1489 /* 'A arglen,argnum,arg,...'
1490 Update the inferior context CTX with the program name and arg
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");
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
;
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");
1535 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
1536 "arglen not followed by comma on 'A' pkt");
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");
1547 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
1548 "arglen not followed by comma on 'A' pkt");
1554 while (c
< buf
&& *c
!= '\0' && c
+ 1 < buf
&& *(c
+ 1) != '\0') {
1557 smallbuf
[1] = *(c
+ 1);
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");
1571 ctx
.PushArgument(arg
.c_str());
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
) {
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.
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");
1604 SetContinueThread(tid
);
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
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
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
1670 nub_size_t numthreads
= DNBProcessGetNumThreads(pid
);
1671 std::ostringstream ostrm
;
1674 for (nub_size_t i
= 0; i
< numthreads
; ++i
) {
1679 nub_thread_t th
= DNBProcessGetThreadAtIndex(pid
, i
);
1680 ostrm
<< std::hex
<< th
;
1682 return SendPacket(ostrm
.str());
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
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");
1702 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
1703 "Illformed qThreadExtraInfo packet");
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
);
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
);
1729 line
.erase(0, space_pos
);
1733 static std::string
get_identifier(std::string
&line
) {
1736 const size_t line_size
= line
.size();
1738 for (end_pos
= 0; end_pos
< line_size
; ++end_pos
) {
1740 if (isalpha(line
[end_pos
]) || line
[end_pos
] == '_')
1742 } else if (isalnum(line
[end_pos
]) || line
[end_pos
] == '_')
1746 word
.assign(line
, 0, end_pos
);
1747 line
.erase(0, end_pos
);
1751 static std::string
get_operator(std::string
&line
) {
1754 if (!line
.empty()) {
1755 if (line
[0] == '=') {
1763 static std::string
get_value(std::string
&line
) {
1766 if (!line
.empty()) {
1772 extern void FileLogCallback(void *baton
, uint32_t flags
, const char *format
,
1775 rnb_err_t
RNBRemote::HandlePacket_qRcmd(const char *p
) {
1776 const char *c
= p
+ strlen("qRcmd,");
1778 while (c
[0] && c
[1]) {
1779 char smallbuf
[3] = {c
[0], c
[1], '\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");
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");
1797 DNBLogSetLogCallback(FileLogCallback
, log_file
);
1798 return SendPacket("OK");
1800 return SendErrorPacket("E71");
1801 } else if (variable
== "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");
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
) {
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())
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
) {
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();
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
) {
1889 ostrm
<< "encoding:uint;";
1892 ostrm
<< "encoding:sint;";
1895 ostrm
<< "encoding:ieee754;";
1898 ostrm
<< "encoding:vector;";
1902 switch (reg_entry
->nub_info
.format
) {
1904 ostrm
<< "format:binary;";
1907 ostrm
<< "format:decimal;";
1910 ostrm
<< "format:hex;";
1913 ostrm
<< "format:float;";
1916 ostrm
<< "format:vector-sint8;";
1919 ostrm
<< "format:vector-uint8;";
1921 case VectorOfSInt16
:
1922 ostrm
<< "format:vector-sint16;";
1924 case VectorOfUInt16
:
1925 ostrm
<< "format:vector-uint16;";
1927 case VectorOfSInt32
:
1928 ostrm
<< "format:vector-sint32;";
1930 case VectorOfUInt32
:
1931 ostrm
<< "format:vector-uint32;";
1933 case VectorOfFloat32
:
1934 ostrm
<< "format:vector-float32;";
1936 case VectorOfUInt128
:
1937 ostrm
<< "format:vector-uint128;";
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;";
1954 case GENERIC_REGNUM_PC
:
1955 ostrm
<< "generic:pc;";
1957 case GENERIC_REGNUM_SP
:
1958 ostrm
<< "generic:sp;";
1960 case GENERIC_REGNUM_RA
:
1961 ostrm
<< "generic:ra;";
1963 case GENERIC_REGNUM_FLAGS
:
1964 ostrm
<< "generic:flags;";
1966 case GENERIC_REGNUM_ARG1
:
1967 ostrm
<< "generic:arg1;";
1969 case GENERIC_REGNUM_ARG2
:
1970 ostrm
<< "generic:arg2;";
1972 case GENERIC_REGNUM_ARG3
:
1973 ostrm
<< "generic:arg3;";
1975 case GENERIC_REGNUM_ARG4
:
1976 ostrm
<< "generic:arg4;";
1978 case GENERIC_REGNUM_ARG5
:
1979 ostrm
<< "generic:arg5;";
1981 case GENERIC_REGNUM_ARG6
:
1982 ostrm
<< "generic:arg6;";
1984 case GENERIC_REGNUM_ARG7
:
1985 ostrm
<< "generic:arg7;";
1987 case GENERIC_REGNUM_ARG8
:
1988 ostrm
<< "generic:arg8;";
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
) {
1999 ostrm
<< RAW_HEXBASE
<< reg_entry
->value_regnums
[i
];
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
) {
2009 ostrm
<< RAW_HEXBASE
<< reg_entry
->invalidate_regnums
[i
];
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
) {
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
!= ';') {
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}'`
2042 // echo " else if (strncmp (p, \"$logname\", sizeof
2043 // (\"$logname\") - 1) == 0)"
2045 // echo " p += sizeof (\"$logname\") - 1;"
2046 // echo " bitmask |= $logname;"
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) ==
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;
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;
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) ==
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) ==
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) ==
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) ==
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) ==
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) ==
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) ==
2153 p
+= sizeof("LOG_RNB_NONE") - 1;
2156 /* Unrecognized logging bit; ignore it. */
2157 const char *c
= strchr(p
, '|');
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
);
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.
2188 else if (strncmp (p
, "mode=", sizeof ("mode=") - 1) == 0)
2190 p
+= sizeof ("mode=") - 1;
2191 if (strncmp (p
, "asl;", sizeof ("asl;") - 1) == 0)
2194 p
+= sizeof ("asl;") - 1;
2196 else if (strncmp (p
, "file;", sizeof ("file;") - 1) == 0)
2199 p
+= sizeof ("file;") - 1;
2203 // Ignore unknown argument
2204 const char *c
= strchr (p
, ';');
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
, ';');
2217 c
= strchr (p
, '\0');
2220 char *fn
= (char *) alloca (c
- p
+ 1);
2221 strlcpy (fn
, p
, c
- p
);
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)
2232 FILE *f
= fopen (fn
, "w");
2235 DNBLogSetLogFile (f
);
2236 DNBEnableLogging (f
, DNBLogGetLogMask ());
2242 #endif /* #if 0 to enforce ASL logging only. */
2244 // Ignore unknown argument
2245 const char *c
= strchr(p
, ';');
2249 p
= strchr(p
, '\0');
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;
2264 const char *bar
= strchr(p
, '|');
2265 if (bar
== nullptr) {
2266 success
= m_ctx
.AddIgnoredException(p
);
2269 std::string
exc_str(p
, bar
- p
);
2270 if (exc_str
.empty()) {
2275 success
= m_ctx
.AddIgnoredException(exc_str
.c_str());
2282 return SendPacket("OK");
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;
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");
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;
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:
2332 StdStringExtractor
packet(p
);
2333 packet
.SetFilePos(7);
2334 char ch
= packet
.GetChar();
2335 while (packet
.GetChar() != ':')
2340 packet
.GetHexByteString(m_ctx
.GetSTDIN());
2341 success
= !m_ctx
.GetSTDIN().empty();
2345 packet
.GetHexByteString(m_ctx
.GetSTDOUT());
2346 success
= !m_ctx
.GetSTDOUT().empty();
2350 packet
.GetHexByteString(m_ctx
.GetSTDERR());
2351 success
= !m_ctx
.GetSTDERR().empty();
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");
2376 m_ctx
.GetWorkingDir().clear();
2377 return SendErrorPacket("E62"); // Working directory isn't a directory...
2380 return SendErrorPacket("E59"); // Invalid path
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");
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");
2405 return SendErrorPacket("E61");
2408 rnb_err_t
RNBRemote::HandlePacket_QSetDetachOnError(const char *p
) {
2409 p
+= sizeof("QSetDetachOnError:") - 1;
2410 bool should_detach
= true;
2413 should_detach
= false;
2416 should_detach
= true;
2419 return HandlePacket_ILLFORMED(
2420 __FILE__
, __LINE__
, p
,
2421 "Invalid value for QSetDetachOnError - should be 0 or 1");
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;
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
2455 p
+= sizeof("QSetMaxPayloadSize:") - 1;
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;
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
2485 QEnvironment:VARIABLE=VALUE
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
2504 QEnvironmentHexEncoded:VARIABLE=VALUE
2506 The VARIABLE=VALUE part is sent hex-encoded so characters like '#' with
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),
2516 p
+= sizeof("QEnvironmentHexEncoded:") - 1;
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");
2529 smallbuf
[1] = *(c
+ 1);
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");
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");
2564 return SendErrorPacket("E80");
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
,
2575 const register_map_entry_t
*reg
,
2576 const DNBRegisterValue
*reg_value_ptr
,
2577 std::optional
<uint8_t> fail_value
) {
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
,
2592 if (!fail_value
|| reg
->nub_info
.size
== 0)
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);
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.
2612 ostrm
<< RAWHEX8(reg
->debugserver_regnum
) << ':';
2613 register_value_in_hex_fixed_width(ostrm
, pid
, tid
, reg
, reg_value_ptr
,
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 {
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
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
);
2643 queue_name
= DNBProcessMemoryReadCString(pid
, label_addr
);
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
)];
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;
2669 if (reg_value
->info
.size
== 4)
2670 fp
= reg_value
->value
.uint32
;
2672 fp
= reg_value
->value
.uint64
;
2674 // Make sure we never recurse more than 256 times so we don't recurse too
2676 // store up too much memory in the expedited cache
2677 if (++frame_count
> backtrace_limit
)
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
) !=
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())
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];
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
;
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
2723 int signum
= tid_stop_info
.details
.signal
.signo
;
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
) {
2735 case EXC_BREAKPOINT
:
2738 case EXC_BAD_ACCESS
:
2739 signum
= TARGET_EXC_BAD_ACCESS
;
2741 case EXC_BAD_INSTRUCTION
:
2742 signum
= TARGET_EXC_BAD_INSTRUCTION
;
2744 case EXC_ARITHMETIC
:
2745 signum
= TARGET_EXC_ARITHMETIC
;
2748 signum
= TARGET_EXC_EMULATION
;
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]);
2755 signum
= TARGET_EXC_SOFTWARE
;
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
<< ';';
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
]);
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
);
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
);
2815 // If we failed to get any of the thread pc values, the size of our
2817 // be the same as the # of threads. Don't provide any expedited thread
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
) {
2825 ostrm
<< std::hex
<< pc_values
[i
];
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());
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))
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)
2876 if (!DNBThreadGetRegisterValueByID(pid
, tid
, regset
,
2877 g_reg_entries
[reg
].nub_info
.reg
,
2881 debugserver_regnum_with_fixed_width_hex_register_value(
2882 ostrm
, pid
, tid
, &g_reg_entries
[reg
], reg_value
.get(),
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());
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
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
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
;
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);
2959 return SendPacket(ostrm
.str());
2961 return SendErrorPacket("E51");
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
:
2981 case eStateStepping
:
2982 case eStateDetached
:
2983 return rnb_success
; // Ignore
2985 case eStateSuspended
:
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
);
2997 case eStateUnloaded
:
2998 case eStateExited
: {
2999 char pid_exited_packet
[16] = "";
3001 // Process exited with exit status
3002 if (!DNBProcessGetExitStatus(pid
, &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
;
3028 exit_packet
<< RAW_HEXBASE
<< "description";
3030 for (size_t i
= 0; exit_info
[i
] != '\0'; i
++)
3031 exit_packet
<< RAWHEX8(exit_info
[i
]);
3033 return SendPacket(exit_packet
.str());
3035 return SendPacket(pid_exited_packet
);
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");
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");
3055 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3056 "Comma sep missing in M packet");
3059 /* Advance 'p' to the length part of the packet. */
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");
3069 return SendPacket("OK");
3073 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3074 "Missing colon in M packet");
3076 /* Advance 'p' to the data part of the packet. */
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");
3085 return SendPacket("OK");
3088 uint8_t *buf
= (uint8_t *)alloca(datalen
/ 2);
3091 while (*p
!= '\0' && *(p
+ 1) != '\0') {
3094 hexbuf
[1] = *(p
+ 1);
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");
3107 DNBProcessMemoryWrite(m_ctx
.ProcessID(), addr
, length
, buf
);
3108 if (wrote
!= length
)
3109 return SendErrorPacket("E09");
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");
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");
3128 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3129 "Comma sep missing in m packet");
3132 /* Advance 'p' to the length part of the packet. */
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");
3142 return SendPacket("");
3145 std::string
buf(length
, '\0');
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.
3167 // ADDR and LEN are both base 16.
3169 // Responds with 'OK' for zero-length request
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");
3184 nub_addr_t addr
= strtoull(p
, &c
, 16);
3186 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3187 "Invalid address in X packet");
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. */
3198 auto length
= strtoul(p
, NULL
, 16);
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
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);
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");
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");
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
3260 including any escaped chars. The data payload may be a little bit smaller
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.
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());
3282 for (it
= data
.begin(); it
!= data
.end(); ++it
) {
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,
3296 Should the setting of the Hg packet determine which thread's registers
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);
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
3322 DNBThreadGetRegisterContext(pid
, tid
, ®_ctx
[0], 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
, ';');
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);
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(®_ctx
[0], reg_ctx
.size(), 0xcc);
3366 if (bytes_extracted
== reg_ctx
.size()) {
3367 // Now write the register context
3369 DNBThreadSetRegisterContext(pid
, tid
, reg_ctx
.data(), reg_ctx
.size());
3370 if (reg_ctx_size
== reg_ctx
.size())
3371 return SendPacket("OK");
3373 return SendErrorPacket("E55");
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();
3393 // FORMAT: _MXXXXXX,PPP
3394 // XXXXXX: big endian hex chars
3395 // PPP: permissions can be any combo of r w x chars
3398 // XXXXXX: hex address of the newly allocated memory
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);
3412 if (packet
.GetChar() == ',') {
3413 uint32_t permissions
= 0;
3415 bool success
= true;
3416 while (success
&& (ch
= packet
.GetChar()) != '\0') {
3419 permissions
|= eMemoryPermissionsReadable
;
3422 permissions
|= eMemoryPermissionsWritable
;
3425 permissions
|= eMemoryPermissionsExecutable
;
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");
3448 // XXXXXX: address that was previously allocated
3451 // OK: address was deallocated
3457 rnb_err_t
RNBRemote::HandlePacket_DeallocateMemory(const char *p
) {
3458 StdStringExtractor
packet(p
);
3459 packet
.SetFilePos(2); // Skip the "_m"
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
3473 // TTTT: thread ID in hex
3476 // SAVEID: Where SAVEID is a decimal number that represents the save ID
3477 // that can be passed back into a "QRestoreRegisterState" packet
3481 // QSaveRegisterState;thread:1E34; (when thread suffix is supported)
3482 // QSaveRegisterState (when thread suffix is NOT
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");
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
);
3502 snprintf(response
, sizeof(response
), "%u", save_id
);
3503 return SendPacket(response
);
3505 return SendErrorPacket("E75");
3508 // FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT; (when thread suffix is
3510 // FORMAT: QRestoreRegisterState:SAVEID (when thread suffix is NOT
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"
3517 // OK: successfully restored registers for the specified thread
3521 // QRestoreRegisterState:1;thread:1E34; (when thread suffix is
3523 // QRestoreRegisterState:1 (when thread suffix is NOT
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");
3535 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3536 "No thread was is set with the Hg packet");
3539 StdStringExtractor
packet(p
);
3541 strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:"
3542 const uint32_t save_id
= packet
.GetU32(0);
3545 // Get the register context size first by calling with NULL buffer
3546 if (DNBThreadRestoreRegisterState(pid
, tid
, save_id
))
3547 return SendPacket("OK");
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') {
3560 smallbuf
[1] = *(p
+ 1);
3564 int ch
= static_cast<int>(strtoul(smallbuf
, NULL
, 16));
3565 if (errno
!= 0 && ch
== 0) {
3570 attach_name
.push_back(ch
);
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
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;
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;";
3602 #if defined(__x86_64__)
3603 reply
<< "SupportedWatchpointTypes=x86_64;";
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
)
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
,
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
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
3645 if (my_uid
!= process_uid
)
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())
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
3672 auditinfo_addr_t info
;
3673 getaudit_addr(&info
, sizeof(info
));
3674 if (info
.ai_flags
& AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS
)
3684 // 'class' : 'rule',
3685 // 'comment' : 'For use by Apple. WARNING: administrators are advised
3686 // not to modify this right.',
3691 // 'authenticate-developer'
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
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
, ¤tRightDict
);
3706 if (status
!= errAuthorizationSuccess
) {
3707 // could not check authorization
3711 bool devmode_enabled
= true;
3713 if (!CFDictionaryContainsKey(currentRightDict
, CFSTR("k-of-n"))) {
3714 devmode_enabled
= false;
3716 CFNumberRef item
= (CFNumberRef
) CFDictionaryGetValue(currentRightDict
, CFSTR("k-of-n"));
3717 if (item
&& CFGetTypeID(item
) == CFNumberGetTypeID()) {
3719 ::CFNumberGetValue(item
, kCFNumberSInt64Type
, &num
);
3721 devmode_enabled
= false;
3724 devmode_enabled
= false;
3728 if (!CFDictionaryContainsKey(currentRightDict
, CFSTR("class"))) {
3729 devmode_enabled
= false;
3731 CFStringRef item
= (CFStringRef
) CFDictionaryGetValue(currentRightDict
, CFSTR("class"));
3732 if (item
&& CFGetTypeID(item
) == CFStringGetTypeID()) {
3734 if (CFStringGetCString (item
, tmpbuf
, sizeof(tmpbuf
), CFStringGetSystemEncoding())) {
3735 tmpbuf
[sizeof (tmpbuf
) - 1] = '\0';
3736 if (strcmp (tmpbuf
, "rule") != 0) {
3737 devmode_enabled
= false;
3740 devmode_enabled
= false;
3743 devmode_enabled
= false;
3747 if (!CFDictionaryContainsKey(currentRightDict
, CFSTR("rule"))) {
3748 devmode_enabled
= false;
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;
3761 devmode_enabled
= false;
3764 ::CFRelease(currentRightDict
);
3766 return devmode_enabled
;
3767 #endif // TARGET_OS_OSX
3773 Attach to a new process with the specified process ID. pid is a hexadecimal
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
3778 mode (see extended mode).
3782 "Any Stop Reply Packet" for success
3785 rnb_err_t
RNBRemote::HandlePacket_v(const char *p
) {
3786 if (strcmp(p
, "vCont;c") == 0) {
3788 return RNBRemote::HandlePacket_c("c");
3789 } else if (strcmp(p
, "vCont;s") == 0) {
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
);
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
;
3812 thread_action
.signal
= static_cast<int>(strtoul(c
, &c
, 16));
3814 return HandlePacket_ILLFORMED(
3815 __FILE__
, __LINE__
, p
, "Could not parse signal in vCont packet");
3816 // Fall through to next case...
3817 [[clang::fallthrough
]];
3820 thread_action
.state
= eStateRunning
;
3825 thread_action
.signal
= static_cast<int>(strtoul(c
, &c
, 16));
3827 return HandlePacket_ILLFORMED(
3828 __FILE__
, __LINE__
, p
, "Could not parse signal in vCont packet");
3829 // Fall through to next case...
3830 [[clang::fallthrough
]];
3833 thread_action
.state
= eStateStepping
;
3837 HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
3838 "Unsupported action in vCont packet");
3843 thread_action
.tid
= strtoul(++c
, &c
, 16);
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());
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 "
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 "
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;");
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(),
3919 attach_pid
= DNBProcessAttach(pid_attaching_to
, &attach_timeout_abstime
,
3920 m_ctx
.GetIgnoredExceptions(),
3921 err_str
, sizeof(err_str
));
3924 return HandlePacket_UNIMPLEMENTED(p
);
3927 if (attach_pid
== INVALID_NUB_PROCESS_ARCH
) {
3928 DNBLogError("debugserver is x86_64 binary running in translation, attach "
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();
3942 DNBLogError("Attach failed");
3943 m_ctx
.LaunchStatus().SetError(-1, DNBError::Generic
);
3945 m_ctx
.LaunchStatus().SetErrorString(err_str
);
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
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 '" +
3985 "' and process is running "
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 "
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 "
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
) {
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");
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
++;
4073 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
4074 "Comma separator missing in z packet");
4077 nub_process_t pid
= m_ctx
.ProcessID();
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");
4085 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
4086 "Comma separator missing in z packet");
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') {
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
4108 return SendPacket("OK");
4110 // We failed to set the software breakpoint
4111 return SendErrorPacket("E09");
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
;
4126 watch_flags
= WATCH_TYPE_READ
| WATCH_TYPE_WRITE
;
4128 if (DNBWatchpointSet(pid
, addr
, byte_size
, watch_flags
, hardware
)) {
4129 return SendPacket("OK");
4131 // We failed to set the watchpoint
4132 return SendErrorPacket("E09");
4139 } else if (packet_cmd
== 'z') {
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");
4147 return SendErrorPacket("E08");
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");
4157 return SendErrorPacket("E08");
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
4172 nub_thread_t
RNBRemote::ExtractThreadIDFromThreadSuffix(const char *p
) {
4173 if (m_thread_suffix_supported
) {
4174 nub_thread_t tid
= INVALID_NUB_THREAD
;
4176 const char *tid_cstr
= strstr(p
, "thread:");
4178 tid_cstr
+= strlen("thread:");
4179 tid
= strtoul(tid_cstr
, NULL
, 16);
4184 return GetCurrentThread();
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();
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
];
4222 std::ostringstream ostrm
;
4223 if (reg_entry
== NULL
) {
4225 "RNBRemote::HandlePacket_p(%s): unknown register number %u requested\n",
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);
4234 if (!register_value_in_hex_fixed_width(ostrm
, pid
, tid
, reg_entry
, NULL
,
4236 return SendErrorPacket("E97");
4238 return SendPacket(ostrm
.str());
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) {
4285 "RNBRemote::HandlePacket_P(%s): unknown register number %u requested\n",
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
,
4303 return SendErrorPacket("E32");
4305 return SendPacket("OK");
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();
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.
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
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
4352 This packet isn't implemented
4355 qMemoryRegionInfo:3a55140
4356 start:3a50000,size:100000,permissions:rwx
4359 error:address in unmapped region
4361 qMemoryRegionInfo:3a551140 (on a different platform)
4362 error:region lookup cannot be performed
4365 OK // this packet is implemented by the remote nub
4368 p
+= sizeof("qMemoryRegionInfo") - 1;
4370 return SendPacket("OK");
4372 return SendErrorPacket("E67");
4373 if (*p
== '0' && (*(p
+ 1) == 'x' || *(p
+ 1) == 'X'))
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
, ®ion_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
)
4398 if (region_info
.permissions
& eMemoryPermissionsWritable
)
4400 if (region_info
.permissions
& eMemoryPermissionsExecutable
)
4404 ostrm
<< "dirty-pages:";
4405 if (region_info
.dirty_pages
.size() > 0) {
4407 for (nub_addr_t addr
: region_info
.dirty_pages
) {
4411 ostrm
<< std::hex
<< addr
;
4415 if (!region_info
.vm_types
.empty()) {
4417 for (size_t i
= 0; i
< region_info
.vm_types
.size(); i
++) {
4420 ostrm
<< region_info
.vm_types
[i
];
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
;
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
);
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
;
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) {
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:");
4519 uint64_t response_size
= ::strtoul(p
, &end
, 16);
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
);
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.
4539 qWatchpointSupportInfo:
4542 qWatchpointSupportInfo
4543 OK // this packet is implemented by the remote nub
4546 p
+= sizeof("qWatchpointSupportInfo") - 1;
4548 return SendPacket("OK");
4550 return SendErrorPacket("E67");
4553 uint32_t num
= DNBWatchpointGetNumSupportedHWP(m_ctx
.ProcessID());
4554 std::ostringstream ostrm
;
4557 ostrm
<< "num:" << std::dec
<< num
<< ';';
4558 return SendPacket(ostrm
.str());
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();
4577 process_signo
= static_cast<int>(strtoul(p
+ 1, &end
, 16));
4579 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
4580 "Could not parse signal in C packet");
4581 else if (*end
== ';') {
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. */
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()))
4610 DNBLog("error while detaching from pid %u due to D packet",
4612 SendErrorPacket("E01");
4615 SendErrorPacket("E04");
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());
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);
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
);
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.
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') {
4693 action
.signal
= static_cast<int>(strtoul(p
+ 1, &end
, 16));
4695 return HandlePacket_ILLFORMED(__FILE__
, __LINE__
, p
,
4696 "Could not parse signal in S packet");
4697 else if (*end
== ';') {
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.
4728 static const char *GetArchName(const uint32_t cputype
,
4729 const uint32_t cpusubtype
) {
4732 switch (cpusubtype
) {
4759 case CPU_TYPE_ARM64
:
4761 case CPU_TYPE_ARM64_32
:
4765 case CPU_TYPE_X86_64
:
4766 switch (cpusubtype
) {
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
,
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
;
4802 len
= sizeof(uint32_t);
4803 if (::sysctlbyname("hw.cpusubtype", &g_host_cpusubtype
, &len
, NULL
, 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
;
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
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;";
4861 strm
<< "ostype:ios;";
4864 // On armv7 we use "synchronous" watchpoints which means the exception is
4865 // delivered before the instruction executes.
4866 strm
<< "watchpoint_exceptions_received:before;";
4868 strm
<< "ostype:macosx;";
4869 strm
<< "watchpoint_exceptions_received:after;";
4872 // len = sizeof(ostype);
4873 // if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0)
4875 // len = strlen(ostype);
4876 // std::transform (ostype, ostype + len, ostype, tolower);
4877 // strm << "ostype:" << std::dec << ostype << ';';
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
;
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;";
4905 strm
<< "ptrsize:8;";
4907 strm
<< "ptrsize:" << std::dec
<< sizeof(void *) << ';';
4909 #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
4910 strm
<< "default_packet_timeout:10;";
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
) {
4921 s
<< INDENT_WITH_SPACES(indent
);
4923 if (!has_attributes
)
4924 s
<< '>' << std::endl
;
4927 void XMLElementStartEndAttributes(std::ostringstream
&s
, bool empty
) {
4930 s
<< '>' << std::endl
;
4933 void XMLElementEnd(std::ostringstream
&s
, uint32_t indent
, const char *name
) {
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) {
4944 s
<< INDENT_WITH_SPACES(indent
);
4945 s
<< '<' << name
<< '>' << value
;
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) {
4955 s
<< INDENT_WITH_SPACES(indent
);
4957 s
<< '<' << name
<< '>' << DECIMAL
<< value
;
4959 XMLElementEnd(s
, 0, name
);
4962 void XMLAttributeString(std::ostringstream
&s
, const char *name
,
4963 const char *value
, const char *default_value
= NULL
) {
4965 if (default_value
&& strcmp(value
, default_value
) == 0)
4966 return; // No need to emit the attribute because it matches the default
4968 s
<< ' ' << name
<< "=\"" << value
<< "\"";
4972 void XMLAttributeUnsignedDecimal(std::ostringstream
&s
, const char *name
,
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
®
) {
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
) {
4991 lldb_encoding
= "uint";
4994 lldb_encoding
= "sint";
4997 lldb_encoding
= "ieee754";
4998 if (reg
.nub_info
.set
> 0)
4999 gdb_group
= "float";
5002 lldb_encoding
= "vector";
5003 if (reg
.nub_info
.set
> 0)
5004 gdb_group
= "vector";
5008 switch (reg
.nub_info
.format
) {
5010 lldb_format
= "binary";
5013 lldb_format
= "decimal";
5016 lldb_format
= "hex";
5020 lldb_format
= "float";
5024 lldb_format
= "vector-sint8";
5028 lldb_format
= "vector-uint8";
5030 case VectorOfSInt16
:
5032 lldb_format
= "vector-sint16";
5034 case VectorOfUInt16
:
5036 lldb_format
= "vector-uint16";
5038 case VectorOfSInt32
:
5040 lldb_format
= "vector-sint32";
5042 case VectorOfUInt32
:
5044 lldb_format
= "vector-uint32";
5046 case VectorOfFloat32
:
5048 lldb_format
= "vector-float32";
5050 case VectorOfUInt128
:
5052 lldb_format
= "vector-uint128";
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";
5079 case GENERIC_REGNUM_PC
:
5080 lldb_generic
= "pc";
5082 case GENERIC_REGNUM_SP
:
5083 lldb_generic
= "sp";
5085 case GENERIC_REGNUM_RA
:
5086 lldb_generic
= "ra";
5088 case GENERIC_REGNUM_FLAGS
:
5089 lldb_generic
= "flags";
5091 case GENERIC_REGNUM_ARG1
:
5092 lldb_generic
= "arg1";
5094 case GENERIC_REGNUM_ARG2
:
5095 lldb_generic
= "arg2";
5097 case GENERIC_REGNUM_ARG3
:
5098 lldb_generic
= "arg3";
5100 case GENERIC_REGNUM_ARG4
:
5101 lldb_generic
= "arg4";
5103 case GENERIC_REGNUM_ARG5
:
5104 lldb_generic
= "arg5";
5106 case GENERIC_REGNUM_ARG6
:
5107 lldb_generic
= "arg6";
5109 case GENERIC_REGNUM_ARG7
:
5110 lldb_generic
= "arg7";
5112 case GENERIC_REGNUM_ARG8
:
5113 lldb_generic
= "arg8";
5118 XMLAttributeString(s
, "generic", lldb_generic
);
5120 bool empty
= reg
.value_regnums
.empty() && reg
.invalidate_regnums
.empty();
5122 if (!reg
.value_regnums
.empty()) {
5123 std::ostringstream regnums
;
5126 for (auto regnum
: reg
.value_regnums
) {
5132 XMLAttributeString(s
, "value_regnums", regnums
.str().c_str());
5135 if (!reg
.invalidate_regnums
.empty()) {
5136 std::ostringstream regnums
;
5139 for (auto regnum
: reg
.invalidate_regnums
) {
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();
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 ®: 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;
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
, ':');
5220 std::string
object(p
, sep
- p
); // "auxv", "backtrace", "features", etc
5222 sep
= strchr(p
, ':');
5224 std::string
rw(p
, sep
- p
); // "read" or "write"
5226 sep
= strchr(p
, ':');
5228 std::string
annex(p
, sep
- p
); // "read" or "write"
5231 sep
= strchr(p
, ',');
5233 std::string
offset_str(p
, sep
- p
); // read the length as a string
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
5240 const uint64_t length
= strtoul(
5241 length_str
.c_str(), &end
, 16); // convert length_str to a length
5243 if (object
== "features" && rw
== "read" &&
5244 annex
== "target.xml") {
5245 std::ostringstream xml_out
;
5248 InitializeRegisters(true);
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
);
5258 xml_out
<< 'm'; // More data needs to be read with a
5260 xml_out
<< binary_encode_string(
5261 std::string(g_target_xml
, offset
, length
));
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
5270 xml_out
<< 'm'; // More data needs to be read with a
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
);
5283 SendErrorPacket("E85");
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
";";
5298 strm
<< "name:debugserver;";
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());
5333 c
+= key_with_quotes
.size();
5335 while (*c
!= '\0' && (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5341 while (*c
!= '\0' &&
5342 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5346 retval
= strtoul(c
, NULL
, 10);
5348 retval
= INVALID_NUB_ADDRESS
;
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
,
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());
5370 c
+= key_with_quotes
.size();
5372 while (*c
!= '\0' && (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5378 while (*c
!= '\0' &&
5379 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5382 if (strncmp(c
, "true", 4) == 0) {
5385 } else if (strncmp(c
, "false", 5) == 0) {
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());
5408 c
+= key_with_quotes
.size();
5410 while (*c
!= '\0' && (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5416 while (*c
!= '\0' &&
5417 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5422 while (*c
!= '\0' &&
5423 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5432 uint64_t value
= strtoul(c
, &endptr
, 10);
5434 ints
.push_back(value
);
5438 if (endptr
== c
|| endptr
== nullptr || *endptr
== '\0') {
5443 while (*c
!= '\0' &&
5444 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
5448 while (*c
!= '\0' &&
5449 (*c
== ' ' || *c
== '\t' || *c
== '\n' || *c
== '\r'))
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
)
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
:
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";
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
);
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(
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());
5535 reason_value
= "exec";
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",
5568 thread_dict_sp
->AddBooleanItem("associated_with_dispatch_queue",
5571 if (dispatch_queue_t
!= INVALID_NUB_ADDRESS
&&
5572 dispatch_queue_t
!= 0)
5573 thread_dict_sp
->AddIntegerItem("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()))
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
) {
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
5709 // it's possible that gathering the genealogy information for this thread
5711 // Ideally fetching this info for a thread in these odd states shouldn't
5713 // we've seen some problems with these new SPI and threads in edge-casey
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
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
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
)
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
)
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
) << "\"";
5768 if (thread_activity_sp
->messages
.size() > 0) {
5769 need_to_print_comma
= true;
5770 if (need_vouchers_comma_sep
)
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
)
5780 printed_one_message
= true;
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
5789 process_info_indexes
.insert(iter
->process_info_index
);
5790 json
<< "\"message\":\""
5791 << json_string_quote_metachars(iter
->message
) << "\"";
5796 if (thread_activity_sp
->breadcrumbs
.size() == 1) {
5797 need_to_print_comma
= true;
5798 if (need_vouchers_comma_sep
)
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
)
5812 if (process_info_indexes
.size() > 0) {
5813 need_to_print_comma
= true;
5814 if (need_vouchers_comma_sep
)
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
)
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;
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
)
5838 json
<< "\"image_uuid\":\"" << uuid_buf
<< "\"";
5842 if (printed_one_process_info
)
5847 if (need_to_print_comma
)
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
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) {
5862 json
<< "\"activity_query_duration\":"
5863 << floating_point_ascii_buffer
;
5869 if (tsd_address
!= INVALID_NUB_ADDRESS
) {
5870 if (need_to_print_comma
)
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
)
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
)
5887 json
<< "\"printable_name\":\""
5888 << json_string_quote_metachars(requested_qos
.printable_name
)
5895 if (pthread_t_value
!= INVALID_NUB_ADDRESS
) {
5896 if (need_to_print_comma
)
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
)
5906 need_to_print_comma
= true;
5907 json
<< "\"dispatch_queue_t\":" << dispatch_queue_t_value
;
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
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.
5932 RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p
) {
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
) &&
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
);
5968 if (json_str
.str().size() > 0) {
5969 return SendPacket(json_str
.str());
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
) {
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
);
6001 if (json_str
.str().size() > 0) {
6002 return SendPacket(json_str
.str());
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
,
6014 DNBLogThreadedIf(LOG_RNB_PROC
, "GetMachHeaderForMainExecutable(pid = %u, "
6015 "addr_size = %u, mach_header_addr = "
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
)) {
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 = "
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 "
6036 pid
, addr_size
, mach_header_addr
);
6044 static nub_addr_t
GetMachHeaderForMainExecutable(const nub_process_t pid
,
6045 const uint32_t addr_size
,
6047 struct AllImageInfos
{
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
);
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
)) {
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
) {
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
) {
6090 DNBProcessMemoryRead(pid
, shlib_addr
, sizeof(AllImageInfos
), bytes
);
6091 if (bytes_read
> 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
)
6107 mach_header_addr
= data
.GetPointer(&offset
);
6108 if (MachHeaderIsMainExecutable(pid
, addr_size
, mach_header_addr
,
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
6121 DNBRegionInfo region_info
;
6122 mach_header_addr
= 0;
6123 while (DNBProcessMemoryRegionInfo(pid
, mach_header_addr
, ®ion_info
)) {
6124 if (region_info
.size
== 0)
6127 if (region_info
.permissions
& eMemoryPermissionsExecutable
) {
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
;
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
6162 symbol_value_str
.assign(p
, sep
- 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
;
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";
6189 // // Lookup next symbol when we have one...
6190 // if (m_qSymbol_index == 1)
6194 if (symbol_name
.empty()) {
6195 // Done with symbol lookups
6196 return SendPacket("OK");
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
);
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) ==
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
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'
6241 // If the process has cputype CPU_TYPE_ARM, then it is an armv7 (32-bit
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
;
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
) {
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
<< ';';
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
6292 rep
<< "real-gid:" << std::hex
<< proc_kinfo
.kp_eproc
.e_pcred
.p_rgid
6294 rep
<< "effective-uid:" << std::hex
<< proc_kinfo
.kp_eproc
.e_ucred
.cr_uid
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] << ';';
6303 cpu_subtype_t cpusubtype
;
6304 if (auto cputypes
= DNBGetMainBinaryCPUTypes(pid
))
6305 std::tie(cputype
, cpusubtype
) = *cputypes
;
6307 std::tie(cputype
, cpusubtype
) = GetCPUTypesFromHost(pid
);
6309 uint32_t addr_size
= 0;
6311 rep
<< "cputype:" << std::hex
<< cputype
<< ";";
6312 rep
<< "cpusubtype:" << std::hex
<< cpusubtype
<< ';';
6313 if (cputype
& CPU_ARCH_ABI64
)
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.
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
));
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
);
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
);
6347 rep
<< "ostype:" << *platform
<< ";";
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
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
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;";
6373 rep
<< "ostype:ios;";
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) ==
6386 DNBDataRef
data(arg_data
, arg_data_size
, false);
6387 DNBDataRef::offset_t offset
= 0;
6388 uint32_t argc
= data
.Get32(&offset
);
6391 cstr
= data
.GetCStr(&offset
);
6395 const char *p
= data
.PeekCStr(offset
);
6396 if ((p
== NULL
) || (*p
!= '\0'))
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=")) ==
6409 is_ios_simulator
= true;
6412 if (cstr
[0] == '\0')
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;";
6426 rep
<< "ostype:ios;";
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;";
6444 if (addr_size
== 0) {
6445 #if (defined(__x86_64__) || defined(__i386__)) && defined(x86_THREAD_STATE)
6446 nub_thread_t thread
= DNBProcessGetCurrentThreadMachPort(pid
);
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;";
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
);
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;";
6472 rep
<< "ptrsize:4;";
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
;
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
6506 // should be uncompressed -- so we can indicate whether the compression was
6508 // or not via OK / Enn returns. After that, all packets sent will be using
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
;