Index: lldb/trunk/docs/lldb-gdb-remote.txt =================================================================== --- lldb/trunk/docs/lldb-gdb-remote.txt +++ lldb/trunk/docs/lldb-gdb-remote.txt @@ -988,6 +988,24 @@ //---------------------------------------------------------------------- //---------------------------------------------------------------------- +// qFileLoadAddress: +// +// BRIEF +// Get the load address of a memory mapped file. +// The load address is defined as the address of the first memory +// region what contains data mapped from the specified file. +// +// RESPONSE +// - Load address of the file in big endian encoding +// "E01" - the requested file isn't loaded +// "EXX" - for any other errors +// +// PRIORITY TO IMPLEMENT +// Low, required if dynamic linker don't fill in the load address of +// some object file in the rendezvous data structure. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- // qModuleInfo:; // // BRIEF Index: lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h =================================================================== --- lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h +++ lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h @@ -16,6 +16,7 @@ #include "lldb/lldb-types.h" #include "lldb/Core/Error.h" #include "lldb/Host/Mutex.h" +#include "llvm/ADT/StringRef.h" #include "NativeBreakpointList.h" #include "NativeWatchpointList.h" @@ -293,6 +294,9 @@ virtual Error GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) = 0; + virtual Error + GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) = 0; + protected: lldb::pid_t m_pid; Index: lldb/trunk/include/lldb/Target/Process.h =================================================================== --- lldb/trunk/include/lldb/Target/Process.h +++ lldb/trunk/include/lldb/Target/Process.h @@ -3036,6 +3036,28 @@ virtual bool GetModuleSpec(const FileSpec& module_file_spec, const ArchSpec& arch, ModuleSpec &module_spec); + //------------------------------------------------------------------ + /// Try to find the load address of a file. + /// The load address is defined as the address of the first memory + /// region what contains data mapped from the specified file. + /// + /// @param[in] file + /// The name of the file whose load address we are looking for + /// + /// @param[out] is_loaded + /// \b True if the file is loaded into the memory and false + /// otherwise. + /// + /// @param[out] load_addr + /// The load address of the file if it is loaded into the + /// processes address space, LLDB_INVALID_ADDRESS otherwise. + //------------------------------------------------------------------ + virtual Error + GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) + { + return Error("Not supported"); + } + protected: //------------------------------------------------------------------ Index: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp =================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -412,6 +412,17 @@ entry.file_spec.SetFile(ReadStringFromMemory(entry.path_addr), false); + // The base_addr is not filled in for some case. + // Try to figure it out based on the load address of the object file. + if (entry.base_addr == 0) + { + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + bool is_loaded = false; + Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); + if (error.Success() && is_loaded) + entry.base_addr = load_addr; + } + return true; } Index: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -152,6 +152,9 @@ Error GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) override; + Error + GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) override; + // --------------------------------------------------------------------- // Interface used by NativeRegisterContext-derived classes. // --------------------------------------------------------------------- Index: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -3649,6 +3649,39 @@ } Error +NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) +{ + load_addr = LLDB_INVALID_ADDRESS; + 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()); + load_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + + // Return false to stop reading the proc file further + return false; + } + + // Return true to continue reading the proc file + return true; + }); + return error; +} + +Error NativeProcessLinux::ResumeThread( lldb::tid_t tid, NativeThreadLinux::ResumeThreadFunction request_thread_resume_function, Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -236,6 +236,9 @@ PacketResult Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet); + PacketResult + Handle_qFileLoadAddress (StringExtractorGDBRemote &packet); + void SetCurrentThreadID (lldb::tid_t tid); Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -53,6 +53,7 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; +using namespace llvm; //---------------------------------------------------------------------- // GDBRemote Errors @@ -134,6 +135,8 @@ &GDBRemoteCommunicationServerLLGS::Handle_qC); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, + &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, @@ -2600,6 +2603,34 @@ return SendPacketNoLock(response.GetData(), response.GetSize()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet) +{ + // 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("qFileLoadAddress:")); + if (packet.GetBytesLeft() == 0) + return SendErrorResponse(68); + + std::string file_name; + packet.GetHexByteString(file_name); + + lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; + Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); + if (error.Fail()) + return SendErrorResponse(69); + + if (file_load_address == LLDB_INVALID_ADDRESS) + return SendErrorResponse(1); // File not loaded + + StreamGDBRemote response; + response.PutHex64(file_load_address); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + void GDBRemoteCommunicationServerLLGS::FlushInferiorOutput () { Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -238,8 +238,11 @@ const ArchSpec& arch, ModuleSpec &module_spec) override; - virtual size_t - LoadModules () override; + size_t + LoadModules() override; + + Error + GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override; protected: friend class ThreadGDBRemote; Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -4121,6 +4121,47 @@ return new_modules.GetSize(); } +Error +ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) +{ + is_loaded = false; + load_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("qFileLoadAddress:"); + 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 qFileLoadAddress packet failed"); + + if (response.IsErrorResponse()) + { + if (response.GetError() == 1) + { + // The file is not loaded into the inferior + is_loaded = false; + load_addr = LLDB_INVALID_ADDRESS; + return Error(); + } + + return Error("Fetching file load address from remote server returned an error"); + } + + if (response.IsNormalResponse()) + { + is_loaded = true; + load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + return Error(); + } + + return Error("Unknown error happened during sending the load address packet"); +} + class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed { public: Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.h =================================================================== --- lldb/trunk/source/Utility/StringExtractorGDBRemote.h +++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h @@ -61,6 +61,7 @@ eServerPacketType_qSpeedTest, eServerPacketType_qUserName, eServerPacketType_qGetWorkingDir, + eServerPacketType_qFileLoadAddress, eServerPacketType_QEnvironment, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, Index: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp +++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp @@ -144,6 +144,10 @@ if (PACKET_STARTS_WITH ("qEcho:")) return eServerPacketType_qEcho; break; + case 'F': + if (PACKET_STARTS_WITH ("qFileLoadAddress:")) return eServerPacketType_qFileLoadAddress; + break; + case 'G': if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName; if (PACKET_MATCHES ("qGetWorkingDir")) return eServerPacketType_qGetWorkingDir;