mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 06:40:01 +08:00
We have been working on reducing the packet count that is sent between LLDB and the debugserver on MacOSX and iOS. Our approach to this was to reduce the packets required when debugging multiple threads. We currently make one qThreadStopInfoXXXX call (where XXXX is the thread ID in hex) per thread except the thread that stopped with a stop reply packet. In order to implement multiple thread infos in a single reply, we need to use structured data, which means JSON. The new jThreadsInfo packet will attempt to retrieve all thread infos in a single packet. The data is very similar to the stop reply packets, but packaged in JSON and uses JSON arrays where applicable. The JSON output looks like:
[
{ "tid":1580681,
"metype":6,
"medata":[2,0],
"reason":"exception",
"qaddr":140735118423168,
"registers": {
"0":"8000000000000000",
"1":"0000000000000000",
"2":"20fabf5fff7f0000",
"3":"e8f8bf5fff7f0000",
"4":"0100000000000000",
"5":"d8f8bf5fff7f0000",
"6":"b0f8bf5fff7f0000",
"7":"20f4bf5fff7f0000",
"8":"8000000000000000",
"9":"61a8db78a61500db",
"10":"3200000000000000",
"11":"4602000000000000",
"12":"0000000000000000",
"13":"0000000000000000",
"14":"0000000000000000",
"15":"0000000000000000",
"16":"960b000001000000",
"17":"0202000000000000",
"18":"2b00000000000000",
"19":"0000000000000000",
"20":"0000000000000000"},
"memory":[
{"address":140734799804592,"bytes":"c8f8bf5fff7f0000c9a59e8cff7f0000"},
{"address":140734799804616,"bytes":"00000000000000000100000000000000"}
]
}
]
It contains an array of dicitionaries with all of the key value pairs that are normally in the stop reply packet. Including the expedited registers. Notice that is also contains expedited memory in the "memory" key. Any values in this memory will get included in a new L1 cache in lldb_private::Process where if a memory read request is made and that memory request fits into one of the L1 memory cache blocks, it will use that memory data. If a memory request fails in the L1 cache, it will fall back to the L2 cache which is the same block sized caching we were using before these changes. This allows a process to expedite memory that you are likely to use and it reduces packet count. On MacOSX with debugserver, we expedite the frame pointer backchain for a thread (up to 256 entries) by reading 2 pointers worth of bytes at the frame pointer (for the previous FP and PC), and follow the backchain. Most backtraces on MacOSX and iOS now don't require us to read any memory!
We will try these packets out and if successful, we should port these to lldb-server in the near future.
<rdar://problem/21494354>
llvm-svn: 240354
379 lines
16 KiB
C++
379 lines
16 KiB
C++
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Created by Greg Clayton on 12/12/07.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef __RNBRemote_h__
|
|
#define __RNBRemote_h__
|
|
|
|
#include "RNBDefs.h"
|
|
#include "DNB.h"
|
|
#include "RNBContext.h"
|
|
#include "RNBSocket.h"
|
|
#include "PThreadMutex.h"
|
|
#include <string>
|
|
#include <vector>
|
|
#include <deque>
|
|
#include <map>
|
|
|
|
class RNBSocket;
|
|
class RNBContext;
|
|
class PThreadEvents;
|
|
|
|
enum event_loop_mode { debug_nub, gdb_remote_protocol, done };
|
|
|
|
enum class compression_types { zlib_deflate, lz4, lzma, lzfse, none };
|
|
|
|
class RNBRemote
|
|
{
|
|
public:
|
|
|
|
typedef enum {
|
|
invalid_packet = 0,
|
|
ack, // '+'
|
|
nack, // '-'
|
|
halt, // ^C (async halt)
|
|
use_extended_mode, // '!'
|
|
why_halted, // '?'
|
|
set_argv, // 'A'
|
|
set_bp, // 'B'
|
|
cont, // 'c'
|
|
continue_with_sig, // 'C'
|
|
detach, // 'D'
|
|
read_general_regs, // 'g'
|
|
write_general_regs, // 'G'
|
|
set_thread, // 'H'
|
|
step_inferior_one_cycle, // 'i'
|
|
signal_and_step_inf_one_cycle, // 'I'
|
|
kill, // 'k'
|
|
read_memory, // 'm'
|
|
write_memory, // 'M'
|
|
read_register, // 'p'
|
|
write_register, // 'P'
|
|
restart, // 'R'
|
|
single_step, // 's'
|
|
single_step_with_sig, // 'S'
|
|
search_mem_backwards, // 't'
|
|
thread_alive_p, // 'T'
|
|
vattach, // 'vAttach;pid'
|
|
vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes
|
|
vattachorwait, // 'vAttachOrWait:XX...' where XX is one or more hex encoded process name ASCII bytes
|
|
vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes
|
|
vcont, // 'vCont'
|
|
vcont_list_actions, // 'vCont?'
|
|
read_data_from_memory, // 'x'
|
|
write_data_to_memory, // 'X'
|
|
insert_mem_bp, // 'Z0'
|
|
remove_mem_bp, // 'z0'
|
|
insert_hardware_bp, // 'Z1'
|
|
remove_hardware_bp, // 'z1'
|
|
insert_write_watch_bp, // 'Z2'
|
|
remove_write_watch_bp, // 'z2'
|
|
insert_read_watch_bp, // 'Z3'
|
|
remove_read_watch_bp, // 'z3'
|
|
insert_access_watch_bp, // 'Z4'
|
|
remove_access_watch_bp, // 'z4'
|
|
|
|
query_monitor, // 'qRcmd'
|
|
query_current_thread_id, // 'qC'
|
|
query_get_pid, // 'qGetPid'
|
|
query_echo, // 'qEcho'
|
|
query_thread_ids_first, // 'qfThreadInfo'
|
|
query_thread_ids_subsequent, // 'qsThreadInfo'
|
|
query_thread_extra_info, // 'qThreadExtraInfo'
|
|
query_thread_stop_info, // 'qThreadStopInfo'
|
|
query_image_offsets, // 'qOffsets'
|
|
query_symbol_lookup, // 'gSymbols'
|
|
query_launch_success, // 'qLaunchSuccess'
|
|
query_register_info, // 'qRegisterInfo'
|
|
query_shlib_notify_info_addr, // 'qShlibInfoAddr'
|
|
query_step_packet_supported, // 'qStepPacketSupported'
|
|
query_supported_features, // 'qSupported'
|
|
query_vattachorwait_supported, // 'qVAttachOrWaitSupported'
|
|
query_sync_thread_state_supported,// 'QSyncThreadState'
|
|
query_host_info, // 'qHostInfo'
|
|
query_gdb_server_version, // 'qGDBServerVersion'
|
|
query_process_info, // 'qProcessInfo'
|
|
json_query_thread_extended_info,// 'jThreadExtendedInfo'
|
|
json_query_threads_info, // 'jThreadsInfo'
|
|
pass_signals_to_inferior, // 'QPassSignals'
|
|
start_noack_mode, // 'QStartNoAckMode'
|
|
prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID
|
|
set_logging_mode, // 'QSetLogging:'
|
|
set_max_packet_size, // 'QSetMaxPacketSize:'
|
|
set_max_payload_size, // 'QSetMaxPayloadSize:'
|
|
set_environment_variable, // 'QEnvironment:'
|
|
set_environment_variable_hex, // 'QEnvironmentHexEncoded:'
|
|
set_launch_arch, // 'QLaunchArch:'
|
|
set_disable_aslr, // 'QSetDisableASLR:'
|
|
set_stdin, // 'QSetSTDIN:'
|
|
set_stdout, // 'QSetSTDOUT:'
|
|
set_stderr, // 'QSetSTDERR:'
|
|
set_working_dir, // 'QSetWorkingDir:'
|
|
set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:'
|
|
sync_thread_state, // 'QSyncThreadState:'
|
|
memory_region_info, // 'qMemoryRegionInfo:'
|
|
get_profile_data, // 'qGetProfileData'
|
|
set_enable_profiling, // 'QSetEnableAsyncProfiling'
|
|
enable_compression, // 'QEnableCompression:'
|
|
watchpoint_support_info, // 'qWatchpointSupportInfo:'
|
|
allocate_memory, // '_M'
|
|
deallocate_memory, // '_m'
|
|
set_process_event, // 'QSetProcessEvent:'
|
|
save_register_state, // '_g'
|
|
restore_register_state, // '_G'
|
|
speed_test, // 'qSpeedTest:'
|
|
set_detach_on_error, // 'QSetDetachOnError:'
|
|
query_transfer, // 'qXfer:'
|
|
unknown_type
|
|
} PacketEnum;
|
|
|
|
typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p);
|
|
|
|
RNBRemote ();
|
|
~RNBRemote ();
|
|
|
|
void Initialize();
|
|
|
|
bool InitializeRegisters (bool force = false);
|
|
|
|
rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL);
|
|
rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL);
|
|
|
|
nub_thread_t GetContinueThread () const
|
|
{
|
|
return m_continue_thread;
|
|
}
|
|
|
|
void SetContinueThread (nub_thread_t tid)
|
|
{
|
|
m_continue_thread = tid;
|
|
}
|
|
|
|
nub_thread_t GetCurrentThread () const
|
|
{
|
|
if (m_thread == 0 || m_thread == -1)
|
|
return DNBProcessGetCurrentThread (m_ctx.ProcessID());
|
|
return m_thread;
|
|
}
|
|
|
|
void SetCurrentThread (nub_thread_t tid)
|
|
{
|
|
DNBProcessSetCurrentThread (m_ctx.ProcessID(), tid);
|
|
m_thread = tid;
|
|
}
|
|
|
|
static void* ThreadFunctionReadRemoteData(void *arg);
|
|
void StartReadRemoteDataThread ();
|
|
void StopReadRemoteDataThread ();
|
|
|
|
void NotifyThatProcessStopped (void);
|
|
|
|
rnb_err_t HandlePacket_A (const char *p);
|
|
rnb_err_t HandlePacket_H (const char *p);
|
|
rnb_err_t HandlePacket_qC (const char *p);
|
|
rnb_err_t HandlePacket_qRcmd (const char *p);
|
|
rnb_err_t HandlePacket_qGetPid (const char *p);
|
|
rnb_err_t HandlePacket_qEcho (const char *p);
|
|
rnb_err_t HandlePacket_qLaunchSuccess (const char *p);
|
|
rnb_err_t HandlePacket_qRegisterInfo (const char *p);
|
|
rnb_err_t HandlePacket_qShlibInfoAddr (const char *p);
|
|
rnb_err_t HandlePacket_qStepPacketSupported (const char *p);
|
|
rnb_err_t HandlePacket_qVAttachOrWaitSupported (const char *p);
|
|
rnb_err_t HandlePacket_qSyncThreadStateSupported (const char *p);
|
|
rnb_err_t HandlePacket_qThreadInfo (const char *p);
|
|
rnb_err_t HandlePacket_jThreadExtendedInfo (const char *p);
|
|
rnb_err_t HandlePacket_jThreadsInfo (const char *p);
|
|
rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
|
|
rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
|
|
rnb_err_t HandlePacket_qHostInfo (const char *p);
|
|
rnb_err_t HandlePacket_qGDBServerVersion (const char *p);
|
|
rnb_err_t HandlePacket_qProcessInfo (const char *p);
|
|
rnb_err_t HandlePacket_QStartNoAckMode (const char *p);
|
|
rnb_err_t HandlePacket_QThreadSuffixSupported (const char *p);
|
|
rnb_err_t HandlePacket_QSetLogging (const char *p);
|
|
rnb_err_t HandlePacket_QSetDisableASLR (const char *p);
|
|
rnb_err_t HandlePacket_QSetSTDIO (const char *p);
|
|
rnb_err_t HandlePacket_QSetWorkingDir (const char *p);
|
|
rnb_err_t HandlePacket_QSetMaxPayloadSize (const char *p);
|
|
rnb_err_t HandlePacket_QSetMaxPacketSize (const char *p);
|
|
rnb_err_t HandlePacket_QEnvironment (const char *p);
|
|
rnb_err_t HandlePacket_QEnvironmentHexEncoded (const char *p);
|
|
rnb_err_t HandlePacket_QLaunchArch (const char *p);
|
|
rnb_err_t HandlePacket_QListThreadsInStopReply (const char *p);
|
|
rnb_err_t HandlePacket_QSyncThreadState (const char *p);
|
|
rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p);
|
|
rnb_err_t HandlePacket_QSetProcessEvent (const char *p);
|
|
rnb_err_t HandlePacket_last_signal (const char *p);
|
|
rnb_err_t HandlePacket_m (const char *p);
|
|
rnb_err_t HandlePacket_M (const char *p);
|
|
rnb_err_t HandlePacket_x (const char *p);
|
|
rnb_err_t HandlePacket_X (const char *p);
|
|
rnb_err_t HandlePacket_g (const char *p);
|
|
rnb_err_t HandlePacket_G (const char *p);
|
|
rnb_err_t HandlePacket_z (const char *p);
|
|
rnb_err_t HandlePacket_T (const char *p);
|
|
rnb_err_t HandlePacket_p (const char *p);
|
|
rnb_err_t HandlePacket_P (const char *p);
|
|
rnb_err_t HandlePacket_c (const char *p);
|
|
rnb_err_t HandlePacket_C (const char *p);
|
|
rnb_err_t HandlePacket_D (const char *p);
|
|
rnb_err_t HandlePacket_k (const char *p);
|
|
rnb_err_t HandlePacket_s (const char *p);
|
|
rnb_err_t HandlePacket_S (const char *p);
|
|
rnb_err_t HandlePacket_qSupported (const char *p);
|
|
rnb_err_t HandlePacket_v (const char *p);
|
|
rnb_err_t HandlePacket_UNIMPLEMENTED (const char *p);
|
|
rnb_err_t HandlePacket_ILLFORMED (const char *file, int line, const char *p, const char *description);
|
|
rnb_err_t HandlePacket_AllocateMemory (const char *p);
|
|
rnb_err_t HandlePacket_DeallocateMemory (const char *p);
|
|
rnb_err_t HandlePacket_SaveRegisterState (const char *p);
|
|
rnb_err_t HandlePacket_RestoreRegisterState (const char *p);
|
|
rnb_err_t HandlePacket_MemoryRegionInfo (const char *p);
|
|
rnb_err_t HandlePacket_GetProfileData(const char *p);
|
|
rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p);
|
|
rnb_err_t HandlePacket_QEnableCompression(const char *p);
|
|
rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p);
|
|
rnb_err_t HandlePacket_qSpeedTest (const char *p);
|
|
rnb_err_t HandlePacket_qXfer (const char *p);
|
|
rnb_err_t HandlePacket_stop_process (const char *p);
|
|
rnb_err_t HandlePacket_QSetDetachOnError (const char *p);
|
|
|
|
rnb_err_t SendStopReplyPacketForThread (nub_thread_t tid);
|
|
rnb_err_t SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer);
|
|
rnb_err_t SendSTDOUTPacket (char *buf, nub_size_t buf_size);
|
|
rnb_err_t SendSTDERRPacket (char *buf, nub_size_t buf_size);
|
|
void FlushSTDIO ();
|
|
void SendAsyncProfileData ();
|
|
rnb_err_t SendAsyncProfileDataPacket (char *buf, nub_size_t buf_size);
|
|
|
|
RNBContext& Context() { return m_ctx; }
|
|
RNBSocket& Comm() { return m_comm; }
|
|
|
|
private:
|
|
// Outlaw some constructors
|
|
RNBRemote (const RNBRemote &);
|
|
|
|
protected:
|
|
|
|
rnb_err_t GetCommData ();
|
|
void CommDataReceived(const std::string& data);
|
|
struct Packet
|
|
{
|
|
typedef std::vector<Packet> collection;
|
|
typedef collection::iterator iterator;
|
|
typedef collection::const_iterator const_iterator;
|
|
PacketEnum type;
|
|
HandlePacketCallback normal; // Function to call when inferior is halted
|
|
HandlePacketCallback async; // Function to call when inferior is running
|
|
std::string abbrev;
|
|
std::string printable_name;
|
|
|
|
bool
|
|
IsPlatformPacket () const
|
|
{
|
|
switch (type)
|
|
{
|
|
case set_logging_mode:
|
|
case query_host_info:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
Packet() :
|
|
type(invalid_packet),
|
|
normal (NULL),
|
|
async (NULL),
|
|
abbrev (),
|
|
printable_name ()
|
|
{
|
|
}
|
|
|
|
Packet( PacketEnum in_type,
|
|
HandlePacketCallback in_normal,
|
|
HandlePacketCallback in_async,
|
|
const char *in_abbrev,
|
|
const char *in_printable_name) :
|
|
type (in_type),
|
|
normal (in_normal),
|
|
async (in_async),
|
|
abbrev (in_abbrev),
|
|
printable_name (in_printable_name)
|
|
{
|
|
}
|
|
};
|
|
|
|
rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait);
|
|
rnb_err_t SendPacket (const std::string &);
|
|
std::string CompressString (const std::string &);
|
|
|
|
void CreatePacketTable ();
|
|
rnb_err_t GetPacketPayload (std::string &);
|
|
|
|
nub_thread_t
|
|
ExtractThreadIDFromThreadSuffix (const char *p);
|
|
|
|
void
|
|
EnableCompressionNextSendPacket (compression_types);
|
|
|
|
compression_types
|
|
GetCompressionType ();
|
|
|
|
RNBContext m_ctx; // process context
|
|
RNBSocket m_comm; // communication port
|
|
std::string m_arch;
|
|
nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all
|
|
nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all
|
|
PThreadMutex m_mutex; // Mutex that protects
|
|
uint32_t m_packets_recvd;
|
|
Packet::collection m_packets;
|
|
std::deque<std::string> m_rx_packets;
|
|
std::string m_rx_partial_data; // For packets that may come in more than one batch, anything left over can be left here
|
|
pthread_t m_rx_pthread;
|
|
uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb
|
|
bool m_extended_mode; // are we in extended mode?
|
|
bool m_noack_mode; // are we in no-ack mode?
|
|
bool m_thread_suffix_supported; // Set to true if the 'p', 'P', 'g', and 'G' packets should be prefixed with the thread ID and colon:
|
|
// "$pRR;thread:TTTT;" instead of "$pRR"
|
|
// "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV"
|
|
// "$g;thread:TTTT" instead of "$g"
|
|
// "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV"
|
|
bool m_list_threads_in_stop_reply;
|
|
|
|
size_t m_compression_minsize; // only packets larger than this size will be compressed
|
|
bool m_enable_compression_next_send_packet;
|
|
|
|
compression_types m_compression_mode;
|
|
};
|
|
|
|
/* We translate the /usr/include/mach/exception_types.h exception types
|
|
(e.g. EXC_BAD_ACCESS) to the fake BSD signal numbers that gdb uses
|
|
in include/gdb/signals.h (e.g. TARGET_EXC_BAD_ACCESS). These hard
|
|
coded values for TARGET_EXC_BAD_ACCESS et al must match the gdb
|
|
values in its include/gdb/signals.h. */
|
|
|
|
#define TARGET_EXC_BAD_ACCESS 0x91
|
|
#define TARGET_EXC_BAD_INSTRUCTION 0x92
|
|
#define TARGET_EXC_ARITHMETIC 0x93
|
|
#define TARGET_EXC_EMULATION 0x94
|
|
#define TARGET_EXC_SOFTWARE 0x95
|
|
#define TARGET_EXC_BREAKPOINT 0x96
|
|
|
|
/* Generally speaking, you can't assume gdb can receive more than 399 bytes
|
|
at a time with a random gdb. This bufsize constant is only specifying
|
|
how many bytes gdb can *receive* from debugserver -- it tells us nothing
|
|
about how many bytes gdb might try to send in a single packet. */
|
|
#define DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE 399
|
|
|
|
#endif // #ifndef __RNBRemote_h__
|