blob: e10a117acbbee7a793e8b842850dfc4bcd5a8122 [file] [log] [blame]
Kate Stoneb9c1b512016-09-06 20:57:50 +00001//===-- CPPLanguageRuntime.cpp
Jim Ingham22777012010-09-23 02:01:19 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Jim Ingham22777012010-09-23 02:01:19 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Target/CPPLanguageRuntime.h"
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000010#include "lldb/Target/ObjCLanguageRuntime.h"
Enrico Granata1d261d12012-02-03 01:41:25 +000011
Greg Clayton6ecb2322013-05-18 00:11:21 +000012#include <string.h>
13
Jonas Devlieghere796ac802019-02-11 23:13:08 +000014#include <memory>
15
Jim Inghamfa39bb42014-10-25 00:33:55 +000016#include "llvm/ADT/StringRef.h"
17
Shafik Yaghmour443e20b2018-09-11 20:58:28 +000018#include "lldb/Symbol/Block.h"
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000019#include "lldb/Symbol/Variable.h"
Shafik Yaghmour443e20b2018-09-11 20:58:28 +000020#include "lldb/Symbol/VariableList.h"
21
Jim Ingham22777012010-09-23 02:01:19 +000022#include "lldb/Core/PluginManager.h"
Enrico Granata1d261d12012-02-03 01:41:25 +000023#include "lldb/Core/UniqueCStringMap.h"
Shafik Yaghmour443e20b2018-09-11 20:58:28 +000024#include "lldb/Symbol/ClangASTContext.h"
25#include "lldb/Target/ABI.h"
Jim Ingham5a369122010-09-28 01:25:32 +000026#include "lldb/Target/ExecutionContext.h"
Shafik Yaghmour443e20b2018-09-11 20:58:28 +000027#include "lldb/Target/RegisterContext.h"
28#include "lldb/Target/SectionLoadList.h"
29#include "lldb/Target/StackFrame.h"
30#include "lldb/Target/ThreadPlanRunToAddress.h"
Shafik Yaghmouraa302682018-10-12 17:20:39 +000031#include "lldb/Target/ThreadPlanStepInRange.h"
Jim Ingham22777012010-09-23 02:01:19 +000032
33using namespace lldb;
34using namespace lldb_private;
35
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000036static ConstString g_this = ConstString("this");
37
Alex Langford056f6f12019-06-08 18:45:00 +000038char CPPLanguageRuntime::ID = 0;
39
Jim Ingham22777012010-09-23 02:01:19 +000040// Destructor
Kate Stoneb9c1b512016-09-06 20:57:50 +000041CPPLanguageRuntime::~CPPLanguageRuntime() {}
42
43CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
44 : LanguageRuntime(process) {}
45
Alex Langfordd7fcee62019-07-01 20:36:33 +000046bool CPPLanguageRuntime::IsWhitelistedRuntimeValue(ConstString name) {
47 return name == g_this;
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000048}
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050bool CPPLanguageRuntime::GetObjectDescription(Stream &str,
51 ValueObject &object) {
52 // C++ has no generic way to do this.
53 return false;
Jim Ingham22777012010-09-23 02:01:19 +000054}
55
Kate Stoneb9c1b512016-09-06 20:57:50 +000056bool CPPLanguageRuntime::GetObjectDescription(
57 Stream &str, Value &value, ExecutionContextScope *exe_scope) {
58 // C++ has no generic way to do this.
59 return false;
Jim Ingham6c68fb42010-09-30 00:54:27 +000060}
Shafik Yaghmour443e20b2018-09-11 20:58:28 +000061
62CPPLanguageRuntime::LibCppStdFunctionCallableInfo
63CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo(
64 lldb::ValueObjectSP &valobj_sp) {
65 LibCppStdFunctionCallableInfo optional_info;
66
67 if (!valobj_sp)
68 return optional_info;
69
70 // Member __f_ has type __base*, the contents of which will hold:
71 // 1) a vtable entry which may hold type information needed to discover the
72 // lambda being called
73 // 2) possibly hold a pointer to the callable object
74 // e.g.
75 //
76 // (lldb) frame var -R f_display
77 // (std::__1::function<void (int)>) f_display = {
78 // __buf_ = {
79 // …
80 // }
81 // __f_ = 0x00007ffeefbffa00
82 // }
83 // (lldb) memory read -fA 0x00007ffeefbffa00
84 // 0x7ffeefbffa00: ... `vtable for std::__1::__function::__func<void (*) ...
85 // 0x7ffeefbffa08: ... `print_num(int) at std_function_cppreference_exam ...
86 //
87 // We will be handling five cases below, std::function is wrapping:
88 //
89 // 1) a lambda we know at compile time. We will obtain the name of the lambda
90 // from the first template pameter from __func's vtable. We will look up
91 // the lambda's operator()() and obtain the line table entry.
92 // 2) a lambda we know at runtime. A pointer to the lambdas __invoke method
93 // will be stored after the vtable. We will obtain the lambdas name from
94 // this entry and lookup operator()() and obtain the line table entry.
95 // 3) a callable object via operator()(). We will obtain the name of the
96 // object from the first template parameter from __func's vtable. We will
97 // look up the objectc operator()() and obtain the line table entry.
98 // 4) a member function. A pointer to the function will stored after the
99 // we will obtain the name from this pointer.
100 // 5) a free function. A pointer to the function will stored after the vtable
101 // we will obtain the name from this pointer.
102 ValueObjectSP member__f_(
103 valobj_sp->GetChildMemberWithName(ConstString("__f_"), true));
Shafik Yaghmour99bc2b22018-12-10 23:26:38 +0000104
105 if (member__f_) {
106 ValueObjectSP sub_member__f_(
107 member__f_->GetChildMemberWithName(ConstString("__f_"), true));
108
109 if (sub_member__f_)
110 member__f_ = sub_member__f_;
111 }
112
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000113 lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0);
114
115 optional_info.member__f_pointer_value = member__f_pointer_value;
116
117 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
118 Process *process = exe_ctx.GetProcessPtr();
119
120 if (process == nullptr)
121 return optional_info;
122
123 uint32_t address_size = process->GetAddressByteSize();
124 Status status;
125
126 // First item pointed to by __f_ should be the pointer to the vtable for
127 // a __base object.
128 lldb::addr_t vtable_address =
129 process->ReadPointerFromMemory(member__f_pointer_value, status);
130
131 if (status.Fail())
132 return optional_info;
133
134 lldb::addr_t address_after_vtable = member__f_pointer_value + address_size;
135 // As commened above we may not have a function pointer but if we do we will
136 // need it.
137 lldb::addr_t possible_function_address =
138 process->ReadPointerFromMemory(address_after_vtable, status);
139
140 if (status.Fail())
141 return optional_info;
142
143 Target &target = process->GetTarget();
144
145 if (target.GetSectionLoadList().IsEmpty())
146 return optional_info;
147
148 Address vtable_addr_resolved;
149 SymbolContext sc;
150 Symbol *symbol;
151
152 if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address,
153 vtable_addr_resolved))
154 return optional_info;
155
156 target.GetImages().ResolveSymbolContextForAddress(
157 vtable_addr_resolved, eSymbolContextEverything, sc);
158 symbol = sc.symbol;
159
160 if (symbol == nullptr)
161 return optional_info;
162
163 llvm::StringRef vtable_name(symbol->GetName().GetCString());
164 bool found_expected_start_string =
165 vtable_name.startswith("vtable for std::__1::__function::__func<");
166
167 if (!found_expected_start_string)
168 return optional_info;
169
170 // Given case 1 or 3 we have a vtable name, we are want to extract the first
171 // template parameter
172 //
173 // ... __func<main::$_0, std::__1::allocator<main::$_0> ...
174 // ^^^^^^^^^
175 //
176 // We do this by find the first < and , and extracting in between.
177 //
178 // This covers the case of the lambda known at compile time.
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000179 size_t first_open_angle_bracket = vtable_name.find('<') + 1;
Jonas Devliegherec712bac2019-03-28 18:10:14 +0000180 size_t first_comma = vtable_name.find(',');
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000181
182 llvm::StringRef first_template_parameter =
183 vtable_name.slice(first_open_angle_bracket, first_comma);
184
185 Address function_address_resolved;
186
187 // Setup for cases 2, 4 and 5 we have a pointer to a function after the
188 // vtable. We will use a process of elimination to drop through each case
189 // and obtain the data we need.
190 if (target.GetSectionLoadList().ResolveLoadAddress(
191 possible_function_address, function_address_resolved)) {
192 target.GetImages().ResolveSymbolContextForAddress(
193 function_address_resolved, eSymbolContextEverything, sc);
194 symbol = sc.symbol;
195 }
196
197 auto get_name = [&first_template_parameter, &symbol]() {
198 // Given case 1:
199 //
200 // main::$_0
201 //
202 // we want to append ::operator()()
203 if (first_template_parameter.contains("$_"))
204 return llvm::Regex::escape(first_template_parameter.str()) +
205 R"(::operator\(\)\(.*\))";
206
Konrad Kleine248a1302019-05-23 11:14:47 +0000207 if (symbol != nullptr &&
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000208 symbol->GetName().GetStringRef().contains("__invoke")) {
209
210 llvm::StringRef symbol_name = symbol->GetName().GetStringRef();
211 size_t pos2 = symbol_name.find_last_of(':');
212
213 // Given case 2:
214 //
215 // main::$_1::__invoke(...)
216 //
217 // We want to slice off __invoke(...) and append operator()()
218 std::string lambda_operator =
219 llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) +
220 R"(operator\(\)\(.*\))";
221
222 return lambda_operator;
223 }
224
225 // Case 3
226 return first_template_parameter.str() + R"(::operator\(\)\(.*\))";
227 ;
228 };
229
230 std::string func_to_match = get_name();
231
232 SymbolContextList scl;
233
Shafik Yaghmour9acaceb2019-05-13 16:48:06 +0000234 target.GetImages().FindSymbolsMatchingRegExAndType(
235 RegularExpression{R"(^)" + func_to_match}, eSymbolTypeAny, scl, true);
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000236
237 // Case 1,2 or 3
238 if (scl.GetSize() >= 1) {
239 SymbolContext sc2 = scl[0];
240
241 AddressRange range;
242 sc2.GetAddressRange(eSymbolContextEverything, 0, false, range);
243
244 Address address = range.GetBaseAddress();
245
246 Address addr;
247 if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target),
248 addr)) {
249 LineEntry line_entry;
250 addr.CalculateSymbolContextLineEntry(line_entry);
251
252 if (first_template_parameter.contains("$_") ||
253 (symbol != nullptr &&
254 symbol->GetName().GetStringRef().contains("__invoke"))) {
255 // Case 1 and 2
256 optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda;
257 } else {
258 // Case 3
259 optional_info.callable_case =
260 LibCppStdFunctionCallableCase::CallableObject;
261 }
262
263 optional_info.callable_symbol = *symbol;
264 optional_info.callable_line_entry = line_entry;
265 optional_info.callable_address = addr;
266 return optional_info;
267 }
268 }
269
270 // Case 4 or 5
Adrian Prantl510f4092019-06-25 19:50:12 +0000271 if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for")) {
Shafik Yaghmour443e20b2018-09-11 20:58:28 +0000272 optional_info.callable_case =
273 LibCppStdFunctionCallableCase::FreeOrMemberFunction;
274 optional_info.callable_address = function_address_resolved;
275 optional_info.callable_symbol = *symbol;
276
277 return optional_info;
278 }
279
280 return optional_info;
281}
Shafik Yaghmouraa302682018-10-12 17:20:39 +0000282
283lldb::ThreadPlanSP
284CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread,
285 bool stop_others) {
286 ThreadPlanSP ret_plan_sp;
287
288 lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
289
290 TargetSP target_sp(thread.CalculateTarget());
291
292 if (target_sp->GetSectionLoadList().IsEmpty())
293 return ret_plan_sp;
294
295 Address pc_addr_resolved;
296 SymbolContext sc;
297 Symbol *symbol;
298
299 if (!target_sp->GetSectionLoadList().ResolveLoadAddress(curr_pc,
300 pc_addr_resolved))
301 return ret_plan_sp;
302
303 target_sp->GetImages().ResolveSymbolContextForAddress(
304 pc_addr_resolved, eSymbolContextEverything, sc);
305 symbol = sc.symbol;
306
307 if (symbol == nullptr)
308 return ret_plan_sp;
309
310 llvm::StringRef function_name(symbol->GetName().GetCString());
311
312 // Handling the case where we are attempting to step into std::function.
313 // The behavior will be that we will attempt to obtain the wrapped
314 // callable via FindLibCppStdFunctionCallableInfo() and if we find it we
315 // will return a ThreadPlanRunToAddress to the callable. Therefore we will
316 // step into the wrapped callable.
317 //
318 bool found_expected_start_string =
319 function_name.startswith("std::__1::function<");
320
321 if (!found_expected_start_string)
322 return ret_plan_sp;
323
324 AddressRange range_of_curr_func;
325 sc.GetAddressRange(eSymbolContextEverything, 0, false, range_of_curr_func);
326
327 StackFrameSP frame = thread.GetStackFrameAtIndex(0);
328
329 if (frame) {
Adrian Prantl1db0f0c2019-05-02 23:07:23 +0000330 ValueObjectSP value_sp = frame->FindVariable(g_this);
Shafik Yaghmouraa302682018-10-12 17:20:39 +0000331
332 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
333 FindLibCppStdFunctionCallableInfo(value_sp);
334
335 if (callable_info.callable_case != LibCppStdFunctionCallableCase::Invalid &&
336 value_sp->GetValueIsValid()) {
337 // We found the std::function wrapped callable and we have its address.
338 // We now create a ThreadPlan to run to the callable.
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000339 ret_plan_sp = std::make_shared<ThreadPlanRunToAddress>(
340 thread, callable_info.callable_address, stop_others);
Shafik Yaghmouraa302682018-10-12 17:20:39 +0000341 return ret_plan_sp;
342 } else {
343 // We are in std::function but we could not obtain the callable.
344 // We create a ThreadPlan to keep stepping through using the address range
345 // of the current function.
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000346 ret_plan_sp = std::make_shared<ThreadPlanStepInRange>(
347 thread, range_of_curr_func, sc, eOnlyThisThread, eLazyBoolYes,
348 eLazyBoolYes);
Shafik Yaghmouraa302682018-10-12 17:20:39 +0000349 return ret_plan_sp;
350 }
351 }
352
353 return ret_plan_sp;
354}