1 //===-- AppleObjCTrampolineHandler.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_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H 10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H 11 12 #include <map> 13 #include <mutex> 14 #include <vector> 15 16 #include "lldb/Expression/UtilityFunction.h" 17 #include "lldb/lldb-public.h" 18 19 namespace lldb_private { 20 21 class AppleObjCTrampolineHandler { 22 public: 23 AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp, 24 const lldb::ModuleSP &objc_module_sp); 25 26 ~AppleObjCTrampolineHandler(); 27 28 lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread, 29 bool stop_others); 30 31 FunctionCaller *GetLookupImplementationFunctionCaller(); 32 AddrIsMsgForward(lldb::addr_t addr)33 bool AddrIsMsgForward(lldb::addr_t addr) const { 34 return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr); 35 } 36 37 struct DispatchFunction { 38 public: 39 enum FixUpState { eFixUpNone, eFixUpFixed, eFixUpToFix }; 40 41 const char *name = nullptr; 42 bool stret_return = false; 43 bool is_super = false; 44 bool is_super2 = false; 45 FixUpState fixedup = eFixUpNone; 46 }; 47 48 lldb::addr_t SetupDispatchFunction(Thread &thread, 49 ValueList &dispatch_values); 50 const DispatchFunction *FindDispatchFunction(lldb::addr_t addr); 51 void ForEachDispatchFunction(std::function<void(lldb::addr_t, 52 const DispatchFunction &)>); 53 54 private: 55 /// These hold the code for the function that finds the implementation of 56 /// an ObjC message send given the class & selector and the kind of dispatch. 57 /// There are two variants depending on whether the platform uses a separate 58 /// _stret passing convention (e.g. Intel) or not (e.g. ARM). The difference 59 /// is only at the very end of the function, so the code is broken into the 60 /// common prefix and the suffix, which get composed appropriately before 61 /// the function gets compiled. 62 /// \{ 63 static const char *g_lookup_implementation_function_name; 64 static const char *g_lookup_implementation_function_common_code; 65 static const char *g_lookup_implementation_with_stret_function_code; 66 static const char *g_lookup_implementation_no_stret_function_code; 67 /// \} 68 69 class AppleObjCVTables { 70 public: 71 // These come from objc-gdb.h. 72 enum VTableFlags { 73 eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend 74 eOBJC_TRAMPOLINE_STRET = (1 << 1), // trampoline is struct-returning 75 eOBJC_TRAMPOLINE_VTABLE = (1 << 2) // trampoline is vtable dispatcher 76 }; 77 78 private: 79 struct VTableDescriptor { VTableDescriptorVTableDescriptor80 VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start) 81 : flags(in_flags), code_start(in_code_start) {} 82 83 uint32_t flags; 84 lldb::addr_t code_start; 85 }; 86 87 class VTableRegion { 88 public: 89 VTableRegion() = default; 90 91 VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr); 92 93 void SetUpRegion(); 94 GetNextRegionAddr()95 lldb::addr_t GetNextRegionAddr() { return m_next_region; } 96 GetCodeStart()97 lldb::addr_t GetCodeStart() { return m_code_start_addr; } 98 GetCodeEnd()99 lldb::addr_t GetCodeEnd() { return m_code_end_addr; } 100 GetFlagsForVTableAtAddress(lldb::addr_t address)101 uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; } 102 IsValid()103 bool IsValid() { return m_valid; } 104 105 bool AddressInRegion(lldb::addr_t addr, uint32_t &flags); 106 107 void Dump(Stream &s); 108 109 bool m_valid = false; 110 AppleObjCVTables *m_owner = nullptr; 111 lldb::addr_t m_header_addr = LLDB_INVALID_ADDRESS; 112 lldb::addr_t m_code_start_addr = 0; 113 lldb::addr_t m_code_end_addr = 0; 114 std::vector<VTableDescriptor> m_descriptors; 115 lldb::addr_t m_next_region = 0; 116 }; 117 118 public: 119 AppleObjCVTables(const lldb::ProcessSP &process_sp, 120 const lldb::ModuleSP &objc_module_sp); 121 122 ~AppleObjCVTables(); 123 124 bool InitializeVTableSymbols(); 125 126 static bool RefreshTrampolines(void *baton, 127 StoppointCallbackContext *context, 128 lldb::user_id_t break_id, 129 lldb::user_id_t break_loc_id); 130 bool ReadRegions(); 131 132 bool ReadRegions(lldb::addr_t region_addr); 133 134 bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags); 135 GetProcessSP()136 lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); } 137 138 private: 139 lldb::ProcessWP m_process_wp; 140 typedef std::vector<VTableRegion> region_collection; 141 lldb::addr_t m_trampoline_header; 142 lldb::break_id_t m_trampolines_changed_bp_id; 143 region_collection m_regions; 144 lldb::ModuleSP m_objc_module_sp; 145 }; 146 147 static const DispatchFunction g_dispatch_functions[]; 148 static const char *g_opt_dispatch_names[]; 149 150 using MsgsendMap = std::map<lldb::addr_t, int>; // This table maps an dispatch 151 // fn address to the index in 152 // g_dispatch_functions 153 MsgsendMap m_msgSend_map; 154 MsgsendMap m_opt_dispatch_map; 155 lldb::ProcessWP m_process_wp; 156 lldb::ModuleSP m_objc_module_sp; 157 std::string m_lookup_implementation_function_code; 158 std::unique_ptr<UtilityFunction> m_impl_code; 159 std::mutex m_impl_function_mutex; 160 lldb::addr_t m_impl_fn_addr; 161 lldb::addr_t m_impl_stret_fn_addr; 162 lldb::addr_t m_msg_forward_addr; 163 lldb::addr_t m_msg_forward_stret_addr; 164 std::unique_ptr<AppleObjCVTables> m_vtables_up; 165 }; 166 167 } // namespace lldb_private 168 169 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H 170