/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- DynamicLoaderDarwinKernel.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_DARWIN_KERNEL_DYNAMICLOADERDARWINKERNEL_H |
10 | | #define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_DARWIN_KERNEL_DYNAMICLOADERDARWINKERNEL_H |
11 | | |
12 | | #include <mutex> |
13 | | #include <string> |
14 | | #include <vector> |
15 | | |
16 | | |
17 | | #include "lldb/Host/SafeMachO.h" |
18 | | |
19 | | #include "lldb/Target/DynamicLoader.h" |
20 | | #include "lldb/Target/Process.h" |
21 | | #include "lldb/Utility/FileSpec.h" |
22 | | #include "lldb/Utility/UUID.h" |
23 | | |
24 | | class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader { |
25 | | public: |
26 | | DynamicLoaderDarwinKernel(lldb_private::Process *process, |
27 | | lldb::addr_t kernel_addr); |
28 | | |
29 | | ~DynamicLoaderDarwinKernel() override; |
30 | | |
31 | | // Static Functions |
32 | | static void Initialize(); |
33 | | |
34 | | static void Terminate(); |
35 | | |
36 | 3.95k | static llvm::StringRef GetPluginNameStatic() { return "darwin-kernel"; } |
37 | | |
38 | | static llvm::StringRef GetPluginDescriptionStatic(); |
39 | | |
40 | | static lldb_private::DynamicLoader * |
41 | | CreateInstance(lldb_private::Process *process, bool force); |
42 | | |
43 | | static void DebuggerInitialize(lldb_private::Debugger &debugger); |
44 | | |
45 | | static lldb::addr_t SearchForDarwinKernel(lldb_private::Process *process); |
46 | | |
47 | | /// Called after attaching a process. |
48 | | /// |
49 | | /// Allow DynamicLoader plug-ins to execute some code after |
50 | | /// attaching to a process. |
51 | | void DidAttach() override; |
52 | | |
53 | | void DidLaunch() override; |
54 | | |
55 | | lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, |
56 | | bool stop_others) override; |
57 | | |
58 | | lldb_private::Status CanLoadImage() override; |
59 | | |
60 | | // PluginInterface protocol |
61 | 0 | llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } |
62 | | |
63 | | protected: |
64 | | void PrivateInitialize(lldb_private::Process *process); |
65 | | |
66 | | void PrivateProcessStateChanged(lldb_private::Process *process, |
67 | | lldb::StateType state); |
68 | | |
69 | | void UpdateIfNeeded(); |
70 | | |
71 | | void LoadKernelModuleIfNeeded(); |
72 | | |
73 | | void Clear(bool clear_process); |
74 | | |
75 | | void PutToLog(lldb_private::Log *log) const; |
76 | | |
77 | | static bool |
78 | | BreakpointHitCallback(void *baton, |
79 | | lldb_private::StoppointCallbackContext *context, |
80 | | lldb::user_id_t break_id, lldb::user_id_t break_loc_id); |
81 | | |
82 | | bool BreakpointHit(lldb_private::StoppointCallbackContext *context, |
83 | | lldb::user_id_t break_id, lldb::user_id_t break_loc_id); |
84 | 0 | uint32_t GetAddrByteSize() { return m_kernel.GetAddressByteSize(); } |
85 | | |
86 | | static lldb::ByteOrder GetByteOrderFromMagic(uint32_t magic); |
87 | | |
88 | | enum { |
89 | | KERNEL_MODULE_MAX_NAME = 64u, |
90 | | // Versions less than 2 didn't have an entry size, |
91 | | // they had a 64 bit name, 16 byte UUID, 8 byte addr, |
92 | | // 8 byte size, 8 byte version, 4 byte load tag, and |
93 | | // 4 byte flags |
94 | | KERNEL_MODULE_ENTRY_SIZE_VERSION_1 = 64u + 16u + 8u + 8u + 8u + 4u + 4u |
95 | | }; |
96 | | |
97 | | // class KextImageInfo represents a single kext or kernel binary image. |
98 | | // The class was designed to hold the information from the |
99 | | // OSKextLoadedKextSummary |
100 | | // structure (in libkern/libkern/OSKextLibPrivate.h from xnu). The kernel |
101 | | // maintains |
102 | | // a list of loded kexts in memory (the OSKextLoadedKextSummaryHeader |
103 | | // structure, |
104 | | // which points to an array of OSKextLoadedKextSummary's). |
105 | | // |
106 | | // A KextImageInfos may have - |
107 | | // |
108 | | // 1. The load address, name, UUID, and size of a kext/kernel binary in memory |
109 | | // (read straight out of the kernel's list-of-kexts loaded) |
110 | | // 2. A ModuleSP based on a MemoryModule read out of the kernel's memory |
111 | | // (very unlikely to have any symbolic information) |
112 | | // 3. A ModuleSP for an on-disk copy of the kext binary, possibly with debug |
113 | | // info |
114 | | // or a dSYM |
115 | | // |
116 | | // For performance reasons, the developer may prefer that lldb not load the |
117 | | // kexts out |
118 | | // of memory at the start of a kernel session. But we should build up / |
119 | | // maintain a |
120 | | // list of kexts that the kernel has told us about so we can relocate a kext |
121 | | // module |
122 | | // later if the user explicitly adds it to the target. |
123 | | |
124 | | class KextImageInfo { |
125 | | public: |
126 | 0 | KextImageInfo() : m_name(), m_module_sp(), m_memory_module_sp(), m_uuid() {} |
127 | | |
128 | 0 | void Clear() { |
129 | 0 | m_load_address = LLDB_INVALID_ADDRESS; |
130 | 0 | m_size = 0; |
131 | 0 | m_name.clear(); |
132 | 0 | m_uuid.Clear(); |
133 | 0 | m_module_sp.reset(); |
134 | 0 | m_memory_module_sp.reset(); |
135 | 0 | m_load_process_stop_id = UINT32_MAX; |
136 | 0 | } |
137 | | |
138 | | bool LoadImageAtFileAddress(lldb_private::Process *process); |
139 | | |
140 | | bool LoadImageUsingMemoryModule(lldb_private::Process *process); |
141 | | |
142 | 0 | bool IsLoaded() { return m_load_process_stop_id != UINT32_MAX; } |
143 | | |
144 | | void SetLoadAddress( |
145 | | lldb::addr_t load_addr); // Address of the Mach-O header for this binary |
146 | | |
147 | | lldb::addr_t |
148 | | GetLoadAddress() const; // Address of the Mach-O header for this binary |
149 | | |
150 | | lldb_private::UUID GetUUID() const; |
151 | | |
152 | | void SetUUID(const lldb_private::UUID &uuid); |
153 | | |
154 | | void SetName(const char *); |
155 | | |
156 | | std::string GetName() const; |
157 | | |
158 | | void SetModule(lldb::ModuleSP module); |
159 | | |
160 | | lldb::ModuleSP GetModule(); |
161 | | |
162 | | // try to fill in m_memory_module_sp from memory based on the m_load_address |
163 | | bool ReadMemoryModule(lldb_private::Process *process); |
164 | | |
165 | | bool IsKernel() |
166 | | const; // true if this is the mach_kernel; false if this is a kext |
167 | | |
168 | | void SetIsKernel(bool is_kernel); |
169 | | |
170 | | uint64_t GetSize() const; |
171 | | |
172 | | void SetSize(uint64_t size); |
173 | | |
174 | | uint32_t |
175 | | GetProcessStopId() const; // the stop-id when this binary was first noticed |
176 | | |
177 | | void SetProcessStopId(uint32_t stop_id); |
178 | | |
179 | | bool operator==(const KextImageInfo &rhs) const; |
180 | | |
181 | | uint32_t GetAddressByteSize(); // as determined by Mach-O header |
182 | | |
183 | | lldb::ByteOrder GetByteOrder(); // as determined by Mach-O header |
184 | | |
185 | | lldb_private::ArchSpec |
186 | | GetArchitecture() const; // as determined by Mach-O header |
187 | | |
188 | | void PutToLog(lldb_private::Log *log) const; |
189 | | |
190 | | typedef std::vector<KextImageInfo> collection; |
191 | | typedef collection::iterator iterator; |
192 | | typedef collection::const_iterator const_iterator; |
193 | | |
194 | | private: |
195 | | std::string m_name; |
196 | | lldb::ModuleSP m_module_sp; |
197 | | lldb::ModuleSP m_memory_module_sp; |
198 | | uint32_t m_load_process_stop_id = |
199 | | UINT32_MAX; // the stop-id when this module was added |
200 | | // to the Target |
201 | | lldb_private::UUID |
202 | | m_uuid; // UUID for this dylib if it has one, else all zeros |
203 | | lldb::addr_t m_load_address = LLDB_INVALID_ADDRESS; |
204 | | uint64_t m_size = 0; |
205 | | bool m_kernel_image = |
206 | | false; // true if this is the kernel, false if this is a kext |
207 | | }; |
208 | | |
209 | | struct OSKextLoadedKextSummaryHeader { |
210 | | uint32_t version = 0; |
211 | | uint32_t entry_size = 0; |
212 | | uint32_t entry_count = 0; |
213 | | lldb::addr_t image_infos_addr = LLDB_INVALID_ADDRESS; |
214 | | |
215 | 0 | OSKextLoadedKextSummaryHeader() = default; |
216 | | |
217 | 0 | uint32_t GetSize() { |
218 | 0 | switch (version) { |
219 | 0 | case 0: |
220 | 0 | return 0; // Can't know the size without a valid version |
221 | 0 | case 1: |
222 | 0 | return 8; // Version 1 only had a version + entry_count |
223 | 0 | default: |
224 | 0 | break; |
225 | 0 | } |
226 | | // Version 2 and above has version, entry_size, entry_count, and reserved |
227 | 0 | return 16; |
228 | 0 | } |
229 | | |
230 | 0 | void Clear() { |
231 | 0 | version = 0; |
232 | 0 | entry_size = 0; |
233 | 0 | entry_count = 0; |
234 | 0 | image_infos_addr = LLDB_INVALID_ADDRESS; |
235 | 0 | } |
236 | | |
237 | 0 | bool IsValid() const { return version >= 1 && version <= 2; } |
238 | | }; |
239 | | |
240 | | void RegisterNotificationCallbacks(); |
241 | | |
242 | | void UnregisterNotificationCallbacks(); |
243 | | |
244 | | void SetNotificationBreakpointIfNeeded(); |
245 | | |
246 | | bool ReadAllKextSummaries(); |
247 | | |
248 | | bool ReadKextSummaryHeader(); |
249 | | |
250 | | bool ParseKextSummaries(const lldb_private::Address &kext_summary_addr, |
251 | | uint32_t count); |
252 | | |
253 | | void |
254 | | UpdateImageInfosHeaderAndLoadCommands(KextImageInfo::collection &image_infos, |
255 | | uint32_t infos_count, |
256 | | bool update_executable); |
257 | | |
258 | | uint32_t ReadKextSummaries(const lldb_private::Address &kext_summary_addr, |
259 | | uint32_t image_infos_count, |
260 | | KextImageInfo::collection &image_infos); |
261 | | |
262 | | static lldb::addr_t |
263 | | SearchForKernelAtSameLoadAddr(lldb_private::Process *process); |
264 | | |
265 | | static lldb::addr_t |
266 | | SearchForKernelWithDebugHints(lldb_private::Process *process); |
267 | | |
268 | | static lldb::addr_t SearchForKernelNearPC(lldb_private::Process *process); |
269 | | |
270 | | static lldb::addr_t |
271 | | SearchForKernelViaExhaustiveSearch(lldb_private::Process *process); |
272 | | |
273 | | static bool |
274 | | ReadMachHeader(lldb::addr_t addr, lldb_private::Process *process, llvm::MachO::mach_header &mh, |
275 | | bool *read_error = nullptr); |
276 | | |
277 | | static lldb_private::UUID |
278 | | CheckForKernelImageAtAddress(lldb::addr_t addr, |
279 | | lldb_private::Process *process, |
280 | | bool *read_error = nullptr); |
281 | | |
282 | | lldb::addr_t m_kernel_load_address; |
283 | | KextImageInfo m_kernel; // Info about the current kernel image being used |
284 | | |
285 | | lldb_private::Address m_kext_summary_header_ptr_addr; |
286 | | lldb_private::Address m_kext_summary_header_addr; |
287 | | OSKextLoadedKextSummaryHeader m_kext_summary_header; |
288 | | KextImageInfo::collection m_known_kexts; |
289 | | mutable std::recursive_mutex m_mutex; |
290 | | lldb::user_id_t m_break_id; |
291 | | |
292 | | private: |
293 | | DynamicLoaderDarwinKernel(const DynamicLoaderDarwinKernel &) = delete; |
294 | | const DynamicLoaderDarwinKernel & |
295 | | operator=(const DynamicLoaderDarwinKernel &) = delete; |
296 | | }; |
297 | | |
298 | | #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_DARWIN_KERNEL_DYNAMICLOADERDARWINKERNEL_H |