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;
42     bool stret_return;
43     bool is_super;
44     bool is_super2;
45     FixUpState fixedup;
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   static const char *g_lookup_implementation_function_name;
56   static const char *g_lookup_implementation_with_stret_function_code;
57   static const char *g_lookup_implementation_no_stret_function_code;
58 
59   class AppleObjCVTables {
60   public:
61     // These come from objc-gdb.h.
62     enum VTableFlags {
63       eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend
64       eOBJC_TRAMPOLINE_STRET = (1 << 1),   // trampoline is struct-returning
65       eOBJC_TRAMPOLINE_VTABLE = (1 << 2)   // trampoline is vtable dispatcher
66     };
67 
68   private:
69     struct VTableDescriptor {
VTableDescriptorVTableDescriptor70       VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start)
71           : flags(in_flags), code_start(in_code_start) {}
72 
73       uint32_t flags;
74       lldb::addr_t code_start;
75     };
76 
77     class VTableRegion {
78     public:
VTableRegion()79       VTableRegion()
80           : m_valid(false), m_owner(nullptr),
81             m_header_addr(LLDB_INVALID_ADDRESS), m_code_start_addr(0),
82             m_code_end_addr(0), m_next_region(0) {}
83 
84       VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr);
85 
86       void SetUpRegion();
87 
GetNextRegionAddr()88       lldb::addr_t GetNextRegionAddr() { return m_next_region; }
89 
GetCodeStart()90       lldb::addr_t GetCodeStart() { return m_code_start_addr; }
91 
GetCodeEnd()92       lldb::addr_t GetCodeEnd() { return m_code_end_addr; }
93 
GetFlagsForVTableAtAddress(lldb::addr_t address)94       uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; }
95 
IsValid()96       bool IsValid() { return m_valid; }
97 
98       bool AddressInRegion(lldb::addr_t addr, uint32_t &flags);
99 
100       void Dump(Stream &s);
101 
102       bool m_valid;
103       AppleObjCVTables *m_owner;
104       lldb::addr_t m_header_addr;
105       lldb::addr_t m_code_start_addr;
106       lldb::addr_t m_code_end_addr;
107       std::vector<VTableDescriptor> m_descriptors;
108       lldb::addr_t m_next_region;
109     };
110 
111   public:
112     AppleObjCVTables(const lldb::ProcessSP &process_sp,
113                      const lldb::ModuleSP &objc_module_sp);
114 
115     ~AppleObjCVTables();
116 
117     bool InitializeVTableSymbols();
118 
119     static bool RefreshTrampolines(void *baton,
120                                    StoppointCallbackContext *context,
121                                    lldb::user_id_t break_id,
122                                    lldb::user_id_t break_loc_id);
123     bool ReadRegions();
124 
125     bool ReadRegions(lldb::addr_t region_addr);
126 
127     bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags);
128 
GetProcessSP()129     lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); }
130 
131   private:
132     lldb::ProcessWP m_process_wp;
133     typedef std::vector<VTableRegion> region_collection;
134     lldb::addr_t m_trampoline_header;
135     lldb::break_id_t m_trampolines_changed_bp_id;
136     region_collection m_regions;
137     lldb::ModuleSP m_objc_module_sp;
138   };
139 
140   static const DispatchFunction g_dispatch_functions[];
141   static const char *g_opt_dispatch_names[];
142 
143   using MsgsendMap = std::map<lldb::addr_t, int>; // This table maps an dispatch
144                                                   // fn address to the index in
145                                                   // g_dispatch_functions
146   MsgsendMap m_msgSend_map;
147   MsgsendMap m_opt_dispatch_map;
148   lldb::ProcessWP m_process_wp;
149   lldb::ModuleSP m_objc_module_sp;
150   const char *m_lookup_implementation_function_code;
151   std::unique_ptr<UtilityFunction> m_impl_code;
152   std::mutex m_impl_function_mutex;
153   lldb::addr_t m_impl_fn_addr;
154   lldb::addr_t m_impl_stret_fn_addr;
155   lldb::addr_t m_msg_forward_addr;
156   lldb::addr_t m_msg_forward_stret_addr;
157   std::unique_ptr<AppleObjCVTables> m_vtables_up;
158 };
159 
160 } // namespace lldb_private
161 
162 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCTRAMPOLINEHANDLER_H
163