diff options
27 files changed, 1231 insertions, 16 deletions
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 56650582791..42904dd9eac 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -703,11 +703,25 @@ public: uint32_t GetVersion (uint32_t *versions, uint32_t num_versions); - // Load an object file from memory. + //------------------------------------------------------------------ + /// Load an object file from memory. + /// + /// If available, the size of the object file in memory may be + /// passed to avoid additional round trips to process memory. + /// If the size is not provided, a default value is used. This + /// value should be large enough to enable the ObjectFile plugins + /// to read the header of the object file without going back to the + /// process. + /// + /// @return + /// The object file loaded from memory or NULL, if the operation + /// failed (see the `error` for more information in that case). + //------------------------------------------------------------------ ObjectFile * GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, - Error &error); + Error &error, + size_t size_to_read = 512); //------------------------------------------------------------------ /// Get the symbol vendor interface for the current architecture. /// diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index e02f43f4fa8..4db423d0b0e 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -80,6 +80,24 @@ public: GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name); //------------------------------------------------------------------ + // JITLoader + //------------------------------------------------------------------ + static bool + RegisterPlugin (const ConstString &name, + const char *description, + JITLoaderCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = NULL); + + static bool + UnregisterPlugin (JITLoaderCreateInstance create_callback); + + static JITLoaderCreateInstance + GetJITLoaderCreateCallbackAtIndex (uint32_t idx); + + static JITLoaderCreateInstance + GetJITLoaderCreateCallbackForPluginName (const ConstString &name); + + //------------------------------------------------------------------ // EmulateInstruction //------------------------------------------------------------------ static bool diff --git a/lldb/include/lldb/Target/JITLoader.h b/lldb/include/lldb/Target/JITLoader.h new file mode 100644 index 00000000000..890afb15577 --- /dev/null +++ b/lldb/include/lldb/Target/JITLoader.h @@ -0,0 +1,83 @@ +//===-- JITLoader.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_JITLoader_h_ +#define liblldb_JITLoader_h_ + +#include <vector> + +#include "lldb/Core/PluginInterface.h" +#include "lldb/Target/JITLoaderList.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class JITLoader JITLoader.h "lldb/Target/JITLoader.h" +/// @brief A plug-in interface definition class for JIT loaders. +/// +/// Plugins of this kind listen for code generated at runtime in the +/// target. They are very similar to dynamic loader, with the difference +/// that they do not have information about the the target's dyld and +/// that there may be multiple JITLoader plugins per process, while +/// there is at most one DynamicLoader. +//---------------------------------------------------------------------- +class JITLoader : + public PluginInterface +{ +public: + //------------------------------------------------------------------ + /// Find a JIT loader plugin for a given process. + /// + /// Scans the installed DynamicLoader plug-ins and tries to find + /// all applicable instances for the current process. + /// + /// @param[in] process + /// The process for which to try and locate a JIT loader + /// plug-in instance. + /// + //------------------------------------------------------------------ + static void + LoadPlugins (Process *process, lldb_private::JITLoaderList &list); + + //------------------------------------------------------------------ + /// Construct with a process. + //------------------------------------------------------------------ + JITLoader (Process *process); + + virtual + ~JITLoader (); + + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + virtual void + DidAttach () = 0; + + //------------------------------------------------------------------ + /// Called after launching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// the process has stopped for the first time on launch. + //------------------------------------------------------------------ + virtual void + DidLaunch () = 0; + +protected: + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + Process* m_process; +}; + +} // namespace lldb_private + +#endif // liblldb_JITLoader_h_ diff --git a/lldb/include/lldb/Target/JITLoaderList.h b/lldb/include/lldb/Target/JITLoaderList.h new file mode 100644 index 00000000000..dea3a6f635f --- /dev/null +++ b/lldb/include/lldb/Target/JITLoaderList.h @@ -0,0 +1,57 @@ +//===-- JITLoaderList.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_JITLoaderList_h_ +#define liblldb_JITLoaderList_h_ + +#include <vector> + +#include "lldb/lldb-forward.h" +#include "lldb/Host/Mutex.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class JITLoaderList JITLoaderList.h "lldb/Target/JITLoaderList.h" +/// +/// Class used by the Process to hold a list of its JITLoaders. +//---------------------------------------------------------------------- +class JITLoaderList +{ +public: + + JITLoaderList(); + ~JITLoaderList(); + + void + Append (const lldb::JITLoaderSP &jit_loader_sp); + + void + Remove (const lldb::JITLoaderSP &jit_loader_sp); + + size_t + GetSize() const; + + lldb::JITLoaderSP + GetLoaderAtIndex (size_t idx); + + void + DidLaunch(); + + void + DidAttach(); + +private: + std::vector<lldb::JITLoaderSP> m_jit_loaders_vec; + lldb_private::Mutex m_jit_loaders_mutex; +}; + +} // namespace lldb_private + +#endif // liblldb_JITLoaderList_h_ diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index e42d89bd628..a79b3b4fcc2 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -42,6 +42,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/JITLoaderList.h" #include "lldb/Target/Memory.h" #include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" @@ -1824,6 +1825,11 @@ public: virtual DynamicLoader * GetDynamicLoader (); +protected: + virtual JITLoaderList & + GetJITLoaders (); + +public: //------------------------------------------------------------------ /// Get the system runtime plug-in for this process. /// @@ -3071,7 +3077,8 @@ public: lldb::ModuleSP ReadModuleFromMemory (const FileSpec& file_spec, - lldb::addr_t header_addr); + lldb::addr_t header_addr, + size_t size_to_read = 512); //------------------------------------------------------------------ /// Attempt to get the attributes for a region of memory in the process. @@ -3768,6 +3775,7 @@ protected: Listener &m_listener; BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend to insert in the target. std::unique_ptr<DynamicLoader> m_dyld_ap; + std::unique_ptr<JITLoaderList> m_jit_loaders_ap; std::unique_ptr<DynamicCheckerFunctions> m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use. std::unique_ptr<OperatingSystem> m_os_ap; std::unique_ptr<SystemRuntime> m_system_runtime_ap; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 43e589e3952..6c522c1d9a9 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -107,6 +107,7 @@ class Instruction; class InstructionList; class IOHandler; class IRExecutionUnit; +class JITLoader; class LanguageRuntime; class SystemRuntime; class LineTable; @@ -305,6 +306,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP; typedef std::shared_ptr<lldb_private::Instruction> InstructionSP; typedef std::shared_ptr<lldb_private::IOHandler> IOHandlerSP; + typedef std::shared_ptr<lldb_private::JITLoader> JITLoaderSP; typedef std::shared_ptr<lldb_private::LanguageRuntime> LanguageRuntimeSP; typedef std::shared_ptr<lldb_private::SystemRuntime> SystemRuntimeSP; typedef std::shared_ptr<lldb_private::LineTable> LineTableSP; diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index 5a2da8989f3..13b5bb5ad5c 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -19,6 +19,7 @@ namespace lldb_private typedef lldb::ABISP (*ABICreateInstance) (const ArchSpec &arch); typedef Disassembler* (*DisassemblerCreateInstance) (const ArchSpec &arch, const char *flavor); typedef DynamicLoader* (*DynamicLoaderCreateInstance) (Process* process, bool force); + typedef lldb::JITLoaderSP (*JITLoaderCreateInstance) (Process *process, bool force); typedef ObjectContainer* (*ObjectContainerCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length); typedef size_t (*ObjectFileGetModuleSpecifications) (const FileSpec &file, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &module_specs); typedef ObjectFile* (*ObjectFileCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec* file, lldb::offset_t file_offset, lldb::offset_t length); diff --git a/lldb/include/lldb/lldb-private-log.h b/lldb/include/lldb/lldb-private-log.h index 9d8d735dcf4..dc37ae2c7c4 100644 --- a/lldb/include/lldb/lldb-private-log.h +++ b/lldb/include/lldb/lldb-private-log.h @@ -46,6 +46,7 @@ #define LIBLLDB_LOG_OS (1u << 24) #define LIBLLDB_LOG_PLATFORM (1u << 25) #define LIBLLDB_LOG_SYSTEM_RUNTIME (1u << 26) +#define LIBLLDB_LOG_JIT_LOADER (1u << 27) #define LIBLLDB_LOG_ALL (UINT32_MAX) #define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\ LIBLLDB_LOG_THREAD |\ diff --git a/lldb/lib/Makefile b/lldb/lib/Makefile index d16ffe0a62c..c2931f68097 100644 --- a/lldb/lib/Makefile +++ b/lldb/lib/Makefile @@ -105,7 +105,8 @@ ifeq ($(HOST_OS),Linux) lldbPluginProcessLinux.a \ lldbPluginProcessPOSIX.a \ lldbPluginDynamicLoaderMacOSX.a \ - lldbPluginProcessElfCore.a + lldbPluginProcessElfCore.a \ + lldbPluginJITLoaderGDB.a endif ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD)) diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt index 33b1342ba85..de5c05c9625 100644 --- a/lldb/source/CMakeLists.txt +++ b/lldb/source/CMakeLists.txt @@ -103,6 +103,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Linux" ) lldbPluginProcessLinux lldbPluginProcessPOSIX lldbPluginProcessElfCore + lldbPluginJITLoaderGDB ) endif () diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt index 16730ac46b2..14dea983c6a 100644 --- a/lldb/source/Core/CMakeLists.txt +++ b/lldb/source/Core/CMakeLists.txt @@ -29,6 +29,8 @@ add_lldb_library(lldbCore FileSpecList.cpp History.cpp IOHandler.cpp + JITLoader.cpp + JITLoaderList.cpp Language.cpp Listener.cpp Log.cpp diff --git a/lldb/source/Core/JITLoader.cpp b/lldb/source/Core/JITLoader.cpp new file mode 100644 index 00000000000..8536d690ece --- /dev/null +++ b/lldb/source/Core/JITLoader.cpp @@ -0,0 +1,38 @@ +//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/JITLoaderList.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +void +JITLoader::LoadPlugins (Process *process, JITLoaderList &list) +{ + JITLoaderCreateInstance create_callback = NULL; + for (uint32_t idx = 0; (create_callback = PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + JITLoaderSP instance_sp(create_callback(process, false)); + if (instance_sp) + list.Append(std::move(instance_sp)); + } +} + +JITLoader::JITLoader(Process *process) : + m_process (process) +{ +} + +JITLoader::~JITLoader() +{ +} diff --git a/lldb/source/Core/JITLoaderList.cpp b/lldb/source/Core/JITLoaderList.cpp new file mode 100644 index 00000000000..a3b24c4bbfa --- /dev/null +++ b/lldb/source/Core/JITLoaderList.cpp @@ -0,0 +1,69 @@ +//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/JITLoaderList.h" + +using namespace lldb; +using namespace lldb_private; + +JITLoaderList::JITLoaderList() + : m_jit_loaders_vec(), m_jit_loaders_mutex(Mutex::eMutexTypeRecursive) +{ +} + +JITLoaderList::~JITLoaderList() +{ +} + +void +JITLoaderList::Append (const JITLoaderSP &jit_loader_sp) +{ + Mutex::Locker locker(m_jit_loaders_mutex); + m_jit_loaders_vec.push_back(jit_loader_sp); +} + +void +JITLoaderList::Remove (const JITLoaderSP &jit_loader_sp) +{ + Mutex::Locker locker(m_jit_loaders_mutex); + m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(), + m_jit_loaders_vec.end(), jit_loader_sp), + m_jit_loaders_vec.end()); +} + +size_t +JITLoaderList::GetSize() const +{ + return m_jit_loaders_vec.size(); +} + +JITLoaderSP +JITLoaderList::GetLoaderAtIndex (size_t idx) +{ + Mutex::Locker locker(m_jit_loaders_mutex); + return m_jit_loaders_vec[idx]; +} + +void +JITLoaderList::DidLaunch() +{ + Mutex::Locker locker(m_jit_loaders_mutex); + for (auto const &jit_loader : m_jit_loaders_vec) + jit_loader->DidLaunch(); +} + +void +JITLoaderList::DidAttach() +{ + Mutex::Locker locker(m_jit_loaders_mutex); + for (auto const &jit_loader : m_jit_loaders_vec) + jit_loader->DidAttach(); +} diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 6ce76dc825b..45ce08f6aab 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -284,7 +284,7 @@ Module::~Module() } ObjectFile * -Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error) +Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error, size_t size_to_read) { if (m_objfile_sp) { @@ -296,13 +296,13 @@ Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t hea if (process_sp) { m_did_load_objfile = true; - std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (512, 0)); + std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (size_to_read, 0)); Error readmem_error; const size_t bytes_read = process_sp->ReadMemory (header_addr, data_ap->GetBytes(), data_ap->GetByteSize(), readmem_error); - if (bytes_read == 512) + if (bytes_read == size_to_read) { DataBufferSP data_sp(data_ap.release()); m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp); diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index 813cec22752..b4ee07aa8ba 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -544,6 +544,116 @@ PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &n return NULL; } +#pragma mark JITLoader + + +struct JITLoaderInstance +{ + JITLoaderInstance() : + name(), + description(), + create_callback(NULL), + debugger_init_callback (NULL) + { + } + + ConstString name; + std::string description; + JITLoaderCreateInstance create_callback; + DebuggerInitializeCallback debugger_init_callback; +}; + +typedef std::vector<JITLoaderInstance> JITLoaderInstances; + + +static Mutex & +GetJITLoaderMutex () +{ + static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static JITLoaderInstances & +GetJITLoaderInstances () +{ + static JITLoaderInstances g_instances; + return g_instances; +} + + +bool +PluginManager::RegisterPlugin +( + const ConstString &name, + const char *description, + JITLoaderCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback +) +{ + if (create_callback) + { + JITLoaderInstance instance; + assert ((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + instance.debugger_init_callback = debugger_init_callback; + Mutex::Locker locker (GetJITLoaderMutex ()); + GetJITLoaderInstances ().push_back (instance); + } + return false; +} + +bool +PluginManager::UnregisterPlugin (JITLoaderCreateInstance create_callback) +{ + if (create_callback) + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->create_callback == create_callback) + { + instances.erase(pos); + return true; + } + } + } + return false; +} + +JITLoaderCreateInstance +PluginManager::GetJITLoaderCreateCallbackAtIndex (uint32_t idx) +{ + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + if (idx < instances.size()) + return instances[idx].create_callback; + return NULL; +} + +JITLoaderCreateInstance +PluginManager::GetJITLoaderCreateCallbackForPluginName (const ConstString &name) +{ + if (name) + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (name == pos->name) + return pos->create_callback; + } + } + return NULL; +} + #pragma mark EmulateInstruction @@ -1945,6 +2055,19 @@ PluginManager::DebuggerInitialize (Debugger &debugger) } } + // Initialize the JITLoader plugins + { + Mutex::Locker locker (GetJITLoaderMutex ()); + JITLoaderInstances &instances = GetJITLoaderInstances (); + + JITLoaderInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->debugger_init_callback) + pos->debugger_init_callback (debugger); + } + } + // Initialize the Platform plugins { Mutex::Locker locker (GetPlatformInstancesMutex ()); diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt index 7142405c324..6b409ef4f97 100644 --- a/lldb/source/Plugins/CMakeLists.txt +++ b/lldb/source/Plugins/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(ABI) add_subdirectory(Disassembler) add_subdirectory(DynamicLoader) add_subdirectory(Instruction) +add_subdirectory(JITLoader) add_subdirectory(LanguageRuntime) add_subdirectory(ObjectContainer) add_subdirectory(ObjectFile) diff --git a/lldb/source/Plugins/JITLoader/CMakeLists.txt b/lldb/source/Plugins/JITLoader/CMakeLists.txt new file mode 100644 index 00000000000..0f005572032 --- /dev/null +++ b/lldb/source/Plugins/JITLoader/CMakeLists.txt @@ -0,0 +1,3 @@ +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + add_subdirectory(GDB) +endif() diff --git a/lldb/source/Plugins/JITLoader/GDB/CMakeLists.txt b/lldb/source/Plugins/JITLoader/GDB/CMakeLists.txt new file mode 100644 index 00000000000..d2208c4c517 --- /dev/null +++ b/lldb/source/Plugins/JITLoader/GDB/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_NO_RTTI 1) + +include_directories(.) + +add_lldb_library(lldbPluginJITLoaderGDB + JITLoaderGDB.cpp + ) + diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp new file mode 100644 index 00000000000..73ef3151338 --- /dev/null +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -0,0 +1,383 @@ +//===-- JITLoaderGDB.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 "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Symbol/SymbolVendor.h" + +#include "JITLoaderGDB.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------ +// Debug Interface Structures +//------------------------------------------------------------------ +typedef enum +{ + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN +} jit_actions_t; + +struct jit_code_entry +{ + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; +}; + +struct jit_descriptor +{ + uint32_t version; + uint32_t action_flag; // Values are jit_action_t + struct jit_code_entry *relevant_entry; + struct jit_code_entry *first_entry; +}; + +JITLoaderGDB::JITLoaderGDB (lldb_private::Process *process) : + JITLoader(process), + m_jit_objects(), + m_jit_break_id(LLDB_INVALID_BREAK_ID) +{ + m_notification_callbacks.baton = this; + m_notification_callbacks.initialize = nullptr; + m_notification_callbacks.process_state_changed = + ProcessStateChangedCallback; + m_process->RegisterNotificationCallbacks(m_notification_callbacks); +} + +JITLoaderGDB::~JITLoaderGDB () +{ + if (LLDB_BREAK_ID_IS_VALID(m_jit_break_id)) + m_process->GetTarget().RemoveBreakpointByID (m_jit_break_id); + m_jit_break_id = LLDB_INVALID_BREAK_ID; +} + +void JITLoaderGDB::DidAttach() +{ + SetJITBreakpoint(); +} + +void JITLoaderGDB::DidLaunch() +{ + SetJITBreakpoint(); +} + +//------------------------------------------------------------------ +// Setup the JIT Breakpoint +//------------------------------------------------------------------ +void +JITLoaderGDB::SetJITBreakpoint() +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + + if ( DidSetJITBreakpoint() ) + return; + + if (log) + log->Printf("JITLoaderGDB::%s looking for JIT register hook", + __FUNCTION__); + + addr_t jit_addr = GetSymbolAddress(ConstString("__jit_debug_register_code"), + eSymbolTypeAny); + if (jit_addr == LLDB_INVALID_ADDRESS) + return; + + if (log) + log->Printf("JITLoaderGDB::%s setting JIT breakpoint", + __FUNCTION__); + + Breakpoint *bp = + m_process->GetTarget().CreateBreakpoint(jit_addr, true, false).get(); + bp->SetCallback(JITDebugBreakpointHit, this, true); + bp->SetBreakpointKind("jit-debug-register"); + m_jit_break_id = bp->GetID(); + + ReadJITDescriptor(true); +} + +bool +JITLoaderGDB::JITDebugBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, user_id_t break_loc_id) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + if (log) + log->Printf("JITLoaderGDB::%s hit JIT breakpoint", + __FUNCTION__); + JITLoaderGDB *instance = static_cast<JITLoaderGDB *>(baton); + return instance->ReadJITDescriptor(false); +} + +bool +JITLoaderGDB::ReadJITDescriptor(bool all_entries) +{ + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_JIT_LOADER)); + Target &target = m_process->GetTarget(); + ModuleList &images = target.GetImages(); + + addr_t jit_addr = GetSymbolAddress(ConstString("__jit_debug_descriptor"), + eSymbolTypeData); + if (jit_addr == LLDB_INVALID_ADDRESS) + { + if (log) + log->Printf( + "JITLoaderGDB::%s failed to find JIT descriptor address", + __FUNCTION__); + return false; + } + + jit_descriptor jit_desc; + const size_t jit_desc_size = sizeof(jit_desc); + Error error; + size_t bytes_read = + m_process->DoReadMemory(jit_addr, &jit_desc, jit_desc_size, error); + if (bytes_read != jit_desc_size || !error.Success()) + { + if (log) + log->Printf("JITLoaderGDB::%s failed to read JIT descriptor", + __FUNCTION__); + return false; + } + + jit_actions_t jit_action = (jit_actions_t)jit_desc.action_flag; + addr_t jit_relevant_entry = (addr_t)jit_desc.relevant_entry; + if (all_entries) + { + jit_action = JIT_REGISTER_FN; + jit_relevant_entry = (addr_t)jit_desc.first_entry; + } + + while (jit_relevant_entry != 0) + { + jit_code_entry jit_entry; + const size_t jit_entry_size = sizeof(jit_entry); + bytes_read = m_process->DoReadMemory(jit_relevant_entry, &jit_entry, jit_entry_size, error); + if (bytes_read != jit_entry_size || !error.Success()) + { + if (log) + log->Printf( + "JITLoaderGDB::%s failed to read JIT entry at 0x%" PRIx64, + __FUNCTION__, jit_relevant_entry); + return false; + } + + const addr_t &symbolfile_addr = (addr_t)jit_entry.symfile_addr; + const size_t &symbolfile_size = (size_t)jit_entry.symfile_size; + ModuleSP module_sp; + + if (jit_action == JIT_REGISTER_FN) + { + if (log) + log->Printf( + "JITLoaderGDB::%s registering JIT entry at 0x%" PRIx64 + " (%" PRIu64 " bytes)", + __FUNCTION__, symbolfile_addr, symbolfile_size); + + char jit_name[64]; + snprintf(jit_name, 64, "JIT(0x%" PRIx64 ")", symbolfile_addr); + module_sp = m_process->ReadModuleFromMemory( + FileSpec(jit_name, false), symbolfile_addr, symbolfile_size); + + if (module_sp && module_sp->GetObjectFile()) + { + bool changed; + m_jit_objects.insert( + std::pair<lldb::addr_t, const lldb::ModuleSP>( + symbolfile_addr, module_sp)); + module_sp->SetLoadAddress(target, 0, true, changed); + + // load the symbol table right away + module_sp->GetObjectFile()->GetSymtab(); + + images.AppendIfNeeded(module_sp); + + ModuleList module_list; + module_list.Append(module_sp); + target.ModulesDidLoad(module_list); + } + else + { + if (log) + log->Printf("JITLoaderGDB::%s failed to load module for " + "JIT entry at 0x%" PRIx64, + __FUNCTION__, symbolfile_addr); + } + } + else if (jit_action == JIT_UNREGISTER_FN) + { + if (log) + log->Printf( + "JITLoaderGDB::%s unregistering JIT entry at 0x%" PRIx64, + __FUNCTION__, symbolfile_addr); + + JITObjectMap::iterator it = m_jit_objects.find(symbolfile_addr); + if (it != m_jit_objects.end()) + { + module_sp = it->second; + ObjectFile *image_object_file = module_sp->GetObjectFile(); + if (image_object_file) + { + const SectionList *section_list = image_object_file->GetSectionList (); + if (section_list) + { + const uint32_t num_sections = section_list->GetSize(); + for (uint32_t i = 0; i<num_sections; ++i) + { + SectionSP section_sp(section_list->GetSectionAtIndex(i)); + if (section_sp) + { + target.GetSectionLoadList().SetSectionUnloaded (section_sp); + } + } + } + } + images.Remove(module_sp); + m_jit_objects.erase(it); + } + } + else if (jit_action == JIT_NOACTION) + { + // Nothing to do + } + else + { + assert(false && "Unknown jit action"); + } + + if (all_entries) + jit_relevant_entry = (addr_t)jit_entry.next_entry; + else + jit_relevant_entry = 0; + } + + return false; // Continue Running. +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +JITLoaderGDB::GetPluginNameStatic() +{ + static ConstString g_name("gdb"); + return g_name; +} + +JITLoaderSP +JITLoaderGDB::CreateInstance(Process *process, bool force) +{ + JITLoaderSP jit_loader_sp(new JITLoaderGDB(process)); + return jit_loader_sp; +} + +const char * +JITLoaderGDB::GetPluginDescriptionStatic() +{ + return "JIT loader plug-in that watches for JIT events using the GDB interface."; +} + +lldb_private::ConstString +JITLoaderGDB::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +JITLoaderGDB::GetPluginVersion() +{ + return 1; +} + +void +JITLoaderGDB::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +JITLoaderGDB::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +bool +JITLoaderGDB::DidSetJITBreakpoint() const +{ + return LLDB_BREAK_ID_IS_VALID(m_jit_break_id); +} + +void +JITLoaderGDB::ProcessStateChangedCallback(void *baton, + lldb_private::Process *process, + lldb::StateType state) +{ + JITLoaderGDB* instance = static_cast<JITLoaderGDB*>(baton); + + switch (state) + { + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + case eStateDetached: + // instance->Clear(false); + break; + + case eStateRunning: + case eStateStopped: + // Keep trying to set our JIT breakpoint each time we stop until we + // succeed + if (!instance->DidSetJITBreakpoint() && process->IsAlive()) + instance->SetJITBreakpoint(); + break; + + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + break; + } +} + +addr_t +JITLoaderGDB::GetSymbolAddress(const ConstString &name, SymbolType symbol_type) const +{ + SymbolContextList target_symbols; + Target &target = m_process->GetTarget(); + ModuleList &images = target.GetImages(); + + if (!images.FindSymbolsWithNameAndType(name, symbol_type, target_symbols)) + return LLDB_INVALID_ADDRESS; + + SymbolContext sym_ctx; + target_symbols.GetContextAtIndex(0, sym_ctx); + + const Address *jit_descriptor_addr = &sym_ctx.symbol->GetAddress(); + if (!jit_descriptor_addr || !jit_descriptor_addr->IsValid()) + return LLDB_INVALID_ADDRESS; + + const addr_t jit_addr = jit_descriptor_addr->GetLoadAddress(&target); + return jit_addr; +} diff --git a/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h new file mode 100644 index 00000000000..15b54e3695e --- /dev/null +++ b/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.h @@ -0,0 +1,100 @@ +//===-- JITLoaderGDB.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_JITLoaderGDB_h_ +#define liblldb_JITLoaderGDB_h_ + +// C Includes +// C++ Includes +#include <map> +#include <vector> +#include <string> + +#include "lldb/Target/JITLoader.h" +#include "lldb/Target/Process.h" + +class JITLoaderGDB : public lldb_private::JITLoader +{ +public: + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb::JITLoaderSP + CreateInstance (lldb_private::Process *process, bool force); + + JITLoaderGDB (lldb_private::Process *process); + + virtual + ~JITLoaderGDB (); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + //------------------------------------------------------------------ + // JITLoader interface + //------------------------------------------------------------------ + virtual void + DidAttach (); + + virtual void + DidLaunch (); + +private: + lldb::addr_t + GetSymbolAddress(const lldb_private::ConstString &name, + lldb::SymbolType symbol_type) const; + + void + SetJITBreakpoint(); + + bool + DidSetJITBreakpoint() const; + + bool + ReadJITDescriptor(bool all_entries); + + static bool + JITDebugBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + static void + ProcessStateChangedCallback(void *baton, + lldb_private::Process *process, + lldb::StateType state); + + // A collection of in-memory jitted object addresses and their corresponding modules + typedef std::map<lldb::addr_t, const lldb::ModuleSP> JITObjectMap; + JITObjectMap m_jit_objects; + + lldb::user_id_t m_jit_break_id; + lldb_private::Process::Notifications m_notification_callbacks; + +}; + +#endif diff --git a/lldb/source/Plugins/JITLoader/GDB/Makefile b/lldb/source/Plugins/JITLoader/GDB/Makefile new file mode 100644 index 00000000000..1383d9d631b --- /dev/null +++ b/lldb/source/Plugins/JITLoader/GDB/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/JITLoader/GDBJIT/Makefile ------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginJITLoaderGDB +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/Makefile b/lldb/source/Plugins/Makefile index 0ca6a69ad0f..dd7b6ad06f3 100644 --- a/lldb/source/Plugins/Makefile +++ b/lldb/source/Plugins/Makefile @@ -37,6 +37,7 @@ ifeq ($(HOST_OS),Linux) DIRS += DynamicLoader/MacOSX-DYLD DIRS += Process/Linux Process/POSIX DIRS += Process/elf-core +DIRS += JITLoader/GDB endif ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD)) diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 335090cc0c3..948e5e8a540 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -72,6 +72,18 @@ public: static unsigned RelocSymbol64(const ELFRelocation &rel); + static unsigned + RelocOffset32(const ELFRelocation &rel); + + static unsigned + RelocOffset64(const ELFRelocation &rel); + + static unsigned + RelocAddend32(const ELFRelocation &rel); + + static unsigned + RelocAddend64(const ELFRelocation &rel); + private: typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion; @@ -80,9 +92,9 @@ private: ELFRelocation::ELFRelocation(unsigned type) { - if (type == DT_REL) + if (type == DT_REL || type == SHT_REL) reloc = new ELFRel(); - else if (type == DT_RELA) + else if (type == DT_RELA || type == SHT_RELA) reloc = new ELFRela(); else { assert(false && "unexpected relocation type"); @@ -143,6 +155,42 @@ ELFRelocation::RelocSymbol64(const ELFRelocation &rel) return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>()); } +unsigned +ELFRelocation::RelocOffset32(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return rel.reloc.get<ELFRel*>()->r_offset; + else + return rel.reloc.get<ELFRela*>()->r_offset; +} + +unsigned +ELFRelocation::RelocOffset64(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return rel.reloc.get<ELFRel*>()->r_offset; + else + return rel.reloc.get<ELFRela*>()->r_offset; +} + +unsigned +ELFRelocation::RelocAddend32(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return 0; + else + return rel.reloc.get<ELFRela*>()->r_addend; +} + +unsigned +ELFRelocation::RelocAddend64(const ELFRelocation &rel) +{ + if (rel.reloc.is<ELFRel*>()) + return 0; + else + return rel.reloc.get<ELFRela*>()->r_addend; +} + } // end anonymous namespace bool @@ -261,6 +309,22 @@ ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT)) + { + const uint8_t *magic = data_sp->GetBytes(); + if (ELFHeader::MagicBytesMatch(magic)) + { + unsigned address_size = ELFHeader::AddressSizeInBytes(magic); + if (address_size == 4 || address_size == 8) + { + std::auto_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); + ArchSpec spec; + if (objfile_ap->GetArchitecture(spec) && + objfile_ap->SetModulesArchitecture(spec)) + return objfile_ap.release(); + } + } + } return NULL; } @@ -453,6 +517,19 @@ ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, m_gnu_debuglink_file.clear(); } +ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, + DataBufferSP& data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) : + ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, data_sp), + m_header(), + m_program_headers(), + m_section_headers(), + m_filespec_ap() +{ + ::memset(&m_header, 0, sizeof(m_header)); +} + ObjectFileELF::~ObjectFileELF() { } @@ -1117,8 +1194,9 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); - // No need to add symbols that have no names - if (symbol_name == NULL || symbol_name[0] == '\0') + // No need to add non-section symbols that have no names + if (symbol.getType() != STT_SECTION && + (symbol_name == NULL || symbol_name[0] == '\0')) continue; //symbol.Dump (&strm, i, &strtab_data, section_list); @@ -1228,7 +1306,7 @@ ObjectFileELF::ParseSymbols (Symtab *symtab, } uint64_t symbol_value = symbol.st_value; - if (symbol_section_sp) + if (symbol_section_sp && CalculateType() != ObjectFile::Type::eTypeObjectFile) symbol_value -= symbol_section_sp->GetFileAddress(); bool is_global = symbol.getBinding() == STB_GLOBAL; uint32_t flags = symbol.st_other << 8 | symbol.st_info; @@ -1526,6 +1604,136 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, strtab_data); } +unsigned +ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, + const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, + DataExtractor &rel_data, DataExtractor &symtab_data, + DataExtractor &debug_data, Section* rel_section) +{ + ELFRelocation rel(rel_hdr->sh_type); + lldb::addr_t offset = 0; + const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; + typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); + reloc_info_fn reloc_type; + reloc_info_fn reloc_symbol; + + if (hdr->Is32Bit()) + { + reloc_type = ELFRelocation::RelocType32; + reloc_symbol = ELFRelocation::RelocSymbol32; + } + else + { + reloc_type = ELFRelocation::RelocType64; + reloc_symbol = ELFRelocation::RelocSymbol64; + } + + for (unsigned i = 0; i < num_relocations; ++i) + { + if (rel.Parse(rel_data, &offset) == false) + break; + + Symbol* symbol = NULL; + + if (hdr->Is32Bit()) + { + switch (reloc_type(rel)) { + case R_386_32: + case R_386_PC32: + default: + assert(false && "unexpected relocation type"); + } + } else { + switch (reloc_type(rel)) { + case R_X86_64_64: + { + symbol = symtab->FindSymbolByID(reloc_symbol(rel)); + if (symbol) + { + addr_t value = symbol->GetAddress().GetFileAddress(); + DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer(); + uint64_t* dst = reinterpret_cast<uint64_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); + *dst = value + ELFRelocation::RelocAddend64(rel); + } + break; + } + case R_X86_64_32: + case R_X86_64_32S: + { + symbol = symtab->FindSymbolByID(reloc_symbol(rel)); + if (symbol) + { + addr_t value = symbol->GetAddress().GetFileAddress(); + value += ELFRelocation::RelocAddend32(rel); + assert((reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) || + (reloc_type(rel) == R_X86_64_32S && + ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + uint32_t truncated_addr = (value & 0xFFFFFFFF); + DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer(); + uint32_t* dst = reinterpret_cast<uint32_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel)); + *dst = truncated_addr; + } + break; + } + case R_X86_64_PC32: + default: + assert(false && "unexpected relocation type"); + } + } + } + + return 0; +} + +unsigned +ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, user_id_t rel_id) +{ + assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); + + // Parse in the section list if needed. + SectionList *section_list = GetSectionList(); + if (!section_list) + return 0; + + // Section ID's are ones based. + user_id_t symtab_id = rel_hdr->sh_link + 1; + user_id_t debug_id = rel_hdr->sh_info + 1; + + const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); + if (!symtab_hdr) + return 0; + + const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id); + if (!debug_hdr) + return 0; + + Section *rel = section_list->FindSectionByID(rel_id).get(); + if (!rel) + return 0; + + Section *symtab = section_list->FindSectionByID(symtab_id).get(); + if (!symtab) + return 0; + + Section *debug = section_list->FindSectionByID(debug_id).get(); + if (!debug) + return 0; + + DataExtractor rel_data; + DataExtractor symtab_data; + DataExtractor debug_data; + + if (ReadSectionData(rel, rel_data) && + ReadSectionData(symtab, symtab_data) && + ReadSectionData(debug, debug_data)) + { + RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, debug_hdr, + rel_data, symtab_data, debug_data, debug); + } + + return 0; +} + Symtab * ObjectFileELF::GetSymtab() { @@ -1588,6 +1796,25 @@ ObjectFileELF::GetSymtab() } } } + + for (SectionHeaderCollIter I = m_section_headers.begin(); + I != m_section_headers.end(); ++I) + { + if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL) + { + if (CalculateType() == eTypeObjectFile) + { + const char *section_name = I->section_name.AsCString(""); + if (strstr(section_name, ".rela.debug") || + strstr(section_name, ".rel.debug")) + { + const ELFSectionHeader &reloc_header = *I; + user_id_t reloc_id = SectionIndex(I); + RelocateDebugSections(&reloc_header, reloc_id); + } + } + } + } return m_symtab_ap.get(); } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 9b7c073d902..44b40a4f123 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -191,6 +191,11 @@ private: lldb::offset_t offset, lldb::offset_t length); + ObjectFileELF (const lldb::ModuleSP &module_sp, + lldb::DataBufferSP& data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; @@ -303,6 +308,32 @@ private: const ELFSectionHeaderInfo *rela_hdr, lldb::user_id_t section_id); + /// Relocates debug sections + unsigned + RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, lldb::user_id_t rel_id); + + unsigned + RelocateSection(lldb_private::Symtab* symtab, const elf::ELFHeader *hdr, const elf::ELFSectionHeader *rel_hdr, + const elf::ELFSectionHeader *symtab_hdr, const elf::ELFSectionHeader *debug_hdr, + lldb_private::DataExtractor &rel_data, lldb_private::DataExtractor &symtab_data, + lldb_private::DataExtractor &debug_data, lldb_private::Section* rel_section); + + /// Loads the section name string table into m_shstr_data. Returns the + /// number of bytes constituting the table. + size_t + GetSectionHeaderStringTable(); + + /// Utility method for looking up a section given its name. Returns the + /// index of the corresponding section or zero if no section with the given + /// name can be found (note that section indices are always 1 based, and so + /// section index 0 is never valid). + lldb::user_id_t + GetSectionIndexByName(const char *name); + + // Returns the ID of the first section that has the given type. + lldb::user_id_t + GetSectionIndexByType(unsigned type); + /// Returns the section header with the given id or NULL. const ELFSectionHeaderInfo * GetSectionHeaderByIndex(lldb::user_id_t id); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index cc4fc83b2ad..2899ef7d2d3 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -30,6 +30,7 @@ #include "lldb/Host/Terminal.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/JITLoader.h" #include "lldb/Target/OperatingSystem.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/CPPLanguageRuntime.h" @@ -1154,6 +1155,7 @@ Process::Finalize() m_os_ap.reset(); m_system_runtime_ap.reset(); m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); m_thread_list_real.Destroy(); m_thread_list.Destroy(); m_extended_thread_list.Destroy(); @@ -2929,13 +2931,14 @@ Process::DeallocateMemory (addr_t ptr) ModuleSP Process::ReadModuleFromMemory (const FileSpec& file_spec, - lldb::addr_t header_addr) + lldb::addr_t header_addr, + size_t size_to_read) { ModuleSP module_sp (new Module (file_spec, ArchSpec())); if (module_sp) { Error error; - ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error); + ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read); if (objfile) return module_sp; } @@ -2988,6 +2991,7 @@ Process::Launch (ProcessLaunchInfo &launch_info) Error error; m_abi_sp.reset(); m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); m_system_runtime_ap.reset(); m_os_ap.reset(); m_process_input_reader.reset(); @@ -3064,6 +3068,8 @@ Process::Launch (ProcessLaunchInfo &launch_info) if (dyld) dyld->DidLaunch(); + GetJITLoaders().DidLaunch(); + SystemRuntime *system_runtime = GetSystemRuntime (); if (system_runtime) system_runtime->DidLaunch(); @@ -3110,6 +3116,8 @@ Process::LoadCore () DynamicLoader *dyld = GetDynamicLoader (); if (dyld) dyld->DidAttach(); + + GetJITLoaders().DidAttach(); SystemRuntime *system_runtime = GetSystemRuntime (); if (system_runtime) @@ -3133,6 +3141,17 @@ Process::GetDynamicLoader () return m_dyld_ap.get(); } +JITLoaderList & +Process::GetJITLoaders () +{ + if (!m_jit_loaders_ap) + { + m_jit_loaders_ap.reset(new JITLoaderList()); + JITLoader::LoadPlugins(this, *m_jit_loaders_ap); + } + return *m_jit_loaders_ap; +} + SystemRuntime * Process::GetSystemRuntime () { @@ -3203,6 +3222,7 @@ Process::Attach (ProcessAttachInfo &attach_info) m_abi_sp.reset(); m_process_input_reader.reset(); m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); m_system_runtime_ap.reset(); m_os_ap.reset(); @@ -3376,6 +3396,8 @@ Process::CompleteAttach () if (dyld) dyld->DidAttach(); + GetJITLoaders().DidAttach(); + SystemRuntime *system_runtime = GetSystemRuntime (); if (system_runtime) system_runtime->DidAttach(); @@ -3546,7 +3568,7 @@ Process::Halt (bool clear_thread_plans) // Wait for 1 second for the process to stop. TimeValue timeout_time; timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds(1); + timeout_time.OffsetWithSeconds(10); bool got_event = halt_listener.WaitForEvent (&timeout_time, event_sp); StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); @@ -5957,6 +5979,7 @@ Process::DidExec () m_system_runtime_ap.reset(); m_os_ap.reset(); m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); m_image_tokens.clear(); m_allocated_memory_cache.Clear(); m_language_runtimes.clear(); diff --git a/lldb/source/lldb-log.cpp b/lldb/source/lldb-log.cpp index 12ec3a546e1..d374b590089 100644 --- a/lldb/source/lldb-log.cpp +++ b/lldb/source/lldb-log.cpp @@ -145,6 +145,7 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm) else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES; else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP; else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS; + else if (0 == ::strcasecmp(arg, "jit")) flag_bits &= ~LIBLLDB_LOG_JIT_LOADER; else { feedback_strm->Printf ("error: unrecognized log category '%s'\n", arg); @@ -220,6 +221,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits |= LIBLLDB_LOG_UNWIND; else if (0 == ::strcasecmp(arg, "verbose")) flag_bits |= LIBLLDB_LOG_VERBOSE; else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits |= LIBLLDB_LOG_WATCHPOINTS; + else if (0 == ::strcasecmp(arg, "jit")) flag_bits |= LIBLLDB_LOG_JIT_LOADER; else { feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); @@ -267,5 +269,6 @@ lldb_private::ListLogCategories (Stream *strm) " types - log type system related activities\n" " unwind - log stack unwind activities\n" " verbose - enable verbose logging\n" - " watch - log watchpoint related activities\n"); + " watch - log watchpoint related activities\n" + " jit - log JIT events in the target\n"); } diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index 4817e7f2b44..c0a8545f504 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -72,6 +72,7 @@ #if defined (__linux__) #include "Plugins/Process/Linux/ProcessLinux.h" +#include "Plugins/JITLoader/GDB/JITLoaderGDB.h" #endif #if defined (__FreeBSD__) @@ -149,6 +150,7 @@ lldb_private::Initialize () // Linux hosted plugins //---------------------------------------------------------------------- ProcessLinux::Initialize(); + JITLoaderGDB::Initialize(); #endif #if defined (__FreeBSD__) ProcessFreeBSD::Initialize(); @@ -231,6 +233,7 @@ lldb_private::Terminate () #if defined (__linux__) ProcessLinux::Terminate(); + JITLoaderGDB::Terminate(); #endif #if defined (__FreeBSD__) |