//===-- AppleObjCTrampolineHandler.h ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H #include #include #include #include "lldb/Expression/UtilityFunction.h" #include "lldb/lldb-public.h" namespace lldb_private { class AppleObjCTrampolineHandler { public: AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp, const lldb::ModuleSP &objc_module_sp); ~AppleObjCTrampolineHandler(); lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread, bool stop_others); FunctionCaller *GetLookupImplementationFunctionCaller(); bool AddrIsMsgForward(lldb::addr_t addr) const { return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr); } struct DispatchFunction { public: enum FixUpState { eFixUpNone, eFixUpFixed, eFixUpToFix }; const char *name = nullptr; bool stret_return = false; bool is_super = false; bool is_super2 = false; FixUpState fixedup = eFixUpNone; }; lldb::addr_t SetupDispatchFunction(Thread &thread, ValueList &dispatch_values); const DispatchFunction *FindDispatchFunction(lldb::addr_t addr); void ForEachDispatchFunction(std::function); private: /// These hold the code for the function that finds the implementation of /// an ObjC message send given the class & selector and the kind of dispatch. /// There are two variants depending on whether the platform uses a separate /// _stret passing convention (e.g. Intel) or not (e.g. ARM). The difference /// is only at the very end of the function, so the code is broken into the /// common prefix and the suffix, which get composed appropriately before /// the function gets compiled. /// \{ static const char *g_lookup_implementation_function_name; static const char *g_lookup_implementation_function_common_code; static const char *g_lookup_implementation_with_stret_function_code; static const char *g_lookup_implementation_no_stret_function_code; /// \} class AppleObjCVTables { public: // These come from objc-gdb.h. enum VTableFlags { eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend eOBJC_TRAMPOLINE_STRET = (1 << 1), // trampoline is struct-returning eOBJC_TRAMPOLINE_VTABLE = (1 << 2) // trampoline is vtable dispatcher }; private: struct VTableDescriptor { VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start) : flags(in_flags), code_start(in_code_start) {} uint32_t flags; lldb::addr_t code_start; }; class VTableRegion { public: VTableRegion() = default; VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr); void SetUpRegion(); lldb::addr_t GetNextRegionAddr() { return m_next_region; } lldb::addr_t GetCodeStart() { return m_code_start_addr; } lldb::addr_t GetCodeEnd() { return m_code_end_addr; } uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; } bool IsValid() { return m_valid; } bool AddressInRegion(lldb::addr_t addr, uint32_t &flags); void Dump(Stream &s); bool m_valid = false; AppleObjCVTables *m_owner = nullptr; lldb::addr_t m_header_addr = LLDB_INVALID_ADDRESS; lldb::addr_t m_code_start_addr = 0; lldb::addr_t m_code_end_addr = 0; std::vector m_descriptors; lldb::addr_t m_next_region = 0; }; public: AppleObjCVTables(const lldb::ProcessSP &process_sp, const lldb::ModuleSP &objc_module_sp); ~AppleObjCVTables(); bool InitializeVTableSymbols(); static bool RefreshTrampolines(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); bool ReadRegions(); bool ReadRegions(lldb::addr_t region_addr); bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags); lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); } private: lldb::ProcessWP m_process_wp; typedef std::vector region_collection; lldb::addr_t m_trampoline_header; lldb::break_id_t m_trampolines_changed_bp_id; region_collection m_regions; lldb::ModuleSP m_objc_module_sp; }; static const DispatchFunction g_dispatch_functions[]; static const char *g_opt_dispatch_names[]; using MsgsendMap = std::map; // This table maps an dispatch // fn address to the index in // g_dispatch_functions MsgsendMap m_msgSend_map; MsgsendMap m_opt_dispatch_map; lldb::ProcessWP m_process_wp; lldb::ModuleSP m_objc_module_sp; std::string m_lookup_implementation_function_code; std::unique_ptr m_impl_code; std::mutex m_impl_function_mutex; lldb::addr_t m_impl_fn_addr; lldb::addr_t m_impl_stret_fn_addr; lldb::addr_t m_msg_forward_addr; lldb::addr_t m_msg_forward_stret_addr; std::unique_ptr m_vtables_up; }; } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H