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