1//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef liblldb_Rendezvous_H_
11#define liblldb_Rendezvous_H_
12
13// C Includes
14// C++ Includes
15#include <list>
16#include <string>
17
18// Other libraries and framework includes
19#include "lldb/lldb-defines.h"
20#include "lldb/lldb-types.h"
21
22namespace lldb_private {
23class Process;
24}
25
26/// @class DYLDRendezvous
27/// @brief Interface to the runtime linker.
28///
29/// A structure is present in a processes memory space which is updated by the
30/// runtime liker each time a module is loaded or unloaded.  This class provides
31/// an interface to this structure and maintains a consistent snapshot of the
32/// currently loaded modules.
33class DYLDRendezvous {
34
35    // This structure is used to hold the contents of the debug rendezvous
36    // information (struct r_debug) as found in the inferiors memory.  Note that
37    // the layout of this struct is not binary compatible, it is simply large
38    // enough to hold the information on both 32 and 64 bit platforms.
39    struct Rendezvous {
40        uint64_t     version;
41        lldb::addr_t map_addr;
42        lldb::addr_t brk;
43        uint64_t     state;
44        lldb::addr_t ldbase;
45
46        Rendezvous()
47            : version(0), map_addr(0), brk(0), state(0), ldbase(0) { }
48    };
49
50public:
51    DYLDRendezvous(lldb_private::Process *process);
52
53    /// Update the internal snapshot of runtime linker rendezvous and recompute
54    /// the currently loaded modules.
55    ///
56    /// This method should be called once one start up, then once each time the
57    /// runtime linker enters the function given by GetBreakAddress().
58    ///
59    /// @returns true on success and false on failure.
60    ///
61    /// @see GetBreakAddress().
62    bool
63    Resolve();
64
65    /// @returns true if this rendezvous has been located in the inferiors
66    /// address space and false otherwise.
67    bool
68    IsValid();
69
70    /// @returns the address of the rendezvous structure in the inferiors
71    /// address space.
72    lldb::addr_t
73    GetRendezvousAddress() const { return m_rendezvous_addr; }
74
75    /// @returns the version of the rendezvous protocol being used.
76    uint64_t
77    GetVersion() const { return m_current.version; }
78
79    /// @returns address in the inferiors address space containing the linked
80    /// list of shared object descriptors.
81    lldb::addr_t
82    GetLinkMapAddress() const { return m_current.map_addr; }
83
84    /// A breakpoint should be set at this address and Resolve called on each
85    /// hit.
86    ///
87    /// @returns the address of a function called by the runtime linker each
88    /// time a module is loaded/unloaded, or about to be loaded/unloaded.
89    ///
90    /// @see Resolve()
91    lldb::addr_t
92    GetBreakAddress() const { return m_current.brk; }
93
94    /// Returns the current state of the rendezvous structure.
95    uint64_t
96    GetState() const { return m_current.state; }
97
98    /// @returns the base address of the runtime linker in the inferiors address
99    /// space.
100    lldb::addr_t
101    GetLDBase() const { return m_current.ldbase; }
102
103    /// @returns true if modules have been loaded into the inferior since the
104    /// last call to Resolve().
105    bool
106    ModulesDidLoad() const { return !m_added_soentries.empty(); }
107
108    /// @returns true if modules have been unloaded from the inferior since the
109    /// last call to Resolve().
110    bool
111    ModulesDidUnload() const { return !m_removed_soentries.empty(); }
112
113    void
114    DumpToLog(lldb_private::Log *log) const;
115
116    /// @brief Constants describing the state of the rendezvous.
117    ///
118    /// @see GetState().
119    enum RendezvousState {
120        eConsistent,
121        eAdd,
122        eDelete
123    };
124
125    /// @brief Structure representing the shared objects currently loaded into
126    /// the inferior process.
127    ///
128    /// This object is a rough analogue to the struct link_map object which
129    /// actually lives in the inferiors memory.
130    struct SOEntry {
131        lldb::addr_t base_addr; ///< Base address of the loaded object.
132        lldb::addr_t path_addr; ///< String naming the shared object.
133        lldb::addr_t dyn_addr;  ///< Dynamic section of shared object.
134        lldb::addr_t next;      ///< Address of next so_entry.
135        lldb::addr_t prev;      ///< Address of previous so_entry.
136        std::string  path;      ///< File name of shared object.
137
138        SOEntry() { clear(); }
139
140        bool operator ==(const SOEntry &entry) {
141            return this->path == entry.path;
142        }
143
144        void clear() {
145            base_addr = 0;
146            path_addr = 0;
147            dyn_addr  = 0;
148            next = 0;
149            prev = 0;
150            path.clear();
151        }
152    };
153
154protected:
155    typedef std::list<SOEntry> SOEntryList;
156
157public:
158    typedef SOEntryList::const_iterator iterator;
159
160    /// Iterators over all currently loaded modules.
161    iterator begin() const { return m_soentries.begin(); }
162    iterator end() const { return m_soentries.end(); }
163
164    /// Iterators over all modules loaded into the inferior since the last call
165    /// to Resolve().
166    iterator loaded_begin() const { return m_added_soentries.begin(); }
167    iterator loaded_end() const { return m_added_soentries.end(); }
168
169    /// Iterators over all modules unloaded from the inferior since the last
170    /// call to Resolve().
171    iterator unloaded_begin() const { return m_removed_soentries.begin(); }
172    iterator unloaded_end() const { return m_removed_soentries.end(); }
173
174protected:
175    lldb_private::Process *m_process;
176
177    // Cached copy of executable pathname
178    char m_exe_path[PATH_MAX];
179
180    /// Location of the r_debug structure in the inferiors address space.
181    lldb::addr_t m_rendezvous_addr;
182
183    /// Current and previous snapshots of the rendezvous structure.
184    Rendezvous m_current;
185    Rendezvous m_previous;
186
187    /// List of SOEntry objects corresponding to the current link map state.
188    SOEntryList m_soentries;
189
190    /// List of SOEntry's added to the link map since the last call to Resolve().
191    SOEntryList m_added_soentries;
192
193    /// List of SOEntry's removed from the link map since the last call to
194    /// Resolve().
195    SOEntryList m_removed_soentries;
196
197    /// Reads @p size bytes from the inferiors address space starting at @p
198    /// addr.
199    ///
200    /// @returns addr + size if the read was successful and false otherwise.
201    lldb::addr_t
202    ReadMemory(lldb::addr_t addr, void *dst, size_t size);
203
204    /// Reads a null-terminated C string from the memory location starting at @p
205    /// addr.
206    std::string
207    ReadStringFromMemory(lldb::addr_t addr);
208
209    /// Reads an SOEntry starting at @p addr.
210    bool
211    ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
212
213    /// Updates the current set of SOEntries, the set of added entries, and the
214    /// set of removed entries.
215    bool
216    UpdateSOEntries();
217
218    bool
219    UpdateSOEntriesForAddition();
220
221    bool
222    UpdateSOEntriesForDeletion();
223
224    /// Reads the current list of shared objects according to the link map
225    /// supplied by the runtime linker.
226    bool
227    TakeSnapshot(SOEntryList &entry_list);
228};
229
230#endif
231