diff options
| author | Greg Clayton <gclayton@apple.com> | 2015-06-23 21:27:50 +0000 |
|---|---|---|
| committer | Greg Clayton <gclayton@apple.com> | 2015-06-23 21:27:50 +0000 |
| commit | 0b90be1c4f151dd3f8eda2a291a68554e67a3742 (patch) | |
| tree | d69bddb32f34798f9d99cb97c2c1d0dcd7dbdc1c /lldb/tools/debugserver | |
| parent | a0d5c5924af5ede48b367723874a0efb7993d041 (diff) | |
| download | bcm5719-llvm-0b90be1c4f151dd3f8eda2a291a68554e67a3742.tar.gz bcm5719-llvm-0b90be1c4f151dd3f8eda2a291a68554e67a3742.zip | |
Implement the "qSymbol" packet in order to be able to read queue information in debugserver and return the info in the stop reply packets.
A "qSymbol::" is sent when shared libraries have been loaded by hooking into the Process::ModulesDidLoad() function from within ProcessGDBRemote. This function was made virtual so that the ProcessGDBRemote version is called, which then first calls the Process::ModulesDidLoad(), and then it queries for any symbol lookups that the remote GDB server might want to do.
This allows debugserver to request the "dispatch_queue_offsets" symbol so that it can read the queue name, queue kind and queue serial number and include this data as part of the stop reply packet. Previously each thread would have to do 3 memory reads in order to read the queue name.
This is part of reducing the number of packets that are sent between LLDB and the remote GDB server.
<rdar://problem/21494354>
llvm-svn: 240466
Diffstat (limited to 'lldb/tools/debugserver')
| -rw-r--r-- | lldb/tools/debugserver/source/DNB.cpp | 80 | ||||
| -rw-r--r-- | lldb/tools/debugserver/source/DNB.h | 4 | ||||
| -rw-r--r-- | lldb/tools/debugserver/source/RNBRemote.cpp | 238 | ||||
| -rw-r--r-- | lldb/tools/debugserver/source/RNBRemote.h | 71 |
4 files changed, 382 insertions, 11 deletions
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index 4d773221a45..4cde3f87b08 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -1257,6 +1257,86 @@ DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void return 0; } +uint64_t +DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value) +{ + union Integers + { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + }; + + if (integer_size <= sizeof(uint64_t)) + { + Integers ints; + if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) + { + switch (integer_size) + { + case 1: return ints.u8; + case 2: return ints.u16; + case 3: return ints.u32 & 0xffffffu; + case 4: return ints.u32; + case 5: return ints.u32 & 0x000000ffffffffffull; + case 6: return ints.u32 & 0x0000ffffffffffffull; + case 7: return ints.u32 & 0x00ffffffffffffffull; + case 8: return ints.u64; + } + } + } + return fail_value; + +} + +nub_addr_t +DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr) +{ + cpu_type_t cputype = DNBProcessGetCPUType (pid); + if (cputype) + { + const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4; + return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0); + } + return 0; + +} + +std::string +DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr) +{ + std::string cstr; + char buffer[256]; + const nub_size_t max_buffer_cstr_length = sizeof(buffer)-1; + buffer[max_buffer_cstr_length] = '\0'; + nub_size_t length = 0; + nub_addr_t curr_addr = addr; + do + { + nub_size_t bytes_read = DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer); + if (bytes_read == 0) + break; + length = strlen(buffer); + cstr.append(buffer, length); + curr_addr += length; + } while (length == max_buffer_cstr_length); + return cstr; +} + +std::string +DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length) +{ + std::string cstr; + char buffer[fixed_length+1]; + buffer[fixed_length] = '\0'; + nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer); + if (bytes_read > 0) + cstr.assign(buffer); + return cstr; +} + + //---------------------------------------------------------------------- // Write memory to the address space of process PID. This call will take // care of setting and restoring permissions and breaking up the memory diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index e57bb08b678..3f032798f23 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -69,6 +69,10 @@ nub_bool_t DNBProcessInterrupt (nub_process_t pid) DNB_EXPORT; nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT; nub_bool_t DNBProcessSendEvent (nub_process_t pid, const char *event) DNB_EXPORT; nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT; +uint64_t DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value) DNB_EXPORT; +nub_addr_t DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; +std::string DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; +std::string DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length) DNB_EXPORT; nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT; nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT; nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 2385246a200..1ddf9027427 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -74,14 +74,81 @@ #define INDENT_WITH_TABS(iword_idx) std::setfill('\t') << std::setw((iword_idx)) << "" // Class to handle communications via gdb remote protocol. + +//---------------------------------------------------------------------- +// Decode a single hex character and return the hex value as a number or +// -1 if "ch" is not a hex character. +//---------------------------------------------------------------------- +static inline int +xdigit_to_sint (char ch) +{ + if (ch >= 'a' && ch <= 'f') + return 10 + ch - 'a'; + if (ch >= 'A' && ch <= 'F') + return 10 + ch - 'A'; + if (ch >= '0' && ch <= '9') + return ch - '0'; + return -1; +} + +//---------------------------------------------------------------------- +// Decode a single hex ASCII byte. Return -1 on failure, a value 0-255 +// on success. +//---------------------------------------------------------------------- +static inline int +decoded_hex_ascii_char(const char *p) +{ + const int hi_nibble = xdigit_to_sint(p[0]); + if (hi_nibble == -1) + return -1; + const int lo_nibble = xdigit_to_sint(p[1]); + if (lo_nibble == -1) + return -1; + return (uint8_t)((hi_nibble << 4) + lo_nibble); +} + +//---------------------------------------------------------------------- +// Decode a hex ASCII string back into a string +//---------------------------------------------------------------------- +static std::string +decode_hex_ascii_string(const char *p, uint32_t max_length = UINT32_MAX) +{ + std::string arg; + if (p) + { + for (const char *c = p; ((c - p)/2) < max_length; c += 2) + { + int ch = decoded_hex_ascii_char(c); + if (ch == -1) + break; + else + arg.push_back(ch); + } + } + return arg; +} + +uint64_t +decode_uint64 (const char *p, int base, char **end = nullptr, uint64_t fail_value = 0) +{ + nub_addr_t addr = strtoull (p, end, 16); + if (addr == 0 && errno != 0) + return fail_value; + return addr; +} + extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args); RNBRemote::RNBRemote () : m_ctx (), m_comm (), + m_arch (), m_continue_thread(-1), m_thread(-1), m_mutex(), + m_dispatch_queue_offsets (), + m_dispatch_queue_offsets_addr (INVALID_NUB_ADDRESS), + m_qSymbol_index (UINT32_MAX), m_packets_recvd(0), m_packets(), m_rx_packets(), @@ -190,11 +257,11 @@ RNBRemote::CreatePacketTable () t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported.")); t.push_back (Packet (query_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported.")); t.push_back (Packet (query_sync_thread_state_supported, &RNBRemote::HandlePacket_qSyncThreadStateSupported,NULL, "qSyncThreadStateSupported", "Replys with OK if the 'QSyncThreadState:' packet is supported.")); - t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); - t.push_back (Packet (query_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion, NULL, "qGDBServerVersion", "Replies with multiple 'key:value;' tuples appended to each other.")); - t.push_back (Packet (query_process_info, &RNBRemote::HandlePacket_qProcessInfo, NULL, "qProcessInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); -// t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups")); - t.push_back (Packet (json_query_thread_extended_info, &RNBRemote::HandlePacket_jThreadExtendedInfo, NULL, "jThreadExtendedInfo", "Replies with JSON data of thread extended information.")); + t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo , NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back (Packet (query_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion , NULL, "qGDBServerVersion", "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back (Packet (query_process_info, &RNBRemote::HandlePacket_qProcessInfo , NULL, "qProcessInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_qSymbol , NULL, "qSymbol:", "Notify that host debugger is ready to do symbol lookups")); + t.push_back (Packet (json_query_thread_extended_info,&RNBRemote::HandlePacket_jThreadExtendedInfo , NULL, "jThreadExtendedInfo", "Replies with JSON data of thread extended information.")); t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets")); t.push_back (Packet (prefix_reg_packets_with_tid, &RNBRemote::HandlePacket_QThreadSuffixSupported , NULL, "QThreadSuffixSupported", "Check if thread specific packets (register packets 'g', 'G', 'p', and 'P') support having the thread ID appended to the end of the command")); t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_QSetLogging , NULL, "QSetLogging:", "Check if register packets ('g', 'G', 'p', and 'P' support having the thread ID prefix")); @@ -2371,18 +2438,19 @@ RNBRemote::HandlePacket_QSetProcessEvent (const char *p) } void -append_hex_value (std::ostream& ostrm, const uint8_t* buf, size_t buf_size, bool swap) +append_hex_value (std::ostream& ostrm, const void *buf, size_t buf_size, bool swap) { int i; + const uint8_t *p = (const uint8_t *)buf; if (swap) { for (i = static_cast<int>(buf_size)-1; i >= 0; i--) - ostrm << RAWHEX8(buf[i]); + ostrm << RAWHEX8(p[i]); } else { for (i = 0; i < buf_size; i++) - ostrm << RAWHEX8(buf[i]); + ostrm << RAWHEX8(p[i]); } } @@ -2452,6 +2520,45 @@ gdb_regnum_with_fixed_width_hex_register_value (std::ostream& ostrm, } } + +void +RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid, + nub_addr_t dispatch_qaddr, + std::string &queue_name, + uint64_t &queue_width, + uint64_t &queue_serialnum) const +{ + queue_name.clear(); + queue_width = 0; + queue_serialnum = 0; + + if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS && dispatch_qaddr != 0) + { + nub_addr_t dispatch_queue_addr = DNBProcessMemoryReadPointer (pid, dispatch_qaddr); + if (dispatch_queue_addr) + { + queue_width = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_width, dqo_width_size, 0); + queue_serialnum = DNBProcessMemoryReadInteger (pid, dispatch_queue_addr + dqo_serialnum, dqo_serialnum_size, 0); + + if (dqo_version >= 4) + { + // libdispatch versions 4+, pointer to dispatch name is in the + // queue structure. + nub_addr_t pointer_to_label_address = dispatch_queue_addr + dqo_label; + nub_addr_t label_addr = DNBProcessMemoryReadPointer (pid, pointer_to_label_address); + if (label_addr) + queue_name = std::move(DNBProcessMemoryReadCString (pid, label_addr)); + } + else + { + // libdispatch versions 1-3, dispatch name is a fixed width char array + // in the queue structure. + queue_name = std::move(DNBProcessMemoryReadCStringFixed(pid, dispatch_queue_addr + dqo_label, dqo_label_size)); + } + } + } +} + rnb_err_t RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) { @@ -2468,8 +2575,14 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) { const bool did_exec = tid_stop_info.reason == eStopTypeExec; if (did_exec) + { RNBRemote::InitializeRegisters(true); + // Reset any symbols that need resetting when we exec + m_dispatch_queue_offsets_addr = INVALID_NUB_ADDRESS; + m_dispatch_queue_offsets.Clear(); + } + std::ostringstream ostrm; // Output the T packet with the thread ostrm << 'T'; @@ -2522,9 +2635,32 @@ RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info)) { if (thread_ident_info.dispatch_qaddr != 0) - ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';'; + { + ostrm << "qaddr:" << std::hex << thread_ident_info.dispatch_qaddr << ';'; + const DispatchQueueOffsets *dispatch_queue_offsets = GetDispatchQueueOffsets(); + if (dispatch_queue_offsets) + { + std::string queue_name; + uint64_t queue_width = 0; + uint64_t queue_serialnum = 0; + dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, queue_name, queue_width, queue_serialnum); + if (!queue_name.empty()) + { + ostrm << "qname:"; + append_hex_value(ostrm, queue_name.data(), queue_name.size(), false); + ostrm << ';'; + } + if (queue_width == 1) + ostrm << "qkind:serial;"; + else if (queue_width > 1) + ostrm << "qkind:concurrent;"; + + if (queue_serialnum > 0) + ostrm << "qserial:" << DECIMAL << queue_serialnum << ';'; + } + } } - + // If a 'QListThreadsInStopReply' was sent to enable this feature, we // will send all thread IDs back in the "threads" key whose value is // a list of hex thread IDs separated by commas: @@ -5003,6 +5139,71 @@ RNBRemote::HandlePacket_jThreadExtendedInfo (const char *p) return SendPacket ("OK"); } + +rnb_err_t +RNBRemote::HandlePacket_qSymbol (const char *command) +{ + const char *p = command; + p += strlen ("qSymbol:"); + const char *sep = strchr(p, ':'); + + std::string symbol_name; + std::string symbol_value_str; + // Extract the symbol value if there is one + if (sep > p) + symbol_value_str.assign(p, sep - p); + p = sep + 1; + + if (*p) + { + // We have a symbol name + symbol_name = std::move(decode_hex_ascii_string(p)); + if (!symbol_value_str.empty()) + { + nub_addr_t symbol_value = decode_uint64(symbol_value_str.c_str(), 16); + if (symbol_name == "dispatch_queue_offsets") + m_dispatch_queue_offsets_addr = symbol_value; + } + ++m_qSymbol_index; + } + else + { + // No symbol name, set our symbol index to zero so we can + // read any symbols that we need + m_qSymbol_index = 0; + } + + symbol_name.clear(); + + if (m_qSymbol_index == 0) + { + if (m_dispatch_queue_offsets_addr == INVALID_NUB_ADDRESS) + symbol_name = "dispatch_queue_offsets"; + else + ++m_qSymbol_index; + } + +// // Lookup next symbol when we have one... +// if (m_qSymbol_index == 1) +// { +// } + + + if (symbol_name.empty()) + { + // Done with symbol lookups + return SendPacket ("OK"); + } + else + { + std::ostringstream reply; + reply << "qSymbol:"; + for (size_t i = 0; i < symbol_name.size(); ++i) + reply << RAWHEX8(symbol_name[i]); + return SendPacket (reply.str().c_str()); + } +} + // Note that all numeric values returned by qProcessInfo are hex encoded, // including the pid and the cpu type. @@ -5193,6 +5394,23 @@ RNBRemote::HandlePacket_qProcessInfo (const char *p) return SendPacket (rep.str()); } +const RNBRemote::DispatchQueueOffsets * +RNBRemote::GetDispatchQueueOffsets() +{ + if (!m_dispatch_queue_offsets.IsValid() && m_dispatch_queue_offsets_addr != INVALID_NUB_ADDRESS && m_ctx.HasValidProcessID()) + { + nub_process_t pid = m_ctx.ProcessID(); + nub_size_t bytes_read = DNBProcessMemoryRead(pid, m_dispatch_queue_offsets_addr, sizeof(m_dispatch_queue_offsets), &m_dispatch_queue_offsets); + if (bytes_read != sizeof(m_dispatch_queue_offsets)) + m_dispatch_queue_offsets.Clear(); + } + + if (m_dispatch_queue_offsets.IsValid()) + return &m_dispatch_queue_offsets; + else + return nullptr; +} + void RNBRemote::EnableCompressionNextSendPacket (compression_types type) { diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index 1f4883ab9e0..3fcccc2e8f3 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -91,7 +91,7 @@ public: query_thread_extra_info, // 'qThreadExtraInfo' query_thread_stop_info, // 'qThreadStopInfo' query_image_offsets, // 'qOffsets' - query_symbol_lookup, // 'gSymbols' + query_symbol_lookup, // 'qSymbol' query_launch_success, // 'qLaunchSuccess' query_register_info, // 'qRegisterInfo' query_shlib_notify_info_addr, // 'qShlibInfoAddr' @@ -195,6 +195,7 @@ public: 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_qSymbol (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); @@ -311,6 +312,68 @@ protected: } }; + + struct DispatchQueueOffsets + { + uint16_t dqo_version; + uint16_t dqo_label; + uint16_t dqo_label_size; + uint16_t dqo_flags; + uint16_t dqo_flags_size; + uint16_t dqo_serialnum; + uint16_t dqo_serialnum_size; + uint16_t dqo_width; + uint16_t dqo_width_size; + uint16_t dqo_running; + uint16_t dqo_running_size; + uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + + DispatchQueueOffsets () + { + Clear(); + } + + void + Clear() + { + dqo_version = UINT16_MAX; + dqo_label = UINT16_MAX; + dqo_label_size = UINT16_MAX; + dqo_flags = UINT16_MAX; + dqo_flags_size = UINT16_MAX; + dqo_serialnum = UINT16_MAX; + dqo_serialnum_size = UINT16_MAX; + dqo_width = UINT16_MAX; + dqo_width_size = UINT16_MAX; + dqo_running = UINT16_MAX; + dqo_running_size = UINT16_MAX; + dqo_suspend_cnt = UINT16_MAX; + dqo_suspend_cnt_size = UINT16_MAX; + dqo_target_queue = UINT16_MAX; + dqo_target_queue_size = UINT16_MAX; + dqo_priority = UINT16_MAX; + dqo_priority_size = UINT16_MAX; + } + + bool + IsValid () const + { + return dqo_version != UINT16_MAX; + } + + void + GetThreadQueueInfo (nub_process_t pid, + nub_addr_t dispatch_qaddr, + std::string &queue_name, + uint64_t &queue_width, + uint64_t &queue_serialnum) const; + }; + 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 &); @@ -327,12 +390,18 @@ protected: compression_types GetCompressionType (); + const DispatchQueueOffsets * + GetDispatchQueueOffsets(); + 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 + DispatchQueueOffsets m_dispatch_queue_offsets; + nub_addr_t m_dispatch_queue_offsets_addr; + uint32_t m_qSymbol_index; uint32_t m_packets_recvd; Packet::collection m_packets; std::deque<std::string> m_rx_packets; |

