DYLDRendezvous.h revision 296417
1238384Sjkim//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===//
2238384Sjkim//
3238384Sjkim//                     The LLVM Compiler Infrastructure
4238384Sjkim//
5238384Sjkim// This file is distributed under the University of Illinois Open Source
6238384Sjkim// License. See LICENSE.TXT for details.
7238384Sjkim//
8238384Sjkim//===----------------------------------------------------------------------===//
9238384Sjkim
10238384Sjkim#ifndef liblldb_Rendezvous_H_
11238384Sjkim#define liblldb_Rendezvous_H_
12238384Sjkim
13238384Sjkim// C Includes
14238384Sjkim// C++ Includes
15238384Sjkim#include <list>
16238384Sjkim#include <string>
17238384Sjkim
18238384Sjkim// Other libraries and framework includes
19238384Sjkim#include "lldb/lldb-defines.h"
20238384Sjkim#include "lldb/lldb-types.h"
21238384Sjkim#include "lldb/Host/FileSpec.h"
22238384Sjkim
23238384Sjkim#include "lldb/Core/LoadedModuleInfoList.h"
24238384Sjkim
25238384Sjkimusing lldb_private::LoadedModuleInfoList;
26238384Sjkim
27238384Sjkimnamespace lldb_private {
28238384Sjkimclass Process;
29238384Sjkim}
30238384Sjkim
31238384Sjkim/// @class DYLDRendezvous
32238384Sjkim/// @brief Interface to the runtime linker.
33238384Sjkim///
34238384Sjkim/// A structure is present in a processes memory space which is updated by the
35238384Sjkim/// runtime liker each time a module is loaded or unloaded.  This class provides
36246772Sjkim/// an interface to this structure and maintains a consistent snapshot of the
37238384Sjkim/// currently loaded modules.
38238384Sjkimclass DYLDRendezvous {
39238384Sjkim
40238384Sjkim    // This structure is used to hold the contents of the debug rendezvous
41238384Sjkim    // information (struct r_debug) as found in the inferiors memory.  Note that
42238384Sjkim    // the layout of this struct is not binary compatible, it is simply large
43238384Sjkim    // enough to hold the information on both 32 and 64 bit platforms.
44238384Sjkim    struct Rendezvous {
45238384Sjkim        uint64_t     version;
46238384Sjkim        lldb::addr_t map_addr;
47238384Sjkim        lldb::addr_t brk;
48238384Sjkim        uint64_t     state;
49238384Sjkim        lldb::addr_t ldbase;
50238384Sjkim
51238384Sjkim        Rendezvous()
52238384Sjkim            : version(0), map_addr(0), brk(0), state(0), ldbase(0) { }
53238384Sjkim    };
54238384Sjkim
55238384Sjkimpublic:
56238384Sjkim    // Various metadata supplied by the inferior's threading library to describe
57238384Sjkim    // the per-thread state.
58238384Sjkim    struct ThreadInfo {
59238384Sjkim        bool     valid;         // whether we read valid metadata
60238384Sjkim        uint32_t dtv_offset;    // offset of DTV pointer within pthread
61238384Sjkim        uint32_t dtv_slot_size; // size of one DTV slot
62238384Sjkim        uint32_t modid_offset;  // offset of module ID within link_map
63238384Sjkim        uint32_t tls_offset;    // offset of TLS pointer within DTV slot
64238384Sjkim    };
65238384Sjkim
66238384Sjkim    DYLDRendezvous(lldb_private::Process *process);
67238384Sjkim
68238384Sjkim    /// Update the internal snapshot of runtime linker rendezvous and recompute
69238384Sjkim    /// the currently loaded modules.
70238384Sjkim    ///
71238384Sjkim    /// This method should be called once one start up, then once each time the
72238384Sjkim    /// runtime linker enters the function given by GetBreakAddress().
73238384Sjkim    ///
74238384Sjkim    /// @returns true on success and false on failure.
75238384Sjkim    ///
76238384Sjkim    /// @see GetBreakAddress().
77238384Sjkim    bool
78238384Sjkim    Resolve();
79238384Sjkim
80238384Sjkim    /// @returns true if this rendezvous has been located in the inferiors
81238384Sjkim    /// address space and false otherwise.
82238384Sjkim    bool
83238384Sjkim    IsValid();
84238384Sjkim
85238384Sjkim    /// @returns the address of the rendezvous structure in the inferiors
86238384Sjkim    /// address space.
87238384Sjkim    lldb::addr_t
88238384Sjkim    GetRendezvousAddress() const { return m_rendezvous_addr; }
89238384Sjkim
90238384Sjkim    /// @returns the version of the rendezvous protocol being used.
91238384Sjkim    uint64_t
92238384Sjkim    GetVersion() const { return m_current.version; }
93238384Sjkim
94238384Sjkim    /// @returns address in the inferiors address space containing the linked
95238384Sjkim    /// list of shared object descriptors.
96238384Sjkim    lldb::addr_t
97238384Sjkim    GetLinkMapAddress() const { return m_current.map_addr; }
98238384Sjkim
99238384Sjkim    /// A breakpoint should be set at this address and Resolve called on each
100238384Sjkim    /// hit.
101238384Sjkim    ///
102238384Sjkim    /// @returns the address of a function called by the runtime linker each
103238384Sjkim    /// time a module is loaded/unloaded, or about to be loaded/unloaded.
104238384Sjkim    ///
105238384Sjkim    /// @see Resolve()
106238384Sjkim    lldb::addr_t
107238384Sjkim    GetBreakAddress() const { return m_current.brk; }
108238384Sjkim
109238384Sjkim    /// Returns the current state of the rendezvous structure.
110238384Sjkim    uint64_t
111238384Sjkim    GetState() const { return m_current.state; }
112238384Sjkim
113238384Sjkim    /// @returns the base address of the runtime linker in the inferiors address
114238384Sjkim    /// space.
115238384Sjkim    lldb::addr_t
116238384Sjkim    GetLDBase() const { return m_current.ldbase; }
117238384Sjkim
118238384Sjkim    /// @returns the thread layout metadata from the inferiors thread library.
119238384Sjkim    const ThreadInfo&
120238384Sjkim    GetThreadInfo();
121238384Sjkim
122238384Sjkim    /// @returns true if modules have been loaded into the inferior since the
123238384Sjkim    /// last call to Resolve().
124238384Sjkim    bool
125238384Sjkim    ModulesDidLoad() const { return !m_added_soentries.empty(); }
126238384Sjkim
127238384Sjkim    /// @returns true if modules have been unloaded from the inferior since the
128238384Sjkim    /// last call to Resolve().
129238384Sjkim    bool
130238384Sjkim    ModulesDidUnload() const { return !m_removed_soentries.empty(); }
131238384Sjkim
132238384Sjkim    void
133238384Sjkim    DumpToLog(lldb_private::Log *log) const;
134238384Sjkim
135238384Sjkim    /// @brief Constants describing the state of the rendezvous.
136238384Sjkim    ///
137238384Sjkim    /// @see GetState().
138238384Sjkim    enum RendezvousState {
139238384Sjkim        eConsistent,
140238384Sjkim        eAdd,
141238384Sjkim        eDelete
142238384Sjkim    };
143238384Sjkim
144238384Sjkim    /// @brief Structure representing the shared objects currently loaded into
145238384Sjkim    /// the inferior process.
146238384Sjkim    ///
147238384Sjkim    /// This object is a rough analogue to the struct link_map object which
148238384Sjkim    /// actually lives in the inferiors memory.
149238384Sjkim    struct SOEntry {
150238384Sjkim        lldb::addr_t link_addr;           ///< Address of this link_map.
151238384Sjkim        lldb::addr_t base_addr;           ///< Base address of the loaded object.
152238384Sjkim        lldb::addr_t path_addr;           ///< String naming the shared object.
153238384Sjkim        lldb::addr_t dyn_addr;            ///< Dynamic section of shared object.
154238384Sjkim        lldb::addr_t next;                ///< Address of next so_entry.
155238384Sjkim        lldb::addr_t prev;                ///< Address of previous so_entry.
156238384Sjkim        lldb_private::FileSpec file_spec; ///< File spec of shared object.
157238384Sjkim
158238384Sjkim        SOEntry() { clear(); }
159238384Sjkim
160238384Sjkim        bool operator ==(const SOEntry &entry) {
161238384Sjkim            return file_spec == entry.file_spec;
162238384Sjkim        }
163238384Sjkim
164238384Sjkim        void clear() {
165238384Sjkim            link_addr = 0;
166238384Sjkim            base_addr = 0;
167238384Sjkim            path_addr = 0;
168238384Sjkim            dyn_addr  = 0;
169238384Sjkim            next = 0;
170238384Sjkim            prev = 0;
171238384Sjkim            file_spec.Clear();
172238384Sjkim        }
173238384Sjkim    };
174238384Sjkim
175238384Sjkimprotected:
176238384Sjkim    typedef std::list<SOEntry> SOEntryList;
177238384Sjkim
178238384Sjkimpublic:
179238384Sjkim    typedef SOEntryList::const_iterator iterator;
180238384Sjkim
181238384Sjkim    /// Iterators over all currently loaded modules.
182238384Sjkim    iterator begin() const { return m_soentries.begin(); }
183238384Sjkim    iterator end() const { return m_soentries.end(); }
184238384Sjkim
185238384Sjkim    /// Iterators over all modules loaded into the inferior since the last call
186238384Sjkim    /// to Resolve().
187238384Sjkim    iterator loaded_begin() const { return m_added_soentries.begin(); }
188238384Sjkim    iterator loaded_end() const { return m_added_soentries.end(); }
189238384Sjkim
190238384Sjkim    /// Iterators over all modules unloaded from the inferior since the last
191238384Sjkim    /// call to Resolve().
192238384Sjkim    iterator unloaded_begin() const { return m_removed_soentries.begin(); }
193238384Sjkim    iterator unloaded_end() const { return m_removed_soentries.end(); }
194238384Sjkim
195238384Sjkimprotected:
196238384Sjkim    lldb_private::Process *m_process;
197238384Sjkim
198238384Sjkim    // Cached copy of executable file spec
199    lldb_private::FileSpec m_exe_file_spec;
200
201    /// Location of the r_debug structure in the inferiors address space.
202    lldb::addr_t m_rendezvous_addr;
203
204    /// Current and previous snapshots of the rendezvous structure.
205    Rendezvous m_current;
206    Rendezvous m_previous;
207
208    /// List of currently loaded SO modules
209    LoadedModuleInfoList m_loaded_modules;
210
211    /// List of SOEntry objects corresponding to the current link map state.
212    SOEntryList m_soentries;
213
214    /// List of SOEntry's added to the link map since the last call to Resolve().
215    SOEntryList m_added_soentries;
216
217    /// List of SOEntry's removed from the link map since the last call to
218    /// Resolve().
219    SOEntryList m_removed_soentries;
220
221    /// Threading metadata read from the inferior.
222    ThreadInfo  m_thread_info;
223
224    /// Reads an unsigned integer of @p size bytes from the inferior's address
225    /// space starting at @p addr.
226    ///
227    /// @returns addr + size if the read was successful and false otherwise.
228    lldb::addr_t
229    ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
230
231    /// Reads an address from the inferior's address space starting at @p addr.
232    ///
233    /// @returns addr + target address size if the read was successful and
234    /// 0 otherwise.
235    lldb::addr_t
236    ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
237
238    /// Reads a null-terminated C string from the memory location starting at @p
239    /// addr.
240    std::string
241    ReadStringFromMemory(lldb::addr_t addr);
242
243    /// Reads an SOEntry starting at @p addr.
244    bool
245    ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
246
247    /// Updates the current set of SOEntries, the set of added entries, and the
248    /// set of removed entries.
249    bool
250    UpdateSOEntries(bool fromRemote = false);
251
252    bool
253    FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo,
254                               SOEntry &entry);
255
256    bool
257    SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list);
258
259    bool
260    AddSOEntriesFromRemote(LoadedModuleInfoList &module_list);
261
262    bool
263    RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list);
264
265    bool
266    AddSOEntries();
267
268    bool
269    RemoveSOEntries();
270
271    void
272    UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
273
274    bool
275    SOEntryIsMainExecutable(const SOEntry &entry);
276
277    /// Reads the current list of shared objects according to the link map
278    /// supplied by the runtime linker.
279    bool
280    TakeSnapshot(SOEntryList &entry_list);
281
282    enum PThreadField { eSize, eNElem, eOffset };
283
284    bool FindMetadata(const char *name, PThreadField field, uint32_t& value);
285};
286
287#endif
288