diff options
Diffstat (limited to 'lldb/source/Plugins/Process/MacOSX-Kernel')
12 files changed, 1186 insertions, 62 deletions
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 2d9522bbe3a..f84eec36840 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -15,10 +15,13 @@ #include <string.h> // C++ Includes +#include "llvm/Support/MachO.h" + // Other libraries and framework includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Log.h" +#include "lldb/Core/State.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" @@ -37,6 +40,7 @@ using namespace lldb_private; //---------------------------------------------------------------------- CommunicationKDP::CommunicationKDP (const char *comm_name) : Communication(comm_name), + m_addr_byte_size (4), m_byte_order (eByteOrderLittle), m_packet_timeout (1), m_sequence_mutex (Mutex::eMutexTypeRecursive), @@ -129,13 +133,9 @@ CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packe LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); if (log) { - PacketStreamType log_strm; - - DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, UINT32_MAX, LLDB_INVALID_ADDRESS); - - log->Printf("send kdp-packet: %.*s", - (uint32_t)log_strm.GetSize(), - log_strm.GetData()); + PacketStreamType log_strm; + DumpPacket (log_strm, packet_data, packet_size); + log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); } ConnectionStatus status = eConnectionStatusSuccess; @@ -298,18 +298,9 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtrac if (log) { PacketStreamType log_strm; - packet.Dump (&log_strm, // Stream to dump to - 0, // Offset into "packet" - eFormatBytes, // Dump as hex bytes - 1, // Size of each item is 1 for single bytes - length, // Number of bytes - UINT32_MAX, // Num bytes per line - LLDB_INVALID_ADDRESS, // Base address - 0, 0); // Bitfield info set to not do anything bitfield related + DumpPacket (log_strm, packet); - log->Printf("recv kdp-packet: %.*s", - (uint32_t)log_strm.GetSize(), - log_strm.GetData()); + log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); } return true; } @@ -336,7 +327,7 @@ CommunicationKDP::SendRequestConnect (uint16_t reply_port, uint16_t exc_port, const char *greeting) { - PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); if (greeting == NULL) greeting = ""; @@ -369,7 +360,7 @@ CommunicationKDP::ClearKDPSettings () bool CommunicationKDP::SendRequestReattach (uint16_t reply_port) { - PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); const CommandType command = eCommandTypeReattach; // Length is 8 bytes for the header plus 2 bytes for the reply UDP port const uint32_t command_length = 8 + 2; @@ -410,7 +401,7 @@ CommunicationKDP::GetFeatureFlags () bool CommunicationKDP::SendRequestVersion () { - PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); const CommandType command = eCommandTypeVersion; const uint32_t command_length = 8; const uint32_t request_sequence_id = m_request_sequence_id; @@ -454,7 +445,7 @@ CommunicationKDP::GetCPUSubtype () bool CommunicationKDP::SendRequestHostInfo () { - PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); const CommandType command = eCommandTypeHostInfo; const uint32_t command_length = 8; const uint32_t request_sequence_id = m_request_sequence_id; @@ -464,9 +455,17 @@ CommunicationKDP::SendRequestHostInfo () { // Reset the sequence ID to zero for reattach uint32_t offset = 8; - m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset); - m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset); - m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset); + m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset); + m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset); + m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset); + + ArchSpec kernel_arch; + kernel_arch.SetArchitecture (eArchTypeMachO, + m_kdp_hostinfo_cpu_type, + m_kdp_hostinfo_cpu_subtype); + + m_addr_byte_size = kernel_arch.GetAddressByteSize(); + m_byte_order = kernel_arch.GetByteOrder(); return true; } return false; @@ -475,7 +474,7 @@ CommunicationKDP::SendRequestHostInfo () bool CommunicationKDP::SendRequestDisconnect () { - PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); const CommandType command = eCommandTypeDisconnect; const uint32_t command_length = 8; const uint32_t request_sequence_id = m_request_sequence_id; @@ -489,3 +488,331 @@ CommunicationKDP::SendRequestDisconnect () return true; } +uint32_t +CommunicationKDP::SendRequestReadMemory (lldb::addr_t addr, + void *dst, + uint32_t dst_len, + Error &error) +{ + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); + bool use_64 = (GetVersion() >= 11); + uint32_t command_addr_byte_size = use_64 ? 8 : 4; + const CommandType command = use_64 ? eCommandTypeReadMemory64 : eCommandTypeReadMemory; + // Size is header + address size + uint32_t length + const uint32_t command_length = 8 + command_addr_byte_size + 4; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + request_packet.PutMaxHex64 (addr, command_addr_byte_size); + request_packet.PutHex32 (dst_len); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Reset the sequence ID to zero for reattach + uint32_t offset = 8; + uint32_t kdp_error = reply_packet.GetU32 (&offset); + uint32_t src_len = reply_packet.GetByteSize() - 12; + + if (src_len > 0) + { + const void *src = reply_packet.GetData(&offset, src_len); + if (src) + { + ::memcpy (dst, src, src_len); + error.Clear(); + return src_len; + } + } + if (kdp_error) + error.SetErrorStringWithFormat ("kdp read memory failed (error %u)", kdp_error); + else + error.SetErrorString ("kdp read memory failed"); + } + return 0; +} + +const char * +CommunicationKDP::GetCommandAsCString (uint8_t command) +{ + switch (command) + { + case eCommandTypeConnect: return "KDP_CONNECT"; + case eCommandTypeDisconnect: return "KDP_DISCONNECT"; + case eCommandTypeHostInfo: return "KDP_HOSTINFO"; + case eCommandTypeVersion: return "KDP_VERSION"; + case eCommandTypeMaxBytes: return "KDP_MAXBYTES"; + case eCommandTypeReadMemory: return "KDP_READMEM"; + case eCommandTypeWriteMemory: return "KDP_WRITEMEM"; + case eCommandTypeReadRegisters: return "KDP_READREGS"; + case eCommandTypeWriteRegisters: return "KDP_WRITEREGS"; + case eCommandTypeLoad: return "KDP_LOAD"; + case eCommandTypeImagePath: return "KDP_IMAGEPATH"; + case eCommandTypeSuspend: return "KDP_SUSPEND"; + case eCommandTypeResume: return "KDP_RESUMECPUS"; + case eCommandTypeException: return "KDP_EXCEPTION"; + case eCommandTypeTermination: return "KDP_TERMINATION"; + case eCommandTypeBreakpointSet: return "KDP_BREAKPOINT_SET"; + case eCommandTypeBreakpointRemove: return "KDP_BREAKPOINT_REMOVE"; + case eCommandTypeRegions: return "KDP_REGIONS"; + case eCommandTypeReattach: return "KDP_REATTACH"; + case eCommandTypeHostReboot: return "KDP_HOSTREBOOT"; + case eCommandTypeReadMemory64: return "KDP_READMEM64"; + case eCommandTypeWriteMemory64: return "KDP_WRITEMEM64"; + case eCommandTypeBreakpointSet64: return "KDP_BREAKPOINT64_SET"; + case eCommandTypeBreakpointRemove64: return "KDP_BREAKPOINT64_REMOVE"; + case eCommandTypeKernelVersion: return "KDP_KERNELVERSION"; + } + return NULL; +} + +void +CommunicationKDP::DumpPacket (Stream &s, const void *data, uint32_t data_len) +{ + DataExtractor extractor (data, data_len, m_byte_order, m_addr_byte_size); + DumpPacket (s, extractor); +} + +void +CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet) +{ + const char *error_desc = NULL; + if (packet.GetByteSize() < 8) + { + error_desc = "error: invalid packet (too short): "; + } + else + { + uint32_t offset = 0; + const uint8_t first_packet_byte = packet.GetU8 (&offset); + const uint8_t sequence_id = packet.GetU8 (&offset); + const uint16_t length = packet.GetU16 (&offset); + const uint32_t key = packet.GetU32 (&offset); + const CommandType command = ExtractCommand (first_packet_byte); + const char *command_name = GetCommandAsCString (command); + if (command_name) + { + const bool is_reply = ExtractIsReply(first_packet_byte); + s.Printf ("%s {%u:%u} <0x%4.4x> %s", + is_reply ? "<--" : "-->", + key, + sequence_id, + length, + command_name); + + if (is_reply) + { + // Dump request reply packets + switch (command) + { + case eCommandTypeConnect: + { + const uint32_t error = packet.GetU32 (&offset); + s.Printf(" (error=0x%8.8x)", error); + } + break; + + case eCommandTypeDisconnect: + case eCommandTypeReattach: + case eCommandTypeHostReboot: + // No return value for the reply, just the header to ack + break; + + case eCommandTypeHostInfo: + { + const uint32_t cpu_mask = packet.GetU32 (&offset); + const uint32_t cpu_type = packet.GetU32 (&offset); + const uint32_t cpu_subtype = packet.GetU32 (&offset); + s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)", cpu_mask, cpu_type, cpu_subtype); + } + break; + + case eCommandTypeVersion: + { + const uint32_t version = packet.GetU32 (&offset); + const uint32_t feature = packet.GetU32 (&offset); + s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature); + } + break; + + case eCommandTypeRegions: + { + const uint32_t region_count = packet.GetU32 (&offset); + s.Printf(" (count = %u", region_count); + for (uint32_t i=0; i<region_count; ++i) + { + const addr_t region_addr = packet.GetPointer (&offset); + const uint32_t region_size = packet.GetU32 (&offset); + const uint32_t region_prot = packet.GetU32 (&offset); + s.Printf("\n\tregion[%i] = { range = [0x%16.16llx - 0x%16.16llx), size = 0x%8.8x, prot = %s }", region_addr, region_addr + region_size, region_size, GetPermissionsAsCString (region_prot)); + } + } + break; + + case eCommandTypeReadMemory: + case eCommandTypeReadMemory64: + case eCommandTypeReadRegisters: + { + const uint32_t error = packet.GetU32 (&offset); + const uint32_t count = packet.GetByteSize() - 12; + s.Printf(" (error = 0x%8.8x <0x%x>:\n", error, count); + if (count > 0) + DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, count), count, 32, LLDB_INVALID_ADDRESS); + } + break; + + case eCommandTypeMaxBytes: + case eCommandTypeWriteMemory: + case eCommandTypeWriteRegisters: + case eCommandTypeLoad: + case eCommandTypeImagePath: + case eCommandTypeSuspend: + case eCommandTypeResume: + case eCommandTypeException: + case eCommandTypeTermination: + case eCommandTypeBreakpointSet: + case eCommandTypeBreakpointRemove: + case eCommandTypeWriteMemory64: + case eCommandTypeBreakpointSet64: + case eCommandTypeBreakpointRemove64: + case eCommandTypeKernelVersion: + break; + + } + } + else + { + // Dump request packets + switch (command) + { + case eCommandTypeConnect: + { + const uint16_t reply_port = packet.GetU16 (&offset); + const uint16_t exc_port = packet.GetU16 (&offset); + s.Printf(" (reply_port=%u, exc_port=%u, greeting=\"%s\")", reply_port, exc_port, packet.GetCStr(&offset)); + } + break; + + case eCommandTypeDisconnect: + case eCommandTypeHostReboot: + case eCommandTypeHostInfo: + case eCommandTypeVersion: + case eCommandTypeRegions: + // No args, just the header in the request... + break; + + case eCommandTypeReadMemory: + { + const uint32_t addr = packet.GetU32 (&offset); + const uint32_t size = packet.GetU32 (&offset); + s.Printf(" (addr = 0x%8.8x, size=%u)", addr, size); + } + break; + + case eCommandTypeReadMemory64: + { + const uint64_t addr = packet.GetU64 (&offset); + const uint32_t size = packet.GetU32 (&offset); + s.Printf(" (addr = 0x%16.16llx, size=%u)", addr, size); + } + break; + + case eCommandTypeReadRegisters: + { + const uint32_t cpu = packet.GetU32 (&offset); + const uint32_t flavor = packet.GetU32 (&offset); + s.Printf(" (cpu = %u, flavor=%u)", cpu, flavor); + } + break; + + case eCommandTypeMaxBytes: + case eCommandTypeWriteMemory: + case eCommandTypeWriteRegisters: + case eCommandTypeLoad: + case eCommandTypeImagePath: + case eCommandTypeSuspend: + case eCommandTypeResume: + case eCommandTypeException: + case eCommandTypeTermination: + case eCommandTypeBreakpointSet: + case eCommandTypeBreakpointRemove: + break; + + case eCommandTypeReattach: + { + const uint16_t reply_port = packet.GetU16 (&offset); + s.Printf(" (reply_port=%u)", reply_port); + } + break; + + case eCommandTypeWriteMemory64: + case eCommandTypeBreakpointSet64: + case eCommandTypeBreakpointRemove64: + case eCommandTypeKernelVersion: + break; + } + } + } + else + { + error_desc = "error: invalid packet command: "; + } + } + + if (error_desc) + { + s.PutCString (error_desc); + + packet.Dump (&s, // Stream to dump to + 0, // Offset into "packet" + eFormatBytes, // Dump as hex bytes + 1, // Size of each item is 1 for single bytes + packet.GetByteSize(), // Number of bytes + UINT32_MAX, // Num bytes per line + LLDB_INVALID_ADDRESS, // Base address + 0, 0); // Bitfield info set to not do anything bitfield related + } +} + +uint32_t +CommunicationKDP::SendRequestReadRegisters (uint32_t cpu, + uint32_t flavor, + void *dst, + uint32_t dst_len, + Error &error) +{ + PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); + const CommandType command = eCommandTypeReadRegisters; + // Size is header + 4 byte cpu and 4 byte flavor + const uint32_t command_length = 8 + 4 + 4; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + request_packet.PutHex32 (cpu); + request_packet.PutHex32 (flavor); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Reset the sequence ID to zero for reattach + uint32_t offset = 8; + uint32_t kdp_error = reply_packet.GetU32 (&offset); + uint32_t src_len = reply_packet.GetByteSize() - 12; + + if (src_len > 0) + { + const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len); + const void *src = reply_packet.GetData(&offset, bytes_to_copy); + if (src) + { + ::memcpy (dst, src, bytes_to_copy); + error.Clear(); + // Return the number of bytes we could have returned regardless if + // we copied them or not, just so we know when things don't match up + return src_len; + } + } + if (kdp_error) + error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error); + else + error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u", cpu, flavor); + } + return 0; +} + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h index 83c8790562b..8e9d8b2235e 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -140,6 +140,9 @@ public: lldb_private::ProcessLaunchInfo &launch_info); + //------------------------------------------------------------------ + // Public Request Packets + //------------------------------------------------------------------ bool SendRequestConnect (uint16_t reply_port, uint16_t exc_port, @@ -152,6 +155,24 @@ public: SendRequestDisconnect (); uint32_t + SendRequestReadMemory (lldb::addr_t addr, + void *buf, + uint32_t size, + lldb_private::Error &error); + + uint32_t + SendRequestReadRegisters (uint32_t cpu, + uint32_t flavor, + void *dst, + uint32_t dst_size, + lldb_private::Error &error); +// size_t +// SendRequestWriteMemory (lldb::addr_t addr, +// const void *buf, +// size_t size, +// lldb_private::Error &error); + + uint32_t GetVersion (); uint32_t @@ -184,9 +205,25 @@ protected: PacketStreamType &request_packet, uint16_t request_length); + //------------------------------------------------------------------ + // Protected Request Packets (use public accessors which will cache + // results. + //------------------------------------------------------------------ bool SendRequestVersion (); + bool + SendRequestHostInfo (); + + + void + DumpPacket (lldb_private::Stream &s, + const void *data, + uint32_t data_len); + + void + DumpPacket (lldb_private::Stream &s, + const lldb_private::DataExtractor& extractor); bool VersionIsValid() const @@ -201,7 +238,21 @@ protected: } bool - SendRequestHostInfo (); + ExtractIsReply (uint8_t first_packet_byte) const + { + // TODO: handle big endian... + return (first_packet_byte & ePacketTypeMask) != 0; + } + + CommandType + ExtractCommand (uint8_t first_packet_byte) const + { + // TODO: handle big endian... + return (CommandType)(first_packet_byte & eCommandTypeMask); + } + + static const char * + GetCommandAsCString (uint8_t command); void ClearKDPSettings (); @@ -214,6 +265,7 @@ protected: //------------------------------------------------------------------ // Classes that inherit from CommunicationKDP can see and modify these //------------------------------------------------------------------ + uint32_t m_addr_byte_size; lldb::ByteOrder m_byte_order; uint32_t m_packet_timeout; lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 77d3d1ced2b..6d33ea28634 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -18,11 +18,12 @@ #include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" // Project includes #include "ProcessKDP.h" #include "ProcessKDPLog.h" -//#include "ThreadKDP.h" +#include "ThreadKDP.h" #include "StopInfoMachException.h" using namespace lldb; @@ -182,7 +183,10 @@ ProcessKDP::DoConnectRemote (const char *remote_url) ArchSpec kernel_arch; kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub); m_target.SetArchitecture(kernel_arch); - // TODO: thread registers based off of architecture... + + SetID (1); + UpdateThreadListIfNeeded (); + SetPrivateState (eStateStopped); } } else @@ -295,34 +299,24 @@ ProcessKDP::UpdateThreadListIfNeeded () log->Printf ("ProcessKDP::%s (pid = %i)", __FUNCTION__, GetID()); Mutex::Locker locker (m_thread_list.GetMutex ()); - // TODO: get the thread list here! const uint32_t stop_id = GetStopID(); - if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID()) + if (m_thread_list.GetSize(false) == 0) { - // Update the thread list's stop id immediately so we don't recurse into this function. -// ThreadList curr_thread_list (this); -// curr_thread_list.SetStopID(stop_id); -// -// std::vector<lldb::tid_t> thread_ids; -// bool sequence_mutex_unavailable = false; -// const size_t num_thread_ids = m_comm.GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable); -// if (num_thread_ids > 0) -// { -// for (size_t i=0; i<num_thread_ids; ++i) -// { -// tid_t tid = thread_ids[i]; -// ThreadSP thread_sp (GetThreadList().FindThreadByID (tid, false)); -// if (!thread_sp) -// thread_sp.reset (new ThreadGDBRemote (*this, tid)); -// curr_thread_list.AddThread(thread_sp); -// } -// } -// -// if (sequence_mutex_unavailable == false) -// { -// m_thread_list = curr_thread_list; -// SetThreadStopInfo (m_last_stop_packet); -// } + // We currently are making only one thread per core and we + // actually don't know about actual threads. Eventually we + // want to get the thread list from memory and note which + // threads are on CPU as those are the only ones that we + // will be able to resume. + ThreadList curr_thread_list (this); + curr_thread_list.SetStopID(stop_id); + const uint32_t cpu_mask = m_comm.GetCPUMask(); + for (uint32_t cpu_mask_bit = 1; cpu_mask_bit & cpu_mask; cpu_mask_bit <<= 1) + { + // The thread ID is currently the CPU mask bit + ThreadSP thread_sp (new ThreadKDP (*this, cpu_mask_bit)); + curr_thread_list.AddThread(thread_sp); + } + m_thread_list = curr_thread_list; } return GetThreadList().GetSize(false); } @@ -549,7 +543,9 @@ ProcessKDP::IsAlive () size_t ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) { - error.SetErrorString ("ProcessKDP::DoReadMemory not implemented"); + if (m_comm.IsConnected()) + return m_comm.SendRequestReadMemory (addr, buf, size, error); + error.SetErrorString ("not connected"); return 0; } diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h index c967e2f41ed..36497130818 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -183,6 +183,12 @@ public: virtual lldb_private::Error DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc); + CommunicationKDP & + GetCommunication() + { + return m_comm; + } + protected: friend class ThreadKDP; friend class CommunicationKDP; @@ -229,12 +235,6 @@ protected: uint32_t UpdateThreadListIfNeeded (); - CommunicationKDP & - GetCommunication() - { - return m_comm; - } - enum { eBroadcastBitAsyncContinue = (1 << 0), diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp new file mode 100644 index 00000000000..fcc68658f2f --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp @@ -0,0 +1,90 @@ +//===-- RegisterContextKDP_arm.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextKDP_arm.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_arm::RegisterContextKDP_arm(ThreadKDP &thread, uint32_t concrete_frame_idx) : + RegisterContextDarwin_arm (thread, concrete_frame_idx), + m_kdp_thread (thread) +{ +} + +RegisterContextKDP_arm::~RegisterContextKDP_arm() +{ +} + +int +RegisterContextKDP_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ + Error error; + if (m_kdp_thread.GetKDPProcess().GetCommunication().SendRequestReadRegisters (tid, + GPRRegSet, + &gpr, sizeof(gpr), + error)) + { + if (error.Success()) + return 0; + } + return -1; +} + +int +RegisterContextKDP_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ + return -1; +} + +int +RegisterContextKDP_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) +{ + return -1; +} + + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h new file mode 100644 index 00000000000..1e547289d9c --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h @@ -0,0 +1,61 @@ +//===-- RegisterContextKDP_arm.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_arm_h_ +#define liblldb_RegisterContextKDP_arm_h_ + +// C Includes + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" + +class ThreadKDP; + +class RegisterContextKDP_arm : public RegisterContextDarwin_arm +{ +public: + + RegisterContextKDP_arm (ThreadKDP &thread, + uint32_t concrete_frame_idx); + + virtual + ~RegisterContextKDP_arm(); + +protected: + + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); + + int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); + + int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); + + int + DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg); + + int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); + + int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); + + int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); + + int + DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg); + + ThreadKDP &m_kdp_thread; +}; + +#endif // liblldb_RegisterContextKDP_arm_h_ diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp new file mode 100644 index 00000000000..7b7fc0f5fee --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp @@ -0,0 +1,71 @@ +//===-- RegisterContextKDP_i386.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +#include <mach/thread_act.h> + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "RegisterContextKDP_i386.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_i386::RegisterContextKDP_i386(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContextDarwin_i386 (thread, concrete_frame_idx) +{ +} + +RegisterContextKDP_i386::~RegisterContextKDP_i386() +{ +} + +int +RegisterContextKDP_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ + mach_msg_type_number_t count = GPRWordCount; + return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count); +} + +int +RegisterContextKDP_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ + mach_msg_type_number_t count = FPUWordCount; + return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count); +} + +int +RegisterContextKDP_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ + mach_msg_type_number_t count = EXCWordCount; + return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count); +} + +int +RegisterContextKDP_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ + return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount); +} + +int +RegisterContextKDP_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ + return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount); +} + +int +RegisterContextKDP_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ + return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount); +} + + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h new file mode 100644 index 00000000000..641e49d8dc7 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h @@ -0,0 +1,49 @@ +//===-- RegisterContextKDP_i386.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_i386_h_ +#define liblldb_RegisterContextKDP_i386_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" + +class RegisterContextKDP_i386 : public RegisterContextDarwin_i386 +{ +public: + RegisterContextKDP_i386 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx); + + virtual + ~RegisterContextKDP_i386(); + +protected: + + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); + + int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); + + int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); + + int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); + + int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); + + int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +}; + +#endif // liblldb_RegisterContextKDP_i386_h_ diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp new file mode 100644 index 00000000000..dc5a47cb1a9 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp @@ -0,0 +1,66 @@ +//===-- RegisterContextKDP_x86_64.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +#include <mach/thread_act.h> + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "RegisterContextKDP_x86_64.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_x86_64::RegisterContextKDP_x86_64(Thread &thread, uint32_t concrete_frame_idx) : + RegisterContextDarwin_x86_64 (thread, concrete_frame_idx) +{ +} + +RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64() +{ +} + +int +RegisterContextKDP_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ + return -1; +} + +int +RegisterContextKDP_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ + return -1; +} + +int +RegisterContextKDP_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ + return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ + return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ + return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ + return -1; +} diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h new file mode 100644 index 00000000000..f1d41cb8302 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h @@ -0,0 +1,50 @@ +//===-- RegisterContextKDP_x86_64.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_x86_64_h_ +#define liblldb_RegisterContextKDP_x86_64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" + +class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64 +{ +public: + + RegisterContextKDP_x86_64 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx); + + virtual + ~RegisterContextKDP_x86_64(); + +protected: + + virtual int + DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); + + int + DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); + + int + DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); + + int + DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); + + int + DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); + + int + DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +}; + +#endif // liblldb_RegisterContextKDP_x86_64_h_ diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp new file mode 100644 index 00000000000..dac551762f3 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -0,0 +1,247 @@ +//===-- ThreadKDP.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "ThreadKDP.h" + +#include "llvm/Support/MachO.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/State.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Breakpoint/WatchpointLocation.h" + +#include "ProcessKDP.h" +#include "ProcessKDPLog.h" +#include "RegisterContextKDP_arm.h" +#include "RegisterContextKDP_i386.h" +#include "RegisterContextKDP_x86_64.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" + +#if defined(__APPLE__) +#include "UnwindMacOSXFrameBackchain.h" +#endif + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Thread Registers +//---------------------------------------------------------------------- + +ThreadKDP::ThreadKDP (ProcessKDP &process, lldb::tid_t tid) : + Thread(process, tid), + m_thread_name (), + m_dispatch_queue_name (), + m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS) +{ + ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::ThreadKDP (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID()); +} + +ThreadKDP::~ThreadKDP () +{ + ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::~ThreadKDP (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID()); + DestroyThread(); +} + + +const char * +ThreadKDP::GetInfo () +{ + return NULL; +} + + +const char * +ThreadKDP::GetName () +{ + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); +} + +const char * +ThreadKDP::GetQueueName () +{ + return NULL; +} + +bool +ThreadKDP::WillResume (StateType resume_state) +{ + ClearStackFrames(); + // Call the Thread::WillResume first. If we stop at a signal, the stop info + // class for signal will set the resume signal that we need below. The signal + // stuff obeys the Process::UnixSignal defaults. + Thread::WillResume(resume_state); + + lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); + if (log) + log->Printf ("Resuming thread: %4.4x with state: %s.", GetID(), StateAsCString(resume_state)); + +// ProcessKDP &process = GetKDPProcess(); +// switch (resume_state) +// { +// case eStateSuspended: +// case eStateStopped: +// // Don't append anything for threads that should stay stopped. +// break; +// +// case eStateRunning: +// case eStateStepping: +// break; +// +// default: +// break; +// } + return true; +} + +void +ThreadKDP::RefreshStateAfterStop() +{ + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The KDPRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded (force); +} + +Unwind * +ThreadKDP::GetUnwinder () +{ + if (m_unwinder_ap.get() == NULL) + { + const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ()); + const llvm::Triple::ArchType machine = target_arch.GetMachine(); + switch (machine) + { + case llvm::Triple::x86_64: + case llvm::Triple::x86: + case llvm::Triple::arm: + case llvm::Triple::thumb: + m_unwinder_ap.reset (new UnwindLLDB (*this)); + break; + + default: +#if defined(__APPLE__) + m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this)); +#endif + break; + } + } + return m_unwinder_ap.get(); +} + +void +ThreadKDP::ClearStackFrames () +{ + Unwind *unwinder = GetUnwinder (); + if (unwinder) + unwinder->Clear(); + Thread::ClearStackFrames(); +} + + +bool +ThreadKDP::ThreadIDIsValid (lldb::tid_t thread) +{ + return thread != 0; +} + +void +ThreadKDP::Dump(Log *log, uint32_t index) +{ +} + + +bool +ThreadKDP::ShouldStop (bool &step_more) +{ + return true; +} +lldb::RegisterContextSP +ThreadKDP::GetRegisterContext () +{ + if (m_reg_context_sp.get() == NULL) + m_reg_context_sp = CreateRegisterContextForFrame (NULL); + return m_reg_context_sp; +} + +lldb::RegisterContextSP +ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame) +{ + lldb::RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex (); + + if (concrete_frame_idx == 0) + { + switch (GetKDPProcess().GetCommunication().GetCPUType()) + { + case llvm::MachO::CPUTypeARM: + reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx)); + break; + case llvm::MachO::CPUTypeI386: + reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx)); + break; + case llvm::MachO::CPUTypeX86_64: + reg_ctx_sp.reset (new RegisterContextKDP_x86_64 (*this, concrete_frame_idx)); + break; + default: + assert (!"Add CPU type support in KDP"); + break; + } + } + else if (m_unwinder_ap.get()) + reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame); + return reg_ctx_sp; +} + +lldb::StopInfoSP +ThreadKDP::GetPrivateStopReason () +{ + const uint32_t process_stop_id = GetProcess().GetStopID(); + if (m_thread_stop_reason_stop_id != process_stop_id || + (m_actual_stop_info_sp && !m_actual_stop_info_sp->IsValid())) + { + // TODO: can we query the initial state of the thread here? + // For now I am just going to pretend that a SIGSTOP happened. + + SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP)); + + // If GetKDPProcess().SetThreadStopInfo() doesn't find a stop reason + // for this thread, then m_actual_stop_info_sp will not ever contain + // a valid stop reason and the "m_actual_stop_info_sp->IsValid() == false" + // check will never be able to tell us if we have the correct stop info + // for this thread and we will continually send qThreadStopInfo packets + // down to the remote KDP server, so we need to keep our own notion + // of the stop ID that m_actual_stop_info_sp is valid for (even if it + // contains nothing). We use m_thread_stop_reason_stop_id for this below. +// m_thread_stop_reason_stop_id = process_stop_id; +// m_actual_stop_info_sp.reset(); + + } + return m_actual_stop_info_sp; +} + + diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h new file mode 100644 index 00000000000..95c2f0577e4 --- /dev/null +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h @@ -0,0 +1,115 @@ +//===-- ThreadKDP.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadKDP_h_ +#define liblldb_ThreadKDP_h_ + +#include <string> + +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +class ProcessKDP; + +class ThreadKDP : public lldb_private::Thread +{ +public: + ThreadKDP (ProcessKDP &process, + lldb::tid_t tid); + + virtual + ~ThreadKDP (); + + virtual bool + WillResume (lldb::StateType resume_state); + + virtual void + RefreshStateAfterStop(); + + virtual const char * + GetInfo (); + + virtual const char * + GetName (); + + virtual const char * + GetQueueName (); + + virtual lldb::RegisterContextSP + GetRegisterContext (); + + virtual lldb::RegisterContextSP + CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + + virtual void + ClearStackFrames (); + + ProcessKDP & + GetKDPProcess () + { + return (ProcessKDP &)m_process; + } + + void + Dump (lldb_private::Log *log, uint32_t index); + + static bool + ThreadIDIsValid (lldb::tid_t thread); + + bool + ShouldStop (bool &step_more); + + const char * + GetBasicInfoAsString (); + + void + SetName (const char *name) + { + if (name && name[0]) + m_thread_name.assign (name); + else + m_thread_name.clear(); + } + + lldb::addr_t + GetThreadDispatchQAddr () + { + return m_thread_dispatch_qaddr; + } + + void + SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr) + { + m_thread_dispatch_qaddr = thread_dispatch_qaddr; + } + +protected: + + friend class ProcessKDP; + + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + std::string m_thread_name; + std::string m_dispatch_queue_name; + lldb::addr_t m_thread_dispatch_qaddr; + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + + virtual lldb_private::Unwind * + GetUnwinder (); + + virtual lldb::StopInfoSP + GetPrivateStopReason (); + + +}; + +#endif // liblldb_ThreadKDP_h_ |