diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt index a3c94c502900..3e6914778eb1 100644 --- a/lldb/docs/lldb-gdb-remote.txt +++ b/lldb/docs/lldb-gdb-remote.txt @@ -836,6 +836,40 @@ For instance, with a Mac OS X process which has nothing mapped in the first The lack of 'permissions:' indicates that none of read/write/execute are valid for this region. +//---------------------------------------------------------------------- +// 'x' - Binary memory read +// +// Like the 'm' (read) and 'M' (write) packets, this is a partner to the +// 'X' (write binary data) packet, 'x'. +// +// It is called like +// +// xADDRESS,LENGTH +// +// where both ADDRESS and LENGTH are big-endian base 16 values. +// +// To test if this packet is available, send a addr/len of 0: +// +// x0,0 +// +// and you will get an "OK" response. +// +// The reply will be the data requested in 8-bit binary data format. +// The standard quoting is applied to the payload -- characters +// } # $ * +// will all be escaped with '}' (0x7d) character and then XOR'ed with 0x20. +// +// A typical use to read 512 bytes at 0x1000 would look like +// +// x0x1000,0x200 +// +// The "0x" prefixes are optional - like most of the gdb-remote packets, +// omitting them will work fine; these numbers are always base 16. +// +// The length of the payload is not provided. A reliable, 8-bit clean, +// transport layer is assumed. +//---------------------------------------------------------------------- + //---------------------------------------------------------------------- // Detach and stay stopped: // diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index fee311bda3e3..71d3b8357c9e 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -136,14 +136,15 @@ RNBRemote::CreatePacketTable () // t.push_back (Packet (restart, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "R", "Restart inferior")); // t.push_back (Packet (search_mem_backwards, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "t", "Search memory backwards")); t.push_back (Packet (thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T", "Is thread alive")); + t.push_back (Packet (query_supported_features, &RNBRemote::HandlePacket_qSupported, NULL, "qSupported", "Query about supported features")); t.push_back (Packet (vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach", "Attach to a new process")); t.push_back (Packet (vattachwait, &RNBRemote::HandlePacket_v, NULL, "vAttachWait", "Wait for a process to start up then attach to it")); t.push_back (Packet (vattachorwait, &RNBRemote::HandlePacket_v, NULL, "vAttachOrWait", "Attach to the process or if it doesn't exist, wait for the process to start up then attach to it")); t.push_back (Packet (vattachname, &RNBRemote::HandlePacket_v, NULL, "vAttachName", "Attach to an existing process by name")); t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont;", "Verbose resume with thread actions")); t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont?", "List valid continue-with-thread-actions actions")); - // The X packet doesn't currently work. If/when it does, remove the line above and uncomment out the line below -// t.push_back (Packet (write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, "X", "Write data to memory")); + t.push_back (Packet (read_data_from_memory, &RNBRemote::HandlePacket_x, NULL, "x", "Read data from memory")); + t.push_back (Packet (write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, "X", "Write data to memory")); // t.push_back (Packet (insert_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z1", "Insert hardware breakpoint")); // t.push_back (Packet (remove_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z1", "Remove hardware breakpoint")); t.push_back (Packet (insert_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, "Z2", "Insert write watchpoint")); @@ -817,10 +818,10 @@ best_guess_cpu_type () /* Read the bytes in STR which are GDB Remote Protocol binary encoded bytes (8-bit bytes). - This encoding uses 0x7d ('}') as an escape character for 0x7d ('}'), - 0x23 ('#'), and 0x24 ('$'). + This encoding uses 0x7d ('}') as an escape character for + 0x7d ('}'), 0x23 ('#'), 0x24 ('$'), 0x2a ('*'). LEN is the number of bytes to be processed. If a character is escaped, - it is 2 characters for LEN. A LEN of -1 means encode-until-nul-byte + it is 2 characters for LEN. A LEN of -1 means decode-until-nul-byte (end of string). */ std::vector @@ -841,7 +842,7 @@ decode_binary_data (const char *str, size_t len) { len--; str++; - c ^= 0x20; + c = *str ^ 0x20; } bytes.push_back (c); } @@ -2537,6 +2538,89 @@ RNBRemote::HandlePacket_m (const char *p) return SendPacket (ostrm.str ()); } +// Read memory, sent it up as binary data. +// Usage: xADDR,LEN +// ADDR and LEN are both base 16. + +// Responds with 'OK' for zero-length request +// or +// +// DATA +// +// where DATA is the binary data payload. + +rnb_err_t +RNBRemote::HandlePacket_x (const char *p) +{ + if (p == NULL || p[0] == '\0' || strlen (p) < 3) + { + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Too short X packet"); + } + + char *c; + p++; + errno = 0; + nub_addr_t addr = strtoull (p, &c, 16); + if (errno != 0) + { + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in X packet"); + } + if (*c != ',') + { + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in X packet"); + } + + /* Advance 'p' to the number of bytes to be read. */ + p += (c - p) + 1; + + errno = 0; + int length = strtoul (p, NULL, 16); + if (errno != 0) + { + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in x packet"); + } + + // zero length read means this is a test of whether that packet is implemented or not. + if (length == 0) + { + return SendPacket ("OK"); + } + + std::vector buf (length); + + if (buf.capacity() != length) + { + return SendPacket ("E79"); + } + int bytes_read = DNBProcessMemoryRead (m_ctx.ProcessID(), addr, buf.size(), &buf[0]); + if (bytes_read == 0) + { + return SendPacket ("E80"); + } + + std::vector buf_quoted; + buf_quoted.reserve (bytes_read + 30); + for (int i = 0; i < bytes_read; i++) + { + if (buf[i] == '#' || buf[i] == '$' || buf[i] == '}' || buf[i] == '*') + { + buf_quoted.push_back(0x7d); + buf_quoted.push_back(buf[i] ^ 0x20); + } + else + { + buf_quoted.push_back(buf[i]); + } + } + length = buf_quoted.size(); + + std::ostringstream ostrm; + for (int i = 0; i < length; i++) + ostrm << buf_quoted[i]; + + return SendPacket (ostrm.str ()); +} + rnb_err_t RNBRemote::HandlePacket_X (const char *p) { @@ -2558,14 +2642,16 @@ RNBRemote::HandlePacket_X (const char *p) return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in X packet"); } - /* Advance 'p' to the length part of the packet. */ + /* Advance 'p' to the length part of the packet. NB this is the length of the packet + including any escaped chars. The data payload may be a little bit smaller after + decoding. */ p += (c - p) + 1; errno = 0; int length = strtoul (p, NULL, 16); if (errno != 0 && length == 0) { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in m packet"); + return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in X packet"); } // I think gdb sends a zero length write request to test whether this @@ -2882,6 +2968,15 @@ GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name) return return_val; } +rnb_err_t +RNBRemote::HandlePacket_qSupported (const char *p) +{ + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less + char buf[64]; + snprintf (buf, sizeof(buf), "PacketSize=%x", max_packet_size); + return SendPacket (buf); +} + /* vAttach;pid diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index 94626ceb1acc..8d5f9a16d3a5 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -67,6 +67,7 @@ public: 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' @@ -92,6 +93,7 @@ public: 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' @@ -202,6 +204,7 @@ public: 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); @@ -215,6 +218,7 @@ public: 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);