1 | //===-- DynamicLoaderMacOSXDYLD.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 | // This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS / |
10 | // watchOS / BridgeOS) |
11 | // platforms earlier than 2016, where lldb would read the "dyld_all_image_infos" |
12 | // dyld internal structure to understand where things were loaded and the |
13 | // solib loaded/unloaded notification function we put a breakpoint on gives us |
14 | // an array of (load address, mod time, file path) tuples. |
15 | // |
16 | // As of late 2016, the new DynamicLoaderMacOS plugin should be used, which uses |
17 | // dyld SPI functions to get the same information without reading internal dyld |
18 | // data structures. |
19 | |
20 | #ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H |
21 | #define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H |
22 | |
23 | #include <mutex> |
24 | #include <vector> |
25 | |
26 | #include "lldb/Host/SafeMachO.h" |
27 | #include "lldb/Target/DynamicLoader.h" |
28 | #include "lldb/Target/Process.h" |
29 | #include "lldb/Utility/FileSpec.h" |
30 | #include "lldb/Utility/StructuredData.h" |
31 | #include "lldb/Utility/UUID.h" |
32 | |
33 | #include "DynamicLoaderDarwin.h" |
34 | |
35 | class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoaderDarwin { |
36 | public: |
37 | DynamicLoaderMacOSXDYLD(lldb_private::Process *process); |
38 | |
39 | ~DynamicLoaderMacOSXDYLD() override; |
40 | |
41 | // Static Functions |
42 | static void Initialize(); |
43 | |
44 | static void Terminate(); |
45 | |
46 | static llvm::StringRef GetPluginNameStatic() { return "macosx-dyld" ; } |
47 | |
48 | static llvm::StringRef GetPluginDescriptionStatic(); |
49 | |
50 | static lldb_private::DynamicLoader * |
51 | CreateInstance(lldb_private::Process *process, bool force); |
52 | |
53 | /// Called after attaching a process. |
54 | /// |
55 | /// Allow DynamicLoader plug-ins to execute some code after |
56 | /// attaching to a process. |
57 | bool ProcessDidExec() override; |
58 | |
59 | lldb_private::Status CanLoadImage() override; |
60 | |
61 | bool GetSharedCacheInformation( |
62 | lldb::addr_t &base_address, lldb_private::UUID &uuid, |
63 | lldb_private::LazyBool &using_shared_cache, |
64 | lldb_private::LazyBool &private_shared_cache) override; |
65 | |
66 | // PluginInterface protocol |
67 | llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } |
68 | |
69 | bool IsFullyInitialized() override; |
70 | |
71 | protected: |
72 | void PutToLog(lldb_private::Log *log) const; |
73 | |
74 | void DoInitialImageFetch() override; |
75 | |
76 | bool NeedToDoInitialImageFetch() override; |
77 | |
78 | bool DidSetNotificationBreakpoint() override; |
79 | |
80 | void DoClear() override; |
81 | |
82 | bool ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr); |
83 | |
84 | static bool |
85 | NotifyBreakpointHit(void *baton, |
86 | lldb_private::StoppointCallbackContext *context, |
87 | lldb::user_id_t break_id, lldb::user_id_t break_loc_id); |
88 | |
89 | uint32_t AddrByteSize(); |
90 | |
91 | bool (lldb::addr_t addr, llvm::MachO::mach_header *, |
92 | lldb_private::DataExtractor *load_command_data); |
93 | |
94 | uint32_t ParseLoadCommands(const lldb_private::DataExtractor &data, |
95 | ImageInfo &dylib_info, |
96 | lldb_private::FileSpec *lc_id_dylinker); |
97 | |
98 | struct DYLDAllImageInfos { |
99 | uint32_t version = 0; |
100 | uint32_t dylib_info_count = 0; // Version >= 1 |
101 | lldb::addr_t dylib_info_addr = LLDB_INVALID_ADDRESS; // Version >= 1 |
102 | lldb::addr_t notification = LLDB_INVALID_ADDRESS; // Version >= 1 |
103 | bool processDetachedFromSharedRegion = false; // Version >= 1 |
104 | bool libSystemInitialized = false; // Version >= 2 |
105 | lldb::addr_t dyldImageLoadAddress = LLDB_INVALID_ADDRESS; // Version >= 2 |
106 | |
107 | DYLDAllImageInfos() = default; |
108 | |
109 | void Clear() { |
110 | version = 0; |
111 | dylib_info_count = 0; |
112 | dylib_info_addr = LLDB_INVALID_ADDRESS; |
113 | notification = LLDB_INVALID_ADDRESS; |
114 | processDetachedFromSharedRegion = false; |
115 | libSystemInitialized = false; |
116 | dyldImageLoadAddress = LLDB_INVALID_ADDRESS; |
117 | } |
118 | |
119 | bool IsValid() const { return version >= 1 && version <= 6; } |
120 | }; |
121 | |
122 | static lldb::ByteOrder GetByteOrderFromMagic(uint32_t magic); |
123 | |
124 | bool SetNotificationBreakpoint() override; |
125 | |
126 | void ClearNotificationBreakpoint() override; |
127 | |
128 | // There is a little tricky bit where you might initially attach while dyld is |
129 | // updating |
130 | // the all_image_infos, and you can't read the infos, so you have to continue |
131 | // and pick it |
132 | // up when you hit the update breakpoint. At that point, you need to run this |
133 | // initialize |
134 | // function, but when you do it that way you DON'T need to do the extra work |
135 | // you would at |
136 | // the breakpoint. |
137 | // So this function will only do actual work if the image infos haven't been |
138 | // read yet. |
139 | // If it does do any work, then it will return true, and false otherwise. |
140 | // That way you can |
141 | // call it in the breakpoint action, and if it returns true you're done. |
142 | bool InitializeFromAllImageInfos(); |
143 | |
144 | bool ReadAllImageInfosStructure(); |
145 | |
146 | bool AddModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr, |
147 | uint32_t image_infos_count); |
148 | |
149 | bool RemoveModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr, |
150 | uint32_t image_infos_count); |
151 | |
152 | void UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos, |
153 | uint32_t infos_count, |
154 | bool update_executable); |
155 | |
156 | bool ReadImageInfos(lldb::addr_t image_infos_addr, uint32_t image_infos_count, |
157 | ImageInfo::collection &image_infos); |
158 | |
159 | lldb::addr_t m_dyld_all_image_infos_addr; |
160 | DYLDAllImageInfos m_dyld_all_image_infos; |
161 | uint32_t m_dyld_all_image_infos_stop_id; |
162 | lldb::user_id_t m_break_id; |
163 | mutable std::recursive_mutex m_mutex; |
164 | bool m_process_image_addr_is_all_images_infos; |
165 | |
166 | private: |
167 | DynamicLoaderMacOSXDYLD(const DynamicLoaderMacOSXDYLD &) = delete; |
168 | const DynamicLoaderMacOSXDYLD & |
169 | operator=(const DynamicLoaderMacOSXDYLD &) = delete; |
170 | }; |
171 | |
172 | #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOSXDYLD_H |
173 | |