1 | //===-- DynamicLoaderDarwin.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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWIN_H |
10 | #define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWIN_H |
11 | |
12 | #include <map> |
13 | #include <mutex> |
14 | #include <vector> |
15 | |
16 | #include "lldb/Host/SafeMachO.h" |
17 | #include "lldb/Target/DynamicLoader.h" |
18 | #include "lldb/Target/Process.h" |
19 | #include "lldb/Utility/FileSpec.h" |
20 | #include "lldb/Utility/StructuredData.h" |
21 | #include "lldb/Utility/UUID.h" |
22 | |
23 | #include "llvm/TargetParser/Triple.h" |
24 | |
25 | namespace lldb_private { |
26 | |
27 | class DynamicLoaderDarwin : public lldb_private::DynamicLoader { |
28 | public: |
29 | DynamicLoaderDarwin(lldb_private::Process *process); |
30 | |
31 | ~DynamicLoaderDarwin() override; |
32 | |
33 | /// Called after attaching a process. |
34 | /// |
35 | /// Allow DynamicLoader plug-ins to execute some code after |
36 | /// attaching to a process. |
37 | void DidAttach() override; |
38 | |
39 | void DidLaunch() override; |
40 | |
41 | lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, |
42 | bool stop_others) override; |
43 | |
44 | void FindEquivalentSymbols( |
45 | lldb_private::Symbol *original_symbol, |
46 | lldb_private::ModuleList &module_list, |
47 | lldb_private::SymbolContextList &equivalent_symbols) override; |
48 | |
49 | lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, |
50 | const lldb::ThreadSP thread, |
51 | lldb::addr_t tls_file_addr) override; |
52 | |
53 | bool AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override; |
54 | |
55 | virtual void DoInitialImageFetch() = 0; |
56 | |
57 | virtual bool NeedToDoInitialImageFetch() = 0; |
58 | |
59 | std::optional<lldb_private::Address> GetStartAddress() override; |
60 | |
61 | protected: |
62 | void PrivateInitialize(lldb_private::Process *process); |
63 | |
64 | void PrivateProcessStateChanged(lldb_private::Process *process, |
65 | lldb::StateType state); |
66 | |
67 | void Clear(bool clear_process); |
68 | |
69 | // Clear method for classes derived from this one |
70 | virtual void DoClear() = 0; |
71 | |
72 | void SetDYLDModule(lldb::ModuleSP &dyld_module_sp); |
73 | |
74 | lldb::ModuleSP GetDYLDModule(); |
75 | |
76 | void ClearDYLDModule(); |
77 | |
78 | class Segment { |
79 | public: |
80 | Segment() : name() {} |
81 | |
82 | lldb_private::ConstString name; |
83 | lldb::addr_t vmaddr = LLDB_INVALID_ADDRESS; |
84 | lldb::addr_t vmsize = 0; |
85 | lldb::addr_t fileoff = 0; |
86 | lldb::addr_t filesize = 0; |
87 | uint32_t maxprot = 0; |
88 | uint32_t initprot = 0; |
89 | uint32_t nsects = 0; |
90 | uint32_t flags = 0; |
91 | |
92 | bool operator==(const Segment &rhs) const { |
93 | return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize; |
94 | } |
95 | |
96 | void PutToLog(lldb_private::Log *log, lldb::addr_t slide) const; |
97 | }; |
98 | |
99 | struct ImageInfo { |
100 | /// Address of mach header for this dylib. |
101 | lldb::addr_t address = LLDB_INVALID_ADDRESS; |
102 | /// The amount to slide all segments by if there is a global |
103 | /// slide. |
104 | lldb::addr_t slide = 0; |
105 | /// Resolved path for this dylib. |
106 | lldb_private::FileSpec file_spec; |
107 | /// UUID for this dylib if it has one, else all zeros. |
108 | lldb_private::UUID uuid; |
109 | /// The mach header for this image. |
110 | llvm::MachO::mach_header ; |
111 | /// All segment vmaddr and vmsize pairs for this executable (from |
112 | /// memory of inferior). |
113 | std::vector<Segment> segments; |
114 | /// The process stop ID that the sections for this image were |
115 | /// loaded. |
116 | uint32_t load_stop_id = 0; |
117 | /// LC_VERSION_MIN_... load command os type. |
118 | llvm::Triple::OSType os_type = llvm::Triple::OSType::UnknownOS; |
119 | /// LC_VERSION_MIN_... load command os environment. |
120 | llvm::Triple::EnvironmentType os_env = |
121 | llvm::Triple::EnvironmentType::UnknownEnvironment; |
122 | /// LC_VERSION_MIN_... SDK. |
123 | std::string min_version_os_sdk; |
124 | |
125 | ImageInfo() = default; |
126 | |
127 | void Clear(bool load_cmd_data_only) { |
128 | if (!load_cmd_data_only) { |
129 | address = LLDB_INVALID_ADDRESS; |
130 | slide = 0; |
131 | file_spec.Clear(); |
132 | ::memset(s: &header, c: 0, n: sizeof(header)); |
133 | } |
134 | uuid.Clear(); |
135 | segments.clear(); |
136 | load_stop_id = 0; |
137 | os_type = llvm::Triple::OSType::UnknownOS; |
138 | os_env = llvm::Triple::EnvironmentType::UnknownEnvironment; |
139 | min_version_os_sdk.clear(); |
140 | } |
141 | |
142 | bool operator==(const ImageInfo &rhs) const { |
143 | return address == rhs.address && slide == rhs.slide && |
144 | file_spec == rhs.file_spec && uuid == rhs.uuid && |
145 | memcmp(s1: &header, s2: &rhs.header, n: sizeof(header)) == 0 && |
146 | segments == rhs.segments && os_type == rhs.os_type && |
147 | os_env == rhs.os_env; |
148 | } |
149 | |
150 | bool UUIDValid() const { return uuid.IsValid(); } |
151 | |
152 | uint32_t GetAddressByteSize() { |
153 | if (header.cputype) { |
154 | if (header.cputype & llvm::MachO::CPU_ARCH_ABI64) |
155 | return 8; |
156 | else |
157 | return 4; |
158 | } |
159 | return 0; |
160 | } |
161 | |
162 | lldb_private::ArchSpec GetArchitecture() const; |
163 | |
164 | const Segment *FindSegment(lldb_private::ConstString name) const; |
165 | |
166 | void PutToLog(lldb_private::Log *log) const; |
167 | |
168 | typedef std::vector<ImageInfo> collection; |
169 | typedef collection::iterator iterator; |
170 | typedef collection::const_iterator const_iterator; |
171 | }; |
172 | |
173 | bool UpdateImageLoadAddress(lldb_private::Module *module, ImageInfo &info); |
174 | |
175 | bool UnloadModuleSections(lldb_private::Module *module, ImageInfo &info); |
176 | |
177 | lldb::ModuleSP FindTargetModuleForImageInfo(const ImageInfo &image_info, |
178 | bool can_create, |
179 | bool *did_create_ptr); |
180 | |
181 | void UnloadImages(const std::vector<lldb::addr_t> &solib_addresses); |
182 | |
183 | void UnloadAllImages(); |
184 | |
185 | virtual bool SetNotificationBreakpoint() = 0; |
186 | |
187 | virtual void ClearNotificationBreakpoint() = 0; |
188 | |
189 | virtual bool DidSetNotificationBreakpoint() = 0; |
190 | |
191 | typedef std::map<uint64_t, lldb::addr_t> PthreadKeyToTLSMap; |
192 | typedef std::map<lldb::user_id_t, PthreadKeyToTLSMap> ThreadIDToTLSMap; |
193 | |
194 | std::recursive_mutex &GetMutex() const { return m_mutex; } |
195 | |
196 | lldb::ModuleSP GetPThreadLibraryModule(); |
197 | |
198 | lldb_private::Address GetPthreadSetSpecificAddress(); |
199 | |
200 | bool JSONImageInformationIntoImageInfo( |
201 | lldb_private::StructuredData::ObjectSP image_details, |
202 | ImageInfo::collection &image_infos); |
203 | |
204 | // Finds/loads modules for a given `image_infos` and returns pairs |
205 | // (ImageInfo, ModuleSP). |
206 | // Prefer using this method rather than calling `FindTargetModuleForImageInfo` |
207 | // directly as this method may load the modules in parallel. |
208 | std::vector<std::pair<ImageInfo, lldb::ModuleSP>> |
209 | PreloadModulesFromImageInfos(const ImageInfo::collection &image_infos); |
210 | |
211 | // If `images` contains / may contain dyld or executable image, call this |
212 | // method to keep our internal record keeping of the special binaries |
213 | // up-to-date. |
214 | void UpdateSpecialBinariesFromPreloadedModules( |
215 | std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images); |
216 | |
217 | // if image_info is a dyld binary, call this method |
218 | bool UpdateDYLDImageInfoFromNewImageInfo(ImageInfo &image_info); |
219 | |
220 | // If image_infos contains / may contain executable image, call this method |
221 | // to keep our internal record keeping of the special dyld binary up-to-date. |
222 | void AddExecutableModuleIfInImageInfos(ImageInfo::collection &image_infos); |
223 | |
224 | bool AddModulesUsingImageInfos(ImageInfo::collection &image_infos); |
225 | bool AddModulesUsingPreloadedModules( |
226 | std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images); |
227 | |
228 | // Whether we should use the new dyld SPI to get shared library information, |
229 | // or read |
230 | // it directly out of the dyld_all_image_infos. Whether we use the (newer) |
231 | // DynamicLoaderMacOS |
232 | // plugin or the (older) DynamicLoaderMacOSX plugin. |
233 | static bool UseDYLDSPI(lldb_private::Process *process); |
234 | |
235 | lldb::ModuleWP m_dyld_module_wp; // the dyld whose file type (mac, ios, etc) |
236 | // matches the process |
237 | lldb::ModuleWP m_libpthread_module_wp; |
238 | lldb_private::Address m_pthread_getspecific_addr; |
239 | ThreadIDToTLSMap m_tid_to_tls_map; |
240 | ImageInfo::collection |
241 | m_dyld_image_infos; // Current shared libraries information |
242 | uint32_t m_dyld_image_infos_stop_id; // The process stop ID that |
243 | // "m_dyld_image_infos" is valid for |
244 | ImageInfo m_dyld; |
245 | mutable std::recursive_mutex m_mutex; |
246 | |
247 | private: |
248 | DynamicLoaderDarwin(const DynamicLoaderDarwin &) = delete; |
249 | const DynamicLoaderDarwin &operator=(const DynamicLoaderDarwin &) = delete; |
250 | }; |
251 | |
252 | } // namespace lldb_private |
253 | |
254 | #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWIN_H |
255 | |