| 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 | |