/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ItaniumABILanguageRuntime.cpp -------------------------------------===// |
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 | | #include "ItaniumABILanguageRuntime.h" |
10 | | |
11 | | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
12 | | #include "lldb/Breakpoint/BreakpointLocation.h" |
13 | | #include "lldb/Core/Mangled.h" |
14 | | #include "lldb/Core/Module.h" |
15 | | #include "lldb/Core/PluginManager.h" |
16 | | #include "lldb/Core/ValueObject.h" |
17 | | #include "lldb/Core/ValueObjectMemory.h" |
18 | | #include "lldb/DataFormatters/FormattersHelpers.h" |
19 | | #include "lldb/Expression/DiagnosticManager.h" |
20 | | #include "lldb/Expression/FunctionCaller.h" |
21 | | #include "lldb/Interpreter/CommandObject.h" |
22 | | #include "lldb/Interpreter/CommandObjectMultiword.h" |
23 | | #include "lldb/Interpreter/CommandReturnObject.h" |
24 | | #include "lldb/Symbol/Symbol.h" |
25 | | #include "lldb/Symbol/SymbolFile.h" |
26 | | #include "lldb/Symbol/TypeList.h" |
27 | | #include "lldb/Target/Process.h" |
28 | | #include "lldb/Target/RegisterContext.h" |
29 | | #include "lldb/Target/SectionLoadList.h" |
30 | | #include "lldb/Target/StopInfo.h" |
31 | | #include "lldb/Target/Target.h" |
32 | | #include "lldb/Target/Thread.h" |
33 | | #include "lldb/Utility/ConstString.h" |
34 | | #include "lldb/Utility/LLDBLog.h" |
35 | | #include "lldb/Utility/Log.h" |
36 | | #include "lldb/Utility/Scalar.h" |
37 | | #include "lldb/Utility/Status.h" |
38 | | |
39 | | #include <vector> |
40 | | |
41 | | using namespace lldb; |
42 | | using namespace lldb_private; |
43 | | |
44 | | LLDB_PLUGIN_DEFINE_ADV(ItaniumABILanguageRuntime, CXXItaniumABI) |
45 | | |
46 | | static const char *vtable_demangled_prefix = "vtable for "; |
47 | | |
48 | | char ItaniumABILanguageRuntime::ID = 0; |
49 | | |
50 | 247k | bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { |
51 | 247k | const bool check_cxx = true; |
52 | 247k | const bool check_objc = false; |
53 | 247k | return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx, |
54 | 247k | check_objc); |
55 | 247k | } |
56 | | |
57 | | TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( |
58 | | ValueObject &in_value, lldb::addr_t original_ptr, |
59 | 274 | lldb::addr_t vtable_load_addr) { |
60 | 274 | if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { |
61 | | // Find the symbol that contains the "vtable_load_addr" address |
62 | 274 | Address vtable_addr; |
63 | 274 | Target &target = m_process->GetTarget(); |
64 | 274 | if (!target.GetSectionLoadList().IsEmpty()) { |
65 | 274 | if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, |
66 | 274 | vtable_addr)) { |
67 | | // See if we have cached info for this type already |
68 | 64 | TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); |
69 | 64 | if (type_info) |
70 | 20 | return type_info; |
71 | | |
72 | 44 | SymbolContext sc; |
73 | 44 | target.GetImages().ResolveSymbolContextForAddress( |
74 | 44 | vtable_addr, eSymbolContextSymbol, sc); |
75 | 44 | Symbol *symbol = sc.symbol; |
76 | 44 | if (symbol != nullptr) { |
77 | 32 | const char *name = |
78 | 32 | symbol->GetMangled().GetDemangledName().AsCString(); |
79 | 32 | if (name && strstr(name, vtable_demangled_prefix) == name) { |
80 | 14 | Log *log = GetLog(LLDBLog::Object); |
81 | 14 | LLDB_LOGF(log, |
82 | 14 | "0x%16.16" PRIx64 |
83 | 14 | ": static-type = '%s' has vtable symbol '%s'\n", |
84 | 14 | original_ptr, in_value.GetTypeName().GetCString(), name); |
85 | | // We are a C++ class, that's good. Get the class name and look it |
86 | | // up: |
87 | 14 | const char *class_name = name + strlen(vtable_demangled_prefix); |
88 | | // We know the class name is absolute, so tell FindTypes that by |
89 | | // prefixing it with the root namespace: |
90 | 14 | std::string lookup_name("::"); |
91 | 14 | lookup_name.append(class_name); |
92 | | |
93 | 14 | type_info.SetName(class_name); |
94 | 14 | const bool exact_match = true; |
95 | 14 | TypeList class_types; |
96 | | |
97 | | // First look in the module that the vtable symbol came from and |
98 | | // look for a single exact match. |
99 | 14 | llvm::DenseSet<SymbolFile *> searched_symbol_files; |
100 | 14 | if (sc.module_sp) |
101 | 14 | sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, |
102 | 14 | searched_symbol_files, class_types); |
103 | | |
104 | | // If we didn't find a symbol, then move on to the entire module |
105 | | // list in the target and get as many unique matches as possible |
106 | 14 | if (class_types.Empty()) |
107 | 1 | target.GetImages().FindTypes(nullptr, ConstString(lookup_name), |
108 | 1 | exact_match, UINT32_MAX, |
109 | 1 | searched_symbol_files, class_types); |
110 | | |
111 | 14 | lldb::TypeSP type_sp; |
112 | 14 | if (class_types.Empty()) { |
113 | 1 | LLDB_LOGF(log, "0x%16.16" PRIx64 ": is not dynamic\n", |
114 | 1 | original_ptr); |
115 | 1 | return TypeAndOrName(); |
116 | 1 | } |
117 | 13 | if (class_types.GetSize() == 1) { |
118 | 13 | type_sp = class_types.GetTypeAtIndex(0); |
119 | 13 | if (type_sp) { |
120 | 13 | if (TypeSystemClang::IsCXXClassType( |
121 | 13 | type_sp->GetForwardCompilerType())) { |
122 | 13 | LLDB_LOGF( |
123 | 13 | log, |
124 | 13 | "0x%16.16" PRIx64 |
125 | 13 | ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 |
126 | 13 | "}, type-name='%s'\n", |
127 | 13 | original_ptr, in_value.GetTypeName().AsCString(), |
128 | 13 | type_sp->GetID(), type_sp->GetName().GetCString()); |
129 | 13 | type_info.SetTypeSP(type_sp); |
130 | 13 | } |
131 | 13 | } |
132 | 13 | } else { |
133 | 0 | size_t i; |
134 | 0 | if (log) { |
135 | 0 | for (i = 0; i < class_types.GetSize(); i++) { |
136 | 0 | type_sp = class_types.GetTypeAtIndex(i); |
137 | 0 | if (type_sp) { |
138 | 0 | LLDB_LOGF( |
139 | 0 | log, |
140 | 0 | "0x%16.16" PRIx64 |
141 | 0 | ": static-type = '%s' has multiple matching dynamic " |
142 | 0 | "types: uid={0x%" PRIx64 "}, type-name='%s'\n", |
143 | 0 | original_ptr, in_value.GetTypeName().AsCString(), |
144 | 0 | type_sp->GetID(), type_sp->GetName().GetCString()); |
145 | 0 | } |
146 | 0 | } |
147 | 0 | } |
148 | |
|
149 | 0 | for (i = 0; i < class_types.GetSize(); i++) { |
150 | 0 | type_sp = class_types.GetTypeAtIndex(i); |
151 | 0 | if (type_sp) { |
152 | 0 | if (TypeSystemClang::IsCXXClassType( |
153 | 0 | type_sp->GetForwardCompilerType())) { |
154 | 0 | LLDB_LOGF( |
155 | 0 | log, |
156 | 0 | "0x%16.16" PRIx64 ": static-type = '%s' has multiple " |
157 | 0 | "matching dynamic types, picking " |
158 | 0 | "this one: uid={0x%" PRIx64 "}, type-name='%s'\n", |
159 | 0 | original_ptr, in_value.GetTypeName().AsCString(), |
160 | 0 | type_sp->GetID(), type_sp->GetName().GetCString()); |
161 | 0 | type_info.SetTypeSP(type_sp); |
162 | 0 | } |
163 | 0 | } |
164 | 0 | } |
165 | |
|
166 | 0 | if (log) { |
167 | 0 | LLDB_LOGF(log, |
168 | 0 | "0x%16.16" PRIx64 |
169 | 0 | ": static-type = '%s' has multiple matching dynamic " |
170 | 0 | "types, didn't find a C++ match\n", |
171 | 0 | original_ptr, in_value.GetTypeName().AsCString()); |
172 | 0 | } |
173 | 0 | } |
174 | 13 | if (type_info) |
175 | 13 | SetDynamicTypeInfo(vtable_addr, type_info); |
176 | 13 | return type_info; |
177 | 14 | } |
178 | 32 | } |
179 | 44 | } |
180 | 274 | } |
181 | 274 | } |
182 | 240 | return TypeAndOrName(); |
183 | 274 | } |
184 | | |
185 | | bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( |
186 | | ValueObject &in_value, lldb::DynamicValueType use_dynamic, |
187 | | TypeAndOrName &class_type_or_name, Address &dynamic_address, |
188 | 534 | Value::ValueType &value_type) { |
189 | | // For Itanium, if the type has a vtable pointer in the object, it will be at |
190 | | // offset 0 in the object. That will point to the "address point" within the |
191 | | // vtable (not the beginning of the vtable.) We can then look up the symbol |
192 | | // containing this "address point" and that symbol's name demangled will |
193 | | // contain the full class name. The second pointer above the "address point" |
194 | | // is the "offset_to_top". We'll use that to get the start of the value |
195 | | // object which holds the dynamic type. |
196 | | // |
197 | | |
198 | 534 | class_type_or_name.Clear(); |
199 | 534 | value_type = Value::ValueType::Scalar; |
200 | | |
201 | | // Only a pointer or reference type can have a different dynamic and static |
202 | | // type: |
203 | 534 | if (!CouldHaveDynamicValue(in_value)) |
204 | 0 | return false; |
205 | | |
206 | | // First job, pull out the address at 0 offset from the object. |
207 | 534 | AddressType address_type; |
208 | 534 | lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); |
209 | 534 | if (original_ptr == LLDB_INVALID_ADDRESS) |
210 | 0 | return false; |
211 | | |
212 | 534 | ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); |
213 | | |
214 | 534 | Process *process = exe_ctx.GetProcessPtr(); |
215 | | |
216 | 534 | if (process == nullptr) |
217 | 0 | return false; |
218 | | |
219 | 534 | Status error; |
220 | 534 | const lldb::addr_t vtable_address_point = |
221 | 534 | process->ReadPointerFromMemory(original_ptr, error); |
222 | | |
223 | 534 | if (!error.Success() || vtable_address_point == 274 LLDB_INVALID_ADDRESS274 ) |
224 | 260 | return false; |
225 | | |
226 | 274 | class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, |
227 | 274 | vtable_address_point); |
228 | | |
229 | 274 | if (!class_type_or_name) |
230 | 241 | return false; |
231 | | |
232 | 33 | CompilerType type = class_type_or_name.GetCompilerType(); |
233 | | // There can only be one type with a given name, so we've just found |
234 | | // duplicate definitions, and this one will do as well as any other. We |
235 | | // don't consider something to have a dynamic type if it is the same as |
236 | | // the static type. So compare against the value we were handed. |
237 | 33 | if (!type) |
238 | 0 | return true; |
239 | | |
240 | 33 | if (TypeSystemClang::AreTypesSame(in_value.GetCompilerType(), type)) { |
241 | | // The dynamic type we found was the same type, so we don't have a |
242 | | // dynamic type here... |
243 | 0 | return false; |
244 | 0 | } |
245 | | |
246 | | // The offset_to_top is two pointers above the vtable pointer. |
247 | 33 | const uint32_t addr_byte_size = process->GetAddressByteSize(); |
248 | 33 | const lldb::addr_t offset_to_top_location = |
249 | 33 | vtable_address_point - 2 * addr_byte_size; |
250 | | // Watch for underflow, offset_to_top_location should be less than |
251 | | // vtable_address_point |
252 | 33 | if (offset_to_top_location >= vtable_address_point) |
253 | 0 | return false; |
254 | 33 | const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( |
255 | 33 | offset_to_top_location, addr_byte_size, INT64_MIN, error); |
256 | | |
257 | 33 | if (offset_to_top == INT64_MIN) |
258 | 0 | return false; |
259 | | // So the dynamic type is a value that starts at offset_to_top above |
260 | | // the original address. |
261 | 33 | lldb::addr_t dynamic_addr = original_ptr + offset_to_top; |
262 | 33 | if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( |
263 | 33 | dynamic_addr, dynamic_address)) { |
264 | 33 | dynamic_address.SetRawAddress(dynamic_addr); |
265 | 33 | } |
266 | 33 | return true; |
267 | 33 | } |
268 | | |
269 | | TypeAndOrName ItaniumABILanguageRuntime::FixUpDynamicType( |
270 | 66 | const TypeAndOrName &type_and_or_name, ValueObject &static_value) { |
271 | 66 | CompilerType static_type(static_value.GetCompilerType()); |
272 | 66 | Flags static_type_flags(static_type.GetTypeInfo()); |
273 | | |
274 | 66 | TypeAndOrName ret(type_and_or_name); |
275 | 66 | if (type_and_or_name.HasType()) { |
276 | | // The type will always be the type of the dynamic object. If our parent's |
277 | | // type was a pointer, then our type should be a pointer to the type of the |
278 | | // dynamic object. If a reference, then the original type should be |
279 | | // okay... |
280 | 66 | CompilerType orig_type = type_and_or_name.GetCompilerType(); |
281 | 66 | CompilerType corrected_type = orig_type; |
282 | 66 | if (static_type_flags.AllSet(eTypeIsPointer)) |
283 | 58 | corrected_type = orig_type.GetPointerType(); |
284 | 8 | else if (static_type_flags.AllSet(eTypeIsReference)) |
285 | 8 | corrected_type = orig_type.GetLValueReferenceType(); |
286 | 66 | ret.SetCompilerType(corrected_type); |
287 | 66 | } else { |
288 | | // If we are here we need to adjust our dynamic type name to include the |
289 | | // correct & or * symbol |
290 | 0 | std::string corrected_name(type_and_or_name.GetName().GetCString()); |
291 | 0 | if (static_type_flags.AllSet(eTypeIsPointer)) |
292 | 0 | corrected_name.append(" *"); |
293 | 0 | else if (static_type_flags.AllSet(eTypeIsReference)) |
294 | 0 | corrected_name.append(" &"); |
295 | | // the parent type should be a correctly pointer'ed or referenc'ed type |
296 | 0 | ret.SetCompilerType(static_type); |
297 | 0 | ret.SetName(corrected_name.c_str()); |
298 | 0 | } |
299 | 66 | return ret; |
300 | 66 | } |
301 | | |
302 | | // Static Functions |
303 | | LanguageRuntime * |
304 | | ItaniumABILanguageRuntime::CreateInstance(Process *process, |
305 | 403k | lldb::LanguageType language) { |
306 | | // FIXME: We have to check the process and make sure we actually know that |
307 | | // this process supports |
308 | | // the Itanium ABI. |
309 | 403k | if (language == eLanguageTypeC_plus_plus || |
310 | 403k | language == eLanguageTypeC_plus_plus_03401k || |
311 | 403k | language == eLanguageTypeC_plus_plus_11401k || |
312 | 403k | language == eLanguageTypeC_plus_plus_14400k ) |
313 | 2.88k | return new ItaniumABILanguageRuntime(process); |
314 | 400k | else |
315 | 400k | return nullptr; |
316 | 403k | } |
317 | | |
318 | | class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed { |
319 | | public: |
320 | | CommandObjectMultiwordItaniumABI_Demangle(CommandInterpreter &interpreter) |
321 | 6.04k | : CommandObjectParsed( |
322 | 6.04k | interpreter, "demangle", "Demangle a C++ mangled name.", |
323 | 6.04k | "language cplusplus demangle [<mangled-name> ...]") { |
324 | 6.04k | CommandArgumentEntry arg; |
325 | 6.04k | CommandArgumentData index_arg; |
326 | | |
327 | | // Define the first (and only) variant of this arg. |
328 | 6.04k | index_arg.arg_type = eArgTypeSymbol; |
329 | 6.04k | index_arg.arg_repetition = eArgRepeatPlus; |
330 | | |
331 | | // There is only one variant this argument could be; put it into the |
332 | | // argument entry. |
333 | 6.04k | arg.push_back(index_arg); |
334 | | |
335 | | // Push the data for the first argument into the m_arguments vector. |
336 | 6.04k | m_arguments.push_back(arg); |
337 | 6.04k | } |
338 | | |
339 | 6.03k | ~CommandObjectMultiwordItaniumABI_Demangle() override = default; |
340 | | |
341 | | protected: |
342 | 4 | bool DoExecute(Args &command, CommandReturnObject &result) override { |
343 | 4 | bool demangled_any = false; |
344 | 4 | bool error_any = false; |
345 | 5 | for (auto &entry : command.entries()) { |
346 | 5 | if (entry.ref().empty()) |
347 | 0 | continue; |
348 | | |
349 | | // the actual Mangled class should be strict about this, but on the |
350 | | // command line if you're copying mangled names out of 'nm' on Darwin, |
351 | | // they will come out with an extra underscore - be willing to strip this |
352 | | // on behalf of the user. This is the moral equivalent of the -_/-n |
353 | | // options to c++filt |
354 | 5 | auto name = entry.ref(); |
355 | 5 | if (name.startswith("__Z")) |
356 | 1 | name = name.drop_front(); |
357 | | |
358 | 5 | Mangled mangled(name); |
359 | 5 | if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) { |
360 | 3 | ConstString demangled(mangled.GetDisplayDemangledName()); |
361 | 3 | demangled_any = true; |
362 | 3 | result.AppendMessageWithFormat("%s ---> %s\n", entry.c_str(), |
363 | 3 | demangled.GetCString()); |
364 | 3 | } else { |
365 | 2 | error_any = true; |
366 | 2 | result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", |
367 | 2 | entry.ref().str().c_str()); |
368 | 2 | } |
369 | 5 | } |
370 | | |
371 | 4 | result.SetStatus( |
372 | 4 | error_any ? lldb::eReturnStatusFailed2 |
373 | 4 | : (2 demangled_any2 ? lldb::eReturnStatusSuccessFinishResult2 |
374 | 2 | : lldb::eReturnStatusSuccessFinishNoResult0 )); |
375 | 4 | return result.Succeeded(); |
376 | 4 | } |
377 | | }; |
378 | | |
379 | | class CommandObjectMultiwordItaniumABI : public CommandObjectMultiword { |
380 | | public: |
381 | | CommandObjectMultiwordItaniumABI(CommandInterpreter &interpreter) |
382 | 6.04k | : CommandObjectMultiword( |
383 | 6.04k | interpreter, "cplusplus", |
384 | 6.04k | "Commands for operating on the C++ language runtime.", |
385 | 6.04k | "cplusplus <subcommand> [<subcommand-options>]") { |
386 | 6.04k | LoadSubCommand( |
387 | 6.04k | "demangle", |
388 | 6.04k | CommandObjectSP( |
389 | 6.04k | new CommandObjectMultiwordItaniumABI_Demangle(interpreter))); |
390 | 6.04k | } |
391 | | |
392 | 6.03k | ~CommandObjectMultiwordItaniumABI() override = default; |
393 | | }; |
394 | | |
395 | 3.92k | void ItaniumABILanguageRuntime::Initialize() { |
396 | 3.92k | PluginManager::RegisterPlugin( |
397 | 3.92k | GetPluginNameStatic(), "Itanium ABI for the C++ language", CreateInstance, |
398 | 6.04k | [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP { |
399 | 6.04k | return CommandObjectSP( |
400 | 6.04k | new CommandObjectMultiwordItaniumABI(interpreter)); |
401 | 6.04k | }); |
402 | 3.92k | } |
403 | | |
404 | 3.92k | void ItaniumABILanguageRuntime::Terminate() { |
405 | 3.92k | PluginManager::UnregisterPlugin(CreateInstance); |
406 | 3.92k | } |
407 | | |
408 | | BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( |
409 | 6 | const BreakpointSP &bkpt, bool catch_bp, bool throw_bp) { |
410 | 6 | return CreateExceptionResolver(bkpt, catch_bp, throw_bp, false); |
411 | 6 | } |
412 | | |
413 | | BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( |
414 | | const BreakpointSP &bkpt, bool catch_bp, bool throw_bp, |
415 | 992 | bool for_expressions) { |
416 | | // One complication here is that most users DON'T want to stop at |
417 | | // __cxa_allocate_expression, but until we can do anything better with |
418 | | // predicting unwinding the expression parser does. So we have two forms of |
419 | | // the exception breakpoints, one for expressions that leaves out |
420 | | // __cxa_allocate_exception, and one that includes it. The |
421 | | // SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in |
422 | | // the runtime the former. |
423 | 992 | static const char *g_catch_name = "__cxa_begin_catch"; |
424 | 992 | static const char *g_throw_name1 = "__cxa_throw"; |
425 | 992 | static const char *g_throw_name2 = "__cxa_rethrow"; |
426 | 992 | static const char *g_exception_throw_name = "__cxa_allocate_exception"; |
427 | 992 | std::vector<const char *> exception_names; |
428 | 992 | exception_names.reserve(4); |
429 | 992 | if (catch_bp) |
430 | 2 | exception_names.push_back(g_catch_name); |
431 | | |
432 | 992 | if (throw_bp) { |
433 | 992 | exception_names.push_back(g_throw_name1); |
434 | 992 | exception_names.push_back(g_throw_name2); |
435 | 992 | } |
436 | | |
437 | 992 | if (for_expressions) |
438 | 986 | exception_names.push_back(g_exception_throw_name); |
439 | | |
440 | 992 | BreakpointResolverSP resolver_sp(new BreakpointResolverName( |
441 | 992 | bkpt, exception_names.data(), exception_names.size(), |
442 | 992 | eFunctionNameTypeBase, eLanguageTypeUnknown, 0, eLazyBoolNo)); |
443 | | |
444 | 992 | return resolver_sp; |
445 | 992 | } |
446 | | |
447 | 992 | lldb::SearchFilterSP ItaniumABILanguageRuntime::CreateExceptionSearchFilter() { |
448 | 992 | Target &target = m_process->GetTarget(); |
449 | | |
450 | 992 | FileSpecList filter_modules; |
451 | 992 | if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) { |
452 | | // Limit the number of modules that are searched for these breakpoints for |
453 | | // Apple binaries. |
454 | 992 | filter_modules.EmplaceBack("libc++abi.dylib"); |
455 | 992 | filter_modules.EmplaceBack("libSystem.B.dylib"); |
456 | 992 | filter_modules.EmplaceBack("libc++abi.1.0.dylib"); |
457 | 992 | filter_modules.EmplaceBack("libc++abi.1.dylib"); |
458 | 992 | } |
459 | 992 | return target.GetSearchFilterForModuleList(&filter_modules); |
460 | 992 | } |
461 | | |
462 | | lldb::BreakpointSP ItaniumABILanguageRuntime::CreateExceptionBreakpoint( |
463 | 986 | bool catch_bp, bool throw_bp, bool for_expressions, bool is_internal) { |
464 | 986 | Target &target = m_process->GetTarget(); |
465 | 986 | FileSpecList filter_modules; |
466 | 986 | BreakpointResolverSP exception_resolver_sp = |
467 | 986 | CreateExceptionResolver(nullptr, catch_bp, throw_bp, for_expressions); |
468 | 986 | SearchFilterSP filter_sp(CreateExceptionSearchFilter()); |
469 | 986 | const bool hardware = false; |
470 | 986 | const bool resolve_indirect_functions = false; |
471 | 986 | return target.CreateBreakpoint(filter_sp, exception_resolver_sp, is_internal, |
472 | 986 | hardware, resolve_indirect_functions); |
473 | 986 | } |
474 | | |
475 | 3.36k | void ItaniumABILanguageRuntime::SetExceptionBreakpoints() { |
476 | 3.36k | if (!m_process) |
477 | 0 | return; |
478 | | |
479 | 3.36k | const bool catch_bp = false; |
480 | 3.36k | const bool throw_bp = true; |
481 | 3.36k | const bool is_internal = true; |
482 | 3.36k | const bool for_expressions = true; |
483 | | |
484 | | // For the exception breakpoints set by the Expression parser, we'll be a |
485 | | // little more aggressive and stop at exception allocation as well. |
486 | | |
487 | 3.36k | if (m_cxx_exception_bp_sp) { |
488 | 2.37k | m_cxx_exception_bp_sp->SetEnabled(true); |
489 | 2.37k | } else { |
490 | 986 | m_cxx_exception_bp_sp = CreateExceptionBreakpoint( |
491 | 986 | catch_bp, throw_bp, for_expressions, is_internal); |
492 | 986 | if (m_cxx_exception_bp_sp) |
493 | 986 | m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); |
494 | 986 | } |
495 | 3.36k | } |
496 | | |
497 | 3.35k | void ItaniumABILanguageRuntime::ClearExceptionBreakpoints() { |
498 | 3.35k | if (!m_process) |
499 | 0 | return; |
500 | | |
501 | 3.35k | if (m_cxx_exception_bp_sp) { |
502 | 3.35k | m_cxx_exception_bp_sp->SetEnabled(false); |
503 | 3.35k | } |
504 | 3.35k | } |
505 | | |
506 | 3.36k | bool ItaniumABILanguageRuntime::ExceptionBreakpointsAreSet() { |
507 | 3.36k | return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled()2.37k ; |
508 | 3.36k | } |
509 | | |
510 | | bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop( |
511 | 71 | lldb::StopInfoSP stop_reason) { |
512 | 71 | if (!m_process) |
513 | 0 | return false; |
514 | | |
515 | 71 | if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint) |
516 | 0 | return false; |
517 | | |
518 | 71 | uint64_t break_site_id = stop_reason->GetValue(); |
519 | 71 | return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( |
520 | 71 | break_site_id, m_cxx_exception_bp_sp->GetID()); |
521 | 71 | } |
522 | | |
523 | | ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( |
524 | 32 | ThreadSP thread_sp) { |
525 | 32 | if (!thread_sp->SafeToCallFunctions()) |
526 | 0 | return {}; |
527 | | |
528 | 32 | TypeSystemClangSP scratch_ts_sp = |
529 | 32 | ScratchTypeSystemClang::GetForTarget(m_process->GetTarget()); |
530 | 32 | if (!scratch_ts_sp) |
531 | 0 | return {}; |
532 | | |
533 | 32 | CompilerType voidstar = |
534 | 32 | scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType(); |
535 | | |
536 | 32 | DiagnosticManager diagnostics; |
537 | 32 | ExecutionContext exe_ctx; |
538 | 32 | EvaluateExpressionOptions options; |
539 | | |
540 | 32 | options.SetUnwindOnError(true); |
541 | 32 | options.SetIgnoreBreakpoints(true); |
542 | 32 | options.SetStopOthers(true); |
543 | 32 | options.SetTimeout(m_process->GetUtilityExpressionTimeout()); |
544 | 32 | options.SetTryAllThreads(false); |
545 | 32 | thread_sp->CalculateExecutionContext(exe_ctx); |
546 | | |
547 | 32 | const ModuleList &modules = m_process->GetTarget().GetImages(); |
548 | 32 | SymbolContextList contexts; |
549 | 32 | SymbolContext context; |
550 | | |
551 | 32 | modules.FindSymbolsWithNameAndType( |
552 | 32 | ConstString("__cxa_current_exception_type"), eSymbolTypeCode, contexts); |
553 | 32 | contexts.GetContextAtIndex(0, context); |
554 | 32 | if (!context.symbol) { |
555 | 0 | return {}; |
556 | 0 | } |
557 | 32 | Address addr = context.symbol->GetAddress(); |
558 | | |
559 | 32 | Status error; |
560 | 32 | FunctionCaller *function_caller = |
561 | 32 | m_process->GetTarget().GetFunctionCallerForLanguage( |
562 | 32 | eLanguageTypeC, voidstar, addr, ValueList(), "caller", error); |
563 | | |
564 | 32 | ExpressionResults func_call_ret; |
565 | 32 | Value results; |
566 | 32 | func_call_ret = function_caller->ExecuteFunction(exe_ctx, nullptr, options, |
567 | 32 | diagnostics, results); |
568 | 32 | if (func_call_ret != eExpressionCompleted || !error.Success()) { |
569 | 0 | return ValueObjectSP(); |
570 | 0 | } |
571 | | |
572 | 32 | size_t ptr_size = m_process->GetAddressByteSize(); |
573 | 32 | addr_t result_ptr = results.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
574 | 32 | addr_t exception_addr = |
575 | 32 | m_process->ReadPointerFromMemory(result_ptr - ptr_size, error); |
576 | | |
577 | 32 | if (!error.Success()) { |
578 | 8 | return ValueObjectSP(); |
579 | 8 | } |
580 | | |
581 | 24 | lldb_private::formatters::InferiorSizedWord exception_isw(exception_addr, |
582 | 24 | *m_process); |
583 | 24 | ValueObjectSP exception = ValueObject::CreateValueObjectFromData( |
584 | 24 | "exception", exception_isw.GetAsData(m_process->GetByteOrder()), exe_ctx, |
585 | 24 | voidstar); |
586 | 24 | ValueObjectSP dyn_exception |
587 | 24 | = exception->GetDynamicValue(eDynamicDontRunTarget); |
588 | | // If we succeed in making a dynamic value, return that: |
589 | 24 | if (dyn_exception) |
590 | 16 | return dyn_exception; |
591 | | |
592 | 8 | return exception; |
593 | 24 | } |
594 | | |
595 | | TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo( |
596 | 64 | const lldb_private::Address &vtable_addr) { |
597 | 64 | std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); |
598 | 64 | DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); |
599 | 64 | if (pos == m_dynamic_type_map.end()) |
600 | 44 | return TypeAndOrName(); |
601 | 20 | else |
602 | 20 | return pos->second; |
603 | 64 | } |
604 | | |
605 | | void ItaniumABILanguageRuntime::SetDynamicTypeInfo( |
606 | 13 | const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) { |
607 | 13 | std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); |
608 | 13 | m_dynamic_type_map[vtable_addr] = type_info; |
609 | 13 | } |