Index: docs/lldb-gdb-remote.txt =================================================================== --- docs/lldb-gdb-remote.txt +++ docs/lldb-gdb-remote.txt @@ -988,6 +988,21 @@ //---------------------------------------------------------------------- //---------------------------------------------------------------------- +// qModuleInfo:; +// +// BRIEF +// Get information for a module by given module path and architecture. +// +// RESPONSE +// "(uuid|md5):...;triple:...;file_offset:...;file_size...;" +// "EXX" - for any errors +// +// PRIORITY TO IMPLEMENT +// Optional, required if dynamic loader cannot fetch module's information like +// UUID directly from inferior's memory. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- // Stop reply packet extensions // // BRIEF Index: include/lldb/Host/FileSystem.h =================================================================== --- include/lldb/Host/FileSystem.h +++ include/lldb/Host/FileSystem.h @@ -36,8 +36,19 @@ static Error Readlink(const char *path, char *buf, size_t buf_len); static Error Unlink(const char *path); + static bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high); + static bool CalculateMD5(const FileSpec &file_spec, + uint64_t offset, + uint64_t length, + uint64_t &low, + uint64_t &high); + static bool CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str); + static bool CalculateMD5AsString(const FileSpec &file_spec, + uint64_t offset, + uint64_t length, + std::string& digest_str); }; } Index: source/Host/common/FileSystem.cpp =================================================================== --- source/Host/common/FileSystem.cpp +++ source/Host/common/FileSystem.cpp @@ -20,22 +20,31 @@ namespace { bool -CalcMD5(const FileSpec &file_spec, llvm::MD5::MD5Result &md5_result) +CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, llvm::MD5::MD5Result &md5_result) { llvm::MD5 md5_hash; std::ifstream file(file_spec.GetPath(), std::ios::binary); if (!file.is_open()) return false; + if (offset > 0) + file.seekg(offset, file.beg); + std::vector read_buf(4096); + uint64_t total_read_bytes = 0; while (!file.eof()) { - file.read(&read_buf[0], read_buf.size()); + const uint64_t to_read = (length > 0) ? std::min(read_buf.size(), length - total_read_bytes) : read_buf.size(); + if (to_read == 0) + break; + + file.read(&read_buf[0], to_read); const auto read_bytes = file.gcount(); if (read_bytes == 0) break; md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes)); + total_read_bytes += read_bytes; } md5_hash.final(md5_result); @@ -47,8 +56,18 @@ bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high) { + return CalculateMD5(file_spec, 0, 0, low, high); +} + +bool +FileSystem::CalculateMD5(const FileSpec &file_spec, + uint64_t offset, + uint64_t length, + uint64_t &low, + uint64_t &high) +{ llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, md5_result)) + if (!CalcMD5(file_spec, offset, length, md5_result)) return false; const auto uint64_res = reinterpret_cast(md5_result); @@ -61,8 +80,17 @@ bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str) { + return CalculateMD5AsString(file_spec, 0, 0, digest_str); +} + +bool +FileSystem::CalculateMD5AsString(const FileSpec &file_spec, + uint64_t offset, + uint64_t length, + std::string& digest_str) +{ llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, md5_result)) + if (!CalcMD5(file_spec, offset, length, md5_result)) return false; llvm::SmallString<32> result_str; Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -534,6 +534,11 @@ bool GetThreadExtendedInfoSupported(); + bool + GetModuleInfo (const char* module_path, + const lldb_private::ArchSpec& arch_spec, + StringExtractorGDBRemote &response); + protected: PacketResult Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3707,3 +3707,21 @@ } return false; } + +bool +GDBRemoteCommunicationClient::GetModuleInfo (const char* module_path, + const lldb_private::ArchSpec& arch_spec, + StringExtractorGDBRemote &response) +{ + if (!(module_path && module_path[0])) + return false; + + StreamString packet; + packet.PutCString("qModuleInfo:"); + packet.PutBytesAsRawHex8(module_path, strlen(module_path)); + packet.PutCString(";"); + const auto& tripple = arch_spec.GetTriple().getTriple(); + packet.PutBytesAsRawHex8(tripple.c_str(), tripple.size()); + + return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; +} Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -126,6 +126,9 @@ Handle_vFile_MD5 (StringExtractorGDBRemote &packet); PacketResult + Handle_qModuleInfo (StringExtractorGDBRemote &packet); + + PacketResult Handle_qPlatform_shell (StringExtractorGDBRemote &packet); PacketResult Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -19,6 +19,8 @@ // Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Config.h" @@ -29,6 +31,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" +#include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -72,6 +75,8 @@ &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo, + &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, @@ -820,7 +825,7 @@ { uint64_t a,b; StreamGDBRemote response; - if (FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b) == false) + if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b)) { response.PutCString("F,"); response.PutCString("x"); @@ -1109,6 +1114,70 @@ return SendErrorResponse (8); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("qModuleInfo:")); + + std::string module_path; + packet.GetHexByteStringTerminatedBy(module_path, ';'); + if (module_path.empty()) + return SendErrorResponse (1); + const FileSpec module_path_spec(module_path.c_str(), true); + + if (packet.GetChar() != ';') + return SendErrorResponse (2); + + std::string triple; + packet.GetHexByteString(triple); + const ModuleSpec module_spec(module_path_spec, ArchSpec(triple.c_str())); + + ModuleSpecList module_specs; + if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs)) + return SendErrorResponse (3); + + ModuleSpec matched_module_spec; + if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) + return SendErrorResponse (4); + + const ModuleSP module(new Module(matched_module_spec)); + + const auto obj_file(module->GetObjectFile()); + const auto file_offset = obj_file->GetFileOffset(); + const auto file_size = obj_file->GetByteSize(); + + StreamGDBRemote response; + + const auto uuid_str = module->GetUUID().GetAsString(); + if (uuid_str.empty()) + { + std::string md5_hash; + if (!FileSystem::CalculateMD5AsString(module_path_spec, file_offset, file_size, md5_hash)) + return SendErrorResponse (5); + response.PutCString ("md5:"); + response.PutCStringAsRawHex8(md5_hash.c_str()); + } + else{ + response.PutCString ("uuid:"); + response.PutCStringAsRawHex8(uuid_str.c_str()); + } + response.PutChar(';'); + + const auto &module_arch = matched_module_spec.GetArchitecture(); + response.PutCString("triple:"); + response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str()); + response.PutChar(';'); + + response.PutCString("file_offset:"); + response.PutHex64(file_offset); + response.PutChar(';'); + response.PutCString("file_size:"); + response.PutHex64(file_size); + response.PutChar(';'); + + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response) Index: source/Utility/StringExtractorGDBRemote.h =================================================================== --- source/Utility/StringExtractorGDBRemote.h +++ source/Utility/StringExtractorGDBRemote.h @@ -55,6 +55,7 @@ eServerPacketType_qLaunchGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, + eServerPacketType_qModuleInfo, eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, eServerPacketType_qUserName, Index: source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- source/Utility/StringExtractorGDBRemote.cpp +++ source/Utility/StringExtractorGDBRemote.cpp @@ -160,6 +160,7 @@ case 'M': if (PACKET_STARTS_WITH ("qMemoryRegionInfo:")) return eServerPacketType_qMemoryRegionInfo; if (PACKET_MATCHES ("qMemoryRegionInfo")) return eServerPacketType_qMemoryRegionInfoSupported; + if (PACKET_STARTS_WITH ("qModuleInfo:")) return eServerPacketType_qModuleInfo; break; case 'P':