brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.3 KiB · b8bdf78 Raw
370 lines · c
1//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H10#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H11 12#include <list>13#include <string>14 15#include "lldb/Utility/FileSpec.h"16#include "lldb/lldb-defines.h"17#include "lldb/lldb-types.h"18 19#include "lldb/Core/LoadedModuleInfoList.h"20 21using lldb_private::LoadedModuleInfoList;22 23namespace lldb_private {24class Log;25class Process;26}27 28/// \class DYLDRendezvous29/// Interface to the runtime linker.30///31/// A structure is present in a processes memory space which is updated by the32/// dynamic linker each time a module is loaded or unloaded.  This class33/// provides an interface to this structure and maintains a consistent34/// snapshot of the currently loaded modules.35///36/// In the dynamic loader sources, this structure has a type of "r_debug" and37/// the name of the structure us "_r_debug". The structure looks like:38///39/// struct r_debug {40///     // Version number for this protocol.41///     int r_version;42///     // Head of the chain of loaded objects.43///     struct link_map *r_map;44///     // The address the debugger should set a breakpoint at in order to get45///     // notified when shared libraries are added or removed46///     uintptr_t r_brk;47///     // This state value describes the mapping change taking place when the48///     // 'r_brk' address is called.49///     enum {50///       RT_CONSISTENT, // Mapping change is complete.51///       RT_ADD,        // Beginning to add a new object.52///       RT_DELETE,     // Beginning to remove an object mapping.53///     } r_state;54///     // Base address the linker is loaded at.55///     uintptr_t r_ldbase;56///   };57///58/// The dynamic linker then defines a global variable using this type named59/// "_r_debug":60///61///   r_debug _r_debug;62///63/// The DYLDRendezvous class defines a local version of this structure named64/// DYLDRendezvous::Rendezvous. See the definition inside the class definition65/// for DYLDRendezvous.66///67/// This structure can be located by looking through the .dynamic section in68/// the main executable and finding the DT_DEBUG tag entry. This value starts69/// out with a value of zero when the program first is initially loaded, but70/// the address of the "_r_debug" structure from ld.so is filled in by the71/// dynamic loader during program initialization code in ld.so prior to loading72/// or unloading and shared libraries.73///74/// The dynamic loader will update this structure as shared libraries are75/// loaded and will call a specific function that LLDB knows to set a76/// breakpoint on (from _r_debug.r_brk) so LLDB will find out when shared77/// libraries are loaded or unloaded. Each time this breakpoint is hit, LLDB78/// looks at the contents of this structure and the contents tell LLDB what79/// needs to be done.80///81/// Currently we expect the "state" in this structure to change as things82/// happen.83///84/// When any shared libraries are loaded the following happens:85/// - _r_debug.r_map is updated with the new shared libraries. This is a86///   doubly linked list of "link_map *" entries.87/// - _r_debug.r_state is set to RT_ADD and the debugger notification88///   function is called notifying the debugger that shared libraries are89///   about to be added, but are not yet ready for use.90/// - Once the the shared libraries are fully loaded, _r_debug.r_state is set91///   to RT_CONSISTENT and the debugger notification function is called again92///   notifying the debugger that shared libraries are ready for use.93///   DYLDRendezvous must remember that the previous state was RT_ADD when it94///   receives a RT_CONSISTENT in order to know to add libraries95///96/// When any shared libraries are unloaded the following happens:97/// - _r_debug.r_map is updated and the unloaded libraries are removed.98/// - _r_debug.r_state is set to RT_DELETE and the debugger notification99///   function is called notifying the debugger that shared libraries are100///   about to be removed.101/// - Once the the shared libraries are removed _r_debug.r_state is set to102///   RT_CONSISTENT and the debugger notification function is called again103///   notifying the debugger that shared libraries have been removed.104///   DYLDRendezvous must remember that the previous state was RT_DELETE when105///   it receives a RT_CONSISTENT in order to know to remove libraries106///107class DYLDRendezvous {108 109  // This structure is used to hold the contents of the debug rendezvous110  // information (struct r_debug) as found in the inferiors memory.  Note that111  // the layout of this struct is not binary compatible, it is simply large112  // enough to hold the information on both 32 and 64 bit platforms.113  struct Rendezvous {114    uint64_t version = 0;115    lldb::addr_t map_addr = 0;116    lldb::addr_t brk = 0;117    uint64_t state = 0;118    lldb::addr_t ldbase = 0;119 120    Rendezvous() = default;121 122    void DumpToLog(lldb_private::Log *log, const char *label);123  };124 125  /// Locates the address of the rendezvous structure.  It updates126  /// m_executable_interpreter if address is extracted from _r_debug.127  ///128  /// \returns address on success and LLDB_INVALID_ADDRESS on failure.129  lldb::addr_t ResolveRendezvousAddress();130 131public:132  // Various metadata supplied by the inferior's threading library to describe133  // the per-thread state.134  struct ThreadInfo {135    bool valid;             // whether we read valid metadata136    uint32_t dtv_offset;    // offset of DTV pointer within pthread137    uint32_t dtv_slot_size; // size of one DTV slot138    uint32_t modid_offset;  // offset of module ID within link_map139    uint32_t tls_offset;    // offset of TLS pointer within DTV slot140  };141 142  DYLDRendezvous(lldb_private::Process *process);143 144  /// Update the cached executable path.145  void UpdateExecutablePath();146 147  /// Update the internal snapshot of runtime linker rendezvous and recompute148  /// the currently loaded modules.149  ///150  /// This method should be called once one start up, then once each time the151  /// runtime linker enters the function given by GetBreakAddress().152  ///153  /// \returns true on success and false on failure.154  ///155  /// \see GetBreakAddress().156  bool Resolve();157 158  /// \returns true if this rendezvous has been located in the inferiors159  /// address space and false otherwise.160  bool IsValid();161 162  /// \returns the address of the rendezvous structure in the inferiors163  /// address space.164  lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }165 166  /// \returns the version of the rendezvous protocol being used.167  uint64_t GetVersion() const { return m_current.version; }168 169  /// \returns address in the inferiors address space containing the linked170  /// list of shared object descriptors.171  lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }172 173  /// A breakpoint should be set at this address and Resolve called on each174  /// hit.175  ///176  /// \returns the address of a function called by the runtime linker each177  /// time a module is loaded/unloaded, or about to be loaded/unloaded.178  ///179  /// \see Resolve()180  lldb::addr_t GetBreakAddress() const { return m_current.brk; }181 182  /// Returns the current state of the rendezvous structure.183  uint64_t GetState() const { return m_current.state; }184 185  /// \returns the base address of the runtime linker in the inferiors address186  /// space.187  lldb::addr_t GetLDBase() const { return m_current.ldbase; }188 189  /// \returns the thread layout metadata from the inferiors thread library.190  const ThreadInfo &GetThreadInfo();191 192  /// \returns true if modules have been loaded into the inferior since the193  /// last call to Resolve().194  bool ModulesDidLoad() const { return !m_added_soentries.empty(); }195 196  /// \returns true if modules have been unloaded from the inferior since the197  /// last call to Resolve().198  bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }199 200  void DumpToLog(lldb_private::Log *log) const;201 202  /// Constants describing the state of the rendezvous.203  ///204  /// These values are defined to match the r_debug.r_state enum from the205  /// actual dynamic loader sources.206  ///207  /// \see GetState().208  enum RendezvousState {209    eConsistent, // RT_CONSISTENT210    eAdd,        // RT_ADD211    eDelete      // RT_DELETE212  };213 214  /// Structure representing the shared objects currently loaded into the215  /// inferior process.216  ///217  /// This object is a rough analogue to the struct link_map object which218  /// actually lives in the inferiors memory.219  struct SOEntry {220    lldb::addr_t link_addr;           ///< Address of this link_map.221    lldb::addr_t base_addr;           ///< Base address of the loaded object.222    lldb::addr_t path_addr;           ///< String naming the shared object.223    lldb::addr_t dyn_addr;            ///< Dynamic section of shared object.224    lldb::addr_t next;                ///< Address of next so_entry.225    lldb::addr_t prev;                ///< Address of previous so_entry.226    lldb_private::FileSpec file_spec; ///< File spec of shared object.227 228    SOEntry() { clear(); }229 230    bool operator==(const SOEntry &entry) {231      return file_spec == entry.file_spec;232    }233 234    void clear() {235      link_addr = 0;236      base_addr = 0;237      path_addr = 0;238      dyn_addr = 0;239      next = 0;240      prev = 0;241      file_spec.Clear();242    }243  };244 245protected:246  typedef std::list<SOEntry> SOEntryList;247 248public:249  typedef SOEntryList::const_iterator iterator;250 251  /// Iterators over all currently loaded modules.252  iterator begin() const { return m_soentries.begin(); }253  iterator end() const { return m_soentries.end(); }254 255  /// Iterators over all modules loaded into the inferior since the last call256  /// to Resolve().257  iterator loaded_begin() const { return m_added_soentries.begin(); }258  iterator loaded_end() const { return m_added_soentries.end(); }259 260  /// Iterators over all modules unloaded from the inferior since the last261  /// call to Resolve().262  iterator unloaded_begin() const { return m_removed_soentries.begin(); }263  iterator unloaded_end() const { return m_removed_soentries.end(); }264 265protected:266  lldb_private::Process *m_process;267 268  // Cached copy of executable file spec269  lldb_private::FileSpec m_exe_file_spec;270 271  /// Location of the r_debug structure in the inferiors address space.272  lldb::addr_t m_rendezvous_addr;273 274  // True if the main program is the dynamic linker/loader/program interpreter.275  bool m_executable_interpreter;276 277  /// Current and previous snapshots of the rendezvous structure.278  Rendezvous m_current;279  Rendezvous m_previous;280 281  /// List of currently loaded SO modules282  LoadedModuleInfoList m_loaded_modules;283 284  /// List of SOEntry objects corresponding to the current link map state.285  SOEntryList m_soentries;286 287  /// List of SOEntry's added to the link map since the last call to288  /// Resolve().289  SOEntryList m_added_soentries;290 291  /// List of SOEntry's removed from the link map since the last call to292  /// Resolve().293  SOEntryList m_removed_soentries;294 295  /// Threading metadata read from the inferior.296  ThreadInfo m_thread_info;297 298  /// Reads an unsigned integer of \p size bytes from the inferior's address299  /// space starting at \p addr.300  ///301  /// \returns addr + size if the read was successful and false otherwise.302  lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);303 304  /// Reads an address from the inferior's address space starting at \p addr.305  ///306  /// \returns addr + target address size if the read was successful and307  /// 0 otherwise.308  lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);309 310  /// Reads a null-terminated C string from the memory location starting at @p311  /// addr.312  std::string ReadStringFromMemory(lldb::addr_t addr);313 314  /// Reads an SOEntry starting at \p addr.315  bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);316 317  /// Updates the current set of SOEntries, the set of added entries, and the318  /// set of removed entries.319  bool UpdateSOEntries();320 321  /// Same as UpdateSOEntries but it gets the list of loaded modules from the322  /// remote debug server (faster when supported).323  bool UpdateSOEntriesFromRemote();324 325  bool FillSOEntryFromModuleInfo(326      LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry);327 328  bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);329 330  bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list);331 332  bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);333 334  bool AddSOEntries();335 336  bool RemoveSOEntries();337 338  void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);339 340  void UpdateFileSpecIfNecessary(SOEntry &entry);341 342  bool SOEntryIsMainExecutable(const SOEntry &entry);343 344  /// Reads the current list of shared objects according to the link map345  /// supplied by the runtime linker.346  bool TakeSnapshot(SOEntryList &entry_list);347 348  enum PThreadField { eSize, eNElem, eOffset };349 350  bool FindMetadata(const char *name, PThreadField field, uint32_t &value);351 352  bool IsCoreFile() const;353 354  enum RendezvousAction {355    eNoAction,356    eTakeSnapshot,357    eAddModules,358    eRemoveModules359  };360 361  static const char *StateToCStr(RendezvousState state);362  static const char *ActionToCStr(RendezvousAction action);363 364  /// Returns the current action to be taken given the current and previous365  /// state366  RendezvousAction GetAction() const;367};368 369#endif370