1 //===-- AppleObjCTrampolineHandler.h ----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef lldb_AppleObjCTrampolineHandler_h_
11 #define lldb_AppleObjCTrampolineHandler_h_
12 
13 #include <map>
14 #include <mutex>
15 #include <vector>
16 
17 #include "lldb/Expression/UtilityFunction.h"
18 #include "lldb/lldb-public.h"
19 
20 namespace lldb_private {
21 
22 class AppleObjCTrampolineHandler {
23 public:
24   AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp,
25                              const lldb::ModuleSP &objc_module_sp);
26 
27   ~AppleObjCTrampolineHandler();
28 
29   lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread,
30                                                 bool stop_others);
31 
32   FunctionCaller *GetLookupImplementationFunctionCaller();
33 
AddrIsMsgForward(lldb::addr_t addr)34   bool AddrIsMsgForward(lldb::addr_t addr) const {
35     return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr);
36   }
37 
38   struct DispatchFunction {
39   public:
40     typedef enum { eFixUpNone, eFixUpFixed, eFixUpToFix } FixUpState;
41 
42     const char *name;
43     bool stret_return;
44     bool is_super;
45     bool is_super2;
46     FixUpState fixedup;
47   };
48 
49   lldb::addr_t SetupDispatchFunction(Thread &thread,
50                                      ValueList &dispatch_values);
51 
52 private:
53   static const char *g_lookup_implementation_function_name;
54   static const char *g_lookup_implementation_with_stret_function_code;
55   static const char *g_lookup_implementation_no_stret_function_code;
56 
57   class AppleObjCVTables {
58   public:
59     // These come from objc-gdb.h.
60     enum VTableFlags {
61       eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend
62       eOBJC_TRAMPOLINE_STRET = (1 << 1),   // trampoline is struct-returning
63       eOBJC_TRAMPOLINE_VTABLE = (1 << 2)   // trampoline is vtable dispatcher
64     };
65 
66   private:
67     struct VTableDescriptor {
VTableDescriptorVTableDescriptor68       VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start)
69           : flags(in_flags), code_start(in_code_start) {}
70 
71       uint32_t flags;
72       lldb::addr_t code_start;
73     };
74 
75     class VTableRegion {
76     public:
VTableRegion()77       VTableRegion()
78           : m_valid(false), m_owner(NULL), m_header_addr(LLDB_INVALID_ADDRESS),
79             m_code_start_addr(0), m_code_end_addr(0), m_next_region(0) {}
80 
81       VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr);
82 
83       void SetUpRegion();
84 
GetNextRegionAddr()85       lldb::addr_t GetNextRegionAddr() { return m_next_region; }
86 
GetCodeStart()87       lldb::addr_t GetCodeStart() { return m_code_start_addr; }
88 
GetCodeEnd()89       lldb::addr_t GetCodeEnd() { return m_code_end_addr; }
90 
GetFlagsForVTableAtAddress(lldb::addr_t address)91       uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; }
92 
IsValid()93       bool IsValid() { return m_valid; }
94 
95       bool AddressInRegion(lldb::addr_t addr, uint32_t &flags);
96 
97       void Dump(Stream &s);
98 
99     public:
100       bool m_valid;
101       AppleObjCVTables *m_owner;
102       lldb::addr_t m_header_addr;
103       lldb::addr_t m_code_start_addr;
104       lldb::addr_t m_code_end_addr;
105       std::vector<VTableDescriptor> m_descriptors;
106       lldb::addr_t m_next_region;
107     };
108 
109   public:
110     AppleObjCVTables(const lldb::ProcessSP &process_sp,
111                      const lldb::ModuleSP &objc_module_sp);
112 
113     ~AppleObjCVTables();
114 
115     bool InitializeVTableSymbols();
116 
117     static bool RefreshTrampolines(void *baton,
118                                    StoppointCallbackContext *context,
119                                    lldb::user_id_t break_id,
120                                    lldb::user_id_t break_loc_id);
121     bool ReadRegions();
122 
123     bool ReadRegions(lldb::addr_t region_addr);
124 
125     bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags);
126 
GetProcessSP()127     lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); }
128 
129   private:
130     lldb::ProcessWP m_process_wp;
131     typedef std::vector<VTableRegion> region_collection;
132     lldb::addr_t m_trampoline_header;
133     lldb::break_id_t m_trampolines_changed_bp_id;
134     region_collection m_regions;
135     lldb::ModuleSP m_objc_module_sp;
136   };
137 
138   static const DispatchFunction g_dispatch_functions[];
139 
140   typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch
141                                                   // fn address to the index in
142                                                   // g_dispatch_functions
143   MsgsendMap m_msgSend_map;
144   lldb::ProcessWP m_process_wp;
145   lldb::ModuleSP m_objc_module_sp;
146   const char *m_lookup_implementation_function_code;
147   std::unique_ptr<UtilityFunction> m_impl_code;
148   std::mutex m_impl_function_mutex;
149   lldb::addr_t m_impl_fn_addr;
150   lldb::addr_t m_impl_stret_fn_addr;
151   lldb::addr_t m_msg_forward_addr;
152   lldb::addr_t m_msg_forward_stret_addr;
153   std::unique_ptr<AppleObjCVTables> m_vtables_ap;
154 };
155 
156 } // namespace lldb_private
157 
158 #endif // lldb_AppleObjCTrampolineHandler_h_
159