170 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H10#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H11 12#include <map>13#include <mutex>14#include <vector>15 16#include "lldb/Expression/UtilityFunction.h"17#include "lldb/lldb-public.h"18 19namespace lldb_private {20 21class AppleObjCTrampolineHandler {22public: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 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 54private:55 /// These hold the code for the function that finds the implementation of56 /// 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 separate58 /// _stret passing convention (e.g. Intel) or not (e.g. ARM). The difference59 /// is only at the very end of the function, so the code is broken into the60 /// common prefix and the suffix, which get composed appropriately before61 /// 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_msgSend74 eOBJC_TRAMPOLINE_STRET = (1 << 1), // trampoline is struct-returning75 eOBJC_TRAMPOLINE_VTABLE = (1 << 2) // trampoline is vtable dispatcher76 };77 78 private:79 struct VTableDescriptor {80 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 95 lldb::addr_t GetNextRegionAddr() { return m_next_region; }96 97 lldb::addr_t GetCodeStart() { return m_code_start_addr; }98 99 lldb::addr_t GetCodeEnd() { return m_code_end_addr; }100 101 uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; }102 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 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 dispatch151 // fn address to the index in152 // g_dispatch_functions153 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_private168 169#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H170