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
19namespace lldb_private {
20
21class AppleObjCTrampolineHandler {
22public:
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
54private:
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

source code of lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h