1061da546Spatrick //===-- AppleObjCTrampolineHandler.h ----------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9dda28197Spatrick #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H
10dda28197Spatrick #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H
11061da546Spatrick 
12061da546Spatrick #include <map>
13061da546Spatrick #include <mutex>
14061da546Spatrick #include <vector>
15061da546Spatrick 
16061da546Spatrick #include "lldb/Expression/UtilityFunction.h"
17061da546Spatrick #include "lldb/lldb-public.h"
18061da546Spatrick 
19061da546Spatrick namespace lldb_private {
20061da546Spatrick 
21061da546Spatrick class AppleObjCTrampolineHandler {
22061da546Spatrick public:
23061da546Spatrick   AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp,
24061da546Spatrick                              const lldb::ModuleSP &objc_module_sp);
25061da546Spatrick 
26061da546Spatrick   ~AppleObjCTrampolineHandler();
27061da546Spatrick 
28061da546Spatrick   lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread,
29061da546Spatrick                                                 bool stop_others);
30061da546Spatrick 
31061da546Spatrick   FunctionCaller *GetLookupImplementationFunctionCaller();
32061da546Spatrick 
AddrIsMsgForward(lldb::addr_t addr)33061da546Spatrick   bool AddrIsMsgForward(lldb::addr_t addr) const {
34061da546Spatrick     return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr);
35061da546Spatrick   }
36061da546Spatrick 
37061da546Spatrick   struct DispatchFunction {
38061da546Spatrick   public:
39061da546Spatrick     enum FixUpState { eFixUpNone, eFixUpFixed, eFixUpToFix };
40061da546Spatrick 
41*f6aab3d8Srobert     const char *name = nullptr;
42*f6aab3d8Srobert     bool stret_return = false;
43*f6aab3d8Srobert     bool is_super = false;
44*f6aab3d8Srobert     bool is_super2 = false;
45*f6aab3d8Srobert     FixUpState fixedup = eFixUpNone;
46061da546Spatrick   };
47061da546Spatrick 
48061da546Spatrick   lldb::addr_t SetupDispatchFunction(Thread &thread,
49061da546Spatrick                                      ValueList &dispatch_values);
50dda28197Spatrick   const DispatchFunction *FindDispatchFunction(lldb::addr_t addr);
51dda28197Spatrick   void ForEachDispatchFunction(std::function<void(lldb::addr_t,
52dda28197Spatrick                                                   const DispatchFunction &)>);
53061da546Spatrick 
54061da546Spatrick private:
55*f6aab3d8Srobert   /// These hold the code for the function that finds the implementation of
56*f6aab3d8Srobert   /// an ObjC message send given the class & selector and the kind of dispatch.
57*f6aab3d8Srobert   /// There are two variants depending on whether the platform uses a separate
58*f6aab3d8Srobert   /// _stret passing convention (e.g. Intel) or not (e.g. ARM).  The difference
59*f6aab3d8Srobert   /// is only at the very end of the function, so the code is broken into the
60*f6aab3d8Srobert   /// common prefix and the suffix, which get composed appropriately before
61*f6aab3d8Srobert   /// the function gets compiled.
62*f6aab3d8Srobert   /// \{
63061da546Spatrick   static const char *g_lookup_implementation_function_name;
64*f6aab3d8Srobert   static const char *g_lookup_implementation_function_common_code;
65061da546Spatrick   static const char *g_lookup_implementation_with_stret_function_code;
66061da546Spatrick   static const char *g_lookup_implementation_no_stret_function_code;
67*f6aab3d8Srobert   /// \}
68061da546Spatrick 
69061da546Spatrick   class AppleObjCVTables {
70061da546Spatrick   public:
71061da546Spatrick     // These come from objc-gdb.h.
72061da546Spatrick     enum VTableFlags {
73061da546Spatrick       eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend
74061da546Spatrick       eOBJC_TRAMPOLINE_STRET = (1 << 1),   // trampoline is struct-returning
75061da546Spatrick       eOBJC_TRAMPOLINE_VTABLE = (1 << 2)   // trampoline is vtable dispatcher
76061da546Spatrick     };
77061da546Spatrick 
78061da546Spatrick   private:
79061da546Spatrick     struct VTableDescriptor {
VTableDescriptorVTableDescriptor80061da546Spatrick       VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start)
81061da546Spatrick           : flags(in_flags), code_start(in_code_start) {}
82061da546Spatrick 
83061da546Spatrick       uint32_t flags;
84061da546Spatrick       lldb::addr_t code_start;
85061da546Spatrick     };
86061da546Spatrick 
87061da546Spatrick     class VTableRegion {
88061da546Spatrick     public:
89be691f3bSpatrick       VTableRegion() = default;
90061da546Spatrick 
91061da546Spatrick       VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr);
92061da546Spatrick 
93061da546Spatrick       void SetUpRegion();
94061da546Spatrick 
GetNextRegionAddr()95061da546Spatrick       lldb::addr_t GetNextRegionAddr() { return m_next_region; }
96061da546Spatrick 
GetCodeStart()97061da546Spatrick       lldb::addr_t GetCodeStart() { return m_code_start_addr; }
98061da546Spatrick 
GetCodeEnd()99061da546Spatrick       lldb::addr_t GetCodeEnd() { return m_code_end_addr; }
100061da546Spatrick 
GetFlagsForVTableAtAddress(lldb::addr_t address)101061da546Spatrick       uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; }
102061da546Spatrick 
IsValid()103061da546Spatrick       bool IsValid() { return m_valid; }
104061da546Spatrick 
105061da546Spatrick       bool AddressInRegion(lldb::addr_t addr, uint32_t &flags);
106061da546Spatrick 
107061da546Spatrick       void Dump(Stream &s);
108061da546Spatrick 
109be691f3bSpatrick       bool m_valid = false;
110be691f3bSpatrick       AppleObjCVTables *m_owner = nullptr;
111be691f3bSpatrick       lldb::addr_t m_header_addr = LLDB_INVALID_ADDRESS;
112be691f3bSpatrick       lldb::addr_t m_code_start_addr = 0;
113be691f3bSpatrick       lldb::addr_t m_code_end_addr = 0;
114061da546Spatrick       std::vector<VTableDescriptor> m_descriptors;
115be691f3bSpatrick       lldb::addr_t m_next_region = 0;
116061da546Spatrick     };
117061da546Spatrick 
118061da546Spatrick   public:
119061da546Spatrick     AppleObjCVTables(const lldb::ProcessSP &process_sp,
120061da546Spatrick                      const lldb::ModuleSP &objc_module_sp);
121061da546Spatrick 
122061da546Spatrick     ~AppleObjCVTables();
123061da546Spatrick 
124061da546Spatrick     bool InitializeVTableSymbols();
125061da546Spatrick 
126061da546Spatrick     static bool RefreshTrampolines(void *baton,
127061da546Spatrick                                    StoppointCallbackContext *context,
128061da546Spatrick                                    lldb::user_id_t break_id,
129061da546Spatrick                                    lldb::user_id_t break_loc_id);
130061da546Spatrick     bool ReadRegions();
131061da546Spatrick 
132061da546Spatrick     bool ReadRegions(lldb::addr_t region_addr);
133061da546Spatrick 
134061da546Spatrick     bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags);
135061da546Spatrick 
GetProcessSP()136061da546Spatrick     lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); }
137061da546Spatrick 
138061da546Spatrick   private:
139061da546Spatrick     lldb::ProcessWP m_process_wp;
140061da546Spatrick     typedef std::vector<VTableRegion> region_collection;
141061da546Spatrick     lldb::addr_t m_trampoline_header;
142061da546Spatrick     lldb::break_id_t m_trampolines_changed_bp_id;
143061da546Spatrick     region_collection m_regions;
144061da546Spatrick     lldb::ModuleSP m_objc_module_sp;
145061da546Spatrick   };
146061da546Spatrick 
147061da546Spatrick   static const DispatchFunction g_dispatch_functions[];
148dda28197Spatrick   static const char *g_opt_dispatch_names[];
149061da546Spatrick 
150dda28197Spatrick   using MsgsendMap = std::map<lldb::addr_t, int>; // This table maps an dispatch
151061da546Spatrick                                                   // fn address to the index in
152061da546Spatrick                                                   // g_dispatch_functions
153061da546Spatrick   MsgsendMap m_msgSend_map;
154dda28197Spatrick   MsgsendMap m_opt_dispatch_map;
155061da546Spatrick   lldb::ProcessWP m_process_wp;
156061da546Spatrick   lldb::ModuleSP m_objc_module_sp;
157*f6aab3d8Srobert   std::string m_lookup_implementation_function_code;
158061da546Spatrick   std::unique_ptr<UtilityFunction> m_impl_code;
159061da546Spatrick   std::mutex m_impl_function_mutex;
160061da546Spatrick   lldb::addr_t m_impl_fn_addr;
161061da546Spatrick   lldb::addr_t m_impl_stret_fn_addr;
162061da546Spatrick   lldb::addr_t m_msg_forward_addr;
163061da546Spatrick   lldb::addr_t m_msg_forward_stret_addr;
164061da546Spatrick   std::unique_ptr<AppleObjCVTables> m_vtables_up;
165061da546Spatrick };
166061da546Spatrick 
167061da546Spatrick } // namespace lldb_private
168061da546Spatrick 
169dda28197Spatrick #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H
170