Index: include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- include/lldb/Host/common/NativeProcessProtocol.h +++ include/lldb/Host/common/NativeProcessProtocol.h @@ -291,6 +291,9 @@ virtual Error GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) = 0; + virtual Error + GetFileEndAddress(const llvm::StringRef& file_name, lldb::addr_t& end_addr) = 0; + //------------------------------------------------------------------ /// Launch a process for debugging. This method will create an concrete /// instance of NativeProcessProtocol, based on the host platform. Index: include/lldb/Target/DynamicLoader.h =================================================================== --- include/lldb/Target/DynamicLoader.h +++ include/lldb/Target/DynamicLoader.h @@ -288,7 +288,8 @@ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr, - bool base_addr_is_offset); + bool base_addr_is_offset, + size_t size_to_read = 512); const lldb_private::SectionList * GetSectionListFromModule(const lldb::ModuleSP module) const; Index: include/lldb/Target/Process.h =================================================================== --- include/lldb/Target/Process.h +++ include/lldb/Target/Process.h @@ -3140,6 +3140,27 @@ return Error("Not supported"); } + //------------------------------------------------------------------ + /// Try to find the end address of a file. + /// The end address is defined as the address of the last memory + /// region what contains data mapped from the specified file. + /// + /// @param[in] file + /// The name of the file whose end address we are looking for + /// + /// @param[out] is_loaded + /// \b True if the file is loaded into the memory and false + /// otherwise. + /// + /// @param[out] end_addr + /// The end address of the file if it is loaded into the + /// processes address space, LLDB_INVALID_ADDRESS otherwise. + //------------------------------------------------------------------ + virtual Error + GetFileEndAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& end_addr) + { + return Error("Not supported"); + } size_t AddImageToken(lldb::addr_t image_ptr); Index: source/Core/DynamicLoader.cpp =================================================================== --- source/Core/DynamicLoader.cpp +++ source/Core/DynamicLoader.cpp @@ -178,7 +178,8 @@ DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr, - bool base_addr_is_offset) + bool base_addr_is_offset, + size_t size_to_read) { Target &target = m_process->GetTarget(); ModuleList &modules = target.GetImages(); @@ -206,7 +207,7 @@ base_addr = load_addr; } - if ((module_sp = m_process->ReadModuleFromMemory(file, base_addr))) + if ((module_sp = m_process->ReadModuleFromMemory(file, base_addr, size_to_read))) { UpdateLoadedSections(module_sp, link_map_addr, base_addr, false); target.GetImages().AppendIfNeeded(module_sp); Index: source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h =================================================================== --- source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -129,7 +129,8 @@ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr, - bool base_addr_is_offset) override; + bool base_addr_is_offset, + size_t size_to_read = 512) override; /// Callback routine invoked when we hit the breakpoint on process entry. /// Index: source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp =================================================================== --- source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -580,7 +580,8 @@ DynamicLoaderHexagonDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr, - bool base_addr_is_offset) + bool base_addr_is_offset, + size_t size_to_read) { Target &target = m_process->GetTarget(); ModuleList &modules = target.GetImages(); Index: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -510,7 +510,13 @@ if (m_vdso_base != LLDB_INVALID_ADDRESS) { FileSpec file_spec("[vdso]", false); - ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS, m_vdso_base, false); + bool is_loaded; + lldb::addr_t end_addr; + size_t size_to_read = 512; + Error error = m_process->GetFileEndAddress(file_spec, is_loaded, end_addr); + if (error.Success() && is_loaded) + size_to_read = end_addr - m_vdso_base; + ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS, m_vdso_base, false, size_to_read); if (module_sp.get()) { module_list.Append(module_sp); Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -113,6 +113,9 @@ Error GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) override; + Error + GetFileEndAddress(const llvm::StringRef& file_name, lldb::addr_t& end_addr) override; + NativeThreadLinuxSP GetThreadByID(lldb::tid_t id); Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -2948,6 +2948,43 @@ return error; } +Error +NativeProcessLinux::GetFileEndAddress(const llvm::StringRef& file_name, lldb::addr_t& end_addr) +{ + end_addr = LLDB_INVALID_ADDRESS; + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + Error error = ProcFileReader::ProcessLineByLine (GetID (), "maps", + [&] (const std::string &line) -> bool + { + StringRef maps_row(line); + + SmallVector maps_columns; + maps_row.split(maps_columns, StringRef(" "), -1, false); + + if (maps_columns.size() < 6) + { + // Return true to continue reading the proc file + return true; + } + + if (maps_columns[5] == file_name) + { + StringExtractor addr_extractor(maps_columns[0].str().c_str()); + addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + char ch = addr_extractor.GetChar('\0'); + if (ch != '\0' && ch != '-') + return true; + + end_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + // Return false to stop reading the proc file further + return false; + } + + return true; + }); + return error; +} + NativeThreadLinuxSP NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -250,6 +250,9 @@ PacketResult Handle_qFileLoadAddress (StringExtractorGDBRemote &packet); + PacketResult + Handle_qFileEndAddress (StringExtractorGDBRemote &packet); + void SetCurrentThreadID (lldb::tid_t tid); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -127,6 +127,8 @@ &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileEndAddress, + &GDBRemoteCommunicationServerLLGS::Handle_qFileEndAddress); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, @@ -2846,6 +2848,42 @@ return SendPacketNoLock(response.GetData(), response.GetSize()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qFileEndAddress (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("GDBRemoteCommunicationServerLLGS::%s qFileEndAddress Start", __FUNCTION__); + // Fail if we don't have a current process. + if (!m_debugged_process_sp || + m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(67); + + packet.SetFilePos(strlen("qFileEndAddress:")); + if (packet.GetBytesLeft() == 0) + return SendErrorResponse(68); + if (log) + log->Printf ("GDBRemoteCommunicationServerLLGS::%s qFileEndAddress", __FUNCTION__); + std::string file_name; + packet.GetHexByteString(file_name); + + if (log) + log->Printf ("GDBRemoteCommunicationServerLLGS::%s %s", __FUNCTION__, file_name.c_str()); + lldb::addr_t file_end_address = LLDB_INVALID_ADDRESS; + Error error = m_debugged_process_sp->GetFileEndAddress(file_name, file_end_address); + if (log) + log->Printf ("GDBRemoteCommunicationServerLLGS::%s %" PRIu64, __FUNCTION__, file_end_address); + if (error.Fail()) + return SendErrorResponse(69); + + if (file_end_address == LLDB_INVALID_ADDRESS) + return SendErrorResponse(1); // File not loaded + + StreamGDBRemote response; + response.PutHex64(file_end_address); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection () { Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -250,6 +250,9 @@ Error GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override; + Error + GetFileEndAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& end_addr) override; + void ModulesDidLoad (ModuleList &module_list) override; Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5024,6 +5024,46 @@ return Error("Unknown error happened during sending the load address packet"); } +Error +ProcessGDBRemote::GetFileEndAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& end_addr) +{ + is_loaded = false; + end_addr = LLDB_INVALID_ADDRESS; + + std::string file_path = file.GetPath(false); + if (file_path.empty ()) + return Error("Empty file name specified"); + + StreamString packet; + packet.PutCString("qFileEndAddress:"); + packet.PutCStringAsRawHex8(file_path.c_str()); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success) + return Error("Sending qFileEndAddress packet failed"); + + if (response.IsErrorResponse()) + { + if (response.GetError() == 1) + { + // The file is not loaded into the inferior + is_loaded = false; + end_addr = LLDB_INVALID_ADDRESS; + return Error(); + } + + return Error("Fetching file end address from remote server returned an error"); + } + + if (response.IsNormalResponse()) + { + is_loaded = true; + end_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + return Error(); + } + + return Error("Unknown error happened during sending the end address packet"); +} void ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list) Index: source/Utility/StringExtractorGDBRemote.h =================================================================== --- source/Utility/StringExtractorGDBRemote.h +++ source/Utility/StringExtractorGDBRemote.h @@ -63,6 +63,7 @@ eServerPacketType_qUserName, eServerPacketType_qGetWorkingDir, eServerPacketType_qFileLoadAddress, + eServerPacketType_qFileEndAddress, eServerPacketType_QEnvironment, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, Index: source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- source/Utility/StringExtractorGDBRemote.cpp +++ source/Utility/StringExtractorGDBRemote.cpp @@ -146,6 +146,7 @@ case 'F': if (PACKET_STARTS_WITH ("qFileLoadAddress:")) return eServerPacketType_qFileLoadAddress; + if (PACKET_STARTS_WITH ("qFileEndAddress:")) return eServerPacketType_qFileEndAddress; break; case 'G':